(2) Android中Binder调用流程 --- Binder环境的初始化
我们知道,在Android里Binder是进程间通信的基础,而且,Android的应用程序天生就支持Binder通信,为什么?没了Binder,Android里的四大组件将没法运转,比如Activity的启动其实是通过AMS来管理的,Activity里的那个token成员变量其实就是Activity在AMS中一条记录的引用,而这些都是跨进程的。
既然Binder是Android里跨进程交换数据的基础,像查询系统服务这些操作也是通过IServiceManager这个IBinder来完成的,那么问题来了,Android世界里的第一个IBinder是什么?在那里实现的?
这就是说我们要找到最先孵化出蛋的小鸡在那里,要不这么多小鸡那里来的:)嗯,这就是关键,还记得上节我们说过的ServiceManager进程的初始化吗?对,就是它,上节我们说这个进程实际上就是IServiceManager这个IBinder的具体实现,到这里可能有点晕了,一个进程怎么是接口的实现呢,准确说是ServiceManager进程的svcmgr_handler函数实现了IServiceManager接口功能的,还是晕,这不符合面向对象编程,但事实就是这样,ServiceManager是借助Binder驱动来完成这些功能,而我们获取的IServiceManager接口实际是通过BpBinder(这个后面会讲)来代理的,其handle为0,下面给出ServiceManager进程启动初始化流程图。
根据上图,我们讲下具体的流程,分为两个部分:IServiceManager初始化和使用。
IServiceManager初始化
1)ServiceManager进程启动;
2)初始化Binder驱动设备;
3)向Binder驱动申请成为Binder的管理者;
4)Binder驱动内部生成一个全局的binder_node节点,并设置其handle为0;
5)ServiceManager进程进入死循环,不断从Binder驱动读取客户端请求;
6) ServiceManager收到客户端请求,解析请求,根据解析出的命令分别处理;
7) 把处理结果通过Binder驱动发送给请求的客户端,完成一次命令处理。
客户端使用请求
我们这里以注册Service为例进行说明。
1)通过ServiceManagerNative获取IServiceManager代理接口;
2)获取的IServiceManager接口远程代理对象在JAVA层对应的是BinderProxy,在Native层对应的是BpBinder;
3)BinderProxy是通过BinderInternal.getContextObject()获取的;
4)BinderInternal.getContextObject()是一个native方法,其内部就是通过handle为0来生成一个BpBinder对象,然后把这个本地对象保存在BinderProxy的mObject成员变量里(在native层通过这个成员变量得到native层的BpBinder)。
5)因此最终IBinder实际调用的是BpBinder的transact()函数;
6)在BpBinder的transact()函数内部,实际调用的是IPCThreadState的transact来处理的,数据经过层层封装,最终调用ioctl(mProcess->mDriverFD,BINDER_WRITE_READ, &bwr)把请求发送到Binder驱动层;
7)Binder驱动层收到请求后,解析发现handle为0,然后找到handle为0对应的进程ServiceManager,最后把请求放到ServiceManager的处理队列并唤醒ServiceManager;
8)ServiceManager收到客户端请求后,根据请求码进行处理,这里是注册Service,因此在列表中插入注册的Service信息,这里要注意,新注册的Service就是个IBinder,其对应handle由Binder驱动生成了,因此,这里会根据handle查询列表是否存在,不存在插入一条Service信息。
通过上面流程的描述,有几个关键点
1)我们实际获取的IServiceManager仅仅是一个代理,其本地对象实现是BpBinder;
2)IServiceManager的handle固定是0,其没有名称,也不需要;
3)IServiceManager的具体实现是ServiceManager结合Binder驱动完成的;
4)每个IBinder对象都和一个32位的整型handle一一对应,并且这个handle是由Binder驱动层生成的。
到这里大家应该明白了Android世界里的第一个IBinder是谁了,没错,就是ServiceManager,其实现了IServiceManager的接口功能,这也是Android设计的巧妙之处。
知道了第一个IBinder之后,接下来我们看下应用进程怎么初始化Binder环境并使用的。其实,在ServiceManager里我们已经知道怎么样使用Binder了,就是通过ioctl系统调用完成的,并使用命令BINDER_WRITE_READ完成一次读写操作。
Binder驱动里定义很多命令,用来控制读写、环境参数设置等。回到主题,看下应用进程怎么初始化Binder环境的。
我们知道应用程序进程是由Zygote进程fork出来的,而这最终会调用ZygoteInit.zygoteInit这个方法。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv,
830 ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
......
837
838 RuntimeInit.commonInit();
839 ZygoteInit.nativeZygoteInit();
840 RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
841 }
我们看到调用了本地方法ZygoteInit.nativeZygoteInit();
frameworks/base/core/jni/AndroidRuntime.cpp
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env,
jobject clazz)
222{
223 gCurRuntime->onZygoteInit();
224}
gCurRuntime就是一个AppRuntime类型的对象:
frameworks/base/cmds/app_process/app_main.cpp
virtual void onZygoteInit()
92 {
93 sp
94 ALOGV("App process: starting thread pool.\n");
95 proc->startThreadPool();
96 }
sp
所以,一开始应用进程仅仅启动一个Binder线程,而SystemService开始启动两个binder线程来处理请求(SystemServer主线程是一个,通过ProcessState启动一个)。
本系列文章均为原创,主要总结作者多年在软件行业的一些经验,和大家共同学习、进步,转载请注明出处,谢谢!
更多相关文章
- OpenGL,Android注意事项初始化顺序 NullPointer
- Android进程与线程基本知识四
- FregServer进程,返回BR_REPLY
- android-2.2以下杀进程方法:restartPackage();
- Android P WMS初始化过程
- FregClient和FregServer进程间通信
- Android 进程间通信:AIDL
- AIDL --- Android中的远程接口(3)
- Android 进程间通信(IPC)