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对象。
';