作者 介绍
胡明明
专注于AndroidFramework、VR开发。
照例来先张图先:
图中我把相关的 jni 里面类也画了出来,这样就能更加明显的看到 java 层和 native 层的对应关系。
代码位置也先说下:
从图可得到,java 层的架构和 native 的很像。也是分为2个部分:实现部分和接口部分(几乎连名字都和 native 的一样)。
实现部分的话,也是一个 IBinder 的基类,额,不对 java 的叫 interface ,这个比 c++ 更加注重抽象。然后实现这个接口的分别是 Binder(Binder.java) 和 BinderProxy(Binder.java),分别对应 native 的 BBinder 和 BpBinder ,同时也分别代表 java 层的服务端和客户端。
Binder 这边的话:
前面几个函数都挺简单的,就是返回 descriptor ,要不返回 IInterface,要不设置下 IInterface 和 desriptor 。transact 这个函数看注释说是啥默认实现,别看它调用了 onTransact (native Bn 端的实现主要在这里)其实就是个摆设,没用的,因为要实现 IBinder 的接口,才必须要有一个实现而已(到后面就就知道了)。然后 onTransact 这个和 native 对应了,不过这里其实也没干声明正事,功能主要是留在service 的接口里实现的。
Java 的 Binder 最主要要看的是它有个叫 mObject 的变量:
看注释说是 native 层要使用,其实是 jni 要使用。来看看这个 mObject 是怎么使用的:
在 Binder 的构造函数中会调用一个 init 的 native 方法,这个方法在 jni android_util_Binder.cpp
里面:
这里创建了一个 JavaBBinderHolder (这个是 c++ 的类)的类,然后把这个指针保存在了 mObject 这个变量里面。int 类型是 32bit 的,指针(地址)在 32bit 系统上也是 32bit 的。这里再先看看 gBinderOffsets 这个东西,其实还有一个叫 gBinderProxyOffsets 的。这2个是 jni 里面 java 的类信息变量,弄成全局变量,如果访问频繁的话,能提高速度,因为每次都要去查 java 的类表很慢的,加载的代码在:
这个 register_android_os_Binder
会在 android 的 java 初始化的时候调用,这个时候需要的类信息就加载好了。gBinderOffsets 对应的是 Binder, gBinderProxyOffsets 对应的是 BinderProxy 。gBinderOffsets 的 mObject 就是 Binder 的 mObject 变量,所以那个注释说不要乱改这个变量的名字,不然这里就找不到了。gBinderOffsets 还有一个保存了 execTransact 的变量,这个注意一下,后面会说到的。
回过来看下 JavaBBinderHolder 这个东西:
这个东西继承自 native 的 RefBase,然后在看它的 get 方法的返回值,可以理解为这个东西就是在 java 里面放了一个 natvie 的 sp 一样。它持有的是 JavaBBinder 对象,这个才是重点:
JavaBBinder 继承自 native 的 BBinder,这下清楚了,java 层最重要还是持有了 native 的 binder 对象。同时这个东西还保存了 java Binder 的对象(相互保存 -_-||),那个 jobject mObject 就是,构造函数传进来的,然后在 JavaBBinderHolder 的 get 那里第一次会触发 new JavaBBinder,参数就是 java 的 Binder,这里后面再说。然后这个类重载了 BBinder 的 onTransact ,前面 native 说过了, Bn 端的实现主要是要重写 onTransact。然后在 onTransact 通过 java 对象 mObject 调用了 java Binder 的 gBinderOffsets 的 mExecTransact 。还记得前面加载 Binder 类信息的时候,说要注意这个 mExecTransact 的么,就是这里用啦,对应 Binder 的 execTransact 函数:
最后是调用了 Binder 的 onTransact 函数,所以还是和 native 的一样,Bn 靠重载 onTransact。所以前面说 Binder 实现 IBinder 的 transact 接口是摆设,因为这个不像 native 层 BBinder 的 transact,java 层的压根就没调用到。总结下,java 的 Bn 是通过 native 的 BBinder 的 transact 被调用,然后 natvie BBinder 的 onTransact(JavaBBinder 重载) 的被调用,然后在 jni 中调用 java 的 Binder 的 onTransact 。
然后是 BinderProxy:
BinderProxy 很多都直接是 native 方法。queryLocalInterface 直接放回 null,和 native 层的一样, Bp 端不实现 Bn 端的方法。它和 Binder 一样有一个 int mObject 的变量,同样这个也是保存 native 对象指针的,这个其实是 sp,这个后面再分析了。所以 java 的 BinderProxy transact 方法就直接调用 native BpBinder 的 transact 。
接下来就是接口部分了。IInterface :
和 native 层的很像,但是这个和 Binder 和 BinderProxy 不一样,java 的 IInterface 和 native 层的没啥关系(Binder 和 BinderProxy 可是保存了 native 层对象的指针的),只是为单纯为了对应而已。
然后同样,java 层的 service 需要继续这个接口,自己写一个 IXxManager 定义自己的服务提供的业务逻辑接口(那个 Manager 的后缀不是必须的,但是 android 系统的 service 都很统一,接口都叫 XxManager,服务都叫 XxManagerServices)。然后 Bn 这边的话,实现接口一般都叫 XxManagerNative 去实现这个 IXxManager 的接口,相当于 native 的 BnXx 实现 BnInterface 一样。然后服务模块继承这个 XxManagerNative,真正实现业务逻辑功能,XxManagerNative 里面的 onTransact 负责接受客户端发送过来的请求,并且调用正确的 service 的业务函数完成功能(和 native 流程一样)。
Bp 这边呢,一般由一个叫 XxProxy 的类实现 IXxManager 的接口,然后它有一个 mRemote 的 IBinder 变量,其实就是 BinderProxy (这个后面实例慢慢分析)。然后接口是通过 Parcel 把请求打包好,通过的 mRemote(BinderProxy,BinderProxy 直接调用 native BpBinder 的 transact) 的 transact 发送给 binder 驱动,最后再转给 Bn 端接收。流程也和 native 的是一样的。最后暴露给应用使用的 XxManager 其实一般都保存了一个 XxProxy 对象,然后 XxManager 的接口,基本上都是马甲,直接调用 XxProxy 对应的方法的(同样后面对照实例慢慢分析)。
前面 uml 中我在 XxManagerNative 和 XxProxy 中还有个括号,我前面说了 android 在 java 搞了个代码自动生成的东西——aidl,那个括号里面的类名是工具生成出来的,括号外面是手动写的。android 那一票 services 绝大部分接口的代码是用工具生成的,但是有几个是手写的,原因么,估计刚开始还没这个工具吧。
android 故意在 java 层上 binder 的框架结构和 native 层保持一致,这是个不错的设计,然后 java 层 binder 通信其实就是 native 的调用而已。上面简单把 binder 的框架梳理了一下,有很多地方后面再慢慢分析,因为 binder 涉及的东西太多了(横跨 java、native 和 kernel),而且进程间通信本来就是比较麻烦的东西,我认为多进程这个是现代智能操作系统的必不可少的基本功能之一。
小贴士
本文由原作者胡明明独家授权Open软件开发小组发布,著作权归原作者所有。如需转载请联系原作者申请授权。