您的位置:首页 > 大数据 > 人工智能

进程间通信 IPC (Binder核心和AIDL)

2014-09-27 10:20 323 查看
     http://blog.csdn.net/luoshengyang/article/details/6618363   老罗

     http://blog.csdn.net/universus/article/details/6211589

AIDL例子:http://blog.csdn.net/singleton1900/article/details/8434643

http://blog.csdn.net/singwhatiwanna/article/details/17041691

一般来说Android 的四大组件都是运行在同一个进程中的,但远程Service运行在不同的进程里。这进程间的通信是使用了Android Binder机制。Android 中Service 有本地Service和远程Service之分,本地Service用法比较简单,而远程Service用法稍微要复杂一些。

AIDL即android接口定义语言。aidl是解决进程间通信用的。在本例中就是Activity(即client端)与Service(即服务端)的通信。

首先,定义Aidl文件,如Service中暴露给Activity的接口可以定义在aidl文件中,反之也一样。下面Service给Activity使用接口文件是ServiceAIDL.aidl

//Service中暴露给Activity的接口可以定义在aidl文件中

interface ServiceAIDL {
    void callService();
   // 在Activity中注册ActivityAIDL到Service中,使Service中可以调用ActivityAIDL中的方法
   void registActivityCallBack(ActivityAIDL callBack);

 }

Activity给Service中使用的ActivityAIDL.aidl

//Activity中暴露给Service的接口可以定义在aidl文件中

interface ActivityAIDL{
     void callActivity();

}

上面两个aidl在会自动在gen目录下生成对应的java文件。

第二步,写Service。写一个MyService继承于Service类,并在onBind()方法中 返回ServiceAidl.Stub对象

// 远程服务

public class MyService extends Service {
public static final String SERVICE_NAME = "com.miloisbadboy.start.MyService";
public static final String TAG = "MyService";
private ActivityAIDL activityAIDL;
@Override
public IBinder onBind(Intent intent) {
   return mBinder;
}
private ServiceAIDL.Stub mBinder = new ServiceAIDL.Stub() {
@Override
public void callService() throws RemoteException {
     Toast.makeText(getApplicationContext(), "Call Service's method ****** callService()", 1000).show();
     activityAIDL.callActivity();
}
@Override
public void registActivityCallBack(ActivityAIDL callBack) throws RemoteException {
      activityAIDL = callBack;
      }
   };

}

MyService中有ActiviyAIDL的一个引用,此类型的实例是在ServiceAIDL.Stud这个代理中得到的,即是在registActivityCallBack(ActivityAIDL callBack)方法中对其赋值,这个方法是在Activity中将ActivityAIDL的接口注册到Service中去的。

在ServiceAidl.Stub mBinder = new ServiceAidl.Stub(){}里面的callService() 和registActivityAidl(ActivityAidl activityAidl)方法就是在Activity将会被调用到的。

// 测试远程Service

public class TestAIDLActivity extends Activity implements OnClickListener{
private Button start;
private Button stop;
private Button callService;
// service call back
private ServiceAIDL serviceAIDL;
@Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        start = (Button)findViewById(R.id.start_service);

        stop = (Button)findViewById(R.id.stop_service);

        callService = (Button)findViewById(R.id.call_service);

 

        start.setOnClickListener(this);

        stop.setOnClickListener(this);

        callService.setOnClickListener(this);

    }
@Override
public void onClick(View v) {
if(v == start){
Intent service = new Intent(MyService.SERVICE_NAME);
//绑定Service 并将ServiceConnection的实例传入
bindService(service, serviceConn, Context.BIND_AUTO_CREATE);
stop.setVisibility(View.VISIBLE);
}else if(v == stop){
unbindService(serviceConn);
}else{
try {
if(serviceAIDL!=null){
serviceAIDL.callService();
}else {
Toast.makeText(this, "Service is not started!", 1000).show();
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
private ServiceConnection serviceConn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
serviceAIDL = null;
Toast.makeText(getApplication(), "Service is unbind!", 1000).show();
}

 
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
serviceAIDL = ServiceAIDL.Stub.asInterface(service);
//在此将Activity暴露给Service的接口实现注册到Service中去
try {
serviceAIDL.registActivityCallBack(activityAidl);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
//  在activity中实现ActivityAIDL接口
private ActivityAIDL activityAidl = new ActivityAIDL.Stub() {

        @Override

        public void callActivity() throws RemoteException {

                Log.i(TAG, "callActivity()");

                Toast.makeText(getApplicationContext(), "service call activity", 1000).show();

        }

   };

}

在activity中有三个按钮分别为 start service ; stop service ;callService特别注意到。在Activity ServiceConnection中 会通过ServiceAIDL.Stub.asInterface(service)得到ServiceAIDL的实例,并且将activityAidl的引用注册到了Service中。

在start service 按钮事件里,通过bindService(service, serviceConn, Context.BIND_AUTO_CREATE)将Service 与Activity绑定。

这个程序跑起来的顺序是,启动Activity后,并start service后 点击callServiceBtn,就会调用MyService中实现的callService()接口,而在callService中又调用了activityAidl即Activity的回调callActivity()方法,这样就模拟了 Activity 与Service两个进程间的通信,即相互调用了对方的对象。

---------------------------------------------------------

一.Linux系统进程间通信有哪些方式? 1.socket; 2.name pipe命名管道; 3.message queue消息队列; 4.singal信号量; 5.share memory共享内存;

二.Java系统的通信方式是什么? 1.socket; 2.name pipe;

三.Android系统通信方式是什么? Binder 通信;

四.Binder通信的优势是什么? 高效率

五.Binder通信的特点是什么? 是同步,而不是异步;

六.Binder通信是如何实现的?

1.Binder通信是通过linux的binder driver来实现的,

2.Binder通信操作类似线程迁移(thread migration),两个进程间IPC看起来就象是一个进程进入另一个进程执行代码然后带着执行的结果返回;

3.Binder的用户空间为每一个进程维护着一个可用的线程池,线程池用于处理到来的IPC以及执行进程本地消息,Binder通信是同步而不是异步。

七. Android中的 Binder通信实现要点:

1. Android中的Binder通信是基于Service与Client的工作模型的;

2. 所有需要IBinder通信的进程都必须创建一个IBinder接口;

3. 系统中有一个进程管理所有的system service:

4. Android不允许用户添加非授权的System service;

5. 现在源码开放了,我们可以修改一些代码来实现添加底层system Service的目的;

6. 对用户程序来说,我们也要创建server,或者Service用于进程间通信;

7. ActivityManagerService管理JAVA应用层所有的service创建与连接(connect),disconnect;

8. 所有的Activity也是通过这个service来启动,加载的;

9. ActivityManagerService也是加载在Systems Servcie中的;

八.Android的 Service工作流程

1.Android虚拟机启动之前系统会先启动service Manager进程;

2.service Manager打开binder驱动,并通知binder kernel驱动程序这个进程将作为System Service Manager;

3.然后该进程将进入一个循环,等待处理来自其他进程的数据。

4.用户创建一个System service后,通过defaultServiceManager得到一个远程ServiceManager的接口,通过这个接口我们可以调用addService函数将System service添加到Service Manager进程中;

5.然后client可以通过getService获取到需要连接的目的Service的IBinder对象,这个IBinder是Service的BBinder在binder kernel的一个参考,

6.所以service IBinder 在binder kernel中不会存在相同的两个IBinder对象,每一个Client进程同样需要打开Binder驱动程序。对用户程序而言,我们获得这个对象就可以通过binder kernel访问service对象中的方法。

7.Client与Service在不同的进程中,通过这种方式实现了类似线程间的迁移的通信方式,对用户程序而言当调用Service返回的IBinder接口后,访问Service中的方法就如同调用自己的函数。
1. binder的结构

  binder是解决ipc和rpc的工具。android使用的是linux os,支持多进程和多线程。同时,对于java app,一个vm占用一个进程。做为完善的开发框架,android必须支持ipc。binder就是解决ipc问题的途径,更进一步,binde还支持rpc。

  进程有自己的地址空间,不同进程间的通信并不能直接引用地址。一般的解决途径是,发送进程把需要传送的数据按照一定格式(marshall)转换成二进制形式/特定格式的数据,发往接收进程;接收进程收到二进制形式、特定格式的数据后,反转换(unmarshall)成原文数据,然后使用。binder使用的就是这种步骤。

  binder使用的是同步c/s模型,s循环阻塞在接收数据操作上,随时处理c的数据,处理后发送回c;c则将请求服务的数据发送到s,阻塞在收取s返回数据,收到数据后,继续自己的工作。

  binder的框架可以分成3层,如图<binder arch>。

  最下层是linux os和binder driver。binder driver本质上是进程间的共享内存,各进程将要发送到其它进程的数据写入到driver,从driver读取其它进程发送来的数据。

  中间层是cpp实现的framework,完成数据的接收发送转换,和c/s流程的支持。

  其实到中间层,binder的架构就已经完全具备了。但android使用的是java做为一般app的开发语言。所以还需要jni和相应java binder类的支持,这就是中间层上面的第三层:jni/java

  假设c,s都是java实现,app ipc一般的情景是这样的, app client 收集ipc的数据,穿过jni,加工下传,经framework,写入driver。数据经driver上传,反加工经framework,穿过jni,上传到app server。

  对于rpc的支持,需要一点点技巧,直接传递函数指针是无法使用的。为了是叙述的方便,先澄清一对概念:本地local和远端remote。定义rpc函数的进程称作本地,调用rpc函数的进程称作远端。rpc的实现实际上是远端定义一个rpc的proxy,远端将proxy想做rpc在本地的实现,貌似本地函数操作一般使用。而这个proxy实际上仅仅是将自己登记在本地的handle和入口参数发送本地,本地根据handle,知晓是哪个远端进程的proxy,调用函数,给定入口参数,执行完毕后,将出口参数再返回远端的proxy(因为我们有handle了)。binder的实现中handle和本地函数的对应关系是保存在driver中管理的。
2. binder driver

  binder driver是binder机制的基础,是实现ipc的通道。

  binder driver与framework和app的功能操作是用ioctl方式实现的。最基本的操作是数据读写操作。一次读写操作有两个子操作组成:写子操作和读子操作。driver为每个进程和线程维护了一个数据结构,其中有一个list,挂接了其它进程写入的数据,还有一个信号量。写子操作负责将数据挂接到接收进程对应数据结构的list上。读子操作负责处理自己进程中list上的数据,传回framework和app。

  binder driver的第二个功能是为了支持rpc,就是维护本地函数和远端proxy的handle之间的对应关系。更复杂的是维护两个远端Proxy的handle之间的对应关系,这两个proxy是同一rpc的proxy。
3. binder framework

  binder的framework是cpp实现的,这里分成本地local/s和远端remote/c两半来描述。

  公共类IBinder派生出两个子类,BBinder用于local,BpBinder用于remote。

  本地实现的类以BBinder为基类派生,接收数据后,处理,并将结构发会远端。

  远端proxy的类使用BpBinder,接收和发送数据到本地。

  进一步方便开发,引入了IInterface类,开发者从Interface派生子类,定义自己需要的rpc操作。

  在IInterface的装饰下,从BBinder派生出了本地的关键类 BnInterface<INTERFACE>;从BpRefBase派生出了包含成员BpBinder对象的远端关键类BpInterface<INTERFACE>。
4. binder jni,java类和aidl工具

  binder framework的机制要被java使用,需要经过包装。除了jni相关部分,android在java中还定义了几个相关的接口和类,IBinder,Binder,BinderProxy,IInterface,BinderInternal。

  aidl工具则是方便java实现c/s结构的一个工具,开发者编写简单的接口描述idl文件,则aidl自动生成local和remote的Binder类。让开发者关注在实际的功能开发上,不必为binder机制耗费无谓的精力。
5. parcel是什么

  为了便于ipc之间传递的数据的操作,binder引入了parcel的概念。parcel可以想成快递公司的包装箱,需要传递的各种类型的数据都被打包进parcel类,binder负责传递parcel对象,接收端则从parcel解出数据。这样的机制即减少了各种数据类型对传递的复杂性,又可以通过增加打包/解包parcel的数据类型,轻易实现扩展。

  parcel已经支持容纳基本数据类型和一些复合数据类型。

  在framework层面,parcel提供了Flattenable基类,可以扩展parcel容纳的数据类型。

  在java parcel层面,parcel提供了Parcelable接口,可以扩展parcel容纳的数据类型。

6. 依赖于binder的service

  ipc/rpc已经被binder机制解决掉了,那么service面临的唯一问题就是service如何让想使用service的client招到service。解决的方案就是 service manager。service manager是一个特殊进程,每个service都会注册登记到service manager中,而client可以从service manager查询得到自己需要使用的service
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: