android进程间通讯(2)–理解Binder及AIDL使用
前言:之前一篇文章记录了Bundle和文件共享的方式来进行进程间通讯,但并不是所有场景都适用的,比如A进程正在进行一个计算,计算完成后要启动B进程并把计算结果传递给B进程,但是计算结果不支持放入Bundle,又或者A进程有个封装好的方法,B进程想要调用A进程里面的方法,使用Bundle则行不通了。因此android提供了一种进程间通讯方式Binder。Binder是Android系统最主要的IPC方式,其中Messenger,AIDL,ContentProvider底层实现都是Binder。由于Binder的实现比较复杂,这里只记录基本原理。
1.Binder机制
了解binder首先要解决几个疑问:1.什么是Binder? 2.Binder的实现原理?3.Binder的具体应用有哪些?
(1).什么是binder
直观来说,Binder是android中的一个类,它实现了IBinder接口。从IPC角度说,Binder是android中的一种跨进程通讯方式。Binder可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通讯的方式在Linux中没有。从Android Framework角度来说,Binder是ServiceManager连接各种Manager比如ActivityManager,WindowManager,InputManager,ResourceManager等等和相应的ManagerService的桥梁。从安卓应用层来说,Binder是客户端和服务端进行通讯的媒介。
(2).Binder实现原理
个人觉得想要理解Binder的实现原理,首先要理解以下两个方面的东西。1.Android的体系架构;2.计算机的内存管理。
<1>.Android体系架构
首先来看一下android架构图,图片来自网络。
1.内核层:Linux 内核和各类硬件设备的驱动,binder驱动/dev/binder位于这一层
2.类库层:由于类库层多是c/c++编写的native代码,所以又叫C库层
3.应用程序框架层:这一层可以理解为 Android SDK,提供四大组件,View 绘制体系等平时开发中用到的基础部件,因为该层主要是java编写,所以又叫java库层
4.应用层:开发人员开发的应用程序层
其实在内核层和类库层还有一层是HAL,硬件抽象层:封装「内核层」硬件驱动,提供可供「系统服务层」调用的统一硬件接口
<2>计算机内存管理
1.早期的机器并没有任何的虚拟地址的概念,被称为“实模式”内存管理。而后期发展出来的设备提供了虚拟地址的硬件实现。最早的操作系统中,并没有严格意义的内存保护机制,对于内存的访问约束完全在于程序编写者的自觉性,这种做法并不靠谱。为了管理内存和保护内存,提出了虚拟内存和进程概念。虚拟内存是一个抽象的概念,它为每个进程提供了一个假象,即每个进程都在独占的使用主存,每个进程看到的内存都是一致的,称为虚拟地址空间。如下图所示,在Linux中,地址空间的最上面区域是保留给操作系统的代码和数据的,这对所有进程来说都一样,地址空间的底部区域存放用户进程定义的代码和数据。
也正是因为这样,每个进程都有自己独立的内存空间,没有办法直接访问它管辖以外的内存空间,所以进程间通讯要通过系统提供的IPC方式进行通讯。而Binder则是android上主要的IPC方式。
从内存访问的角度来看,Binder的作用就是让两个进程可以访问同一块内存空间,实现数据交换,如图:图片来自http://gityuan.com/2015/10/31/binder-prepare/
每个Android的进程,只能运行在自己进程所拥有的虚拟地址空间。对应一个4GB的虚拟地址空间,其中3GB是用户空间,1GB是内核空间,当然内核空间的大小是可以通过参数配置调整的。对于用户空间,不同进程之间彼此是不能共享的,而内核空间却是可共享的。Client进程向Server进程通信,恰恰是利用进程间可共享的内核内存空间来完成底层通信工作的,Client端与Server端进程往往采用ioctl等方法跟内核空间的驱动进行交互
<3>Binder实现机制
Android系统Binder机制中的四个组件Client、Server、Service Manager和Binder驱动程序的关系如下图所示:
1. Client、Server和Service Manager实现在用户空间中,Binder驱动程序实现在内核空间中
2. Binder驱动程序和Service Manager在Android平台中已经实现,开发者只需要在用户空间实现自己的Client和Server
3. Binder驱动程序提供设备文件/dev/binder与用户空间交互,Client、Server和Service Manager通过open和ioctl文件操作函数与Binder驱动程序进行通信
4. Client和Server之间的进程间通信通过Binder驱动程序间接实现
5. Service Manager是一个守护进程,用来管理Server,并向Client提供查询Server接口的能力
2.Binder具体应用
从Binder的实现机制可以知道,使用Binder需要创建Client(客户端)和Server(服务端)。应用层使用Binder进行进程间通讯具体实现有Messenger,AIDL,ContentProvider,由于Messenger底层是AIDL,Contentprovider涉及到数据库。这里只记录AIDL的使用方式。
服务端创建:
步骤1.首先新建一个工程,并在app的module的mian文件下创建文件夹aidl,如图:
步骤2:创建.aidl文件,如图中的hdcPearAIDL.aidl文件,并添加两个方法,hdcPearAIDL.aidl内容如下:
package pear.cn.hdcsdktest;
interface hdcPearAIDL {
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
int add(int a,int b);
void shellCommand(String cmd);
}
build项目之后会在build>generated->source->aidl->debug->下面生成hdcPearAIDL的java文件,这文件是系统自动生成的,如下图:
步骤3.创建服务并注册,如下图:
服务内容如下,AidlService继承Service,重写onBind()方法,并返回IBinder的实例。并在iBinder里面实现接口定义的方法,提供给其他进程调用。
/**
* Created by hdc on 2016/11/28.
*
*/
public class AidlService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
private IBinder iBinder = new hdcPearAIDL.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public int add(int a, int b) throws RemoteException {
LogUtil.i("hdcTest"," use the method "+a+"/"+b);
return a+b;
}
@Override
public void shellCommand(String cmd) throws RemoteException {
LogUtil.i("hdcTest"," use the method shellCommand "+cmd);
ShellUtil.execCommand(cmd,ShellUtil.checkSuRoot());
}
};
}
别忘记在AndroidManifest中注册AidlService。
<service android:name=".services.AidlService">
<intent-filter>
<action android:name="pear.cn.hdcsdktest.services.AidlService"/>
</intent-filter>
</service>
客户端创建:
步骤1:同样在app的module的mian文件夹下面创建aidl文件夹和相同包名,相同名字的aidl文件,可以将服务端的aidl文件直接copy过来,如下图:
步骤2:绑定服务,在客户端的activity的onCreate方法里面绑定服务,在onServiceConnected()方法返回hdcPearAIDL对象,可以使用aidl对象来调用服务端的方法。
public class MainActivity extends AppCompatActivity {
private hdcPearAIDL aidl;
private ServiceConnection serviceConnection =new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
aidl= hdcPearAIDL.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
aidl=null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService();
}
private void bindService() {
Intent intent = new Intent();
//绑定服务端的service
intent.setAction("pear.cn.hdcsdktest.services.AidlService");
//新版本(5.0后)必须显式intent启动 绑定服务
intent.setComponent(new ComponentName("pear.cn.hdcsdktest","pear.cn.hdcsdktest.services.AidlService"));
//绑定的时候服务端自动创建
bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
总结
1.Binder是android中最主要的IPC方式
2.Binder实现原理涉及到android框架体系以及操作系统的内存管理机制
3.Messager,AIDL,ContentProvider的底层原理是Binder