android进程间通讯(2)--Binder解析及AIDL的使用

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。

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


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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,459评论 25 707
  • Android跨进程通信IPC整体内容如下 1、Android跨进程通信IPC之1——Linux基础2、Andro...
    隔壁老李头阅读 11,810评论 11 56
  • 逆位星币3,读牌1、我是那个站在凳子上的人,其他两个人在挑我的毛病,这是我的第一感觉,就像我平时的状态,在面对这种...
    塔罗师默默阅读 172评论 0 0
  • 一个人的奋斗应该是这样的 你有过拿自己和别人做比较,然后感到慌张、惆怅吗?你有过把自己最宝贵的时间浪费在错误的人身...
    水哥1022阅读 336评论 0 0
  • “老师,出上海了吗……?” “老师,到浙江了啊?……” 对于这群叽叽喳喳的孩子们而言,一路抑制不住的兴奋和激动。是...
    阳光Sunflower阅读 450评论 0 4