8.3.3 乾坤大挪移的JNI层分析

前文讲述的内容都集中在Java层,按照流程顺序下面要分析JNI层的内容了。

1.Surface的无参构造分析

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


[—>Surface.java]

public Surface(){

……

//CompatibleCanvas从Canvas类派生。

mCanvas=new CompatibleCanvas();

}


Canvas是什么?根据SDK文档的介绍可知,画图需要“四大金刚”相互合作,这四大金刚是:

Bitmap:用于存储像素,也就是画布。可把它当做一块数据存储区域。

Canvas:用于记载画图的动作,比如画一个圆,画一个矩形等。Canvas类提供了这些基本的绘图函数。

Drawing primitive:绘图基元,例如矩形、圆、弧线、文本、图片等。

Paint:它用来描述绘画时使用的颜色、风格(如实线、虚线等)等。

在一般情况下,Canvas会封装一块Bitmap,而作图就是基于这块Bitmap的。前面所说的画布,其实指的就是Canvas中的这块Bitmap。

这些知识稍微了解一下即可,不必深究。Surface的无参构造函数没有什么有价值的内容,接着看下面的内容。

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

public Surface(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]

static void Surface_init(

JNIEnv*env,jobject clazz,

jobject session,

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

{

//从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);

}


4.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。

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

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

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

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

setSurfaceControl(env,clazz,rhs);

}

}


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

5.writeToParcel分析

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


[—>android_view_Surface.cpp]

static void Surface_writeToParcel(JNIEnv*env,jobject clazz,

jobject argParcel,jint flags)

{

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

}

}


6.readFromParcel分析

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


[—>android_view_Surface.cpp]

static void Surface_readFromParcel(

JNIEnv*env,jobject clazz,jobject argParcel)

{

Parcelparcel=(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对象非常重要,可它到底有什么用呢?这正是下一节要讲的内容。