[Android] [Android的视窗系统及显示机制][下] [底层显示子系统Surface与SurfaceFlinger]

前注: 原分析文章来自深入理解Android卷一

一、Surface绘制的精简流程

在这里插入图片描述

二、深入分析Surface与SurfaceFlinger

2.1 Surface

2.1.1 与Surface相关的基础知识介绍

  1. 显示层(Layer)和屏幕组成
    在这里插入图片描述

图8-10 屏幕组成示意图

从图8-10中可以看出:

· 屏幕位于一个三维坐标系中,其中Z轴从屏幕内指向屏幕外。

· 编号为①②③的矩形块叫显示层(Layer)。每一层有自己的属性,例如颜色、透明度、所处屏幕的位置、宽、高等。除了属性之外,每一层还有自己对应的显示内容,也就是需要显示的图像。

在Android中,Surface系统工作时,会由SurfaceFlinger对这些按照Z轴排好序的显示层进行图像混合,混合后的图像就是在屏幕上看到的美妙画面了。这种按Z轴排序的方式符合我们在日常生活中的体验,例如前面的物体会遮挡住后面的物体。

注意,Surface系统中定义了一个名为Layer类型的类,为了区分广义概念上的Layer和代码中的Layer,这里称广义层的Layer为显示层,以免混淆。

  1. FrameBuffer和PageFlipping
    我们知道,在Audio系统中,音频数据传输的过程是:

· 由客户端把数据写到共享内存中。

· 然后由AudioFlinger从共享内存中取出数据再往Audio HAL中发送。

根据以上介绍可知,在音频数据传输的过程中,共享内存起到了数据承载的重要作用。 无独有偶,Surface系统中的数据传输也存在同样的过程,但承载图像数据的是鼎鼎大名的FrameBuffer(简称FB)。下面先来介绍FrameBuffer,然后再介绍Surface的数据传输过程。

(1)FrameBuffer的介绍
FrameBuffer的中文名叫帧缓冲,它实际上包括两个不同的方面:

· Frame:帧,就是指一幅图像。在屏幕上看到的那幅图像就是一帧。

· Buffer:缓冲,就是一段存储区域,可这个区域存储的是帧。

FrameBuffer的概念很清晰,它就是一个存储图形/图像帧数据的缓冲。这个缓冲来自哪里?理解这个问题,需要简单介绍一下Linux平台的虚拟显示设备FrameBuffer Device(简称FBD)。FBD是Linux系统中的一个虚拟设备,设备文件对应为/dev/fb%d(比如/dev/fb0)。这个虚拟设备将不同硬件厂商实现的真实设备统一在一个框架下,这样应用层就可以通过标准的接口进行图形/图像的输入和输出了。图8-12展示了FBD示意图:

在这里插入图片描述
图8-12 Linux系统中的FBD示意图

从上图中可以看出,应用层通过标准的ioctl或mmap等系统调用,就可以操作显示设备,用起来非常方便。这里,把mmap的调用列出来,相信大部分读者都知道它的作用了。

FrameBuffer中的Buffer,就是通过mmap把设备中的显存映射到用户空间的,在这块缓冲上写数据,就相当于在屏幕上绘画。

(2)PageFlipping
图形/图像数据和音频数据不太一样,我们一般把音频数据叫音频流,它是没有边界的, 而图形/图像数据是一帧一帧的,是有边界的。这一点非常类似UDP和TCP之间的区别。所以在图形/图像数据的生产/消费过程中,人们使用了一种叫PageFlipping的技术。

PageFlipping的中文名叫画面交换,其操作过程如下所示:

· 分配一个能容纳两帧数据的缓冲,前面一个缓冲叫FrontBuffer,后面一个缓冲叫BackBuffer。

· 消费者使用FrontBuffer中的旧数据,而生产者用新数据填充BackBuffer,二者互不干扰。

· 当需要更新显示时,BackBuffer变成FrontBuffer,FrontBuffer变成BackBuffer。如此循环,这样就总能显示最新的内容了。这个过程很像我们平常的翻书动作,所以它被形象地称为PageFlipping。

说白了,PageFlipping其实就是使用了一个只有两个成员的帧缓冲队列,以后在分析数据传输的时候还会见到诸如dequeue和queue的操作。

  1. 图像混合
    我们知道,在AudioFlinger中有混音线程,它能将来自多个数据源的数据混合后输出,那么,SurfaceFlinger是不是也具有同样的功能呢?

答案是肯定的,否则它就不会叫Flinger了。Surface系统支持软硬两个层面的图像混合:

· 软件层面的混合:例如使用copyBlt进行源数据和目标数据的混合。

· 硬件层面的混合:使用Overlay系统提供的接口。

无论是硬件还是软件层面,都需将源数据和目标数据进行混合,混合需考虑很多内容,例如源的颜色和目标的颜色叠加后所产生的颜色。关于这方面的知识,读者可以学习计算机图形/图像学。这里只简单介绍一下copyBlt和Overlay。

· copyBlt,从名字上看,是数据拷贝,它也可以由硬件实现,例如现在很多的2D图形加速就是将copyBlt改由硬件来实现,以提高速度的。但不必关心这些,我们只需关心如何调用copyBlt相关的函数进行数据混合即可。

· Overlay方法必须有硬件支持才可以,它主要用于视频的输出,例如视频播放、摄像机摄像等,因为视频的内容往往变化很快,所以如改用硬件进行混合效率会更高。

2.1.2 客户端进程的Surface相关操作精简流程

这里,先总结一下前面讲解中和Surface有关的流程:

· 在ViewRoot构造时,会创建一个Surface,它使用无参构造函数,
· ViewRoot通过IWindowSession和WMS交互,而WMS中会调用的一个attach函数,会构造一个SurfaceSession,
· ViewRoot在performTransval的处理过程中会调用IWindowSession的relayout函数。从WMS获取有效显存的SurfaceControl对象,而后构造有效的Surface对象
· ViewRoot调用Surface的lockCanvas,得到一块画布。
· ViewRoot调用Surface的unlockCanvasAndPost释放这块画布。
在这里插入图片描述

2.1.3 Surface之乾坤大挪移

1. 乾坤大挪移的表象
relayout的函数是一个跨进程的调用,由WMS完成实际处理。先到ViewRoot中看看调用方的用法,代码如下所示:
relayout的函数是一个跨进程的调用,由WMS完成实际处理。

先到ViewRoot中看看调用方的用法,代码如下所示:

[–>ViewRoot.java]

private int relayoutWindow(WindowManager.LayoutParams params,

int viewVisibility, boolean insetsPending)

throws RemoteException {

   int relayoutResult = sWindowSession.relayout(

            mWindow, params,

           (int) (mView.mMeasuredWidth * appScale + 0.5f),

           (int) (mView.mMeasuredHeight * appScale + 0.5f),

           viewVisibility, insetsPending, mWinFrame,

           mPendingContentInsets, mPendingVisibleInsets,

           mPendingConfiguration, mSurface);//mSurface传了进去

    ......

   return relayoutResult;

}

再看接收方的处理。它在WMS的Session中,代码如下所示:

[–>WindowManagerService.java::Session]

public int relayout(IWindow window,WindowManager.LayoutParams attrs,

           int requestedWidth, int requestedHeight, int viewFlags,

           boolean insetsPending, Rect outFrame, Rect outContentInsets,

           Rect outVisibleInsets, Configuration outConfig,

Surface outSurface) {

//注意最后这个参数的名字,叫outSurface

//调用外部类对象的relayoutWindow

  returnrelayoutWindow(this, window, attrs,

                requestedWidth,requestedHeight, viewFlags, insetsPending,

                outFrame, outContentInsets,outVisibleInsets, outConfig,

outSurface);

}

[–>WindowManagerService.java]

public int relayoutWindow(Session session,IWindow client,

       WindowManager.LayoutParams attrs, int requestedWidth,

       int requestedHeight, int viewVisibility, boolean insetsPending,

       Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,

        Configuration outConfig, SurfaceoutSurface){

    .....

 try {

     //win就是WinState,这里将创建一个本地的Surface对象

     Surfacesurface = win.createSurfaceLocked();

      if(surface != null) {

        //先创建一个本地surface,然后在outSurface的对象上调用copyFrom

       //将本地Surface的信息拷贝到outSurface中,为什么要这么麻烦呢?

       outSurface.copyFrom(surface);

    ......

}

[–>WindowManagerService.java::WindowState]

Surface createSurfaceLocked() {

 ......

 try {

 //mSurfaceSession就是在Session上创建的SurfaceSession对象

 //这里,以它为参数,构造一个新的Surface对象

    mSurface = new Surface(

            mSession.mSurfaceSession, mSession.mPid,

             mAttrs.getTitle().toString(),

             0, w, h, mAttrs.format, flags);

  }

     Surface.openTransaction();//打开一个事务处理

    ......

     Surface.closeTransaction();//关闭一个事务处理。关于事务处理以后再分析

     ......

}

上面的代码段好像有点混乱。用图8-7来表示一下这个流程:
在这里插入图片描述
根据图8-7可知:

· WMS中的Surface是乾坤中的乾,它的构造使用了带SurfaceSession参数的构造函数。
· ViewRoot中的Surface是乾坤中的坤,它的构造使用了无参构造函数。
· copyFrom就是挪移,它将乾中的Surface信息,拷贝到坤中的Surface即outSurface里。

要是觉得乾坤大挪移就是这两三下,未免就太小看它了。为彻底揭示这期间的复杂过程,我们将使用必杀技——aidl工具。
2. 揭秘Surface的乾坤大挪移
aidl可以把XXX.aidl文件转换成对应的Java文件。刚才所说的乾坤大挪移发生在ViewRoot调用IWindowSession的relayout函数中,它在IWindowSession.adil中的定义如下:

[–>IWindowSesson.aidl]
interface IWindowSession {

......

 intrelayout(IWindow window, in WindowManager.LayoutParams attrs,

       int requestedWidth, int requestedHeight, int viewVisibility,

       boolean insetsPending, out Rect outFrame, out Rect outContentInsets,

       out Rect outVisibleInsets, out Configuration outConfig,

       out Surface outSurface);

… 略

3. 乾坤大挪移的真相
这里,总结一下乾坤大挪移的整个过程,如图8-8表示:
在这里插入图片描述
8.3.3 分析乾坤大挪移的JNI层
前文讲述的内容都集中在Java层,下面要按照流程顺序分析JNI层的内容。

  1. Surface的无参构造分析
    在JNI层,第一个被调用的是Surface的无参构造函数,其代码如下所示:

[–>Surface.java]

public Surface() {

    ......

   //CompatibleCanvas从Canvas类派生

   mCanvas = new CompatibleCanvas();

}
  1. SurfaceSession的构造
    现在要分析的是SurfaceSession,其构造函数如下所示:

[–>SurfaceSession.java]

public SurfaceSession() {

      init();//这是一个native函数

}

init是一个native函数。去看看它的JNI实现,它在android_view_Surface.cpp中,代码如下所示:

[–>android_view_Surface.cpp]

static void SurfaceSession_init(JNIEnv* env,jobject clazz)

{

 //创建一个SurfaceComposerClient对象

	   sp<SurfaceComposerClient> client = new SurfaceComposerClient;

client->incStrong(clazz);

//在Java对象中保存这个client对象的指针,类型为SurfaceComposerClient

   env->SetIntField(clazz, sso.client, (int)client.get());

}

这里先不讨论SurfaceComposerClient的内容,拟继续把乾坤大挪移的流程走完。
3. Surface的有参构造
下一个调用的是Surface的有参构造,其参数中有一个SurfaceSession。先看Java层的代码,如下所示:

[–>Surface.java]

publicSurface(SurfaceSession s,//传入一个SurfaceSession对象

       int pid, String name, int display, int w, int h, int format, int flags)

   throws OutOfResourcesException {

    ......

   mCanvas = new CompatibleCanvas();

  //又一个native函数,注意传递的参数:display以后再说,w,h代表绘图区域的宽高值

   init(s,pid,name,display,w,h,format,flags);

   mName = name;

}

Surface的native init函数的JNI实现,也在android_view_Surface.cpp中,一起来看:

[–>android_view_Surface.cpp]
Surface的native init函数的JNI实现,也在android_view_Surface.cpp中,一起来看:

[–>android_view_Surface.cpp]

static void Surface_init(

    JNIEnv*env, jobject clazz,

   jobject session,

   jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jintflags)

{

//从SurfaceSession对象中取出之前创建的那个SurfaceComposerClient对象

SurfaceComposerClient* client =

       (SurfaceComposerClient*)env->GetIntField(session, sso.client);



  sp<SurfaceControl> surface;//注意它的类型是SurfaceControl

if (jname == NULL) {

/*

调用SurfaceComposerClient的createSurface函数,返回的surface是一个

SurfaceControl类型。

*/

   surface = client->createSurface(pid, dpy, w, h, format, flags);

} else{

    ......

}

  //把这个surfaceControl对象设置到Java层的Surface对象中,对这个函数就不再分析了

  setSurfaceControl(env, clazz, surface);

}
  1. copyFrom的分析
    现在要分析的就是copyFrom了。它就是一个native函数。看它的JNI层代码:

[–>android_view_Surface.cpp]

static void Surface_copyFrom(JNIEnv* env,jobject clazz, jobject other)

{

   //根据JNI函数的规则,clazz是copyFrom的调用对象,而other是copyFrom的参数。

   //目标对象此时还没有设置SurfaceControl,而源对象在前面已经创建了SurfaceControl

   constsp<SurfaceControl>& surface = getSurfaceControl(env, clazz);

   constsp<SurfaceControl>& rhs = getSurfaceControl(env, other);

if (!SurfaceControl::isSameSurface(surface, rhs)) {

        //把源SurfaceControl对象设置到目标Surface中。

       setSurfaceControl(env, clazz, rhs);

    }

}

这一步还是比较简单的,下面看第五步writeToParcel函数的调用。

  1. writeToParcel的分析
    多亏了必杀技aidl工具的帮忙,才挖出这个隐藏的writeToParcel函数调用,下面就来看看它,代码如下所示:

[–>android_view_Surface.cpp]

static void Surface_writeToParcel(JNIEnv* env,jobject clazz,

jobject argParcel, jint flags)

{

   Parcel* parcel = (Parcel*)env->GetIntField(argParcel, no.native_parcel);

//clazz就是Surface对象,从这个Surface对象中取出保存的SurfaceControl对象

const sp<SurfaceControl>&control(getSurfaceControl(env, clazz));

/*

把SurfaceControl中的信息写到Parcel包中,然后利用Binder通信传递到对端,

对端通过readFromParcel来处理Parcel包。

*/

   SurfaceControl::writeSurfaceToParcel(control, parcel);

if (flags & PARCELABLE_WRITE_RETURN_VALUE) {

       //还记得PARCELABLE_WRITE_RETURN_VALUE吗?flags的值就等于它

       //所以本地Surface对象的SurfaceControl值被置空了

       setSurfaceControl(env, clazz, 0);

    }

}
  1. readFromParcel的分析
    再看作为客户端的ViewRoot所调用的readFromParcel函数。它也是一个native函数,JNI层的代码如下所示:

[–>android_view_Surface.cpp]

static void Surface_readFromParcel(

       JNIEnv* env, jobject clazz, jobject argParcel)

{

   Parcel* parcel = (Parcel*)env->GetIntField( argParcel,no.native_parcel);

  

   //注意下面定义的变量类型是Surface,而不是SurfaceControl

   const sp<Surface>&control(getSurface(env, clazz));

   //根据服务端传递的Parcel包来构造一个新的surface。

   sp<Surface> rhs = new Surface(*parcel);

if (!Surface::isSameSurface(control, rhs)) {

//把这个新surface赋给ViewRoot中的mSurface对象。

      setSurface(env,clazz, rhs);

    }

}

7. Surface乾坤大挪移的小结
可能有人会问,乾坤大挪移怎么这么复杂?这期间出现了多少对象?来总结一下,在此期间一共有三个关键对象(注意我们这里只考虑JNI层的Native对象),它们分别是:
· SurfaceComposerClient。
· SurfaceControl。
· Surface,这个Surface对象属于Native层,和Java层的Surface相对应。
其中转移到ViewRoot成员变量mSurface中的,就是最后这个Surface对象了。这一路走来,真是异常坎坷。来回顾并概括总结一下这段历程。至于它的作用应该是很清楚了。以后要破解SurfaceFlinger,靠的就是这个精简的流程。
· 创建一个SurfaceComposerClient。
· 调用SurfaceComposerClient的createSurface得到一个SurfaceControl对象。
· 调用SurfaceControl的writeToParcel把一些信息写到Parcel包中。
· 根据Parcel包的信息构造一个Surface对象。这个Surface对象保存到Java层的mSurface对象中。这样,大挪移的结果是ViewRoot得到一个Native的Surface对象。

精简流程后,寥寥数语就可把过程说清楚。以后我们在研究代码时,也可以采取这种方式。

这个Surface对象非常重要,可它到底有什么用呢?这正是下一节要讲的内容。

2.1.4 Surface详细构造过程

2.1.4.1 Surface底层相关类概览

Java层只认识Surface,而实际上,底层错踪复杂
Surface包含一个SurfaceControl对象,SurfaceControl包含SurfaceComposerClient对象,这只是开始,其余的关系如下图
在这里插入图片描述

2.1.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 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]

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());

    returnbclient;

}

上面代码中提到,Client会创建一块共享内存。熟悉Audio的读者或许会认为,这可能是Surface的ControlBlock对象了!是的。CB对象在协调生产/消费步调时,起到了决定性的控制作用,所以非常重要,下面来看:

[–>SurfaceFlinger.cpp]

Client::Client(ClientID clientID, constsp<SurfaceFlinger>& 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<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:

    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的示意图:
在这里插入图片描述
图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, constsp<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在客户端的对应物。

  1. 到底有多少种对象?
    这一节,出现了好几种类型的对象,通过图8-14来看看它们:
    图8-14 类之间关系展示图
    在这里插入图片描述
    从上图中可以看出:

· SurfaceFlinger是从Thread派生的,所以它会有一个单独运行的工作线程。
· BClient和SF之间采用了Proxy模式,BClient支持Binder通信,它接收客户端的请求,并派发给SF执行。
· SharedClient构建于一块共享内存中,SurfaceComposerClient和Client对象均持有这块共享内存。
在精简流程中,关于SurfaceComposerClient就分析到这里,下面分析第二个步骤中的SurfaceControl对象。

8.4.3 SurfaceControl的分析

  1. SurfaceControl的来历
    根据精简的流程可知,这一节要分析的是SurfaceControl对象。先回顾一下这个对象的创建过程,代码如下所示:

[–>android_view_Surface.cpp]

  1. SurfaceControl的来历
    根据精简的流程可知,这一节要分析的是SurfaceControl对象。先回顾一下这个对象的创建过程,代码如下所示:

[–>android_view_Surface.cpp]

static void Surface_init(JNIEnv* env, jobjectclazz, jobject session,

   jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jintflags)

{

SurfaceComposerClient* client =

       (SurfaceComposerClient*)env->GetIntField(session, sso.client);

//注意这个变量,类型是SurfaceControl,名字却叫surface,稍不留神就出错了。

sp<SurfaceControl>surface;

if (jname == NULL) {

//调用Client的createSurface函数,得到一个SurfaceControl对象。

surface= client->createSurface(pid, dpy, w, h, format, flags);

}

//将这个SurfaceControl对象设置到Java层的对象中保存。

setSurfaceControl(env, clazz, surface);

}

**通过上面的代码可知,SurfaceControl对象由createSurface得来,**下面看看这个函数。

此时,读者或许会被代码中随意起的变量名搞糊涂,因为我的处理方法碰到了容易混淆的地方,尽量以对象类型来表示这个对象。

(1)分析createSurface的请求端
在createSurface内部会使用Binder通信将请求发给SF,所以它分为请求和响应两端,先看请求端,代码如下所示:

[–>SurfaceComposerClient.cpp]

spSurfaceComposerClient::createSurface(

   int pid,

   DisplayID display,//DisplayID是什么意思?

   uint32_t w,

   uint32_t h,

   PixelFormat format,

   uint32_t flags)

{

String8 name;

constsize_t SIZE = 128;

charbuffer[SIZE];

snprintf(buffer, SIZE, “<pid_%d>”, getpid());

name.append(buffer);

//调用另外一个createSurface,多一个name参数

returnSurfaceComposerClient::createSurface(pid, name, display,

       w, h, format, flags);

}

在分析另外一个createSurface之前,应先介绍一下DisplayID的含义

typedef int32_t DisplayID;

DisplayID是一个int整型,它的意义是屏幕编号,例如**双屏手机就有内屏和外屏两块屏幕。**由于目前Android的Surface系统只支持一块屏幕,所以这个变量的取值都是0。

再分析另外一个createSurface函数,它的代码如下所示:

[–>SurfaceComposerClient.cpp]

spSurfaceComposerClient::createSurface(

   int pid,const String8& name,DisplayID display,uint32_t w,

   uint32_t h,PixelFormat format,uint32_t flags)

{

sp result;

if(mStatus == NO_ERROR) {

   ISurfaceFlingerClient::surface_data_t data;

    //调用BpSurfaceFlingerClient的createSurface函数

   sp<ISurface> surface = mClient->createSurface(&data, pid,name,

                             display, w, h,format, flags);

    if(surface != 0) {

       if (uint32_t(data.token) < NUM_LAYERS_MAX) {

           //以返回的ISurface对象创建一个SurfaceControl对象

           result = new SurfaceControl(this, surface, data, w, h,

format, flags);

       }

    }

}

returnresult;//返回的是SurfaceControl对象

}

请求端的处理比较简单:

· 调用跨进程的createSurface函数,得到一个ISurface对象,根据Binder一章的知识可知,这个对象的真实类型是BpSurface。不过以后统称之为ISurface。
· 以这个ISurface对象为参数,构造一个SurfaceControl对象。
createSurface函数的响应端在SurfaceFlinger进程中,下面去看这个函数。

在Surface系统定义了很多类型,咱们也中途休息一下,不妨来看看和字符串“Surface”有关的有多少个类,权当其为小小的娱乐:

Native层有Surface、ISurface、SurfaceControl、SurfaceComposerClient。

Java层有Surface、SurfaceSession。

上面列出的还只是一部分,后面还有呢!&@&%¥*

(2)分析createSurface的响应端
前面讲过,可把BClient看作是SF的Proxy,它会把来自客户端的请求派发给SF处理,通过代码来看看,是不是这样的?如下所示:

[–>SurfaceFlinger.cpp]

sp BClient::createSurface(

   ISurfaceFlingerClient::surface_data_t* params, int pid,

   const String8& name,

   DisplayID display, uint32_t w, uint32_t h, PixelFormat format,

   uint32_t flags)

{

//果然是交给SF处理,以后我们将跳过BClient这个代理。

return mFlinger->createSurface(mId, pid,name, params, display, w, h,

       format, flags);

}

来看createSurface函数,它的目的就是创建一个ISurface对象,不过这中间的玄机还挺多,代码如下所示:

[–>SurfaceFlinger.cpp]

spSurfaceFlinger::createSurface(ClientID clientId, int pid,

   const String8& name, ISurfaceFlingerClient::surface_data_t* params,

   DisplayID d, uint32_t w, uint32_t h, PixelFormat format,

   uint32_t flags)

{

sp layer;//LayerBaseClient是Layer家族的基类

//这里又冒出一个LayerBaseClient的内部类,它也叫Surface,是不是有点头晕了?

spLayerBaseClient::Surface surfaceHandle;

Mutex::Autolock _l(mStateLock);

//根据clientId找到createConnection时加入的那个Client对象

sp client = mClientsMap.valueFor(clientId);

......

//注意这个id,它的值表示Client创建的是第几个显示层,根据图8-14可以看出,这个id

//同时也表示将使用SharedBufferStatck数组的第id个元素。

int32_t id = client->generateId(pid);

//一个Client不能创建多于NUM_LAYERS_MAX个的Layer。

if(uint32_t(id) >= NUM_LAYERS_MAX) {

   return surfaceHandle;

}

//根据flags参数来创建不同类型的显示层,我们在8.4.1节介绍过相关知识

switch(flags & eFXSurfaceMask) {

   case eFXSurfaceNormal:

       if (UNLIKELY(flags & ePushBuffers)) {

         //创建PushBuffer类型的显示层,我们将在拓展思考部分分析它

        layer = createPushBuffersSurfaceLocked(client, d, id,

                    w, h, flags);

       } else {

           //①创建Normal类型的显示层,我们分析待会这个

           layer = createNormalSurfaceLocked(client, d, id,

                    w, h, flags, format);

       }

       break;

   case eFXSurfaceBlur:

        //创建Blur类型的显示层

       layer = createBlurSurfaceLocked(client, d, id, w, h, flags);

       break;

    case eFXSurfaceDim:

        //创建Dim类型的显示层

       layer = createDimSurfaceLocked(client, d, id, w, h, flags);

       break;

}



if(layer != 0) {

   layer->setName(name);

   setTransactionFlags(eTransactionNeeded);

//从显示层对象中取出一个ISurface对象赋值给SurfaceHandle

   surfaceHandle = layer->getSurface();

    if(surfaceHandle != 0) {

       params->token = surfaceHandle->getToken();

       params->identity = surfaceHandle->getIdentity();

       params->width = w;

       params->height = h;

       params->format = format;

    }

}

returnsurfaceHandle;//ISurface的Bn端就是这个对象。

}

上面代码中的函数倒是很简单,知识代码里面冒出来的几个新类型和它们的名字却让人有点头晕。先用文字总结一下:

· LayerBaseClient:前面提到的显示层在代码中的对应物,就是这个LayerBaseClient,不过这是一个大家族,不同类型的显示层将创建不同类型的LayerBaseClient。
· LayerBaseClient中有一个内部类,名字叫Surface,这是一个支持Binder通信的类,它派生于ISurface。

关于Layer的故事,后面会有单独的章节来介绍。这里先继续分析createNormalSurfaceLocked函数。它的代码如下所示:

[–>SurfaceFlinger.cpp]

spSurfaceFlinger::createNormalSurfaceLocked(

   const sp<Client>& client, DisplayID display,

   int32_t id, uint32_t w, uint32_t h, uint32_t flags,

   PixelFormat& format)

{

switch(format) { //一些图像方面的参数设置,可以不去管它。

casePIXEL_FORMAT_TRANSPARENT:

casePIXEL_FORMAT_TRANSLUCENT:

   format = PIXEL_FORMAT_RGBA_8888;

   break;

casePIXEL_FORMAT_OPAQUE:

   format = PIXEL_FORMAT_RGB_565;

   break;

}

//①创建一个Layer类型的对象

sp layer = new Layer(this, display,client, id);

//②设置Buffer

status_t err = layer->setBuffers(w, h, format, flags);

if (LIKELY(err == NO_ERROR)) {

     //初始化这个新layer的一些状态

   layer->initStates(w, h, flags);

   //③ 还记得在图8-10中提到的Z轴吗?下面这个函数把这个layer加入到Z轴大军中。

   addLayer_l(layer);

}

returnlayer;

}

createNormalSurfaceLocked函数有三个关键点,它们是:

· 构造一个Layer对象。

· 调用Layer对象的setBuffers函数。

· 调用SF的addLayer_l函数。

暂且记住这三个关键点,后文有单独章节分析它们。先继续分析SurfaceControl的流程。

(3)创建SurfaceControl对象
当跨进程的createSurface调用返回一个ISurface对象时,将通过下面的代码创建一个SurfaceControl对象:

result = new SurfaceControl(this, surface, data,w, h,format, flags);

下面来看这个SurfaceControl对象为何物。它的代码如下所示:

[–>SurfaceControl.cpp]

SurfaceControl::SurfaceControl(

   const sp<SurfaceComposerClient>& client,

   const sp<ISurface>& surface,

   const ISurfaceFlingerClient::surface_data_t& data,

   uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)

//mClient为SurfaceComposerClient,而mSurface指向跨进程createSurface调用

//返回的ISurface对象。

:mClient(client), mSurface(surface),

 mToken(data.token), mIdentity(data.identity),

 mWidth(data.width), mHeight(data.height), mFormat(data.format),

 mFlags(flags)

{

}

SurfaceControl类可以看作是一个wrapper类:
它封装了一些函数,通过这些函数可以方便地调用mClient或ISurface提供的函数。
在SurfaceControl的分析过程中,还遗留了和Layer相关的部分,下面就来解决它们。

2. Layer和它的家族
**我们在createSurface中创建的是Normal的Layer,**下面先看这个Layer的构造函数。

(1)Layer的构造
Layer是从LayerBaseClient派生的,其代码如下所示:

[–>Layer.cpp]

Layer::Layer(SurfaceFlinger* flinger, DisplayIDdisplay,

   const sp<Client>& c, int32_t i)//这个i表示SharedBufferStack数组的索引

:   LayerBaseClient(flinger, display, c, i),//先调用基类构造函数

   mSecure(false),

   mNoEGLImageForSwBuffers(false),

   mNeedsBlending(true),

   mNeedsDithering(false)

{

 //getFrontBuffer实际取出的是FrontBuffer的位置

mFrontBufferIndex = lcblk->getFrontBuffer();

}

再来看基类LayerBaseClient的构造函数,代码如下所示:

[–>LayerBaseClient.cpp]

LayerBaseClient::LayerBaseClient(SurfaceFlinger*flinger, DisplayID display,

   const sp<Client>& client, int32_t i)

:LayerBase(flinger, display), lcblk(NULL), client(client), mIndex(i),

  mIdentity(uint32_t(android_atomic_inc(&sIdentity)))

{

/*

创建一个SharedBufferServer对象,注意它使用了SharedClient对象,

并且传入了表示SharedBufferStack数组索引的i和一个常量NUM_BUFFERS

*/

lcblk = new SharedBufferServer(

       client->ctrlblk, i, NUM_BUFFERS,//该值为常量2,在Layer.h中定义

       mIdentity);

}

SharedBufferServer是什么?它和SharedClient有什么关系?

其实,之前在介绍SharedClient时曾提过与此相关的内容,这里再来认识一下,先看图8-15:
在这里插入图片描述

图8-15 ShardBufferServer的示意图

根据上图并结合前面的介绍,可以得出以下结论:

· 在SF进程中,Client的一个Layer将使用SharedBufferStack数组中的一个成员,并通过SharedBufferServer结构来控制这个成员,我们知道SF是消费者,所以可由SharedBufferServer来控制数据的读取。
· 与之相对应,客户端的进程也会有一个对象来使用这个SharedBufferStatck,可它是通过另外一个叫SharedBufferClient的结构来控制的。客户端为SF提供数据,所以可由SharedBufferClient控制数据的写入。在后文的分析中还会碰到SharedBufferClient。

注意,在拓展思考部分,会有单独章节来分析生产/消费过程中的读写控制。

通过前面的代码可知**,Layer对象被new出来后,传给了一个sp对象,读者还记得sp中的onFirstRef函数吗?Layer家族在这个函数中还有一些处理。一起去看看,但这个函数由基类LayerBaseClient实现。**

[–>LayerBase.cpp]

void LayerBaseClient::onFirstRef()

{

sp client(this->client.promote());

if (client != 0) {

//把自己加入client对象的mLayers数组中,这部分内容比较简单,读者可以自行研究

   client->bindLayer(this, mIndex);

}

}

好,Layer创建完毕,下面来看第二个重要的函数setBuffers。

(2)setBuffers的分析
setBuffers,Layer类以及Layer的基类都有实现。由于创建的是Layer类型的对象,所以请读者直接到Layer.cpp中寻找setBuffers函数。**这个函数的目的就是创建用于PageFlipping的FrontBuffer和BackBuffer。**一起来看,代码如下所示:

[–>Layer.cpp]

status_t Layer::setBuffers( uint32_t w, uint32_th,

                        PixelFormat format,uint32_t flags)

{

PixelFormatInfo info;

status_t err = getPixelFormatInfo(format, &info);

if(err) return err;

//DisplayHardware是代表显示设备的HAL对象,0代表第一块屏幕的显示设备。

//这里将从HAL中取出一些和显示相关的信息。

constDisplayHardware& hw(graphicPlane(0).displayHardware());

uint32_t const maxSurfaceDims = min(

       hw.getMaxTextureSize(), hw.getMaxViewportDims());

PixelFormatInfo displayInfo;

getPixelFormatInfo(hw.getFormat(),&displayInfo);

constuint32_t hwFlags = hw.getFlags();



......

/*

创建Buffer,这里将创建两个GraphicBuffer。这两个GraphicBuffer就是我们前面

所说的FrontBuffer和BackBuffer。

*/

for (size_t i=0 ; i<NUM_BUFFERS ; i++) {

//注意,这里调用的是GraphicBuffer的无参构造函数,mBuffers是一个二元数组。

   mBuffers[i] = new GraphicBuffer();

}

//又冒出来一个SurfaceLayer类型,#¥%……&*!@

mSurface = new SurfaceLayer(mFlinger, clientIndex(), this);

returnNO_ERROR;

}

setBuffers函数的工作内容比较简单,就是:

· 创建一个GraphicBuffer缓冲数组,元素个数为2,即FrontBuffer和BackBuffer。

· 创建一个SurfaceLayer,关于它的身世我们后续再介绍。

GraphicBuffer是Android提供的显示内存管理类,关于它的故事,将在8.4.7节中介绍。我们暂把它当做普通的Buffer即可。

setBuffers中出现的SurfaceLayer类是什么?读者可能对此感觉有些晕乎。待把最后一个关键函数addLayer_l介绍完,或许就不太晕了。

(3)addLayer_l的分析
addLayer_l把这个新创建的layer加入自己的Z轴大军,下面来看:

[–>SurfaceFlinger.cpp]

status_t SurfaceFlinger::addLayer_l(constsp& layer)

{

/*

mCurrentState是SurfaceFlinger定义的一个结构,它有一个成员变量叫

layersSortedByZ,其实就是一个排序数组。下面这个add函数将把这个新的layer按照

它在Z轴的位置加入到排序数组中。mCurrentState保存了所有的显示层。

*/

ssize_t i = mCurrentState.layersSortedByZ.add(

                         layer,&LayerBase::compareCurrentStateZ);

sp lbc =

LayerBase::dynamicCast< LayerBaseClient*>(layer.get());

if(lbc != 0) {

   mLayerMap.add(lbc->serverIndex(), lbc);

}

returnNO_ERROR;

}

对Layer的三个关键函数都已分析过了,下面正式介绍Layer家族。

(4)Layer家族的介绍
前面的内容确让人头晕眼花,现在应该帮大家恢复清晰的头脑。先来“一剂猛药”,见图8-16:
在这里插入图片描述
图8-16 Layer家族

通过上图可知:

· LayerBaseClient从LayerBase类派生。

· LayerBaseClient还有四个派生类,分别是Layer、LayerBuffer、LayerDim和LayerBlur。

· LayerBaseClient定义了一个内部类Surface,这个Surface从ISurface类派生,它支持Binder通信。

· 针对不同的类型,Layer和LayerBuffer分别有一个内部类SurfaceLayer和SurfaceLayerBuffer,它们继承了LayerBaseClient的Surface类。所以对于Normal类型的显示层来说,getSurface返回的ISurface对象的真正类型是SurfaceLayer。

· LayerDim和LayerBlur类没有定义自己的内部类,所以对于这两种类型的显示层来说,它们直接使用了LayerBaseClient的Surface。

· ISurface接口提供了非常简单的函数,如requestBuffer、postBuffer等。

这里大量使用了内部类。我们知道,内部类最终都会把请求派发给外部类对象来处理,既然如此,在以后分析中,如果没有特殊情况,就会直接跳到外部类的处理函数中。

强烈建议Google把Surface相关代码好好整理一下,至少让类型名取得更直观些,现在这样确实有点让人头晕。好,来小小娱乐一下。看之前介绍的和“Surface”有关的名字:

Native层有Surface、ISurface、SurfaceControl、SurfaceComposerClient。

Java层有Surface、SurfaceSession。

在介绍完Layer家族后,与它相关的名字又多了几个,它们是

LayerBaseClient::Surface、Layer::SurfaceLayer、LayerBuffer::SurfaceLayerBuffer。

3. SurfaceControl总结
SurfaceControl创建后得到了什么呢?可用图8-17来表示:

在这里插入图片描述
图8-17 SurfaceControl创建后的结果图

通过上图可以知道:
· mClient成员变量指向SurfaceComposerClient。
· mSurface的Binder通信响应端为SurfaceLayer。
· SurfaceLayer有一个变量mOwner指向它的外部类Layer,而Layer有一个成员变量mSurface指向SurfaceLayer。这个SurfaceLayer对象由getSurface函数返回。
注意,mOwner变量由SurfaceLayer的基类Surface(LayBaseClient的内部类)定义。

接下来就是writeToParcel分析和Native Surface对象的创建了。注意,这个Native的Surface可不是LayBaseClient的内部类Surface。

8.4.4 writeToParcel和Surface对象的创建
从乾坤大挪移的知识可知,前面创建的所有对象都在WindowManagerService所在的进程system_server中,而writeToParcel则需要把一些信息打包到Parcel后,发送到Activity所在的进程。到底哪些内容需要回传给Activity所在的进程呢?

后文将Activity所在的进程简称为Activity端。

  1. writeToParcel分析
    writeToParcel比较简单,就是把一些信息写到Parcel中去。代码如下所示:

[–>SurfaceControl.cpp]

status_t SurfaceControl::writeSurfaceToParcel(

   const sp<SurfaceControl>& control, Parcel* parcel)

{

uint32_t flags = 0;

uint32_t format = 0;

SurfaceID token = -1;

uint32_t identity = 0;

uint32_t width = 0;

uint32_t height = 0;

sp client;

sp sur;

if(SurfaceControl::isValid(control)) {

   token    = control->mToken;

    identity= control->mIdentity;

   client   = control->mClient;

   sur      = control->mSurface;

   width    = control->mWidth;

   height   = control->mHeight;

   format   = control->mFormat;

   flags    = control->mFlags;

}

//SurfaceComposerClient的信息需要传递到Activity端,这样客户端那边会构造一个

//SurfaceComposerClient对象

parcel->writeStrongBinder(client!=0 ? client->connection() : NULL);

//把ISurface对象信息也写到Parcel中,这样Activity端那边也会构造一个ISurface对象

parcel->writeStrongBinder(sur!=0?sur->asBinder(): NULL);

parcel->writeInt32(token);

parcel->writeInt32(identity);

parcel->writeInt32(width);

parcel->writeInt32(height);

parcel->writeInt32(format);

parcel->writeInt32(flags);

returnNO_ERROR;

}

Parce包发到Activity端后,readFromParcel将根据这个Parcel包构造一个Native的Surface对象,一起来看相关代码。

2. 分析Native的Surface创建过程
[–>android_view_Surface.cpp]

static void Surface_readFromParcel(

   JNIEnv* env, jobject clazz, jobject argParcel)

{

Parcel* parcel = (Parcel*)env->GetIntField( argParcel, no.native_parcel);

const sp& control(getSurface(env,clazz));

//根据服务端的parcel信息来构造客户端的Surface

sp rhs = new Surface(*parcel);

if(!Surface::isSameSurface(control, rhs)) {

     setSurface(env, clazz, rhs);

}

}

Native的Surface是怎么利用这个Parcel包的?代码如下所示:

[–>Surface.cpp]

Surface::Surface(const Parcel& parcel)

:mBufferMapper(GraphicBufferMapper::get()),

mSharedBufferClient(NULL)

{

/*

Surface定义了一个mBuffers变量,它是一个sp的二元数组,也就是说Surface也存在二个GraphicBuffer,而之前在创建Layer的时候也有两个GraphicBuffer,难道一共有四个GraphicBuffer?这个问题,后面再解答。

*/

sp clientBinder =parcel.readStrongBinder();

//得到ISurface的Bp端BpSurface。

mSurface =interface_cast(parcel.readStrongBinder());

mToken = parcel.readInt32();

mIdentity = parcel.readInt32();

mWidth = parcel.readInt32();

mHeight = parcel.readInt32();

mFormat = parcel.readInt32();

mFlags = parcel.readInt32();

if (clientBinder != NULL) {

 /*

根据ISurfaceFlingerClient对象构造一个SurfaceComposerClient对象,注意我们

现在位于Activity端,这里还没有创建SurfaceComposerClient对象,所以需要创建一个

  */

   mClient = SurfaceComposerClient::clientForConnection(clientBinder);

   //SharedBuffer家族的最后一员ShardBufferClient终于出现了。

   mSharedBufferClient = new SharedBufferClient(

                         mClient->mControl, mToken, 2,mIdentity);

}

init();//做一些初始化工作。

}

在Surface创建完后,得到什么了呢?看图8-18就可知道:
在这里插入图片描述
图8-18 Native Surface的示意图

上图很清晰地说明:

· ShardBuffer家族依托共享内存结构SharedClient与它共同组成了Surface系统生产/消费协调的中枢控制机构,它在SF端的代表是SharedBufferServer,在Activity端的代表是SharedBufferClient。
· Native的Surface将和SF中的SurfaceLayer建立Binder联系。

另外,图中还特意画出了承载数据的GraphicBuffer数组,在代码的注释中也针对GraphicBuffer提出了一个问题:Surface中有两个GraphicBuffer,Layer也有两个,一共就有四个GraphicBuffer了,可是为什么这里只画出两个呢?

答案是,咱们不是有共享内存吗?这四个GraphicBuffer其实操纵的是同一段共享内存,所以为了简单,就只画了两个GraphicBuffer。在8.4.7节再介绍GraphicBuffer的故事。

下面,来看中枢控制机构的SharedBuffer家族。

3. SharedBuffer家族介绍
(1)SharedBuffer家族成员
SharedBuffer是一个家族名称,它包括多少成员呢?来看SharedBuffer的家族图谱,如图8-19所示:
在这里插入图片描述
图8-19 SharedBuffer家族介绍

从上图可以知道:

· XXXCondition、XXXUpdate等都是内部类,它们主要是用来更新读写位置的。不过这些操作,为什么要通过类来封装呢?因为SharedBuffer的很多操作都使用了C++中的Function Object(函数对象),而这些内部类的实例就是函数对象。函数对象是什么?它怎么使用?对此,在以后的分析中会介绍。

(2)SharedBuffer家族和SharedClient的关系
前面介绍过,SharedBufferServer和SharedBufferClient控制的其实只是SharedBufferStack数组中的一个,下面通过SharedBufferBase的构造函数,来看是否如此。

[–>SharedBufferStack.cpp]

SharedBufferBase::SharedBufferBase(SharedClient*sharedClient,

   int surface, int num, int32_t identity)

: mSharedClient(sharedClient),

mSharedStack(sharedClient->surfaces+ surface),

mNumBuffers(num), //根据前面PageFlipping的知识可知,num值为2

mIdentity(identity)

{

/*

上面的赋值语句中最重要的是第二句:

mSharedStack(sharedClient->surfaces +surface)

这条语句使得这个SharedBufferXXX对象,和SharedClient中SharedBufferStack数组

的第surface个元素建立了关系

*/

}

4. Native Surface总结
至此,Activity端Java的Surface对象**,终于和一个Native Surface对象挂上了钩,并且这个Native Surface还准备好了绘图所需的一切,其中包括:
· 两个GraphicBuffer,这就是PageFlipping所需要的FrontBuffer和BackBuffer。
· SharedBufferServer和SharedBufferClient结构,这两个结构将用于生产/消费的过程控制。
· 一个ISurface对象,这个对象连接着SF中的一个SurfaceLayer对象。
· 一个SurfaceComposerClient对象,这个对象连接着SF中的一个BClient对象。
资源都已经准备好了,可以开始绘制UI了。下面,分析两个关键的函数lockCanvas和unlockCanvasAndPost。**

8.4.5 lockCanvas和unlockCanvasAndPost的分析
这一节,分析精简流程中的最后两个函数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* buffer) {

android_native_buffer_t* out;

status_t err = dequeueBuffer(&out);//调用另外一个dequeueBuffer

if(err == NO_ERROR) {

   *buffer = GraphicBuffer::getSelf(out);

}

returnerr;

}
。。。 。。。
至此,getBufferLocked的目的,已比较清晰了:

· 调用ISurface的requestBuffer得到一个GraphicBuffer对象,这个GraphicBuffer对象被设置到本地的mBuffers数组中。看来Surface定义的这两个GraphicBuffer和Layer定义的两个GraphicBuffer是有联系的,所以图8-18中只画了两个GraphicBuffer。

我们已经知道,ISurface的Bn端实际上是定义在Layer.类中的SurfaceLayer,下面来看它实现的requestBuffer。由于SurfaceLayer是Layer的内部类,它的工作最终都会交给Layer来处理,所以这里可直接看Layer的requestBuffer函数:

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();

}

不管怎样,此时跨进程的这个requestBuffer返回的GraphicBuffer,已经和一块物理存储绑定到一起了。所以dequeueBuffer顺利返回了它所需的东西。接下来则需调用lockBuffer。
(2)lockBuffer的分析
lockBuffer的代码如下所示:

[–>Surface.cpp]
。。。。
OK,lockCanvas返回后,应用层将在这块画布上尽情作画。假设现在已经在BackBuffer上绘制好了图像,下面就要通过unlockCanvasAndPost进行后续工作了。一起来看。

  1. unlockCanvasAndPost的分析
    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 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

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表示:

在这里插入图片描述
8.4.6 GraphicBuffer的介绍
GraphicBuffer是Surface系统中一个高层次的显示内存管理类,它封装了和硬件相关的一些细节,简化了应用层的处理逻辑。先来认识一下它。

  1. 初识GraphicBuffer
    GraphicBuffer的代码如下所示:

[–>GraphicBuffer.h]
class GraphicBuffer

:public EGLNativeBase<android_native_buffer_t,

           GraphicBuffer,LightRefBase<GraphicBuffer>>,

public Flattenable
其中,EGLNativeBase是一个模板类。它的定义,代码如下所示:

[–>Android_natives.h]
template <typename NATIVE_TYPE, typenameTYPE, typename REF>

class EGLNativeBase : public NATIVE_TYPE, publicREF
通过替换,可得到GraphicBuffer的派生关系,如图8-21所示:
在这里插入图片描述
图8-21 GraphicBuffer派生关系的示意图

从图中可以看出:

· 从LightRefBase派生使GraphicBuffer支持轻量级的引用计数控制。

· 从Flattenable派生使GraphicBuffer支持序列化,它的flatten和unflatten函数用于序列化和反序列化,这样,GraphicBuffer的信息就可以存储到Parcel包中并被Binder传输了。

另外,图中的android_native_buffer_t是GraphicBuffer的父类,它是一个struct结构体。可以将C++语言中的struct和class当作同一个东西,所以GraphicBuffer能从它派生。其代码如下所示:

[–>android_native_buffer.h]
typedef struct android_native_buffer_t

{

#ifdef __cplusplus

android_native_buffer_t() {

   common.magic = ANDROID_NATIVE_BUFFER_MAGIC;

   common.version = sizeof(android_native_buffer_t);

   memset(common.reserved, 0, sizeof(common.reserved));

}

#endif

//这个android_native_base_t是struct的第一个成员,根据C/C++编译的特性,这个成员

//在它的派生类对象所占有的内存中也是排第一个。

structandroid_native_base_t common;

intwidth;

intheight;

intstride;

intformat;

intusage;

void* reserved[2];

//这是一个关键成员,保存一些和显示内存分配/管理相关的内容

buffer_handle_t handle;

void*reserved_proc[8];

} android_native_buffer_t;

GraphicBuffer和显示内存分配相关的部分主要集中在buffer_handle_t这个变量上,它实际上是一个指针,定义如下:

[–>gralloc.h]
[–>gralloc.h]

typedef const native_handle* buffer_handle_t;

native_handle的定义如下:

[–>native_handle.h]

typedef struct

{

intversion;        /* version值为sizeof(native_handle_t) */

intnumFds;       

intnumInts;       

intdata[0];        /* data是数据存储空间的首地址 */

} native_handle_t;

typedef native_handle_t native_handle;

读者可能要问,一个小小的GraphicBuffer为什么这么复杂?要回答这个问题,应先对GraphicBuffer有比较全面的了解。按照图8-20中的流程来看GraphicBuffer。
2. GraphicBuffer和存储的分配
GraphicBuffer的构造函数最有可能分配存储了。注意,流程中使用的是无参构造函数,所以应先看无参构造函数。

(1)无参构造函数的分析
代码如下所示:

[–>GraphicBuffer.cpp]

GraphicBuffer::GraphicBuffer()

:BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),

 mInitCheck(NO_ERROR), mVStride(0), mIndex(-1)

{

/*

其中mBufferMapper为GraphicBufferMapper类型,它的创建采用的是单例模式,也就是每个

进程只有一个GraphicBufferMapper对象,读者可以去看看get的实现。

*/

width =

height=

stride=

format=

usage = 0;

handle= NULL; //handle为空

}

在无参构造函数中没有发现和存储分配有关的操作。那么,根据流程,下一个有可能的地方就是reallocate函数了。

(2)reallocate的分析
Reallocate的代码如下所示:

[–>GraphicBuffer.cpp]

status_t GraphicBuffer::reallocate(uint32_t w,uint32_t h, PixelFormat f,

   uint32_t reqUsage)

{

if(mOwner != ownData)

   return INVALID_OPERATION;



if(handle) {//handle值在无参构造函数中初始化为空,所以不满足if的条件

   GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());

   allocator.free(handle);

   handle = 0;

}

returninitSize(w, h, f, reqUsage);//调用initSize函数

}

InitSize函数的代码如下所示:

[–>GraphicBuffer.cpp]

status_t GraphicBuffer::initSize(uint32_t w,uint32_t h, PixelFormat format,

   uint32_t reqUsage)

{

if(format == PIXEL_FORMAT_RGBX_8888)

   format = PIXEL_FORMAT_RGBA_8888;

/*

GraphicBufferAllocator才是真正的存储分配的管理类,它的创建也是采用的单例模式,

也就是每个进程只有一个GraphicBufferAllocator对象

*/

GraphicBufferAllocator& allocator =GraphicBufferAllocator::get();

//调用GraphicBufferAllocator的alloc来分配存储,注意handle作为指针

//被传了进去,看来handle的值会被修改

status_t err = allocator.alloc(w, h, format, reqUsage, &handle,&stride);

if(err == NO_ERROR) {

   this->width  = w;

   this->height = h;

   this->format = format;

   this->usage  = reqUsage;

   mVStride = 0;

}

returnerr;

}

(3)GraphicBufferAllocator的介绍
从上面的代码中可以发现,GraphicBuffer的存储分配和GraphicBufferAllocator有关。一个小小的存储分配为什么需要经过这么多道工序呢?还是先来看GraphicBufferAllocator,代码如下所示:

[–>GraphicBufferAllocator.cpp]

GraphicBufferAllocator::GraphicBufferAllocator()

:mAllocDev(0)

{

hw_module_t const* module;

//调用hw_get_module,得到hw_module_t

interr = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);

if (err == 0) {

//调用gralloc_open函数,注意我们把module参数传了进去。

   gralloc_open(module, &mAllocDev);

}

}

GraphicBufferAllocator在创建时,会首先调用hw_get_module取出一个hw_module_t类型的对象。从名字上看,它和硬件平台有关系。它会加载一个叫libgralloc.硬件平台名.so的动态库。比如,我的HTC G7手机上加载的库是/system/lib/hw/libgraolloc.qsd-8k.so。这个库的源代码在hardware/msm7k/libgralloc-qsd8k目录下。

这个库有什么用呢?简言之,就是为了分配一块用于显示的内存,但为什么需要这种层层封装呢?答案很简单:

封装的目的就是为了屏蔽不同硬件平台的差别。

读者可通过执行adb getprop ro.board.platform命令,得到具体手机上硬件平台的名字。图8-22总结了GraphicBufferAllocator分配内存的途径。这部分代码,读者可参考hardware/libhardware/hardware.c和hardware/msm7k/libgralloc-qsd8k/gralloc.cpp,后文将不再深入探讨和硬件平台有关的知识。
在这里插入图片描述
图8-22 GraphicBufferAllocator内存的分配途径

注意,这里是以G7的libgralloc.qsk-8k.so为示例的。其中pmem设备用来创建一块连续的内存,因为有些硬件设备(例如Camera)工作时需要使用一块连续的内存,对于这种情况,一般就会使用pmem设备来分配内存。

这里,仅讨论图8-22中与硬件无关的分配方式。在这种情况下,将使用ashmem分配共享内存。下面看GraphicBufferAllocator的alloc函数,其代码如下所示:

[–>GraphicBufferAllocator.cpp]

status_t GraphicBufferAllocator::alloc(uint32_tw, uint32_t h, PixelFormat format,int usage, buffer_handle_t* handle, int32_t*stride)

{

//根据前面的定义可知buffer_handle_t为native_handle_t*类型

status_t err;

if (usage & GRALLOC_USAGE_HW_MASK) {

err =mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);

} else {

   //SW分配,可以做到和HW无关了。

   err = sw_gralloc_handle_t::alloc(w, h, format, usage, handle, stride);

}

returnerr;

}

下面,来看软件分配的方式:

[–>GraphicBufferAllocator.cpp]

status_t sw_gralloc_handle_t::alloc(uint32_t w,uint32_t h, int format,

    int usage, buffer_handle_t* pHandle, int32_t*pStride)

{

intalign = 4;

intbpp = 0;

......//格式转换

size_tbpr = (w*bpp + (align-1)) & ~(align-1);

size_tsize = bpr * h;

size_tstride = bpr / bpp;

size =(size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);

//直接使用了ashmem创建共享内存

int fd= ashmem_create_region("sw-gralloc-buffer", size);

//进行内存映射,得到共享内存起始地址

void*base = mmap(0, size, prot, MAP_SHARED, fd, 0);

sw_gralloc_handle_t* hnd = new sw_gralloc_handle_t();

hnd->fd = fd;//保存文件描述符

hnd->size = size;//保存共享内存的大小

hnd->base = intptr_t(base);//intptr_t将void类型转换成int类型

hnd->prot = prot;//保存属性

*pStride = stride;

*pHandle = hnd; //pHandle就是传入的那个handle变量的指针,这里对它进行赋值

returnNO_ERROR;

}

我们知道,调用GraphicBuffer的reallocate函数后,会导致物理存储被分配。前面曾说过,Layer会创建两个GraphicBuffer,而Native Surface端也会创建两个GraphicBuffer,那么这两个GraphicBuffer是怎么建立联系的呢?为什么说native_handle_t是GraphicBuffer的精髓呢?
3. flatten和unflatten的分析
试想,Native Surface的GraphicBuffer是怎么和Layer的GraphicBuffer建立联系的:

先通过requestBuffer函数返回一个GraphicBuffer,然后这个GraphicBuffer被Native Surface保存。

这中间的过程其实是一个mini版的乾坤挪移,来看看,代码如下所示:

[–>ISurface.cpp]

//requestBuffer的响应端

status_t BnSurface::onTransact(

uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

switch(code) {

   case REQUEST_BUFFER: {

       CHECK_INTERFACE(ISurface, data, reply);

       int bufferIdx = data.readInt32();

       int usage = data.readInt32();

       sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage));

       ......

  /*

requestBuffer的返回值被写到Parcel包中,由于GraphicBuffer从

Flattenable类派生,这将导致它的flatten函数被调用

 */

       return reply->write(*buffer);

    }

  .......

}

//再来看请求端的处理,在BpSurface中

virtual sp requestBuffer(intbufferIdx, int usage)

{

Parcel data, reply;

data.writeInterfaceToken(ISurface::getInterfaceDescriptor());

data.writeInt32(bufferIdx);

data.writeInt32(usage);

remote()->transact(REQUEST_BUFFER, data, &reply);

sp<GraphicBuffer> buffer = new GraphicBuffer();

reply.read(*buffer);//Parcel调用unflatten函数把信息反序列化到这个buffer中。

return buffer;//requestBuffer实际上返回的是本地new出来的这个GraphicBuffer

}

通过上面的代码可以发现,挪移的关键体现在flatten和unflatten函数上。请看:

(1)flatten的分析
flatten的代码如下所示:

[–>GraphicBuffer.cpp]

status_t GraphicBuffer::flatten(void* buffer,size_t size,

   int fds[], size_t count) const

{

//buffer是装载数据的缓冲区,由Parcel提供

 ......



if(handle) {

   buf[6] = handle->numFds;

   buf[7] = handle->numInts;

   native_handle_t const* const h = handle;

   //把handle的信息也写到buffer中

   memcpy(fds,     h->data,             h->numFds*sizeof(int));

   memcpy(&buf[8], h->data + h->numFds,h->numInts*sizeof(int));

}



returnNO_ERROR;

}

flatten的工作就是把GraphicBuffer的handle变量信息写到Parcel包中。那么接收端如何使用这个包呢?这就是unflatten的工作了。

(2)unflatten分析
unflatten的代码如下所示:

[–>GraphicBuffer.cpp]

status_t GraphicBuffer::unflatten(void const*buffer, size_t size,

   int fds[], size_t count)

{

    ......



if(numFds || numInts) {

   width  = buf[1];

   height = buf[2];

   stride = buf[3];

   format = buf[4];

   usage  = buf[5];

    native_handle* h =native_handle_create(numFds, numInts);

   memcpy(h->data,         fds,     numFds*sizeof(int));

    memcpy(h->data + numFds, &buf[8],numInts*sizeof(int));

   handle = h;//根据Parcel包中的数据还原一个handle

} else{

   width = height = stride = format = usage = 0;

   handle = NULL;

}

mOwner= ownHandle;

returnNO_ERROR;

}

unflatten最重要的工作是,根据Parcel包中native_handle的信息,在Native Surface端构造一个对等的GraphicBuffer。这样,Native Surface端的GraphicBuffer实际上就和Layer端的GraphicBuffer管理着同一块共享内存。

  1. registerBuffer的分析
    registerBuffer有什么用呢?上一步调用unflatten后得到了代表共享内存的文件句柄,regiserBuffer的目的就是对它进行内存映射,代码如下所示:

[–>GraphicBufferMapper.cpp]

status_tsw_gralloc_handle_t::registerBuffer(sw_gralloc_handle_t* hnd)

{

if (hnd->pid != getpid()) {

    //原来是做一次内存映射操作

   void* base = mmap(0, hnd->size, hnd->prot, MAP_SHARED, hnd->fd,0);

    ......

   //base保存着共享内存的起始地址

   hnd->base = intptr_t(base);

}

returnNO_ERROR;

}

  1. lock和unlock的分析
    GraphicBuffer在使用前需要通过lock来得到内存地址,使用完后又会通过unlock释放这块地址。在SW分配方案中,这两个函数实现却非常简单,如下所示:

[–>GraphicBufferMapper.cpp]

//lock操作

int sw_gralloc_handle_t::lock(sw_gralloc_handle_t*hnd, int usage,

   int l, int t, int w, int h, void** vaddr)

{

*vaddr= (void*)hnd->base;//得到共享内存的起始地址,后续作画就使用这块内存了。

returnNO_ERROR;

}

//unlock操作

status_tsw_gralloc_handle_t::unlock(sw_gralloc_handle_t* hnd)

{

returnNO_ERROR;//没有任何操作

}

对GraphicBuffer的介绍就到这里。虽然采用的是SW方式,但是相信读者也能通过树木领略到森林的风采。从应用层角度看,可以把GraphicBuffer当做一个构架在共享内存之上的数据缓冲。对想深入研究的读者,我建议可按图8-20中的流程来分析。因为流程体现了调用顺序,表达了调用者的意图和目的,只有把握了流程,分析时才不会迷失在茫茫的源码海洋中,才不会被不熟悉的知识阻拦前进的脚步。

8.4.7 深入分析Surface总结
Surface系统最难的部分,是这个Native Surface的创建和使用,它包括三个方面:

· Activity的UI和Surface的关系是怎样的?这是8.2节回答的问题。

· Activity中所使用的Surface是怎么和SurfaceFlinger挂上关系的?这是8.3节回答的问题。

· 本节对第2个问题进行了较深入的研究,分析了Surface和SurfaceFlinger之间的关系,以及生产/消费步调的中枢控制机构SharedBuffer家族和数据的承载者GraphicBuffer。

从上面分析可看出,本章前四节均围绕着这个Surface讲解,一路下来确实遇到了不少曲折和坎坷,望读者跟着源码反复阅读,体会。

2.2 SurfaceFlinger的分析

8.5 SurfaceFlinger的分析
这一节要对SurfaceFlinger进行分析。相比较而言,SurfaceFlinger不如AudioFlinger复杂。

8.5.1 SurfaceFlinger的诞生
SurfaceFlinger驻留于system_server进程,这一点和Audio系统的几个Service不太一样。它创建的位置在SystemServer的init1函数中(第4章4.3.2节的第3点)。虽然位于SystemServer这个重要进程中,但是SF创建的代码却略显波澜不惊,没有什么特别之处。SF的创建首先会调用instantiate函数,代码如下所示:

[–>SurfaceFlinger.cpp]

void SurfaceFlinger::instantiate() {

   defaultServiceManager()->addService(

           String16("SurfaceFlinger"), new SurfaceFlinger());

}

前面在图8-14中指出了SF,同时从BnSurfaceComposer和Thread类中派生,相关代码如下所示:
从Thread派生这件事给了我们一个很明确的提示:

· SurfaceFlinger会单独启动一个工作线程。

我们知道,Thread类的工作线程要通过调用它的run函数来创建,那这个run函数是在什么地方调用的呢?当然,最有可能的就是在构造函数中:

[–>SurfaceFlinger.cpp]

  1. onFirstRef的分析
    void SurfaceFlinger::onFirstRef()

{

//真是梦里寻他千百度,果然是在onFirstRef中创建了工作线程

run(“SurfaceFlinger”,PRIORITY_URGENT_DISPLAY);

/*

mReadyToRunBarrier类型为Barrier,这个类就是封装了一个Mutex对象和一个Condition

对象。如果读者还记得第5章有关同步类的介绍,理解这个Barrier就非常简单了。下面调用的

wait函数表示要等待一个同步条件的满足。

*/

mReadyToRunBarrier.wait();

}

onFirstRef创建工作线程后,将等待一个同步条件,那么这个同步条件在哪里被触发呢?相信不用多说 大家也知道:

在工作线程中被触发,而且极有可能是在readyToRun函数中。

不清楚Thread类的读者可以复习一下与第5章有关的Thread类的知识。

  1. readyToRun的分析
    SF的readyToRun函数将完成一些初始化工作,代码如下所示:

[–>SurfaceFlinger.cpp]

status_t SurfaceFlinger::readyToRun()

{

    intdpy = 0;

    {

        //①GraphicPlane是什么?

       GraphicPlane& plane(graphicPlane(dpy));

        //②为这个GraphicPlane设置一个HAL对象——DisplayHardware

       DisplayHardware* const hw = new DisplayHardware(this, dpy);

       plane.setDisplayHardware(hw);

    }

 

 //创建Surface系统中的“CB”对象,按照老规矩,应该先创建一块共享内存,然后使用placment new

   mServerHeap = new MemoryHeapBase(4096,

                            MemoryHeapBase::READ_ONLY,

                            "SurfaceFlingerread-only heap");

   /*

注意这个“CB“对象的类型是surface_flinger_cblk_t。为什么在CB上打引号呢?因为这个对象

谈不上什么控制,只不过被用来存储一些信息罢了。其控制作用完全达不到audio_track_cblk_t

的程度。基于这样的事实,我们把前面提到的SharedBuffer家族称之为CB对象。

*/

   mServerCblk=

      static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());

   //placementnew创建surface_flinger_cblk_t

   new(mServerCblk) surface_flinger_cblk_t;

 

    constGraphicPlane& plane(graphicPlane(dpy));

    constDisplayHardware& hw = plane.displayHardware();

    constuint32_t w = hw.getWidth();

    constuint32_t h = hw.getHeight();

    constuint32_t f = hw.getFormat();

   hw.makeCurrent();

 

    //当前只有一块屏

    mServerCblk->connected|= 1<<dpy;

    //屏幕在“CB”对象中的代表是display_cblk_t

   display_cblk_t* dcblk = mServerCblk->displays + dpy;

   memset(dcblk, 0, sizeof(display_cblk_t));

   dcblk->w            =plane.getWidth();

   dcblk->h            =plane.getHeight();

    ......//获取屏幕信息

 

   //还用上了内联汇编语句。

   asmvolatile ("":::"memory");

  /*

   下面是一些和OpenGL相关的函数调用。读者如感兴趣,可以研究一下,

   至少SurfaceFlinger.cpp中所涉及的相关代码还不算难懂

  */

   glActiveTexture(GL_TEXTURE0);

   glBindTexture(GL_TEXTURE_2D, 0);

   ......

   glOrthof(0, w, h, 0, 0, 1);

 

   //LayerDim是Dim类型的Layer

  LayerDim::initDimmer(this, w, h);

 

    //还记得在onFirstRef函数中的wait吗?下面的open将触发这个同步条件

    mReadyToRunBarrier.open();

    //资源准备好后,init将启动bootanim程序,这样就见到开机动画了。

   property_set("ctl.start", "bootanim");

   

    returnNO_ERROR;

}

在上面的代码中,列出了两个关键点,下面一一进行分析。

(1)GraphicPlane的介绍
GraphicPlane是屏幕在SF代码中的对应物,根据前面的介绍,目前Android只支持一块屏幕,所以SF定义了一个一元数组:
GraphicPlane mGraphicPlanes[1];

GraphicPlane虽无什么特别之处,但它有一个重要的函数,叫setDisplayHardware,这个函数把代表显示设备的HAL对象和GraphicPlane关联起来。这也是下面要介绍的第二个关键点DisplayHardware。
(2)DisplayHardware的介绍
从代码上看,这个和显示相关的HAL对象是在工作线程中new出来的,先看它的构造函数,代码如下所示:

[–>DisplayHardware.cpp]

DisplayHardware::DisplayHardware(

       const sp<SurfaceFlinger>& flinger,

       uint32_t dpy)

    :DisplayHardwareBase(flinger, dpy)

{

   init(dpy); //最重要的是这个init函数。

}

init函数非常重要,应进去看看。下面先思考一个问题。

前面在介绍FrameBuffer时说过,显示这一块需要使用FrameBuffer,但在GraphicBuffer中用的却是ashmem创建的共享内存。也就是说,之前在共享内存中绘制的图像和FrameBuffer没有什么关系。那么FrameBuffer是在哪里创建的呢?

答案就在init函数中,代码如下所示:

[–>DisplayHardware.cpp]

void DisplayHardware::init(uint32_t dpy)

{

//FrameBufferNativeWindow实现了对FrameBuffer的管理和操作,该类中创建了两个

//FrameBuffer,分别起到FrontBuffer和BackBuffer的作用。

mNativeWindow = new FramebufferNativeWindow();

 

   framebuffer_device_t const * fbDev = mNativeWindow->getDevice();

 

   mOverlayEngine = NULL;

   hw_module_t const* module;//Overlay相关

    if(hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {

       overlay_control_open(module, &mOverlayEngine);

    }

......

 

    EGLint w, h, dummy;

    EGLintnumConfigs=0;

   EGLSurface surface;

   EGLContext context;

    mFlags= CACHED_BUFFERS;

  //EGLDisplay在EGL中代表屏幕

   EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

    ......

   /*

    surface是EGLSurface类型,下面这个函数会将EGL和Android中的Display系统绑定起来,

    后续就可以利用OpenGL在这个Surface上绘画,然后通过eglSwappBuffers输出图像了。

    */

    surface= eglCreateWindowSurface(display, config,

    mNativeWindow.get(),NULL);

   ......

   mDisplay = display;

   mConfig  = config;

   mSurface = surface;

   mContext = context;

   mFormat  = fbDev->format;

   mPageFlipCount = 0;

}

根据上面的代码,现在可以回答前面的问题了:

· SF创建FrameBuffer,并将各个Surface传输的数据(通过GraphicBuffer)混合后,再由自己传输到FrameBuffer中进行显示。

本节的内容,实际上涉及另外一个比Surface更复杂的Display系统,出于篇幅和精力的原因,本书目前不打算讨论它。

8.5.2 SF工作线程的分析
SF中的工作线程就是来做图像混合的,比起AudioFlinger来,它相当简单,下面是它的代码:

[–>SurfaceFlinger.cpp]

bool SurfaceFlinger::threadLoop()

{

   waitForEvent();//① 等待什么事件呢?

 

   if (UNLIKELY(mConsoleSignals)) {

       handleConsoleEvents();

    }

    if(LIKELY(mTransactionCount == 0)) {

      const uint32_t mask = eTransactionNeeded | eTraversalNeeded;

       uint32_t transactionFlags = getTransactionFlags(mask);

        if(LIKELY(transactionFlags)) {

            //Transaction(事务)处理,放到本节最后来讨论

           handleTransaction(transactionFlags);

        }

    }

 

    //②处理PageFlipping工作

   handlePageFlip();

 

    constDisplayHardware& hw(graphicPlane(0).displayHardware());

if (LIKELY(hw.canDraw() && !isFrozen())) {

        //③处理重绘

        handleRepaint();

        hw.compositionComplete();

        //④投递BackBuffer

       unlockClients();

        postFramebuffer();

    } else{

       unlockClients();

       usleep(16667);

    }

    returntrue;

}

ThreadLoop一共有四个关键点,这里,分析除Transaction外的三个关键点。

  1. waitForEvent
    SF工作线程一上来就等待事件,它会是什么事件呢?来看代码:

[–>SurfaceFlinger.cpp]

	void SurfaceFlinger::waitForEvent()
	
	{
	
	    while(true) {
	
	       nsecs_t timeout = -1;
	
	       const nsecs_t freezeDisplayTimeout = ms2ns(5000);
	
	        ......
	
	 
	
	       MessageList::value_type msg = mEventQueue.waitMessage(timeout);
	
	 
	
	        ......//还有一些和冻屏相关的内容
	
	        if(msg != 0) {
	
	           switch (msg->what) {
	
	//千辛万苦就等这一个重绘消息
	
	               case MessageQueue::INVALIDATE:
	
	                     return;
	
	           }
	
	        }
	
	    }
	
	}
SF收到重绘消息后,将退出等待。那么,是谁发送的这个重绘消息呢?还记得在unlockCanvasAndPost函数中调用的signal吗?它在SF端的实现代码如下:

[-->SurfaceFlinger]


void SurfaceFlinger::signal() const {

    const_cast<SurfaceFlinger*>(this)->signalEvent();

}

void SurfaceFlinger::signalEvent() {

   mEventQueue.invalidate(); //往消息队列中加入INVALIDATE消息

}
  1. 分析handlePageFlip
    SF工作线程从waitForEvent中返回后,下一步要做的就是处理事务和handlePageFlip了。先看handlePageFlip,从名字上可知,它和PageFlipping工作有关。

注意:事务处理将在8.5.3节中介绍。

代码如下所示:

(3)handlePageFlip的总结
handlePageFlip的工作其实很简单,以Layer类型为例来总结一下:

各个Layer需要从FrontBuffer中取得新数据,并生成一张OpenGL中的纹理。纹理可以看做是一个图片,这个图片的内容就是FrontBuffer中的图像。

现在每一个Layer都准备好了新数据,下一步的工作当然就是绘制了。来看handleRepaint函数。

3. 分析handleRepaint函数
handleRepaint这个函数基本上就是按Z轴的顺序对每一层进行重绘,重绘的方法就是使用OpenGL。
嵌入式平台上用的其实是OpenGL ES。这里,还有一本书叫《OpenGL ES 2.0 Programming Guide》,它介绍了OpenGL ES的开发,读者可认真修习。

  1. unlockClients和postFrameBuffer的分析
    在绘制完图后,还有两项工作需要做,一个涉及unlockClients函数,另外一个涉及postFrameBuffer函数,这两个函数分别干了什么呢?unlockClients的代码如下所示:
    [–>SurfaceFlinger.cpp]

void SurfaceFlinger::unlockClients()

{

    constLayerVector& drawingLayers(mDrawingState.layersSortedByZ);

    constsize_t count = drawingLayers.size();

   sp<LayerBase> const* const layers = drawingLayers.array();

    for (size_t i=0 ; i<count ; ++i) {

       const sp<LayerBase>& layer = layers[i];

       layer->finishPageFlip();

    }

}

再看Layer的finishPageFlip函数,代码如下所示:

[–>Layer.cpp]

void Layer::finishPageFlip()

{

    //释放FrontBufferIndex

   status_t err = lcblk->unlock( mFrontBufferIndex );

}

原来,unlockClients会释放之前占着的FrontBuffer的索引号。下面看最后一个函数postFrameBuffer,代码如下所示:

[–>SurfaceFlinger.cpp]

void SurfaceFlinger::postFramebuffer()

{

    if(!mInvalidRegion.isEmpty()) {

       const DisplayHardware& hw(graphicPlane(0).displayHardware());

       const nsecs_t now = systemTime();

       mDebugInSwapBuffers = now;

//调用这个函数后,混合后的图像就会传递到屏幕中显示了

       hw.flip(mInvalidRegion);

       mLastSwapBufferTime = systemTime() - now;

       mDebugInSwapBuffers = 0;

       mInvalidRegion.clear();

    }

}

flip将调用在DisplayHardware一节中提到的eglSwapBuffer函数,来完成FrameBuffer的PageFlip操作,代码如下所示:

[–>DisplayHardware.cpp]

void DisplayHardware::flip(const Region&dirty) const

{

   checkGLErrors();

 

   EGLDisplay dpy = mDisplay;

   EGLSurface surface = mSurface;

 

......

    if(mFlags & PARTIAL_UPDATES) {

       mNativeWindow->setUpdateRectangle(dirty.getBounds());

    }

   

   mPageFlipCount++;

   eglSwapBuffers(dpy, surface);//PageFlipping,此后图像终于显示在屏幕上了!

   

}

8.5.3 Transaction的分析
Transaction是“事务”的意思。在我脑海中,关于事务的知识来自于数据库。在数据库操作中,事务意味着一次可以提交多个SQL语句,然后一个commit就可让它们集中执行,而且数据库中的事务还可以回滚,即恢复到事务提交前的状态。

SurfaceFlinger为什么需要事务呢?从上面对数据库事务的描述来看,是不是意味着一次执行多个请求呢?如直接盯着SF的源码来分析,可能不太容易搞清楚事务的前因后果,我想还是用老办法,从一个例子入手吧。

在WindowManagerService.java中,有一个函数之前分析过,现在再看看,代码如下所示:

[–>WindowManagerService.java::WinState]
Surface createSurfaceLocked() {

Surface.openTransaction(); //开始一次transaction

try {

 try {

     mSurfaceX = mFrame.left + mXOffset;

      mSurfaceY = mFrame.top + mYOffset;

      //设置Surface的位置

     mSurface.setPosition(mSurfaceX, mSurfaceY);

      ......

    }

   }finally {

         Surface.closeTransaction(); //关闭这次事务

 }

这个例子很好地展示了事务的调用流程,它会依次调用:

· openTransaction

· setPosition

· closeTransaction

下面就来分析这几个函数的调用。

  1. openTransaction的分析
    看JNI对应的函数,代码如下所示:

[–>android_View_Surface.cpp]

static void Surface_openTransaction(JNIEnv* env,jobject clazz)

{

//调用SurfaceComposerClient的openGlobalTransaction函数

SurfaceComposerClient::openGlobalTransaction();

}

下面转到SurfaceComposerClient,代码如下所示:

[–>SurfaceComposerClient.cpp]

voidSurfaceComposerClient::openGlobalTransaction()

{

Mutex::Autolock _l(gLock);

......



constsize_t N = gActiveConnections.size();

for(size_t i=0; i<N; i++) {

    sp<SurfaceComposerClient>client(gActiveConnections.valueAt(i).promote());

    //gOpenTransactions存储当前提交事务请求的Client

    if(client != 0 && gOpenTransactions.indexOf(client) < 0) {

       //Client是保存在全局变量gActiveConnections中的SurfaceComposerClient

        //对象,调用它的openTransaction。

       if (client->openTransaction() == NO_ERROR) {

           if (gOpenTransactions.add(client) < 0) {

               client->closeTransaction();

          }

       }

       ......

    }

}

}

上面是一个静态函数,内部调用了各个SurfaceComposerClient对象的openTranscation,代码如下所示:

[–>SurfaceComposerClient.cpp]

status_tSurfaceComposerClient::openTransaction()

{

if(mStatus != NO_ERROR)

   return mStatus;

Mutex::Autolock _l(mLock);

mTransactionOpen++; //一个计数值,用来控制事务的提交。

if(mPrebuiltLayerState == 0) {

   mPrebuiltLayerState = new layer_state_t;

}

returnNO_ERROR;

}

layer_state_t是用来保存Surface的一些信息的,比如位置、宽、高等信息。实际上,调用的setPosition等函数,就是为了改变这个layer_state_t中的值。

  1. setPosition的分析
    上文说过,SFC中有一个layer_state_t对象用来保存Surface的各种信息。这里以setPosition为例,来看它的使用情况。这个函数是用来改变surface在屏幕上的位置的,代码如下所示:

[–>android_View_Surface.cpp]

static void Surface_setPosition(JNIEnv* env,jobject clazz, jint x, jint y)

{

constsp<SurfaceControl>& surface(getSurfaceControl(env, clazz));

if(surface == 0) return;

status_t err = surface->setPosition(x, y);

}

[–>Surface.cpp]

status_t SurfaceControl::setPosition(int32_t x,int32_t y) {

constsp<SurfaceComposerClient>& client(mClient);

status_t err = validate();

if (err < 0) return err;

//调用SurfaceComposerClient的setPosition函数

returnclient->setPosition(mToken, x, y);

}

[–>SurfaceComposerClient.cpp]

status_tSurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y)

{

layer_state_t* s = _lockLayerState(id); //找到对应的layer_state_t

if(!s) return BAD_INDEX;

s->what |= ISurfaceComposer::ePositionChanged;

s->x = x;

s->y = y; //上面几句修改了这块layer的参数

_unlockLayerState(); //该函数将unlock一个同步对象,其他没有做什么工作

returnNO_ERROR;

}

setPosition就是修改了layer_state_t中的一些参数,那么,这个状态是什么时候传递到SurfaceFlinger中的呢?

  1. 分析closeTransaction
    相信读者此时已明白为什么叫“事务”了。原来,在openTransaction和closeTransaction中可以有很多操作,然后由closeTransaction一次性地把这些修改提交到SF上,来看代码:

[–>android_View_Surface.cpp]

static void Surface_closeTransaction(JNIEnv*env, jobject clazz)

{

SurfaceComposerClient::closeGlobalTransaction();

}

[–>SurfaceComposerClient.cpp]

voidSurfaceComposerClient::closeGlobalTransaction()

{

const size_t N = clients.size();

spsm(getComposerService());

//①先调用SF的openGlobalTransaction

sm->openGlobalTransaction();

for (size_t i=0; i<N; i++) {

//②然后调用每个SurfaceComposerClient对象的closeTransaction

clients[i]->closeTransaction();

}

//③最后调用SF的closeGlobalTransaction

sm->closeGlobalTransaction();

}

上面一共列出了三个函数,它们都是跨进程的调用,下面对其一一进行分析。

(1)SurfaceFlinger的openGlobalTransaction分析
这个函数其实很简单,略看就行了。

[–>SurfaceFlinger.cpp]

void SurfaceFlinger::openGlobalTransaction()

{

android_atomic_inc(&mTransactionCount);//又是一个计数控制

}

(2)SurfaceComposerClient的closeTransaction分析
代码如下所示:

[–>SurfaceComposerClient.cpp]

status_tSurfaceComposerClient::closeTransaction()

{

if(mStatus != NO_ERROR)

   return mStatus;

Mutex::Autolock _l(mLock);

constssize_t count = mStates.size();

if (count) {

 //mStates是这个SurfaceComposerClient中保存的所有layer_state_t数组,也就是

//每个Surface一个。然后调用跨进程的setState

   mClient->setState(count, mStates.array());

   mStates.clear();

}

returnNO_ERROR;

}

BClient的setState,最终会转到SF的setClientState上,代码如下所示:

[–>SurfaceFlinger.cpp]

status_t SurfaceFlinger::setClientState(ClientIDcid, int32_t count,

                      const layer_state_t*states)

{

Mutex::Autolock _l(mStateLock);

uint32_t flags = 0;

cid<<= 16;

for(int i=0 ; i<count ; i++) {

   const layer_state_t& s = states[i];

   sp<LayerBaseClient> layer(getLayerUser_l(s.surface | cid));

    if(layer != 0) {

       const uint32_t what = s.what;

       if (what & ePositionChanged) {

           if (layer->setPosition(s.x, s.y))

                //eTraversalNeeded表示需要遍历所有显示层

                flags |= eTraversalNeeded;

       }

        ....

if(flags) {

   setTransactionFlags(flags);//这里将会触发threadLoop的事件。

}

returnNO_ERROR;

}

[–>SurfaceFlinger.cpp]

uint32_tSurfaceFlinger::setTransactionFlags(uint32_t flags, nsecs_t delay)

{

uint32_t old = android_atomic_or(flags, &mTransactionFlags);

if((old & flags)==0) {

    if(delay > 0) {

       signalDelayedEvent(delay);

    }else {

        signalEvent();  //设置完mTransactionFlags后,触发事件。

    }

}

returnold;

}

(3)SurfaceFlinger的closeGlobalTransaction分析
来看代码:

[–>SurfaceFlinger.cpp]

void SurfaceFlinger::closeGlobalTransaction()

{

if (android_atomic_dec(&mTransactionCount) ==1) {

//注意下面语句的执行条件,当mTransactionCount变为零时才执行,这意味着

//openGlobalTransaction两次的话,只有最后一个closeGlobalTransaction调用

//才会真正地提交事务

   signalEvent();



   Mutex::Autolock _l(mStateLock);

   //如果这次事务涉及尺寸调整,则需要等一段时间

   while (mResizeTransationPending) {

       status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));

       if (CC_UNLIKELY(err != NO_ERROR)) {

           mResizeTransationPending = false;

           break;

       }

    }

}

}

关于事务的目的,相信读者已经比较清楚了:
· 就是将一些控制操作(例如setPosition)的修改结果,一次性地传递给SF进行处理。
那么,哪些操作需要通过事务来传递呢?通过查看Surface.h可以知道,下面这些操作需要通过事务来传递(这里只列出了几个经常用的函数):setPosition、setAlpha、show/hide、setSize、setFlag等。
由于这些修改不像重绘那么简单,有时它会涉及其他的显示层,例如在显示层A的位置调整后,之前被A遮住的显示层B,现在可能变得可见了。对于这种情况,所提交的事务会设置eTraversalNeeded标志,这个标志表示要遍历所有显示层进行处理。关于这一点,来看工作线程中的事务处理。

  1. 工作线程中的事务处理
    还是从代码入手分析,如下所示:

[–>SurfaceFlinger.cpp]

bool SurfaceFlinger::threadLoop()

{

waitForEvent();

if(LIKELY(mTransactionCount == 0)) {

 const uint32_t mask = eTransactionNeeded | eTraversalNeeded;

  uint32_ttransactionFlags = getTransactionFlags(mask);

    if(LIKELY(transactionFlags)) {

       handleTransaction(transactionFlags);

    }

}

}

getTransactionFlags函数的实现蛮有意思,不妨看看其代码,如下所示:

[–>SurfaceFlinger.cpp]

uint32_t SurfaceFlinger::getTransactionFlags(uint32_tflags)

{

//先通过原子操作去掉mTransactionFlags中对应的位。

//而后原子操作返回的旧值和flags进行与操作

return android_atomic_and(~flags,&mTransactionFlags) & flags;

}

getTransactionFlags所做的工作不仅仅是get那么简单,它还设置了mTransactionFlags,从这个角度来看,getTransactionFlags这个名字有点名不副实。

接着来看最重要的handleTransaction函数,代码如下所示:

[–>SurfaceFlinger.cpp]

void SurfaceFlinger::handleTransaction(uint32_ttransactionFlags)

{

Vector< sp > ditchedLayers;

{

   Mutex::Autolock _l(mStateLock);

    //调用handleTransactionLocked函数处理

   handleTransactionLocked(transactionFlags, ditchedLayers);

}





constsize_t count = ditchedLayers.size();

for(size_t i=0 ; i<count ; i++) {

    if(ditchedLayers[i] != 0) {

    //ditch是丢弃的意思,有些显示层可能被hide了,所以这里做些收尾的工作

      ditchedLayers[i]->ditch();

    }

}

}

[–>SurfaceFlinger.cpp]

void SurfaceFlinger::handleTransactionLocked(

   uint32_t transactionFlags, Vector< sp<LayerBase> >&ditchedLayers)

{

//这里使用了mCurrentState,它的layersSortedByZ数组存储了SF中所有的显示层

constLayerVector& currentLayers(mCurrentState.layersSortedByZ);

constsize_t count = currentLayers.size();



 constbool layersNeedTransaction = transactionFlags & eTraversalNeeded;

 //如果需要遍历所有显示的话。

if(layersNeedTransaction) {

   for (size_t i=0 ; i<count ; i++) {

       const sp<LayerBase>& layer = currentLayers[i];

       uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);

       if (!trFlags) continue;

       //调用各个显示层的doTransaction函数。

        constuint32_t flags = layer->doTransaction(0);

       if (flags & Layer::eVisibleRegion)

           mVisibleRegionsDirty = true;

    }

}

if(transactionFlags & eTransactionNeeded) {

    if(mCurrentState.orientation != mDrawingState.orientation) {

     //横竖屏如果发生切换,需要对应变换设置。

       const int dpy = 0;

       const int orientation = mCurrentState.orientation;

       const uint32_t type = mCurrentState.orientationType;

       GraphicPlane& plane(graphicPlane(dpy));

       plane.setOrientation(orientation);



       ......

    }

 /*

  mLayersRemoved变量在显示层被移除的时候设置,例如removeLayer函数,这些函数

  也会触发handleTranscation函数的执行

 */

  if(mLayersRemoved) {

       mLayersRemoved = false;

       mVisibleRegionsDirty = true;

       const LayerVector& previousLayers(mDrawingState.layersSortedByZ);

       const size_t count = previousLayers.size();

       for (size_t i=0 ; i<count ; i++) {

           const sp<LayerBase>& layer(previousLayers[i]);

           if (currentLayers.indexOf( layer ) < 0) {

              ditchedLayers.add(layer);

               mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);

           }

        }

    }

   free_resources_l();

}

//提交事务处理,有必要进去看看。

commitTransaction();

}

每个显示层对事务的具体处理,都在它们的doTranscation函数中,读者若有兴趣,可进去看看。需要说明的是,每个显示层内部也有一个状态变量,doTransaction会更新这些状态变量。

回到上面的函数,最后它将调用commitTransaction提交事务,代码如下所示:

[–>SurfaceFlinger.cpp]

void SurfaceFlinger::commitTransaction()

{

//mDrawingState将使用更新后的mCurrentState

mDrawingState = mCurrentState;

mResizeTransationPending = false;

//触发一个条件变量,这样等待在closeGlobalTransaction函数中的线程可以放心地返回了。

mTransactionCV.broadcast();

}

8.5.4 SurfaceFlinger的总结
通过前面的分析,使我们感受了SurfaceFlinger的风采。从整体上看,SurfaceFlinger不如AudioFlinger复杂,它的工作集中在工作线程中,下面用图8-23来总线一下SF工作线程:
在这里插入图片描述

8.6.2 ViewRoot的你问我答
ViewRoot是Surfac系统甚至UI系统中一个非常关键的类,下面把网上一些关于ViewRoot的问题做个总结,希望这样能帮助读者对ViewRoot有更加清楚的认识。

· ViewRoot和View类的关系是什么?

ViewRoot是View视图体系的根。每一个Window(注意是Window,比如PhoneWindow)有一个ViewRoot,它的作用是处理layout和View视图体系的绘制。那么视图体系又是什么呢?它包括Views和ViewGroups,也就是SDK中能看到的View类都属于视图体系。根据前面的分析可知,这些View是需要通过draw画出来的。而ViewRoot就是用来draw它们的,ViewRoot本身没有draw/onDraw函数。

· ViewRoot和它所控制的View及其子View使用同一个Canvas吗?

这个问题的答案就很简单了,我们在ViewRoot的performTraversals中见过。ViewRoot提供Canvas给它所控制的View,所以它们使用同一个Canvas。但Canvas使用的内存却不是固定的,而是通过Surface的lockCanvas得到的。

· View、Surface和Canvas之间的关系是怎样的?我认为,每一个view将和一个canvas,以及一个surface绑定到一起(这里的“我”表示提问人)。

这个问题的答案也很简单。一个Window将和一个Surface绑定在一起,绘制前ViewRoot会从Surface中lock出一个Canvas。

· Canvas有一个bitmap,那么绘制UI时,数据是画在Canvas的这个bitmap中吗?

答案是肯定的,bitmap实际上包括了一块内存,绘制的数据最终都在这块内存上。

· 同一个ViewRoot下,不同类型的View(不同类型指不同的UI单元,例如按钮、文本框等)使用同一个Surface吗?

是的,但是SurfaceView要除外。因为SurfaceView的绘制一般在单独的线程上,并且由应用层主动调用lockCanvas、draw和unlockCanvasAndPost来完成绘制流程。应用层相当于抛开了ViewRoot的控制,直接和屏幕打交道,这在camera、video方面用得最多。

发布了67 篇原创文章 · 获赞 1 · 访问量 1万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览