文章都是通过阅读源码分析出来的,还在不断完善与改进中,其中难免有些地方理解得不对,欢迎大家批评指正。
转载请注明:From LXS. http://blog.csdn.net/uiop78uiop78/
针对应用程序端的本地窗口是SurfaceTextureClient,和FramebufferNativeWindow一样,它必须继承ANativeWindow:
class SurfaceTextureClient
: publicANativeObjectBase<ANativeWindow, SurfaceTextureClient,RefBase>
这个本地窗口当然也需要实现ANativeWindow所制定的“协议”,我们的重点是关注它与前面的FramebufferNativeWindow有什么不同。SurfaceTextureClient的构造函数只是简单地调用了init函数,后者则对ANativeWindow::dequeueBuffer等函数指针及内部变量赋了初值。由于整个函数的功能很简单,我们只摘录其中的一部分:
/*frameworks/native/libs/gui/SurfaceTextureClient.cpp*/
void SurfaceTextureClient::init() {
/*给ANativeWindow中的函数指针赋值*/
ANativeWindow::setSwapInterval =hook_setSwapInterval;
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
…
/*为各内部变量赋值,因为此时用户还没有真正发起申请,所以基本是0*/
mReqWidth = 0;
mReqHeight = 0;
…
mDefaultWidth = 0;
mDefaultHeight = 0;
mUserWidth = 0;
mUserHeight = 0;…
}
SurfaceTextureClient是面向Android系统中所有UI应用程序的,也就是说它承担着单个应用进程中的UI显示需求。基于这点考虑,可以推测出它的内部实现至少会有以下几点:
Ø 提供给上层(主要是java层)绘制图像的“画板”
前面说过,这个本地窗口分配的内存应该不是来自于帧缓冲区,那么具体是由谁分配的,又是如何管理的呢?
Ø 它与SurfaceFlinger间是如何分工的
显然SurfaceFlinger需要收集系统中所有应用程序绘制的图像数据,然后集中显示到物理屏幕上。在这个过程中,SurfaceTextureClient扮演了什么样的角色呢?
我们先来解释下这个类中的一些重要的成员变量,如下表所示:
表格 11‑4 SurfaceTextureClient部分成员变量一览
成员变量 |
说明 |
sp<ISurfaceTexture> mSurfaceTexture |
这个变量是SurfaceTextureClient的核心,很多“协议”就是通过它实现的,后面会有详细讲解 |
BufferSlot mSlots[NUM_BUFFER_SLOTS] |
从名称上可以看出,这是Client内部用于存储buffer的地方,容量NUM_BUFFER_SLOTS最多达32个。BufferSlot类内部又由一个GraphicBuffer和一个dirtyRegion组成,当有用户dequeueBuffer时就会分配真正的空间 |
uint32_t mReqWidth |
SurfaceTextureClient中有多组相似的宽高变量,它们之间是有区别的。这里的宽和高是指下一次dequeue时将会申请的尺寸,初始值都是1 |
uint32_t mReqHeight |
|
uint32_t mReqFormat |
和上面的两变量类似,这是指下次dequeue时将会申请的buffer的像素格式,初始值是PIXEL_FORMAT_RGBA_8888 |
uint32_t mReqUsage |
指下次dequeue时将会指定的usage类型 |
Rect mCrop |
Crop表示“修剪”,这个变量将在下次queue时用于修剪缓冲区,可以调用setCrop来设置具体的值 |
int mScalingMode |
同样,这个变量将用于下次queue时对缓冲区进行scale,可以调用setScalingMode来设置具体的值 |
uint32_t mTransform |
用于下次queue时的图形翻转等操作(Transform) |
uint32_t mDefaultWidth |
默认情况下的缓冲区宽高值 |
uint32_t mDefaultHeight |
|
uint32_t mUserWidth |
如果不为零的话,就是应用层指定的值,将会覆盖前面的mDefaultWidth/ mDefaultHeight |
uint32_t mUserHeight |
|
sp<GraphicBuffer> mLockedBuffer |
这三个值需要锁的保护,接下来还会有分析 |
sp<GraphicBuffer> mPostedBuffer |
|
Region mDirtyRegion |
从这些内部变量的描述中,我们可以大概了解到两点:SurfaceTextureClient中将通过mSurfaceTexture来获得buffer,而且这些缓冲区会被记录在mSlots数组中。接下来就来分析其中的实现细节。
前面SurfaceTextureClient构造函数里我们看到ANativeWindow中的函数指针赋予的是各种以hook开头的函数,这些函数内部又直接调用了SurfaceTextureClient中真正的实现,比如hook_dequeueBuffer对应的是dequeueBuffer。这就好像是“钩子”一样,所以称之为hook。
int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t**buffer) {…
Mutex::Autolocklock(mMutex);
int buf = -1;
/*Step1. 宽高计算*/
int reqW = mReqWidth ?mReqWidth : mUserWidth;
int reqH = mReqHeight ? mReqHeight :mUserHeight;
/*Step2. dequeueBuffer得到一个缓冲区*/
status_t result =mSurfaceTexture->dequeueBuffer(&buf, reqW, reqH,mReqFormat, mReqUsage);
…
sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);//注意buf只是一个int值,代表的是mSlots数组序号
…
/*Step3. requestBuffer*/
if ((result &ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
result =mSurfaceTexture->requestBuffer(buf, &gbuf);
…
}
*buffer = gbuf.get();
return OK;
}
Step1@ SurfaceTextureClient::dequeueBuffer。用于UI绘制的图形缓冲区一定有宽高属性,具体的值由mReqWidth/mReqHeight或者mUserWidth/mUserHeight决定,其中前者的优先级比后者高
Step2@ SurfaceTextureClient::dequeueBuffer。可以看到,真正执行dequeueBuffer操作的确实是mSurfaceTexture(ISurfaceTexture)。这个变量的赋值有两个来源:作为SurfaceTextureClient的构造函数参数传入,然后间接调用setISurfaceTexture来设置的;或者SurfaceTextureClient的子类通过直接调用setISurfaceTexture来生成。
在应用进程环境中,属于后面一种情况。
具体流程就是:当Java层的Surface进行init时,实际上执行的函数是Surface_init@android_view_Surface.cpp。这个JNI函数将进一步调用SurfaceComposerClient::createSurface生成一个SurfaceControl,后者是用于管理Surface的类。它将在SurfaceControl::getSurface时生成一个Surface实例,在构造时通过SurfaceControl:: getSurfaceTexture来获得一个ISurfaceTexture。而Surface类实际上又继承自SurfaceTextureClient,所以它可以调用setISurfaceTexture。
由于Android源码有多处称为Surface的地方,取名极其混乱,我们下面通过一张完整的流程图来帮助大家把这些关系理顺:
图 11‑10 ISurfaceTexture创建流程
从这个图中可以看到,ISurfaceTexture是由ISurface::getSurfaceTexture生成的,而ISurface则是由SurfaceFlinger生成的。在这一过程中,总共使用到了三个匿名binderserver,它们所提供的接口整理如下表:
表格 11‑5 与Surface相关的三个匿名binder
匿名Binder |
提供的接口 |
ISurfaceComposerClient |
sp<ISurface> createSurface(…); status_t destroySurface(SurfaceID sid); |
ISurface |
sp<ISurfaceTexture> getSurfaceTexture(…); |
ISurfaceTexture |
status_t requestBuffer(int slot, sp<GraphicBuffer>* buf); status_t setBufferCount(int bufferCount); status_t dequeueBuffer(…); status_t queueBuffer(…); void cancelBuffer(int slot); int query(int what, int* value); status_t setSynchronousMode(bool enabled); status_t connect(int api, QueueBufferOutput* output); status_t disconnect(int api); |
由此可见,这三个匿名binder是一环扣一环的,也就是说我们访问的顺序只能是ISurfaceComposerClientàISurfaceàISurfaceTexture。当然,第一个匿名binder就一定是需要由一个实名binder来提供,它就是SurfaceFlinger,而SurfaceFlinger则是在ServiceManager中“注册在案”的。具体是在SurfaceComposerClient::onFirstRef()这个函数中,通过向ServiceManager查询名称为“SurfaceFlinger”的binder server来获得的。不过和其它常见binder server不同的是,SurfaceFlinger虽然在ServiceManager中注册的名称为“SurfaceFlinger”,但它在server端实现的binder接口却是ISurfaceComposer,因而SurfaceComposerClient得到的其实是ISurfaceComposer,这点大家要特别注意,否则可能会搞乱。
//我们可以从SurfaceFlinger的继承关系中看出这一区别,如下代码片断
class SurfaceFlinger :
publicBinderService<SurfaceFlinger>, //在ServiceManager中注册为“SurfaceFlinger”
public BnSurfaceComposer, //实现的接口却叫ISurfaceComposer,不知道为什么要这么设计。。。
绕了一大圈后,我们接着分析前面dequeueBuffer函数的实现。很显然SurfaceTextureClient只是一个中介,它间接调用mSurfaceTexture也就是ISurfaceTexture的服务。那么ISurfaceTexture在Server端又是由谁来完成的呢?
图 11‑11 ISurfaceTexture的本地端实现
因为这里面牵扯到很多新的类,我们先不做过多解释,到后面BufferQueue小节再详细分析其中的依赖关系。
当mSurfaceTexture->dequeueBuffer返回后,buf变量就是mSlots[]数组中可用的成员序号。接下来就要通过这个序号来获取真正的buffer地址,即mSlots[buf].buffer。
Step3@ SurfaceTextureClient::dequeueBuffer。假如返回值result中的标志包含了BUFFER_NEEDS_REALLOCATION,说明BufferQueue为这个Slot重新分配了空间,具体细节请参见下一个小节。此时我们还需要另外调用requestBuffer来确定gbuf的值,这其中又牵涉到很多东西,我们放在下面小节统一解释原因。
通过这两个小节,我们学习了显示系统中两个重要的本地窗口,即FramebufferNativewindow和SurfaceTextureClient。第一个窗口是专门为SurfaceFlinger服务的,它由Gralloc提供支持,相对逻辑上很好理解。而SurfaceTextureClient则是为应用程序服务的,同时它从本质上还是由SurfaceFlinger服务统一管理的,因而涉及到很多跨进程的通信细节。这个小节我们只是简单地勾勒出其中的框架,接下去就要分几个方面来做完整的分析了。
Ø BufferQueue
为应用程序服务的本地窗口SurfaceTextureClient在server端的实现是BufferQueue。我们将详细解析BufferQueue的内部实现,并结合应用程序端的使用流程来理解清楚它们之间的关系。
Ø Buffer、Consumer、Producer是“生产者-消费者”模型中的三个参与对象,如何协调好它们的工作是应用程序能否正常显示UI的关键。在接下来内容的安排上,我们先讲解Buffer(BufferQueue)与Producer(应用程序)间的交互,然后再专门切入Consumer(SurfaceFlinger)做详细分析