Android IPC 进程间通信实现理解

众所周知,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进行详细的学习:

1.Android Bander设计与实现 - 设计篇

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的使用)

         AIDL Demo


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




   



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值