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<SurfaceComposerClient>client;

sp<ISurface>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);

return NO_ERROR;

}


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

2.分析Native的Surface创建过程


[—>android_view_Surface.cpp]

static void Surface_readFromParcel(

JNIEnv*env,jobject clazz,jobject argParcel)

{

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

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

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

sp<Surface>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<GraphicBuffer>的二元数组,也就是说Surface也存在两个GraphicBuffer,可之前在创建Layer的时候也有两个GraphicBuffer,难道一共有四个GraphicBuffer?这个问题后面再解答。

*/

sp<IBinder>clientBinder=parcel.readStrongBinder();

//得到ISurface的Bp端BpSurface。

mSurface=interface_cast<ISurface>(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.4.4 writeToParcel和Surface对象的创建 - 图1

图 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.4.4 writeToParcel和Surface对象的创建 - 图2

图 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值为2mIdentity(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。