8.4.2 SurfaceComposerClient分析
SurfaceComposerClient的出现是因为:
Java层SurfaceSession对象的构造函数会调用Native的SurfaceSession_init函数,而该函数的主要目的就是创建SurfaceComposerClient。
先回顾一下SurfaceSession_init函数,代码如下所示:
[—>android_view_Surface.cpp]
static void SurfaceSession_init(JNIEnv*env,jobject clazz)
{
//new一个SurfaceComposerClient对象。
sp<SurfaceComposerClient>client=new SurfaceComposerClient;
//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<ISurfaceComposer>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]
sp<ISurfaceFlingerClient>SurfaceFlinger:createConnection()
{
Mutex:Autolock_l(mStateLock);
uint32_t token=mTokens.acquire();
//先创建一个Client。
sp<Client>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>bclient=
new BClient(this,token,client->getControlBlockMemory());
return bclient;
}
上面代码中提到,Client会创建一块共享内存。熟悉Audio的读者或许会想到,这可能是Surface的ControlBlock对象!确实是的。CB对象在协调生产/消费步调时,起到了决定性的控制作用,所以非常重要,下面来看:
[—>SurfaceFlinger.cpp]
Client:Client(ClientID clientID,const sp<SurfaceFlinger>&flinger)
:ctrlblk(0),cid(clientID),mPid(0),mBitmap(0),mFlinger(flinger)
{
const int pgsize=getpagesize();
//下面这个操作会使cblksize为页的大小,目前是4096字节。
const int cblksize=((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));
//MemoryHeapBase是我们的老朋友了,不熟悉的读者可以回顾Audio系统中所介绍的内容。
mCblkHeap=new MemoryHeapBase(cblksize,0,
"SurfaceFlinger Client control-block");
ctrlblk=static_cast<SharedClient*>(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:
Mutex lock;
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的编号。
volatile status_t status;//状态码
……
}
注意,上面定义的SharedBufferStack是一个通用的控制结构,而不仅是针对于只有两个Buffer的情况。根据前面介绍的PageFlipping知识可知,如果只有两个FB,那么,SharedBufferStack的控制就比较简单了:
要么SF读1号Buffer,客户端写0号Buffer,要么SF读0号Buffer,客户端写1号Buffer。
图8-13是展示了SharedClient的示意图:
图 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<ISurfaceComposer>&sm,const sp<ISurfaceFlingerClient>&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<SharedClient*>(mControlMemory->getBase());
}
_init函数的作用,就是初始化SurfaceComposerClient中的一些成员变量。最重要的是得到了三个成员:
mSignalServer,它其实是SurfaceFlinger在客户端的代理BpSurfaceFlinger,它的主要作用是,在客户端更新完BackBuffer后(也就是刷新了界面后),通知SF进行PageFlipping和输出等工作。
mControl,它是跨进程共享的SharedClient,是Surface系统的ControlBlock对象。
mClient,它是BClient在客户端的对应物。
2.到底有多少种对象?
这一节出现了好几种类型的对象,通过图8-14来看看它们:
图 8-14 类之间关系的展示图
从上图中可以看出:
SurfaceFlinger是从Thread派生的,所以它会有一个单独运行的工作线程。
BClient和SF之间采用了Proxy模式,BClient支持Binder通信,它接收客户端的请求,并派发给SF执行。
SharedClient构建于一块共享内存中,SurfaceComposerClient和Client对象均持有这块共享内存。
在精简流程中,关于SurfaceComposerClient就分析到这里,下面分析第二个步骤中的SurfaceControl对象。