6. 1.서피스 플링거 연결 요청
-서피스 클라이언트 리모트 서비스의 역할
1.서피스 플링거 서비스의 래퍼:
서피스 플링거 서비스 기능 중 일부를 사용할 수 있도록 제공함
(서피스 생성,삭제,서피스 상태 변경)
2.애플리케이션별 레이어 관리:
서피스 클라이언트 별로 서피스에 대한 지역 식별자를 할당하고, DefaultKeyedVector에
지역식별자와 layer를 함께 추가함.
3. 레이어 상태 변경:애플리케이션이 서피스의 상태 변경(가로,세로 전환)을 서피스 클라이언트 리모트
서비스에게 요청한다.
4.애플리케이션 레이어의 생명 주기 관리:
서피스 생성을 요청한 애플리케이션이 비정상적으로 동작을 종료하더라도 관리하고 있는 서피스와
관련 자원을 서피스 클라이언트의 소멸자에서 자동으로 해제해 준다.
(why? Client class는 Refbase class를 상속 받는데 이 Refbase class는 참조하는 곳이 없어질때
자동으로 소멸자를 불러주게 된다.)
6
8. 2.노말 서피스 생성 요청 (서비스 클라이언트)
1)노말 서피스 생성 요청(C5)
Surface.java
struct surface_data_t {
public Surface()
int32_t token; 지역 식별자
{
int32_t identity; 전역 식별자
init(s,pid,name,display,w,h,format,flags);
status_t readFromParcel(const Parcel& parcel);
}
status_t writeToParcel(Parcel* parcel) const;
};
Android_view_surface.cpp
static void Surface_init
{
surface = client->createSurface(dpy, w, h, format, flags);}
sp<SurfaceControl> SurfaceComposerClient::createSurface(…)
{
ISurfaceComposerClient::surface_data_t data;
p<ISurface> surface = mClient->createSurface(&data, name, display, w, h, format, flags);
서피스 클라이언트의 createSurface를 호출한다.
서피스가 생성되면 서피스 핸들의 서비스 프록시(ISurface)가 반환된다.(C6)
Isurface 서비스 프록시는 서피스 텍스쳐 리모트 서비스의 서비스 프록시(ISurfaceTexture)를 반환하는 함수를 제공한다.
if (surface != 0) {
result = new SurfaceControl(this, surface, data, w, h, format, flags);
return된 Isurface proxy를 이용해서 SurfaceControl class를 생성한다.
이 class는 BufferQueue 리모트 서비스의 서비스 프락시를 획득하거나,서피스의 상태 변경을 할 수 있다.
}
서피스 클라이언트 리모트 서비스는 서피스 플링거 서비스의 메시지 큐에 서피스
return result; 생성 메시지를 넣는다.
} 그런면 서피스 플링거는 루퍼에서 메시지를 가져와 핸들러를 호출한다.
이 때 호출되는 핸들러가 서피스 플링거에 있는 createSurface 함수 이다.
8
9. 2.노말 서피스 생성 (서비스 서버)
sp<ISurface> Client::createSurface(ISurfaceComposerClient::surface_data_t* params, const String8& name,
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags)
{
class MessageCreateSurface : public MessageBase {
public:
MessageCreateSurface(SurfaceFlinger* flinger,
ISurfaceComposerClient::surface_data_t* params,
const String8& name, Client* client,
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags)
: flinger(flinger), params(params), client(client), name(name),
display(display), w(w), h(h), format(format), flags(flags)
{
}
sp<ISurface> getResult() const { return result; }
virtual bool handler() {
result = flinger->createSurface(params, name, client, display, w, h, format, flags);
메시지 큐의 핸들러에서 서피스 플링거의 createSurface를 불러 줌.
return true;
}
};
sp<MessageBase> msg = new MessageCreateSurface(mFlinger.get(),params, name, this, display, w, h, format, flags);
메시지 큐와 핸들러 생성(S3)
mFlinger->postMessageSync(msg); 생성된 메시지를 서피스 플링거 서비스의 메시지 큐에 넣음.(S4)
return static_cast<MessageCreateSurface*>( msg.get() )->getResult();
}
9
10. 2.노말 서피스 생성 (서비스 서버)
sp<ISurface> SurfaceFlinger::createSurface(…)
{
sp<LayerBaseClient> layer;
sp<Layer> normalLayer;
switch (flags & eFXSurfaceMask) {
case eFXSurfaceNormal:
normalLayer = createNormalSurface(client, d, w, h, flags, format);
1.노말 레이어를 생성 함.(S5)
노말 레이어 생성 시 BufferQueue 리모트 서비스가 생성 됨. 또한, SurfaceTexture 객체도 생성 됨.(S6)
layer = normalLayer;
break;
}
if (layer != 0) {
layer->initStates(w, h, flags); 2.생성된 layer 상태 초기화(S7)
ssize_t token = addClientLayer(client, layer); 3.전역 레이어 목록과 지역 레이어 목록에 추가
surfaceHandle = layer->getSurface(); 4. 서피스 핸들의 서비스 프록시(Isurface)를 반환 함.(S8)
if (surfaceHandle != 0) { mClient->createSurface 호출시 넘겨준 surface_data_t 구조체에 값을 채움.
params->token = token; 서피스 지역 식별자
params->identity = surfaceHandle->getIdentity(); 서피스 전역 식별자
}
setTransactionFlags(eTransactionNeeded); 서피스 플링거가 합성 시 참조하는 상태 플래그에 설정.
return surfaceHandle; 서피스 핸들 proxy(Isurface)를 return함.
}
10
11. 2.노말 서피스 생성 (서비스 서버)-메시지 큐와 핸들러 생성
sp<ISurface> Client::createSurface(ISurfaceComposerClient::surface_data_t* params, const String8& name,
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags)
{
sp<MessageBase> msg = new MessageCreateSurface(mFlinger.get(),params, name, this, display, w, h, format, flags);
메시지 큐와 핸들러 생성
mFlinger->postMessageSync(msg); 생성된 메시지를 서피스 플링거 서비스에게 전달(동기식)
return static_cast<MessageCreateSurface*>( msg.get() )->getResult();
}
status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime, uint32_t flags)
{
status_t res = mEventQueue.postMessage(msg, reltime);
생성된 메시지를 메시지 큐로 보냄. 이 메시지는 서피스 플링거 서비스의 네이티브 루퍼에서 처리 됨.
msg->wait(); 메시지의 핸들러가 수행이 완료 될 때 까지 기다림.
}
11
12. 2.노말 서피스 생성 (서비스 서버)-메시지 큐와 핸들러 생성
MessageQueue.cpp
status_t MessageQueue::postMessage(const sp<MessageBase>& messageHandler, nsecs_t relTime)
{
const Message dummyMessage;
if (relTime > 0) {
mLooper->sendMessageDelayed(relTime, messageHandler, dummyMessage);
} else {
mLooper->sendMessage(messageHandler, dummyMessage);
서피스 플링거 서비스 네이티브 루퍼에게 메시지 전달
}
return NO_ERROR;
}
class MessageCreateSurface : public MessageBase {
virtual bool handler() {
result = flinger->createSurface(params, name, client, display, w, h, format, flags);
메시지 큐의 핸들러에서 서피스 플링거의 createSurface를 불러 줌.
return true;
}
};
12
13. 2.노말 서피스 생성 (서비스 서버)-레이어 생성
sp<Layer> SurfaceFlinger::createNormalSurface(..) LayerBase(레이어 상태 변경 관리)
{
sp<Layer> layer = new Layer(this, display, client);
this:Surfaceflinger 인스턴스, LayerBaseClient
display:출력될 display의 번호, (클라이언트 리모트 서비스의 자원 관리
client:서피스 클라이언트
status_t err = layer->setBuffers(w, h, format, flags);
레이어 멥버 변수 초기 값 설정, 서피스 텍스처 기본 크기 결정. Layer Layer
return layer; 생성된 레이어 반환 Layer
Screenshot Dim
}
Layer class 생성 시 LayerBase의 생성자 부터 호출된다.
Layerbase.cpp
LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
: dpy(display), contentDirty(false),
sequence(uint32_t(android_atomic_inc(&sSequence))), SurfaceFlinger
sSequence 값을 sequence에 저장하고 sSequence를 1증가 시킨다. 지역 레이어 목록
sequence 변수는 동일 Z-order 값을 가지는 레이어를 정렬할때 사용 함.
전역 레이어 목록 Client 1
{
… zorder Token=1
mIdentity
} Token=2
4 4
LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, 3 1
지역 레이어 목록
const sp<Client>& client) 2 2
: LayerBase(flinger, display), mClientRef(client), 1 3 Client 2
mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
서피스 전역 식별자인 mIdentity의 값을 설정한다. Token=1
{ Token=2
}
13
14. 2.노말 서피스 생성 (서비스 서버)-레이어 생성
Layer::Layer(SurfaceFlinger* flinger,
DisplayID display, const sp<Client>& client)
: LayerBaseClient(flinger, display, client), mTextureName,(텍스쳐 번호), …
{
glGenTextures(1, &mTextureName);
서피스 플링거 서비스는 하나의 레이어를 하나의 텍스쳐로 사용하여 합성함.
따라서, 각 레이어를 구별할 수 있는 인자가 필요한데, glGenTextures에서 mTextureName에 ID를 생성 함.
}
Layer Class는 RefBase를 상속했음으로, onFirstRef()가 불림.(BufferQueue 리모트 서비스 생성)
void Layer::onFirstRef()
{
struct FrameQueuedListener : public SurfaceTexture::FrameAvailableListener {
FrameQueuedListener(Layer* layer) : mLayer(layer) { }
private:
wp<Layer> mLayer;
virtual void onFrameAvailable() {
sp<Layer> that(mLayer.promote()); void Layer::onFrameQueued() {
if (that != 0) { android_atomic_inc(&mQueuedFrames);
that->onFrameQueued(); mFlinger->signalEvent();
} }
}
};
// Creates a custom BufferQueue for SurfaceTexture to use
sp<BufferQueue> bq = new SurfaceTextureLayer();
SurfaceTextureLayer 객체를 생성 한다. SurfaceTextureLayer는 BufferQueue class를 상속 받고 있다.
BufferQueue는 서피스 플링거와 어플리케이션 사이에서 그래픽 버퍼 공유 및 버퍼 획득,전달을 담당 함.
mSurfaceTexture = new SurfaceTexture(mTextureName, true,GL_TEXTURE_EXTERNAL_OES, false, bq);
SurfaceTexture 생성 시 BufferQueue 의 포인터를 인자로 생성 함.
(SurfaceTexture 에서 BufferQueue 를 이용해서 버퍼 획득,전달을 하겠다는 의미)
mSurfaceTexture->setFrameAvailableListener(new FrameQueuedListener(this));
SurfaceTextureLayer의 listener를 FrameAvailableListener 로 등록 한다.
14
15. 2.노말 서피스 생성 (서비스 서버)-레이어 생성
mSurfaceTexture->setSynchronousMode(true);
버퍼 출력 모드를 동기식으로 설정 함.
Cf. 동기 모드: 애플리케이션이 출력 요청 한 순서대로 서피스 플링거가 합성하여 화면에 출력
비동기 모드:애플리케이션이 여러 번 출력 요청을 하더라도, 서피스 플링거 서비스는 가장 마지막에 출력 요청된 그래픽
버퍼만 화면에 출력 함.
mSurfaceTexture->setBufferCountServer(3); 트리플 버퍼 설정.
}
15
16. 2.노말 서피스 생성 (서비스 서버)-BufferQueue 리모트 서비스 생성
▶ 서피스 전달,획득 출력 요청등에 대한 모든 과정은 애플리케이션 측의 SurfaceTextureClient와 서버측의 BufferQueue 가
담당한다.
▶ BufferQueue 는 레이어 생성 시 생성 됨.
BufferQueue::BufferQueue( bool allowSynchronousMode, int bufferCount ) :
mDefaultWidth(1), 생성될 버퍼의 width
mDefaultHeight(1), 생성될 버퍼의 Height
mPixelFormat(PIXEL_FORMAT_RGBA_8888), 버퍼의 핏셀 포맷
…
mBufferCount(mMinAsyncBufferSlots), 클라이언트와 서버 간에 동시에 유지하고 있는 버퍼 슬롯의 수
mClientBufferCount(0), 클라이언트에서 요청한 버퍼 슬롯의 수
mServerBufferCount(mMinAsyncBufferSlots), 서버 측에서 요청한 버퍼 슬롯의 수
mSynchronousMode(false), 버퍼 출력 모드 (true:동기식, false:비동기식)
…
{
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
서피스 플링거 서비스에게 GraphicBufferAlloc 리모트 서비스의 생성을 요청 하고, IGraphicBufferAlloc 서비스 프록시를
획득한다.
}
Surfaceflinger.cpp
sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
{
sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
return gba;
}
BufferQueue의 그래픽 버퍼 할당은 GraphicBufferAlloc를 통해서만 이루어짐.
16
17. 2.노말 서피스 생성 (서비스 서버)-서피스 텍스처 생성
▶ 서피스 플링거 서비스가 서피스를 텍스처로 다룰 수 있도록 도움을 주는 class이다.
SurfaceTexture.cpp
SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) :
…
{
if (bufferQueue == 0) {
mBufferQueue = new BufferQueue(allowSynchronousMode);
어플리케이션(서비스 클라이언트) 측에서 SurfaceTexture를 생성하는 경우 여기서 BufferQueue 가 생성 됨.
}
else {
mBufferQueue = bufferQueue;
}
…
listener = static_cast<BufferQueue::ConsumerListener*>(this);
SurfaceTexture는 BufferQueue::ConsumerListener를 상속 받는다.
BufferQueue::ConsumerListener는 그래픽 버퍼가 추가(onFrameAvailable) 되거나,
해제 될때 (onBuffersReleased) 불려지는 함수의 interface이다.
proxy = new BufferQueue::ProxyConsumerListener(listener);
BufferQueue::ProxyConsumerListener를 생성 한다.
status_t err = mBufferQueue->consumerConnect(proxy);
생성한 BufferQueue::ProxyConsumerListener를 BufferQueue의 이벤트 리스너로 등록한다.
이 의미는 BufferQueue::ProxyConsumerListener::onFrameAvailable() ->
BufferQueue::ConsumerListener의 onFrameAvailable ->
SurfaceTexture::onFrameAvailable() ->
virtual void onFrameAvailable()(Layer.cpp) ->
mFlinger->signalEvent();
로 호출된다.
17
18. 2.노말 서피스 생성 (서비스 서버)-노말 레이어 초기화
2.생성된 layer 상태 초기화
layer->initStates(w, h, flags);
Layerbase class의 initStates 가 호출됨.
void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags)
{
mCurrentState.z = 0; mCurrentState.w = w; mCurrentState.h = h;
mCurrentState.requested_w = w; mCurrentState.requested_h = h;
mCurrentState.sequence = 0;
sequence 값은 드로잉 프레임에서의 레이어와 현재 프레임의 레이어 상태가 변경될 때 1씩 증가
mDrawingState = mCurrentState;
mDrawingState (화면에 출력중인 레이어의 상태 저장)과
mCurrentState(화면 출력을 위해 합성중인 레이어의 상태 저장)를 동일하게 설정
}
3.전역 레이어 목록과 지역 레이어 목록에 추가
ssize_t token = addClientLayer(client, layer);
SurfaceFlinger 1.전역 레이어 목록
-서피스 플링거 서비스에서 생성된 전체 레이어 목록
지역 레이어 목록 -정렬 순서:zorder 순서
전역 레이어 목록 - mCurrentState.layersSortedByZ 변수로 관리
Client 1
layersSortedByZ 2.지역 레이어 목록
mLayers
zorder mIdentity -특정 Client에서 생성된 레이어 목록
Token=1
4 4 -지역 레이어 목록의 레이어는 전역 레이어 목록에
3 1
Token=2 추가됨.
-Client class의 mLayers 변수로 관리
18
19. 2.노말 서피스 생성 (서비스 서버)-노말 레이어 초기화
ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
const sp<LayerBaseClient>& lbc)
{
// 지역 레이어 목록에 추가
size_t name = client->attachLayer(lbc);
// 전역 레이어 목록에 추가
addLayer_l(lbc);
return ssize_t(name);
}
size_t Client::attachLayer(const sp<LayerBaseClient>& layer)
{
size_t name = mNameGenerator++;
mLayers.add(name, layer);
return name;
}
status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer)
{
ssize_t i = mCurrentState.layersSortedByZ.add(layer);
return (i < 0) ? status_t(i) : status_t(NO_ERROR);
}
19
20. 2.노말 서피스 생성 (서비스 서버)-리모트 서비스 생성 후 반환
4. Isurfacetexture 서비스 프락시를 획득하기 위한 함수를 제공하는 서피스 핸들 리모트 서비스(Bsurface) 생성 후 반환한다.
surfaceHandle = layer->getSurface();
Layerbase.cpp의 getSurface가 호출 됨.
sp<LayerBaseClient::Surface> LayerBaseClient::getSurface()
{
sp<Surface> s;
Mutex::Autolock _l(mLock);
s = mClientSurface.promote();
if (s == 0) {
s = createSurface();
mClientSurface = s;
}
return s; Layer.cpp의 오버라이딩 된 createSurface를 부른다.
}
class BSurface : public BnSurface, public LayerCleaner {
wp<const Layer> mOwner;
Layer.cpp virtual sp<ISurfaceTexture> getSurfaceTexture() const {
sp<ISurface> Layer::createSurface() sp<ISurfaceTexture> res;
{ sp<const Layer> that( mOwner.promote() );
sp<ISurface> sur(new BSurface(mFlinger, this)); if (that != NULL) {
return sur; res = that->mSurfaceTexture->getBufferQueue;
Isurfacetexture 서비스 프락시를 획득하기 위한 res는 BufferQueue의 sp를 가리킴.
BSurface class를 생성하고 Bsurface의 proxy인 }
return res;
Isurface를 return한다.
}
서피스 핸들을 반환 받은 서비스 클라이언트에서는
public:
getSurfaceTexture() 로 BufferQueue에 BSurface(const sp<SurfaceFlinger>& flinger,
접근할 수 있다. const sp<Layer>& layer)
} : LayerCleaner(flinger, layer), mOwner(layer) { }
};
21. 3.SurfaceTextureClient 생성(서비스 클라이언트)
ISurface Proxy를 가진 SurfaceControl class의 getSurface함수를 통하여 ISurfaceTexture 서비스 proxy를 얻을 수 있다.
ISurfaceTexture 는 BufferQueue와 연결 되어 있어 서피스의 그래픽 버퍼 생성,요청,출력등을 제공 한다.
Android_view_Surface.cpp
static sp<Surface> getSurface(JNIEnv* env, jobject clazz)
{
result = control->getSurface();
}
Surface.cpp
sp<Surface> SurfaceControl::getSurface() const
{
if (mSurfaceData == 0) {
sp<SurfaceControl> surface_control(const_cast<SurfaceControl*>(this));
mSurfaceData = new Surface(surface_control);
SurfaceTextureClient 클래스를 상속 받은 Surface class를 생성 한다.
}
return mSurfaceData; Surface class의 주요 함수
}
함수 명 설명
isValid() Surface 생성시 초기화가 정상적으로 이루어 졌는지 check
getIdentity() 해당 서피스의 전역 식별자를 획득한다.
Lock() 그래픽 버퍼의 가상 주소를 획득한다.
Unlockandpost() 서피스 플링거 서비스에게 출력을 요청한다.
getSurfaceTexture() 서피스 텍스쳐 리모트 서비스의 서비스 프락시(ISurfaceTexture)를
획득한다.
22. 3.SurfaceTextureClient 생성(서비스 클라이언트)
Surface::Surface(const sp<SurfaceControl>& surface) SurfaceTextureClient::SurfaceTextureClient() {
: SurfaceTextureClient() SurfaceTextureClient 의 생성자 호출 SurfaceTextureClient::init();
mSurface(surface->mSurface), }
mIdentity(surface->mIdentity)
{ ANativeWindow 함수 포인터에
sp<ISurfaceTexture> st; SurfaceTextureClient 함수를 할당 함.
if (mSurface != NULL) { void SurfaceTextureClient::init() {
st = mSurface->getSurfaceTexture(); ANativeWindow::dequeueBuffer
ISurfaceTexture proxy를 획득한다. = hook_dequeueBuffer;
(SurfaceTexture는 BufferQueue를 가지고 있다.) ANativeWindow::cancelBuffer
} = hook_cancelBuffer;
init(st); ANativeWindow::lockBuffer
} = hook_lockBuffer;
ANativeWindow::queueBuffer
= hook_queueBuffer;
}
void Surface::init(const sp<ISurfaceTexture>& surfaceTexture)
{
if (mSurface != NULL || surfaceTexture != NULL) {
if (surfaceTexture != NULL) {
setISurfaceTexture(surfaceTexture);
setUsage(GraphicBuffer::USAGE_HW_RENDER);그래픽 버퍼의 속성값을 지정 함.
USAGE_HW_RENDER:그래픽 버퍼를 openGLES의 렌더링 대상으로 사용한다는 의미
}
}
void SurfaceTextureClient::setISurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture)
{
mSurfaceTexture = surfaceTexture;
}
23. 3.서피스 생성 요청 전체 그림
Client SurfaceFlinger
Client
BSurface
surfacecomposerclient Layer
ISurfaceTexture BufferQueue
surfacecontrol
Surfacetexturelayer
ANativeWindow Refbase
surfacetextureclient surfacetexture
surface
23
24. 참고.ANativeWindow 인터페이스
애플리케이션과 서피스 플링거는 ANativeWindow 인터페이스를 통해 그래픽 버퍼와 네이티브 버퍼를 획득 또는 출력한다.
차이점은, 애플리케이션은 출력대상이 그래픽 버퍼이고, 서피스 플링거는 네이티브 버퍼 이다.
24
25. 참고.ANativeWindow 인터페이스
애플리케이션 측- SurfaceTextureClient 이용
1)애플리케이션은 SurfaceTextureclient 를 이용하여 그래픽 버퍼를 획득하고 출력한다.
2) SurfaceTextureclient 는 ANativeWidnow interface를 상속 받는다.
3) ANativeWidnow interface에 SurfaceTextureclient 함수 포인터를 매핑한다.
이 말은, 애플리케이션이 ANativeWidnow interface를 이용하여 버퍼를 할당 받고자 할때 실제 불리는
함수는 SurfaceTextureclient 에 있는 함수가 불리게 된다.
서피스 플링거의 경우는 FramebufferNativewindow의 함수를 부르게 된다.
4)Surfacetexture class는 클라이언트로 부터 그래픽 버퍼 요청이 오면 사용 가능한 버퍼를 검색하여 인덱스
번호를 전달하고, 출력 요청이 오면 출력 대기 큐(mQueue)에 저장한다.
서피스 플링거 서비스 측- FramebufferNativewindow 사용
5)합성 요청 signal(Vsync)를 받으면 합성을 시작하게 된다.
6)서피스 플링거 서비스는 FramebufferNativewindow 를 사용하여 네이티브 버퍼를 획득하고, 출력 요청한다.
7) FramebufferNativewindow 클래스의 함수가 ANativeWidnow interface 에 매핑된다.
FramebufferNativewindow의 출력 대상은 프레임 버퍼이다.
8)버퍼 할당 요청이 오면 프레임 버퍼를 전달하고 출력 요청이 오면 디스플레이에 출력 요청을 한다.
25
26. 참고자료
안드로이드 미디어 프레임워크 –”개발자가 행복한 세상”
Goolge Jelly bean Source
26