ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
前文讲述的内容都集中在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** ~~~ 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<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 constsp<SurfaceControl>& surface = getSurfaceControl(env, clazz); constsp<SurfaceControl>& 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<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) { Parcel* parcel = (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对象。 >[info] **注意**:精简流程后,寥寥数语就可把过程说清楚。以后我们在研究代码时,也可以采取这种方式。 这个Surface对象非常重要,可它到底有什么用呢?这正是下一节要讲的内容。