前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android Binder 分析系列——原理(下)

Android Binder 分析系列——原理(下)

作者头像
open
发布2020-03-19 17:03:52
7300
发布2020-03-19 17:03:52
举报

作者 介绍

胡明明

专注于AndroidFramework、VR开发。

温馨提示:

请先阅读《Android Binder 分析系列——原理(上)》

框架设计——java

照例来先张图先:

图中我把相关的 jni 里面类也画了出来,这样就能更加明显的看到 java 层和 native 层的对应关系。

代码位置也先说下:

代码语言:javascript
复制

从图可得到,java 层的架构和 native 的很像。也是分为2个部分:实现部分和接口部分(几乎连名字都和 native 的一样)。

实现部分的话,也是一个 IBinder 的基类,额,不对 java 的叫 interface ,这个比 c++ 更加注重抽象。然后实现这个接口的分别是 Binder(Binder.java) 和 BinderProxy(Binder.java),分别对应 native 的 BBinder 和 BpBinder ,同时也分别代表 java 层的服务端和客户端。

Binder 这边的话:

代码语言:javascript
复制

前面几个函数都挺简单的,就是返回 descriptor ,要不返回 IInterface,要不设置下 IInterface 和 desriptor 。transact 这个函数看注释说是啥默认实现,别看它调用了 onTransact (native Bn 端的实现主要在这里)其实就是个摆设,没用的,因为要实现 IBinder 的接口,才必须要有一个实现而已(到后面就就知道了)。然后 onTransact 这个和 native 对应了,不过这里其实也没干声明正事,功能主要是留在service 的接口里实现的。

Java 的 Binder 最主要要看的是它有个叫 mObject 的变量:

代码语言:javascript
复制

看注释说是 native 层要使用,其实是 jni 要使用。来看看这个 mObject 是怎么使用的:

代码语言:javascript
复制

在 Binder 的构造函数中会调用一个 init 的 native 方法,这个方法在 jni android_util_Binder.cpp 里面:

代码语言:javascript
复制

这里创建了一个 JavaBBinderHolder (这个是 c++ 的类)的类,然后把这个指针保存在了 mObject 这个变量里面。int 类型是 32bit 的,指针(地址)在 32bit 系统上也是 32bit 的。这里再先看看 gBinderOffsets 这个东西,其实还有一个叫 gBinderProxyOffsets 的。这2个是 jni 里面 java 的类信息变量,弄成全局变量,如果访问频繁的话,能提高速度,因为每次都要去查 java 的类表很慢的,加载的代码在:

代码语言:javascript
复制

这个 register_android_os_Binder 会在 android 的 java 初始化的时候调用,这个时候需要的类信息就加载好了。gBinderOffsets 对应的是 Binder, gBinderProxyOffsets 对应的是 BinderProxy 。gBinderOffsets 的 mObject 就是 Binder 的 mObject 变量,所以那个注释说不要乱改这个变量的名字,不然这里就找不到了。gBinderOffsets 还有一个保存了 execTransact 的变量,这个注意一下,后面会说到的。

回过来看下 JavaBBinderHolder 这个东西:

代码语言:javascript
复制

这个东西继承自 native 的 RefBase,然后在看它的 get 方法的返回值,可以理解为这个东西就是在 java 里面放了一个 natvie 的 sp 一样。它持有的是 JavaBBinder 对象,这个才是重点:

代码语言:javascript
复制

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 函数:

代码语言:javascript
复制

最后是调用了 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:

代码语言:javascript
复制

BinderProxy 很多都直接是 native 方法。queryLocalInterface 直接放回 null,和 native 层的一样, Bp 端不实现 Bn 端的方法。它和 Binder 一样有一个 int mObject 的变量,同样这个也是保存 native 对象指针的,这个其实是 sp,这个后面再分析了。所以 java 的 BinderProxy transact 方法就直接调用 native BpBinder 的 transact 。

接下来就是接口部分了。IInterface :

代码语言:javascript
复制

和 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软件开发小组发布,著作权归原作者所有。如需转载请联系原作者申请授权。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Open软件开发小组 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 温馨提示:
  • 请先阅读《Android Binder 分析系列——原理(上)》
  • 框架设计——java
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档