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架构图,图片来自网络。


image

1.内核层:Linux 内核和各类硬件设备的驱动,binder驱动/dev/binder位于这一层
2.类库层:由于类库层多是c/c++编写的native代码,所以又叫C库层
3.应用程序框架层:这一层可以理解为 Android SDK,提供四大组件,View 绘制体系等平时开发中用到的基础部件,因为该层主要是java编写,所以又叫java库层
4.应用层:开发人员开发的应用程序层
其实在内核层和类库层还有一层是HAL,硬件抽象层:封装「内核层」硬件驱动,提供可供「系统服务层」调用的统一硬件接口

<2>计算机内存管理

1.早期的机器并没有任何的虚拟地址的概念,被称为“实模式”内存管理。而后期发展出来的设备提供了虚拟地址的硬件实现。最早的操作系统中,并没有严格意义的内存保护机制,对于内存的访问约束完全在于程序编写者的自觉性,这种做法并不靠谱。为了管理内存和保护内存,提出了虚拟内存和进程概念。虚拟内存是一个抽象的概念,它为每个进程提供了一个假象,即每个进程都在独占的使用主存,每个进程看到的内存都是一致的,称为虚拟地址空间。如下图所示,在Linux中,地址空间的最上面区域是保留给操作系统的代码和数据的,这对所有进程来说都一样,地址空间的底部区域存放用户进程定义的代码和数据。


VmYUGfo.png

也正是因为这样,每个进程都有自己独立的内存空间,没有办法直接访问它管辖以外的内存空间,所以进程间通讯要通过系统提供的IPC方式进行通讯。而Binder则是android上主要的IPC方式。

从内存访问的角度来看,Binder的作用就是让两个进程可以访问同一块内存空间,实现数据交换,如图:图片来自http://gityuan.com/2015/10/31/binder-prepare/

C0ddZIP.png

每个Android的进程,只能运行在自己进程所拥有的虚拟地址空间。对应一个4GB的虚拟地址空间,其中3GB是用户空间,1GB是内核空间,当然内核空间的大小是可以通过参数配置调整的。对于用户空间,不同进程之间彼此是不能共享的,而内核空间却是可共享的。Client进程向Server进程通信,恰恰是利用进程间可共享的内核内存空间来完成底层通信工作的,Client端与Server端进程往往采用ioctl等方法跟内核空间的驱动进行交互

<3>Binder实现机制

Android系统Binder机制中的四个组件Client、Server、Service Manager和Binder驱动程序的关系如下图所示:


image

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,如图:


image

步骤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文件,这文件是系统自动生成的,如下图:


DjISWbB.png

步骤3.创建服务并注册,如下图:

image

服务内容如下,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。

                                     

客户端创建:
步骤1:同样在app的module的mian文件夹下面创建aidl文件夹和相同包名,相同名字的aidl文件,可以将服务端的aidl文件直接copy过来,如下图:


image

步骤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

更多相关文章

  1. Android(安卓)分析(一)四层结构分析
  2. android init进程分析 init脚本解析和处理
  3. 一个BAT大厂面试者整理的Android面试题目!
  4. android 文件存储调试细节(小米系统)
  5. Android完整知识体系路线(菜鸟-资深-大牛必进之路)
  6. 《Android内核剖析》读书笔记 第6章 应用框架Framework概述
  7. android studio 使用AIDL实现IPC
  8. Android内核开发:系统启动速度优化
  9. android 应用生命周期 及应用重要性

随机推荐

  1. edittext 随文字换行 而高度增加
  2. pytest-skip详解
  3. 2011.10.17——— android 多点触控
  4. 解决Android(安卓)Studio 和 Android(安
  5. android调用系统打电话功能
  6. Android(安卓)Studio第二十四期 - Gson封
  7. Android工程 单元测试
  8. Android(安卓)设置边距总结
  9. Android(安卓)JNI 分析
  10. Android(安卓)WebView相关属性