8.3.3 乾坤大挪移的JNI层分析
最后更新于:2022-04-02 05:52:18
前文讲述的内容都集中在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 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**
~~~
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 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
constsp& surface = getSurfaceControl(env, clazz);
constsp& rhs = getSurfaceControl(env, other);
if (!SurfaceControl::isSameSurface(surface, rhs)) {
//把源SurfaceControl对象设置到目标Surface中。
setSurfaceControl(env, clazz, rhs);
}
}
~~~
这一步还是比较简单的,下面看第五步writeToParcel函数的调用。
5. 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&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)
{
Parcel* parcel = (Parcel*)env->GetIntField( argParcel,no.native_parcel);
//注意下面定义的变量类型是Surface,而不是SurfaceControl
const sp&control(getSurface(env, clazz));
//根据服务端传递的Parcel包来构造一个新的surface。
sp 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对象。
>[info] **注意**:精简流程后,寥寥数语就可把过程说清楚。以后我们在研究代码时,也可以采取这种方式。
这个Surface对象非常重要,可它到底有什么用呢?这正是下一节要讲的内容。
';