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-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值为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。