众所周知,Android中的IPC(进程间通信)采用了Binder机制,那么要理解进程间通信是如何实现的,理解Binder机制就相当关键了。
首先,为什么Android的IPC要采用Binder机制呢,查阅资料,Binder机制的优点在于其少了一次拷贝过程,传统的IPC需要将发送端
发送的数据从用户空间copy到内核空间,在给到接受者时,再从内核空间copy给接受者,一次IPC请求需要两次拷贝,而Binder机制
不同的时仅做一个copy操作,发送IPC请求,会将Client端携带的数据copy到内核空间,放在共享内存中,通过内核与用户空间的内
存映射到同一片物理空间,从而Server通过相关地址直接获取到该共享内存中的相关数据,而不需要将其从内核空间copy到用
户空间,这样的机制提高了IPC的性能。
其次,Binder机制的组成:
1) 用户空间:
Client: 发起IPC请求,通过从ServiceManager处获取的Service进程Binder代理对象的引用,从而调用Service的相关方法(Service的服务接口可以通过AIDL文件定义或者自定义接口类)
Service:需要在ServiceManager中注册,实现AIDL中的Stub类,其中包含提供的服务接口,Publish Service的Binder对象
ServiceManager:负责管理系统中的Service,维护Service的Binder对象的引用,提供给Client以名称方式查询Service的服务接口以及Service
的Binder对象引用
2) 内核空间:
Binder驱动:负责进程间的数据的传递,通过mmap内存映射实现共享内存, 连接 Client端与Server端
其实个人觉得Binder机制的原理大致了解一些就ok了,因为毕竟Binder机制大多数时候不需要去修改,而关键的是在理解Binder机制的基础上
如何在Binder机制基础上实现IPC,以及能够看懂Android系统中的IPC实现,解决进程间通信出现的问题。
如果从Code中去详细了解Binder的具体实现,可以参考如下blog进行详细的学习:
2.浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路
在Android Framework中有很多需要用到IPC的地方,比如startActivity, 在APP中调用startActivity这其实就发起了一次IPC请求,因为APP一般跑在
自己的进程中,而ActivityManagerSerive(AMS)运行在system_server进程中,这里启动Activity的请求其实就是一次IPC请求,APP进程将该请求发
送到AMS所在进程中,通过请求AMS的startActivity服务将想要启动的activity启动起来。
在实现IPC通信的时候,每个进程都会定义自己的Binder类,并创建Binder对象,一般Binder实体对象存在于Server进程中,而Client进程想要通过
Binder机制进行服务请求,需要通过ServiceManager获取一个Server进程中Binder代理对象的引用。
实现Binder对象很关键,也比较繁琐,所以为了方便开发者进行IPC的开发,Android提供的AIDL(Android Interface Definition Language)接口定义语言,
ADT中的aidl工具会根据用AIDL书写的XXX.aidl文件自动生成对应的接口类,接口类继承android.os.IInterface,其包含Stub和Proxy两个内部类,它
们的作用分别是:
接口类: 例如IServiceAIDL.aidl,其生成的接口类为IServiceAIDL.java,继承自android.os.IInterface, 包含在XXX.aidl文件中定义的所有接口
Stub类: 供Server进程用,抽象类,继承自android.os.Binder,implements IServiceAIDL接口,Server进程中Binder对象的类型,即Server进程的Code
会去具体实现此Binder类并将其中的接口进行具体的实现,定义继承自此类的子类或者直接匿名类实现对应的接口,此类中包含onTransact方法,这
个方法会被Binder驱动回调,根据传入的接口代码(int代号),找到需要调用Server进程的哪个接口。
Proxy类: 供Client进程用,implements IServiceAIDL接口类,实现该接口类中的所有方法,其为Stub类的内部类,Server进程Binder类的代理对象,Client
调用Proxy中的接口(即在XXX.aidl文件中定义的服务接口),Proxy中对该接口的实现最终通过调用IBinder的transact方法进入到Binder驱动程序的实
现流程中,Binder驱动处理完成即回调Stub类的onTransact方法去调用Server的服务实现
这里多说一句,为什么要提定义接口呢,进程间进行通信无非是想要用目标进程的服务,那么为了使得程序松耦合,服务定义完接口就不再修改,
Client如果想使用某个服务,直接调用对应的接口就可以了,不用关心Server是如何实现的,相当与在Client和Server之间抽象出一层接口,Server定
义好接口之后,具体实现可以根据具体情况进行修改,不会影响到Client接口的使用。
AIDL方便了IInterface接口类的自动生成,让开发者专注在服务接口的定义上,不用关注IInterface的繁琐的细节实现,当然根据自己的需求完全可以自己写
继承自IInterface的接口类,不需要借助AIDL工具。AIDL只是一个IPC的工具,跟IPC实现原理没有关系,仅帮忙将aidl定义的接口生成符合Binder机制的如上
讲解的三个重要类。下面分析分析IPC中这个必备的IInterface子类的实现方式:
1)通过aidl文件方式自动生成IInterface的子类,以一个简单的AIDL Demo来说明
a. 仅关注接口定义服务端需要提供的接口,按照AIDL规则书写XXX.aidl文件
aidl文件书写规则参考Android Interface Definition Language (AIDL)
IServiceAIDL.aidl
// IServiceAIDL.aidl
package com.xm.androiddemo;
//aidl仅支持一些接本的java类型,除了那些基本类型均必须import进来
import com.xm.androiddemo.IActivityAIDL;
// Declare any non-default types here with import statements
//Server 提供给 client 的接口文件定义
//Service(Server) 暴露给 Activity(Client) 的接口定义在 aidl文件中
interface IServiceAIDL {
void callService();
//在 Activity 中注册 ActivityADIL 到Service中,使得 Service 可以回调 Activity 中的方法
void registActivityCallBack(IActivityAIDL callback);
}
b. Eclipse或者Android Studio会自动根据如上aidl文件生成IServiceAIDL.java文件
Eclipse生成的gen目录下,Studio生成在$CodePath/app/build/generated/source/aidl/
debug/com/xm/androiddemo/IServiceAIDL.java
同样你可以自己运行aidl工具来生成.aidl文件对应的java文件: aidl IServiceAIDL.aidl $outputPath
具体的Code我就不贴了,自行在IServiceAIDL.java中找到IServiceAIDL, Stub, Proxy三个类,
仔细看看理解一下
c. Server进程中需要提供服务的Code中实现Stub类中的接口
d.Client进程中通过创建IServiceAIDL对象来调用aidl文件中定义的服务接口
Demo的细节参考如下两个例子:
一个简单的demo学习Android远程Service(AIDL的使用)
2)开发者自己写IInterface子类,定义必要的接口,以ActivityManagerService为例来说明
IPC Binder机制涉及的三个类对应名字:
接口类:IActivityManager.java 包含所有ActivityManagerService的提供的服务接口以及接口代码(数字代号)
Stub类:ActivityManagerNative.java 继承自Binder并implements IActivityManager接口类
Proxy类:ActivityManagerProxy.java ActivityManagerNative的内部类,implements IActivityManager接口类
Client与Server对以上各类的实现:
Client进程: Instrumentation类通过ActivityManagerNative.getDefault()获取到IActivityManager接口对象,由于AMS
属于远端进程因此queryLocalInterface应该返回null,从而new一个ActivityManagerProxy对象,传入AMS
进程的Binder对象引用,调用ActivityManagerProxy的startActivity方法,在startActivity的实现主要将IPC
需要传输的数据封装成Parcel对象,然后调用Binder的transact方法,进入Binder驱动流程。
Server进程: ActivityManagerService继承自ActivityManagerNative,也即ActivityManagerService本身为本进程的Binder
类型,实现IActivityManager定义的服务接口。接着上面Client的startActivity执行流程,进入Binder驱动流程
之后,底层驱动处理完毕之后回调上层ActivityManagerNative的onTransact方法,根据传入的接口代号调用
ActivityManagerService的实现的startActivity
印证如上的分析,简单添加了几句log,打印顺序同上面分析一致
01-01 08:08:16.112 D/ipclog ( 1817): ActivityManagerProxy transact START_ACTIVITY_TRANSACTION
01-01 08:08:16.122 D/ipclog ( 596): ActivityManagerNative onTransact START_ACTIVITY_TRANSACTION
01-01 08:08:16.122 D/ipclog ( 596): ActivityManagerService startActivity
如上log信息可以看两个进程号1817和596,596为AMS所在Server进程,1817为应用进程
应用进程transact一个IPC请求之后,Binder驱动通过onTransact回调到Server进程调用服务接口的实现。
IPC的内容暂且分析到这里,总的来说对这个流程有了个初步的认识,深层次的东西回头再学习补充。。。
参考
1.http://blog.youkuaiyun.com/linmiansheng/article/details/42438813