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