Android Binder框架实现之Java层Binder服务跨进程调用源码分析
前言
兜兜转转几个春秋,通过前面的博客Android Binder框架实现之Framework层Binder服务注册过程源码分析和Android Binder框架实现之Java层获取Binder服务源码分析我们终于将Android Framework层的Binder框架整体分析完毕了,而我们也可以通过ServiceManagerProxy的getService获取远程Java BInder服务的代理端IXXXServiceManagerProxy,而我恩今天的博客将来了解这最后一段逆缘,即我们获取远程Java Binder服务的的代理端IXXXServiceManagerProxy以后怎么通过它跨进程调用到Java Binder服务实体端(这里我们以AMP跨进程调用AMS为例说明)。
- 注意:本篇的介绍是基于Android 7.xx平台为基础的,其中涉及的代码路径如下:
framework/base/core/java/android/os/
---IInterface.java
---IServiceManager.java
---ServiceManager.java
---ServiceManagerNative.java(内含ServiceManagerProxy类)
framework/base/core/java/android/os/
---IBinder.java
---Binder.java(内含BinderProxy类)
---Parcel.java
framework/base/core/java/com/android/internal/os/
---BinderInternal.java
framework/base/core/jni/
---AndroidRuntime.cpp
---android_os_Parcel.cpp
---android_util_Binder.cpp
frameworks/native/libs/binder/BpBinder.cpp
frameworks/native/include/binder/IBinder.h
frameworks/native/libs/binder/Binder.cpp
frameworks/native/include/binder/Parcel.h
frameworks/native/libs/binder/Parcel.cpp
frameworks/base/core/jni/core_jni_helpers.h
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks//base/core/java/android/app/ActivityThread.java
- 为了后续的书写方便会将ActivityManagerService简述为AMS,ServiceManager简述为SM,ServiceManagerProxy简述为SMP,ServiceManagerNative简述为SMN,ActivityManagerProxy简称AMP, ActivityManagerNative简称AMN以上特此申明!并且在这里附上Java跨进程调用Framework Binder服务整体流程图:
一.AMP跨进程调用AMS服务流程分析
1.1 AMP服务代理端的获取
还记得我们在前面博客中Android Binder框架实现之Java层获取Binder服务源码分析中我们以AMS服务为例,讲述了怎么获取其远程服务代理端AMP,在正式开始流程分析前我们先看看AMS的家族关系的类图结构(包括服务端和远程服务代理端的),如下:
-
这里我们可以看到AMS服务代理端AMP继承于接口业务类IActivityManager,从而可以使第三方应用在获取到AMS远程代理端以后可以忽略跨进程调用如同使用本地对象一样使用AMS提供的业务逻辑方法。而其AMP的数据传输最后都是通过mRemote的transact方法来实现的,而这个mRemote又是AMP在构造的时候new AMP(BinderProxy(BpBidner(handle)))传入的。
-
而我们的BinderProxy由对应的BpBinder构造而来,且BinderProxy与BpBinder相互引用,BinderProxy的transact()方法会通过JNI层调用到对应的成员变量mObject中的BpBinder的transact()方法;
-
通过JNI层的支持,native层的JavaBBinder对象对java层的Binder持有引用,在Binder初始化时即通过JavaBBinderHolder持有了Java Binder的引用,Java Binder的引用保存在JavaBBinder的成员变量mObject中,因此AMP响应时是由JavaBBinder这个BBinder的子类通过JNI层通知上层Java Binder继而实现java层服务的响应请求。
总之关于这三者的具体关系的获取,可以参见Android Binder框架实现之Java层获取Binder服务源码分析博客,而三者之间的关系可以使用如下的示意图来表示,如下:
1.2 AMP跨进程调用AMS远程服务
//ActivityManagerNative.java
class ActivityManagerProxy implements IActivityManager
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
..
//这里的mRemote指向BinderProxy
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
...
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
}
这里我们以AMP的startActivity方法的跨进程调度为例,这个流程和前面博客Java层获取Binder服务的调度逻辑是一样的,其基本操作逻辑如下:
- 先执行BinderProxy对象的transact()方法通过JNI层的传递调用到Native层中对应的BpBinder(handle)的transact()方法
- 接下来就是通过BpBinder中的IPCThreadState与Binder驱动进行交互了
上述的流程我们已经烂熟于心了,这个不是重点,重点是AMS怎么获取Binder服务传递过来的信息,并相应服务请求!
1.2 AMS服务怎么影响远程端调度请求
在前面的博客 Android系统启动之SystemServer大揭秘中我们分析到了在system_server进程的其中过程中会调用如下的代码逻辑:
//app_main.cpp
virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();//开启binder线程,是不是有中似曾相识的熟悉感觉
}
ProcessState::self()是单例模式,主要工作是调用open()打开/dev/binder驱动设备,再利用mmap()映射内核的地址空间,将Binder驱动的fd赋值ProcessState对象中的变量mDriverFD,用于交互操作。startThreadPool()是创建一个新的binder线程,不断进行talkWithDriver(),在binder系列文章中Android Binder框架实现之Binder服务的消息循环有关于该部分的详细的讲解,这里就不过多阐述了。这样将当前线程注册到Binder驱动程序中,这样我们创建的线程就加入了Binder线程池中,这样新创建的system_server进程就支持Binder进程间通信了。即我们system_server进程中IPCThread线程会不断向Binder驱动查看是否有请求数据的到来,而此时AMP的数据通过Binder驱动传递过来了,我们的AMS服务的进程就会通过IPCThread线程接收到。至于这其中的复杂调用逻辑过程,就不是本篇的重点可以参见Android Binder框架实现之之Binder Native Service的Java调用流程。