这一节,分析精简流程中的最后两个函数lockCanvas和unlockCanvasAndPost。
1. lockCanvas分析
据前文分析可知,UI在绘制前都需要通过lockCanvas得到一块存储空间,也就是所说的BackBuffer。这个过程中最终会调用Surface的lock函数。其代码如下所示:
**Surface.cpp**
~~~
status_t Surface::lock(SurfaceInfo* other,Region* dirtyIn, bool blocking)
{
//传入的参数中,other用来接收一些返回信息,dirtyIn表示需要重绘的区域
......
if (mApiLock.tryLock() != NO_ERROR) {//多线程的情况下要锁住
......
returnWOULD_BLOCK;
}
//设置usage标志,这个标志在GraphicBuffer分配缓冲时有指导作用
setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
//定义一个GraphicBuffer,名字就叫backBuffer。
sp<GraphicBuffer>backBuffer;
//①还记得我们说的2个元素的缓冲队列吗?下面的dequeueBuffer将取出一个空闲缓冲
status_terr = dequeueBuffer(&backBuffer);
if (err== NO_ERROR) {
//② 锁住这块buffer
err = lockBuffer(backBuffer.get());
if(err == NO_ERROR) {
const Rect bounds(backBuffer->width, backBuffer->height);
Region scratch(bounds);
Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
......
//mPostedBuffer是上一次绘画时使用的Buffer,也就是现在的frontBuffer
const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
if (frontBuffer !=0 &&
backBuffer->width ==frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
!(mFlags & ISurfaceComposer::eDestroyBackbuffer))
{
const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
if (!copyback.isEmpty() && frontBuffer!=0) {
/③把frontBuffer中的数据拷贝到BackBuffer中,这是为什么?
copyBlt(backBuffer,frontBuffer, copyback);
}
}
mDirtyRegion = newDirtyRegion;
mOldDirtyRegion = newDirtyRegion;
void* vaddr;
//调用GraphicBuffer的lock得到一块内存,内存地址被赋值给了vaddr,
//后续的作画将在这块内存上展开
status_t res = backBuffer->lock(
GRALLOC_USAGE_SW_READ_OFTEN |GRALLOC_USAGE_SW_WRITE_OFTEN,
newDirtyRegion.bounds(),&vaddr);
mLockedBuffer = backBuffer;
//other用来接收一些信息。
other->w =backBuffer->width; //宽度信息
other->h =backBuffer->height;
other->s =backBuffer->stride;
other->usage =backBuffer->usage;
other->format = backBuffer->format;
other->bits = vaddr; //最重要的是这个内存地址
}
}
mApiLock.unlock();
returnerr;
}
~~~
在上面的代码中,列出了三个关键点:
- 调用dequeueBuffer得到一个空闲缓冲,也可以叫空闲缓冲出队。
- 调用lockBuffer。
- 调用copyBlt函数,把frontBuffer数据拷贝到backBuffer中,这是为什么?
来分析这三个关键点。
(1)dequeueBuffer的分析
dequeueBuffer的目的很简单,就是选取一个空闲的GraphicBuffer,其代码如下所示:
**Surface.cpp**
~~~
status_tSurface::dequeueBuffer(sp<GraphicBuffer>* buffer) {
android_native_buffer_t* out;
status_t err = dequeueBuffer(&out);//调用另外一个dequeueBuffer
if(err == NO_ERROR) {
*buffer = GraphicBuffer::getSelf(out);
}
returnerr;
}
~~~
这其中又调用了另外一个dequeueBuffer函数。它的代码如下所示:
**Surface.cpp**
~~~
intSurface::dequeueBuffer(android_native_buffer_t** buffer)
{
sp<SurfaceComposerClient> client(getClient());
//①调用SharedBufferClient的dequeue函数,它返回当前空闲的缓冲号
ssize_tbufIdx = mSharedBufferClient->dequeue();
const uint32_t usage(getUsage());
/*
mBuffers就是我们前面在Surface创建中介绍的那个二元sp<GraphicBuffer>数组。
这里定义的backBuffer是一个引用类型,也就是说如果修改backBuffer的信息,
就相当于修改了mBuffers[bufIdx]
*/
const sp<GraphicBuffer>&backBuffer(mBuffers[bufIdx]);
//mBuffers定义的GraphicBuffer使用的也是无参构造函数,所以此时还没有真实的存储被创建
if(backBuffer == 0 || //第一次进来满足backBuffer为空这个条件
((uint32_t(backBuffer->usage) & usage) != usage) ||
mSharedBufferClient->needNewBuffer(bufIdx))
{
//调用getBufferLocked,需要进去看看。
err = getBufferLocked(bufIdx, usage);
if(err == NO_ERROR) {
mWidth =uint32_t(backBuffer->width);
mHeight = uint32_t(backBuffer->height);
}
}
......
}
~~~
上面列出了一个关键点,就是SharedBufferClient的dequeue函数,暂且记住这个调用,后面会有单独章节分析生产/消费步调控制。先看getBufferLocked函数,其代码如下所示:
**Surface.cpp**
~~~
tatus_t Surface::getBufferLocked(int index, intusage)
{
sp<ISurface> s(mSurface);
status_t err = NO_MEMORY;
//注意这个currentBuffer也被定义为引用类型
sp<GraphicBuffer>¤tBuffer(mBuffers[index]);
//终于用上了ISurface对象,调用它的requestBuffer得到指定索引index的Buffer
sp<GraphicBuffer> buffer =s->requestBuffer(index, usage);
if (buffer != 0) {
err = mSharedBufferClient->getStatus();
if(!err && buffer->handle != NULL) {
//getBufferMapper返回GraphicBufferMapper对象
//调用它的registerBuffer干什么?这个问题我们在8.4.7节回答
err = getBufferMapper().registerBuffer(buffer->handle);
if (err == NO_ERROR) {
//把requestBuffer得到的值赋给currentBuffer,由于currentBuffer是引用类型,
//实际上相当于mBuffers[index]=buffer
currentBuffer = buffer;
//设置currentBuffer的编号
currentBuffer->setIndex(index);
mNeedFullUpdate = true;
}
}else {
err = err<0 ? err : NO_MEMORY;
}
return err;
}
~~~
至此,getBufferLocked的目的,已比较清晰了:
- 调用ISurface的requestBuffer得到一个GraphicBuffer对象,这个GraphicBuffer对象被设置到本地的mBuffers数组中。看来Surface定义的这两个GraphicBuffer和Layer定义的两个GraphicBuffer是有联系的,所以图8-18中只画了两个GraphicBuffer。
我们已经知道,ISurface的Bn端实际上是定义在Layer.类中的SurfaceLayer,下面来看它实现的requestBuffer。由于SurfaceLayer是Layer的内部类,它的工作最终都会交给Layer来处理,所以这里可直接看Layer的requestBuffer函数:
**Layer.cpp**
~~~
sp<GraphicBuffer> Layer::requestBuffer(intindex, int usage)
{
sp<GraphicBuffer> buffer;
sp<Client> ourClient(client.promote());
//lcblk就是那个SharedBufferServer对象,下面这个调用确保index号GraphicBuffer
//没有被SF当做FrontBuffer使用。
status_t err = lcblk->assertReallocate(index);
......
if(err != NO_ERROR) {
return buffer;
}
uint32_t w, h;
{
Mutex::Autolock _l(mLock);
w= mWidth;
h= mHeight;
/*
mBuffers是SF端创建的一个二元数组,这里取出第index个元素,之前说过,
mBuffers使用的也是GraphicBuffer的无参构造函数,所以此时也没有真实存储被创建。
*/
buffer = mBuffers[index];
mBuffers[index].clear();
}
constuint32_t effectiveUsage = getEffectiveUsage(usage);
if(buffer!=0 && buffer->getStrongCount() == 1) {
//①分配物理存储,后面会分析这个。
err = buffer->reallocate(w, h, mFormat, effectiveUsage);
} else{
buffer.clear();
//使用GraphicBuffer的有参构造,这也使得物理存储被分配
buffer = new GraphicBuffer(w, h, mFormat, effectiveUsage);
err = buffer->initCheck();
}
......
if(err == NO_ERROR && buffer->handle != 0) {
Mutex::Autolock _l(mLock);
if(mWidth && mHeight) {
mBuffers[index] = buffer;
mTextures[index].dirty = true;
}else {
buffer.clear();
}
}
returnbuffer;//返回
}
~~~
不管怎样,此时跨进程的这个requestBuffer返回的GraphicBuffer,已经和一块物理存储绑定到一起了。所以dequeueBuffer顺利返回了它所需的东西。接下来则需调用lockBuffer。
(2)lockBuffer的分析
lockBuffer的代码如下所示:
**Surface.cpp**
~~~
int Surface::lockBuffer(android_native_buffer_t*buffer)
{
sp<SurfaceComposerClient> client(getClient());
status_t err = validate();
int32_t bufIdx = GraphicBuffer::getSelf(buffer)->getIndex();
err =mSharedBufferClient->lock(bufIdx); //调用SharedBufferClient的lock
return err;
}
~~~
来看这个lock函数:
**SharedBufferStack.cpp**
~~~
status_t SharedBufferClient::lock(int buf)
{
LockCondition condition(this, buf);//这个buf是BackBuffer的索引号
status_t err = waitForCondition(condition);
returnerr;
}
~~~
* * * * *
**注意**,给waitForCondition函数传递的是一个LockCondition类型的对象,前面所说的函数对象的作用将在这里见识到,先看waitForCondition函数:
* * * * *
**SharedBufferStack.h**
~~~
template <typename T> //这是一个模板函数
status_t SharedBufferBase::waitForCondition(Tcondition)
{
constSharedBufferStack& stack( *mSharedStack );
SharedClient& client( *mSharedClient );
constnsecs_t TIMEOUT = s2ns(1);
Mutex::Autolock _l(client.lock);
while((condition()==false) && //注意这个condition()的用法
(stack.identity == mIdentity) &&
(stack.status == NO_ERROR))
{
status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
if(CC_UNLIKELY(err != NO_ERROR)) {
if (err == TIMED_OUT) {
if (condition()) {//注意这个:condition(),condition是一个对象
break;
} else {
}
} else {
return err;
}
}
}
return(stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status;
}
~~~
waitForCondition函数比较简单,就是等待一个条件为真,这个条件是否满足由condition()这条语句来判断。但这个condition不是一个函数,而是一个对象,这又是怎么回事?
这就是Funcition Object(函数对象)的概念。函数对象的本质是一个对象,不过是重载了操作符(),这和重载操作符+、-等没什么区别。可以把它当作是一个函数来看待。
为什么需要函数对象呢?因为对象可以保存信息,所以调用这个对象的()函数就可以利用这个对象的信息了。
来看condition对象的()函数。刚才传进来的是LockCondition,它的()定义如下:
**SharedBufferStack.cpp**
~~~
boolSharedBufferClient::LockCondition::operator()() {
//stack、buf等都是这个对象的内部成员,这个对象的目的就是根据读写位置判断这个buffer是
//否空闲。
return(buf != stack.head ||
(stack.queued > 0 && stack.inUse != buf));
}
~~~
SharedBufferStack的读写控制,比Audio中的环形缓冲看起来要简单,实际上它却比较复杂。本章会在扩展部分进行分析。这里给读者准备一个问题,也是我之前百思不得其解的问题:
既然已经调用dequeue得到了一个空闲缓冲,为什么这里还要lock呢?
(3)拷贝旧数据
在第三个关键点中,可看到这样的代码:
**Surface.cpp**
~~~
status_t Surface::lock(SurfaceInfo* other,Region* dirtyIn, bool blocking)
{
......
const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
if (frontBuffer !=0 &&
backBuffer->width ==frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
!(mFlags & ISurfaceComposer::eDestroyBackbuffer))
{
const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
if (!copyback.isEmpty() && frontBuffer!=0) {
//③把frontBuffer中的数据拷贝到BackBuffer中,这是为什么?
copyBlt(backBuffer,frontBuffer, copyback);
}
}
......
}
~~~
上面这段代码所解决的,其实是下面这个问题:
在大部分情况下,UI只有一小部分会发生变化(例如一个按钮被按下去,导致颜色发生变化),这一小部分UI只对应整个GraphicBuffer中的一小块存储(就是在前面代码中见到的dirtyRegion),如果整块存储都更新,则会极大地浪费资源。怎么办?
这就需要将变化的图像和没有发生变化的图像进行叠加。上一次绘制的信息保存在mPostedBuffer中,而这个mPostedBuffer则要在unLockAndPost函数中设置。这里将根据需要,把mPostedBuffer中的旧数据拷贝到BackBuffer中。后续的绘画只要更新脏区域就可以了,这会节约不少资源。
OK,lockCanvas返回后,应用层将在这块画布上尽情作画。假设现在已经在BackBuffer上绘制好了图像,下面就要通过unlockCanvasAndPost进行后续工作了。一起来看。
2. unlockCanvasAndPost的分析
进入精简流程的最后一步,就是unlockCanvasAndPost函数,它的代码如下所示:
**Surface.cpp**
~~~
status_t Surface::unlockAndPost()
{
//调用GraphicBuffer的unlock函数
status_t err = mLockedBuffer->unlock();
//get返回这个GraphicBuffer的编号,queueBuffer将含有新数据的缓冲加入队中。
err =queueBuffer(mLockedBuffer.get());
mPostedBuffer = mLockedBuffer; //保存这个BackBuffer为mPostedBuffer
mLockedBuffer = 0;
returnerr;
}
~~~
来看queueBuffer调用,代码如下所示:
**Surface.cpp**
~~~
intSurface::queueBuffer(android_native_buffer_t* buffer)
{
sp<SurfaceComposerClient> client(getClient());
int32_t bufIdx =GraphicBuffer::getSelf(buffer)->getIndex();
//设置脏Region
mSharedBufferClient->setDirtyRegion(bufIdx,mDirtyRegion);
//更新写位置。
err =mSharedBufferClient->queue(bufIdx);
if (err== NO_ERROR) {
//client是BpSurfaceFlinger,调用它的signalServer,这样SF就知道新数据准备好了
client->signalServer();
}
returnerr;
}
~~~
这里,与读写控制有关的是queue函数,其代码如下所示:
**SharedBufferStack.cpp**
~~~
status_t SharedBufferClient::queue(int buf)
{
//QueueUpdate也是一个函数对象
QueueUpdate update(this);
//调用updateCondition函数。
status_t err = updateCondition( update );
SharedBufferStack& stack( *mSharedStack );
constnsecs_t now = systemTime(SYSTEM_TIME_THREAD);
stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
returnerr;
}
~~~
这个updateCondition函数的代码如下所示:
**SharedBufferStack.h**
~~~
template <typename T>
status_t SharedBufferBase::updateCondition(Tupdate) {
SharedClient& client( *mSharedClient );
Mutex::Autolock _l(client.lock);
ssize_t result = update();//调用update对象的()函数
client.cv.broadcast(); //触发同步对象
returnresult;
}
~~~
updateCondition函数和前面介绍的waitForCondition函数一样,都是使用的函数对象。queue操作使用的是QueueUpdate类,关于它的故事,将在拓展部分讨论。
3. lockCanvas和unlockCanvasAndPost的总结
总结一下lockCanvas和unlockCanvasAndPost这两个函数的工作流程,用图8-20表示:
:-: ![](http://img.blog.csdn.net/20150802162842059?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图8-20 lockCanvas和unlockCanvasAndPost流程总结
- 前言
- 第1章 阅读前的准备工作
- 1.1 系统架构
- 1.1.1 Android系统架构
- 1.1.2 本书的架构
- 1.2 搭建开发环境
- 1.2.1 下载源码
- 1.2.2 编译源码
- 1.3 工具介绍
- 1.3.1 Source Insight介绍
- 1.3.2 Busybox的使用
- 1.4 本章小结
- 第2章 深入理解JNI
- 2.1 JNI概述
- 2.2 学习JNI的实例:MediaScanner
- 2.3 Java层的MediaScanner分析
- 2.3.1 加载JNI库
- 2.3.2 Java的native函数和总结
- 2.4 JNI层MediaScanner的分析
- 2.4.1 注册JNI函数
- 2.4.2 数据类型转换
- 2.4.3 JNIEnv介绍
- 2.4.4 通过JNIEnv操作jobject
- 2.4.5 jstring介绍
- 2.4.6 JNI类型签名介绍
- 2.4.7 垃圾回收
- 2.4.8 JNI中的异常处理
- 2.5 本章小结
- 第3章 深入理解init
- 3.1 概述
- 3.2 init分析
- 3.2.1 解析配置文件
- 3.2.2 解析service
- 3.2.3 init控制service
- 3.2.4 属性服务
- 3.3 本章小结
- 第4章 深入理解zygote
- 4.1 概述
- 4.2 zygote分析
- 4.2.1 AppRuntime分析
- 4.2.2 Welcome to Java World
- 4.2.3 关于zygote的总结
- 4.3 SystemServer分析
- 4.3.1 SystemServer的诞生
- 4.3.2 SystemServer的重要使命
- 4.3.3 关于 SystemServer的总结
- 4.4 zygote的分裂
- 4.4.1 ActivityManagerService发送请求
- 4.4.2 有求必应之响应请求
- 4.4.3 关于zygote分裂的总结
- 4.5 拓展思考
- 4.5.1 虚拟机heapsize的限制
- 4.5.2 开机速度优化
- 4.5.3 Watchdog分析
- 4.6 本章小结
- 第5章 深入理解常见类
- 5.1 概述
- 5.2 以“三板斧”揭秘RefBase、sp和wp
- 5.2.1 第一板斧--初识影子对象
- 5.2.2 第二板斧--由弱生强
- 5.2.3 第三板斧--破解生死魔咒
- 5.2.4 轻量级的引用计数控制类LightRefBase
- 5.2.5 题外话-三板斧的来历
- 5.3 Thread类及常用同步类分析
- 5.3.1 一个变量引发的思考
- 5.3.2 常用同步类
- 5.4 Looper和Handler类分析
- 5.4.1 Looper类分析
- 5.4.2 Handler分析
- 5.4.3 Looper和Handler的同步关系
- 5.4.4 HandlerThread介绍
- 5.5 本章小结
- 第6章 深入理解Binder
- 6.1 概述
- 6.2 庖丁解MediaServer
- 6.2.1 MediaServer的入口函数
- 6.2.2 独一无二的ProcessState
- 6.2.3 时空穿越魔术-defaultServiceManager
- 6.2.4 注册MediaPlayerService
- 6.2.5 秋风扫落叶-StartThread Pool和join Thread Pool分析
- 6.2.6 你彻底明白了吗
- 6.3 服务总管ServiceManager
- 6.3.1 ServiceManager的原理
- 6.3.2 服务的注册
- 6.3.3 ServiceManager存在的意义
- 6.4 MediaPlayerService和它的Client
- 6.4.1 查询ServiceManager
- 6.4.2 子承父业
- 6.5 拓展思考
- 6.5.1 Binder和线程的关系
- 6.5.2 有人情味的讣告
- 6.5.3 匿名Service
- 6.6 学以致用
- 6.6.1 纯Native的Service
- 6.6.2 扶得起的“阿斗”(aidl)
- 6.7 本章小结
- 第7章 深入理解Audio系统
- 7.1 概述
- 7.2 AudioTrack的破解
- 7.2.1 用例介绍
- 7.2.2 AudioTrack(Java空间)分析
- 7.2.3 AudioTrack(Native空间)分析
- 7.2.4 关于AudioTrack的总结
- 7.3 AudioFlinger的破解
- 7.3.1 AudioFlinger的诞生
- 7.3.2 通过流程分析AudioFlinger
- 7.3.3 audio_track_cblk_t分析
- 7.3.4 关于AudioFlinger的总结
- 7.4 AudioPolicyService的破解
- 7.4.1 AudioPolicyService的创建
- 7.4.2 重回AudioTrack
- 7.4.3 声音路由切换实例分析
- 7.4.4 关于AudioPolicy的总结
- 7.5 拓展思考
- 7.5.1 DuplicatingThread破解
- 7.5.2 题外话
- 7.6 本章小结
- 第8章 深入理解Surface系统
- 8.1 概述
- 8.2 一个Activity的显示
- 8.2.1 Activity的创建
- 8.2.2 Activity的UI绘制
- 8.2.3 关于Activity的总结
- 8.3 初识Surface
- 8.3.1 和Surface有关的流程总结
- 8.3.2 Surface之乾坤大挪移
- 8.3.3 乾坤大挪移的JNI层分析
- 8.3.4 Surface和画图
- 8.3.5 初识Surface小结
- 8.4 深入分析Surface
- 8.4.1 与Surface相关的基础知识介绍
- 8.4.2 SurfaceComposerClient分析
- 8.4.3 SurfaceControl分析
- 8.4.4 writeToParcel和Surface对象的创建
- 8.4.5 lockCanvas和unlockCanvasAndPost分析
- 8.4.6 GraphicBuffer介绍
- 8.4.7 深入分析Surface的总结
- 8.5 SurfaceFlinger分析
- 8.5.1 SurfaceFlinger的诞生
- 8.5.2 SF工作线程分析
- 8.5.3 Transaction分析
- 8.5.4 关于SurfaceFlinger的总结
- 8.6 拓展思考
- 8.6.1 Surface系统的CB对象分析
- 8.6.2 ViewRoot的你问我答
- 8.6.3 LayerBuffer分析
- 8.7 本章小结
- 第9章 深入理解Vold和Rild
- 9.1 概述
- 9.2 Vold的原理与机制分析
- 9.2.1 Netlink和Uevent介绍
- 9.2.2 初识Vold
- 9.2.3 NetlinkManager模块分析
- 9.2.4 VolumeManager模块分析
- 9.2.5 CommandListener模块分析
- 9.2.6 Vold实例分析
- 9.2.7 关于Vold的总结
- 9.3 Rild的原理与机制分析
- 9.3.1 初识Rild
- 9.3.2 RIL_startEventLoop分析
- 9.3.3 RIL_Init分析
- 9.3.4 RIL_register分析
- 9.3.5 关于Rild main函数的总结
- 9.3.6 Rild实例分析
- 9.3.7 关于Rild的总结
- 9.4 拓展思考
- 9.4.1 嵌入式系统的存储知识介绍
- 9.4.2 Rild和Phone的改进探讨
- 9.5 本章小结
- 第10章 深入理解MediaScanner
- 10.1 概述
- 10.2 android.process.media分析
- 10.2.1 MSR模块分析
- 10.2.2 MSS模块分析
- 10.2.3 android.process.media媒体扫描工作的流程总结
- 10.3 MediaScanner分析
- 10.3.1 Java层分析
- 10.3.2 JNI层分析
- 10.3.3 PVMediaScanner分析
- 10.3.4 关于MediaScanner的总结
- 10.4 拓展思考
- 10.4.1 MediaScannerConnection介绍
- 10.4.2 我问你答
- 10.5 本章小结