6

Android10.0 Binder通信原理(八)-Framework层分析

 1 year ago
source link: https://blog.csdn.net/yiranfeng/article/details/105313236
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

摘要:本节主要来讲解Android10.0 Binder 在Framework的使用分析

阅读本文大约需要花费15分钟。

文章首发微信公众号:IngresGe

专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢!

欢迎关注我的公众号!

20200113052246361.jpg

[Android取经之路] 的源码都基于Android-Q(10.0) 进行分析

[Android取经之路] 系列文章:

《系统启动篇》

《日志系统篇》

《Binder通信原理》

  《HwBinder通信原理》

《编译原理》

前面几节,我们已经把Native层和Binder驱动层的Binder数据流转给理清楚了,也知道了相应的概念。这一节让我们继续往上进行分析,我们进入到Framework层,看看Framework是如何实现服务的注册、获取的流程。

2.Binder架构

Framework层要实现服务的注册需要通过JNI 来调用Native C\C++层的相应接口,最终把服务注册到Native层的ServiceManager中。
应用层的进行通过Framework的接口,也经过JNI技术进入Native C\C++,最终在Native层的ServiceManager中得到服务handle,最终转成相应的服务对象。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

3.源码分析

3.1 Binder-JNI

当Init进程启动后,孵化Zygote进程时,会有一个虚拟机注册过程,在这个过程中完成了JNI的注册,我们现在不需要深入去理解JNI的原理,后面有时间,我再单独出一章来进行分析。

现在我们只要知道 JAVA和Native侧的函数对应关系在哪里即可。

Binder的JNI中有个三个Binder的映射数组:gBinderMethods、gBinderInternalMethods、gBinderInternalMethods。

我们在撸代码时,是要根据JAVA的函数入口找到JNI的函数调用即可,不要太追求细枝末节。

gBinderMethods:

gBinderInternalMethods:

gBinderInternalMethods:

3.2 服务注册

在上一节的Framework Binder Demo示例中,我们知道服务注册的时候,调用的是ServiceManager.java的addService(),那我们就拿addService()开刀。

注册服务调用栈:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

3.2.1 addService()

拿到ServiceManagerProxy对象,来执行addService操作,这个ServiceManagerProxy对象需要我们来揭开面纱。

3.2.2 getIServiceManager()

这里也采用了单例模式来获取ServiceManagerProxy对象,减少对象重复创建。

asInterface()中的主要作用就是创建ServiceManagerProxy()对象,但是需要带一个IBinder的 obj,我来看看这个obj是如何拿到的。

3.2.3 getContextObject()

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

BinderInternal.java中有一个native方法getContextObject(),JNI调用执行上述方法,在JNI的 gBinderInternalMethods数组中找到了getContextObject的对应关系,即为android_os_BinderInternal_getContextObject。

ProcessState::self()->getContextObject(NULL) 在《Binder--Native-C\C++实例分析》 的[5.3.1]节已经进行了详细分析,最终等价于 new BpBinder(0),这里就不重复展开了。

javaObjectForIBinder()

如果参数是JavaBBinder,返回用于创建它的Java对象;否则返回一个BinderProxy的对象。

如果上一个调用被传递给同一个IBinder,而原来的BinderProxy还活着,返回同样的BinderProxy。

javaObjectForIBinder()中,申请一个BinderProxyNativeData的内存,传入的BpBinder的对象地址保存到BinderProxyNativeData.mObject成员变量中,通过虚拟机的转换,BinderProxyNativeData在JAVA空间会被转换成 BinderProxy对象。

最终,BinderInternal.getContextObject()等价于 new BinderProxy(),所以getIServiceManager等价于new ServiceManagerProxy(new BinderProxy())。

3.2.4 ServiceManagerProxy.addService()

上一节,我们已经拿到了ServiceManager在JAVA空间的代理,即ServiceManagerProxy,接着调用addService()来进行服务的注册。

组装一个Parcel数据,把服务的名称和对象写入Parcel中,然后把它拍扁,服务转成flat_binder_object对象,在Native层为Binder实体。

3.2.5  writeStrongBinder()

把传入的服务对象拍扁,转成flat_binder_object对象,代码流程太罗嗦,这里列出以下调用栈流程:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

data.writeStrongBinder(service)等价于parcel->writeStrongBinder(new JavaBBinder(env, obj));最终调用的是flatten_binder(),目的是把一个Binder实体“压扁”并写入Parcel。

这里"压扁"的含义,其实就是把Binder对象整理成flat_binder_object变量。如果压扁的是Binder实体,那么flat_binder_object用cookie域记录binder实体的指针,即BBinder指针,而如果打扁的是Binder代理,那么flat_binder_object用handle域记录的binder代理的句柄值。

接着flatten_binder()调用了一个关键的finish_flatten_binder()函数。这个函数内部会记录下刚刚被扁平化的flat_binder_object在parcel中的位置。说得更详细点儿就是,parcel对象内部会有一个buffer,记录着parcel中所有扁平化的数据,有些扁平数据是普通数据,而另一些扁平数据则记录着binder对象。所以parcel中会构造另一个mObjects数组,专门记录那些binder扁平数据所在的位置,示意图如下:

20200404172432854.jpg

flatten_binder()的流程可以参考《Binder--Native-C\C++实例分析》 的[5.4]节

3.2.6 mRemote对象

mRemote 是ServiceManagerProxy的一个成员,执行一个IBinder对象,mRemote在ServiceManagerProxy()构造函数中进行了赋值,从[4.2.3]和[4.2.4] 可知getIServiceManager()中调用了 如下内容:

sServiceManager = ServiceManagerNative.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()))

从而可知 mRemote = BinderInternal.getContextObject() = new BinderProxy(),所以mRemote就是BinderProxy的对象。

mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0) 等价于BinderProxy.transact(ADD_SERVICE_TRANSACTION, data, reply, 0)

3.2.7 BiderProxy.transact()

逻辑很简单,先检查Parcel的大小是否大于800K,然后调用了transactNative()进行数据传递。 

transactNative()一个Native方法,根据之前的JNI数组表,可以查到JNI的对应入口。

根据我们之前获取的对象流程来看,BinderProxy在Native空间,对应的是BpBinder,target即为BpBinder对象。所以target->transact() 等价于BpBinder::transact(), 接下来的流程参考前面Native-C\C++层的分析,这里的细节不再阐述,参考 《Binder--Native-C\C++实例分析》 和 《Binder数据如何定向打击》,也可以看到上面注册服务的调用栈。

3.2.8 服务注册总结

framework层的ServiceManager的调用实际的工作确实交给ServiceManagerProxy的成员变量BinderProxy;而BinderProxy通过jni方式,最终会调用BpBinder对象;可见上层binder架构的核心功能依赖native架构的服务来完成的。

注册服务的核心部分,就是JAVA侧把服务名称和对象,转入Parcel“扁平”数据,通过Native BpBinder,把code:ADD_SERVICE_TRANSACTION发给Binder驱动,再转到Native的ServiceManager,ServiceManager把服务名称和转换后的handler进行存储,供Client进行服务获取。

3.3 服务获取

在上一节的Framework Binder Demo示例中,我们知道服务注册的时候,调用的是ServiceManager.java的getService(),那么获取服务就从getService()入口。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

3.3.2 rawGetService()

从上面可知getIServiceManager() 等价于 new ServiceManagerProxy(new BinderProxy()),getIServiceManager().getService(name)等价于ServiceManagerProxy().getService(name)

3.3.3 getService()

从[4.2.6]可知,mRemote.transact(XXX) 等价于BinderProxy.transact(xx),这里不展开,和[4.2.7流程]一样,只是ServiceManager获取到服务的handle后,存入了reply信息中,这里会再调用reply.readStrongBinder()把binder对象给取出来。

3.3.4 readStrongBinder()

调用栈如下:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

Parcel.cpp -> readStrongBinder() 参考 《Binder--Native-C\C++实例分析》 中的[6.4]节,  javaObjectForIBinder()参考[4.2.3]

readStrongBinder()最终是从reply的Parcel数据中获得BpBinder对象,再转成BinderProxy对象,参与JAVA层的工作。

3.3.5 allowBlocking

作用:

  1. 允许在给定接口上阻塞调用,重写请求的{setWarnOnBlocking(boolean)}值。
  2. 只有当您完全确定远程接口是一个永远无法升级的内置系统组件时,才应该很少调用此命令。尤其是,决不能对包托管的、可升级或替换的接口调用此命令,否则,如果远程接口接入,将有系统不稳定的风险。

3.3.6 获取服务小结

和注册服务类似,都是需要依赖Native层的接口与Binder驱动通信,获取服务主要是从Native的ServieManager取到Binder对象。

3.4 Client-Server接口调用

在[3.2] 和[3.3]中,我们知道了服务注册addService()和获取服务getService()的流程,接下来我们再看一看接口调用是如何进行的。

上面调用的流程,其实和addService()、getService()类似,都是组装Parcel数据,准备服务端的code,调用BinderProxy.transact()发送到服务端。

但是和服务注册不同的是,在服务注册中,Native的ServiceManager是Server端,服务实体是Client端。接口调用时,服务实体是Server端。

服务端接收到CLient的请求后,根据下图的流程,最终流转到服务实体的onTransact()中,对解析出来的Parcel数据进行处理。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

Framework层获取服务、注册服务,其实都是由JAVA层的ServiceManager代理 ServiecManagerProxy ,通过Binder驱动,访问Native层的ServiceManager,进行服务注册和获取动作。

这一节只是单独在Framework层进行了分析,很多情况下我们都是在应用层进行处理流程,通过AIDL接口进行通信,下一节会对AIDL进行一下分析。

代码路径:

Framework:

/frameworks/base/core/java/android/os/Binder.java
/frameworks/base/core/java/android/os/IBinder.java
/frameworks/base/core/java/android/os/BinderProxy.java
/frameworks/base/core/java/android/os/BinderProxy.java
/frameworks/base/core/java/android/os/ServiceManager.java
/frameworks/base/core/java/android/os/IServiceManager.java
/frameworks/base/core/java/android/os/ServiceManagerNative.java
/frameworks/base/core/java/com/android/internal/os/BinderInternal.java

JNI:

/frameworks/base/core/jni/android_util_Binder.h
/frameworks/base/core/jni/android_util_Binder.cpp
/frameworks/base/core/jni/android_os_Parcel.h
/frameworks/base/core/jni/android_os_Parcel.cpp

参考:

《Binder framework层分析》

我的微信公众号:IngresGe

20200113052246361.jpg

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK