8.4.2 SurfaceComposerClient分析

最后更新于:2022-04-02 05:52:29

SurfaceComposerClient的出现是因为: Java层SurfaceSession对象的构造函数会调用Native的SurfaceSession_init函数,而该函数的主要目的就是创建SurfaceComposerClient。 先回顾一下SurfaceSession_init函数,代码如下所示: **android_view_Surface.cpp** ~~~ static void SurfaceSession_init(JNIEnv* env,jobject clazz) { //new 一个SurfaceComposerClient对象 sp client = newSurfaceComposerClient; //sp的使用也有让人烦恼的地方,有时需要显式地增加强弱引用计数,要是忘记,可就麻烦了 client->incStrong(clazz); env->SetIntField(clazz, sso.client,(int)client.get()); } ~~~ 上面代码中,显式地构造了一个SurfaceComposerClient对象。接下来看它是何方神圣。 1. 创建SurfaceComposerClient SurfaceComposerClient这个名字隐含的意思是: 这个对象会和SurfaceFlinger进行交互,因为SurfaceFlinger派生于SurfaceComposer。 通过它的构造函数来看是否是这样的。代码如下所示: **SurfaceComposerClient.cpp** ~~~ SurfaceComposerClient::SurfaceComposerClient() { //getComposerService()将返回SF的Binder代理端的BpSurfaceFlinger对象 sp sm(getComposerService()); //先调用SF的createConnection,再调用_init _init(sm, sm->createConnection()); if(mClient != 0) { Mutex::Autolock _l(gLock); //gActiveConnections是全局变量,把刚才创建的client保存到这个map中去 gActiveConnections.add(mClient->asBinder(), this); } } ~~~ 果然如此,SurfaceComposerClient建立了和SF的交互通道,下面直接转到SF的createConnection函数去观察。 (1)createConnection的分析 直接看代码,如下所示: **SurfaceFlinger.cpp** ~~~ spSurfaceFlinger::createConnection() { Mutex::Autolock _l(mStateLock); uint32_t token = mTokens.acquire(); //先创建一个Client。 sp client = new Client(token, this); //把这个Client对象保存到mClientsMap中,token是它的标识。 status_t err = mClientsMap.add(token, client); /* 创建一个用于Binder通信的BClient,BClient派生于ISurfaceFlingerClient, 它的作用是接受客户端的请求,然后把处理提交给SF,注意,并不是提交给Client。 Client会创建一块共享内存,该内存由getControlBlockMemory函数返回 */ sp bclient = new BClient(this, token,client->getControlBlockMemory()); returnbclient; } ~~~ 上面代码中提到,Client会创建一块共享内存。熟悉Audio的读者或许会认为,这可能是Surface的ControlBlock对象了!是的。CB对象在协调生产/消费步调时,起到了决定性的控制作用,所以非常重要,下面来看: **SurfaceFlinger.cpp** ~~~ Client::Client(ClientID clientID, constsp& flinger) :ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger) { const int pgsize = getpagesize(); //下面这个操作会使cblksize为页的大小,目前是4096字节。 constint cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1)); //MemoryHeapBase是我们的老朋友了,不熟悉的读者可以回顾Audio系统中所介绍的内容 mCblkHeap = new MemoryHeapBase(cblksize, 0, "SurfaceFlinger Clientcontrol-block"); ctrlblk = static_cast(mCblkHeap->getBase()); if(ctrlblk) { new(ctrlblk) SharedClient; //再一次觉得眼熟吧?使用了placement new } } ~~~ 原来,Surface的CB对象就是在共享内存中创建的这个SharedClient对象。先来认识一下这个SharedClient。 (2)SharedClient的分析 SharedClient定义了一些成员变量,代码如下所示: ~~~ class SharedClient { public: SharedClient(); ~SharedClient(); status_t validate(size_t token) const; uint32_t getIdentity(size_t token) const;//取出标识本Client的token private: Mutexlock; Condition cv; //支持跨进程的同步对象 //NUM_LAYERS_MAX为31,SharedBufferStack是什么? SharedBufferStack surfaces[ NUM_LAYERS_MAX ]; }; //SharedClient的构造函数,没什么新意,不如Audio的CB对象复杂 SharedClient::SharedClient() :lock(Mutex::SHARED), cv(Condition::SHARED) { } ~~~ SharedClient的定义似乎简单到极致了,不过不要高兴得过早,在这个SharedClient的定义中,没有发现和读写控制相关的变量,那怎么控制读写呢? 答案就在看起来很别扭的SharedBufferStack数组中,它有31个元素。关于它的作用就不必卖关子了,答案是: 一个Client最多支持31个显示层。每一个显示层的生产/消费步调都由会对应的SharedBufferStack来控制。而它内部就用了几个成员变量来控制读写位置。 认识一下SharedBufferStack的这几个控制变量,如下所示: **SharedBufferStack.h** ~~~ class SharedBufferStack{ ...... //Buffer是按块使用的,每个Buffer都有自己的编号,其实就是数组中的索引号。 volatile int32_t head; //FrontBuffer的编号 volatile int32_t available; //空闲Buffer的个数 volatile int32_t queued; //脏Buffer的个数,脏Buffer表示有新数据的Buffer volatile int32_t inUse; //SF当前正在使用的Buffer的编号 volatilestatus_t status; //状态码 ...... } ~~~ 注意,上面定义的SharedBufferStack是一个通用的控制结构,而不仅是针对于只有两个Buffer的情况。根据前面介绍的PageFlipping知识,如果只有两个FB,那么,SharedBufferStack的控制就比较简单了: 要么SF读1号Buffer,客户端写0号Buffer,要么SF读0号Buffer,客户端写1号Buffer。 图8-13是展示了SharedClient的示意图: :-: ![](http://img.blog.csdn.net/20150802162602596?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图8-13 SharedClient的示意图 从上图可知: - SF的一个Client分配一个跨进程共享的SharedClient对象。这个对象有31个SharedBufferStack元素,每一个SharedBufferStack对应于一个显示层。 - 一个显示层将创建两个Buffer,后续的PageFlipping就是基于这两个Buffer展开的。 另外,每一个显示层中,其数据的生产和消费并不是直接使用SharedClient对象来进行具体控制的,而是基于SharedBufferServer和SharedBufferClient两个结构,由这两个结构来对该显示层使用的SharedBufferStack进行操作,这些内容在以后的分析中还会碰到。 * * * * * **注意**,这里的显示层指的是Normal类型的显示层。 * * * * * 来接着分析后面的_init函数。 (3)_init函数的分析 先回顾一下之前的调用,代码如下所示: **SurfaceComposerClient.cpp** ~~~ SurfaceComposerClient::SurfaceComposerClient() { ...... _init(sm, sm->createConnection()); ...... } ~~~ 来看这个_init函数,代码如下所示: **SurfaceComposerClient.cpp** ~~~ void SurfaceComposerClient::_init( const sp& sm, constsp& conn) { mPrebuiltLayerState = 0; mTransactionOpen = 0; mStatus = NO_ERROR; mControl = 0; mClient = conn;//mClient就是BClient的客户端 mControlMemory =mClient->getControlBlock(); mSignalServer = sm;// mSignalServer就是BpSurfaceFlinger //mControl就是那个创建于共享内存之中的SharedClient mControl = static_cast(mControlMemory->getBase()); } ~~~ _init函数的作用,就是初始化SurfaceComposerClient中的一些成员变量。最重要的是得到了三个成员: - mSignalServer ,它其实是SurfaceFlinger在客户端的代理BpSurfaceFlinger,它的主要作用是,在客户端更新完BackBuffer后(也就是刷新了界面后),通知SF进行PageFlipping和输出等工作。 - mControl,它是跨进程共享的SharedClient,是Surface系统的ControlBlock对象。 - mClient,它是BClient在客户端的对应物。 2. 到底有多少种对象? 这一节,出现了好几种类型的对象,通过图8-14来看看它们: :-: ![](http://img.blog.csdn.net/20150802162626479?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图8-14 类之间关系展示图 从上图中可以看出: - SurfaceFlinger是从Thread派生的,所以它会有一个单独运行的工作线程。 - BClient和SF之间采用了Proxy模式,BClient支持Binder通信,它接收客户端的请求,并派发给SF执行。 - SharedClient构建于一块共享内存中,SurfaceComposerClient和Client对象均持有这块共享内存。 在精简流程中,关于SurfaceComposerClient就分析到这里,下面分析第二个步骤中的SurfaceControl对象。
';