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

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

参考文章:
http://gityuan.com/2015/10/31/binder-prepare/
http://blog.csdn.net/luoshengyang/article/details/6618363

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值