android IPC机制

作者: Mr_dvbkhm | 来源:发表于2019-04-28 20:40 被阅读23次
    生活既是修行

    1. android 中多进程模式

    android 进程间通信的方式
    1.Intent
    2.文件共享
    3.AIDL
    4.Messenger
    5.ContentProvider
    6.RemoteViews
    7.socket

    1.1 多进程的开启方式

    android中使用多进程只有一种方法,就是给四大组件在AndroidMenifest 中指定android:processs属性,那么问题来了,我们常常会使用两种指定方式:

    android:process=":remote"
    android:process="com.android.test"

    这两种方式有何区别?

    • 1.":"的含义是要在进程名“remote”前加上包名的,加":"是一种简写
      1. ":"开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中。不以":"命名的进程属于全局进程,其他应用通过ShareUID 方式可以和它跑在同一个进程中

    android 系统会为每个应用分配一个唯一的UID,相同UID的应该可以共享数据,如果两个应用通过相同ShareUID跑在同一个进程中,还需要有相同签名才可以相互访问私有数据,比如 data目录、组件信息等,跑在同一进程中,当然可以共享内存数据。
    所有运行在不同进程中的四大组件,如果他们需要通过内存来共享数据,都会失败
    一般来说,多进程会照成如下的一些问题:

    1.静态成员和单例模式完全失效
    2.线程同步机制失效
    3.SharePreferences 的可靠性下降
    4.Application 可能多次创建

    2. IPC中一些基础概念

    2.1Seriailzable 接口

    Serializable 是Java 提供的一个序列化接口,是一个空接口,为对象提供标准的序列化和反序列化操作,
    SerialVersionUID 需指定,否则可能会导致反序列化失败

    2.2 Parcelable 接口

    Parcelable接口也是一个接口,只要实现这个接口,这个类对象就可以实现序列化并通过Intent、Binder传递

    3.下面主要分析下使用AIDL文件进行进程间通信

    1. 举一个使用aidl 进行IPC通信的例子
      MainActivity 和PersonService 分属于两个进程,我们用aidl 进行双向通信
      完成 MainActivity创建person对象传到service 中进行保存,activity主动向service
      拿所有数据,service以集合的方式返回所有数据

    我们定义的IPersonService.aidl (aidl 文件路径要和package定义的包名路劲下)

    // IPersonService.aidl
     package com.prsioner.androidaidldemo;
     
     // Declare any non-default types here with import statements
     import com.prsioner.androidaidldemo.Person;
     interface IPersonService {
             void savePersonInfo(in Person person);
             List<Person> getAllPerson();
     }
    

    Person.aidl

    // Person.aidl
    package com.prsioner.androidaidldemo;
    
    // Declare any non-default types here with import statements
    
    parcelable Person;
    

    编译后自动生成的接口类IPersonService 在build/generated/source/aidl/....

    activity 作为client 端通过bindService启动service进程,传入一个ServiceConnection 来接受服务端在
    客户端的引用 iService

    IPersonService iService;
    ServiceConnection serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.e(tag,"onServiceConnected");
                iService = IPersonService.Stub.asInterface(service);
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.e(tag,"onServiceDisconnected()");
            }
    };
    

    activity 发送数据和接受数据

    iService.savePersonInfo(person);
    
    List<Person> personList = iService.getAllPerson();
    

    service 服务端的部分代码:

    public IBinder onBind(Intent intent) {
            return iBinder;
        }
    
    
    private final IPersonService.Stub iBinder = new IPersonService.Stub(){
    
    @Override
    public void savePersonInfo(Person person) throws RemoteException {
           if(person !=null){
                    personList.add(person);
           }
           }
    
           @Override
           public List<Person> getAllPerson() throws RemoteException {
                return personList;
           }
    };
    

    我们来看aidl 完成通信的具体实现过程

    package com.prsioner.androidaidldemo;
    public interface IPersonService extends android.os.IInterface
    {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.prsioner.androidaidldemo.IPersonService
    {
    private static final java.lang.String DESCRIPTOR = "com.prsioner.androidaidldemo.IPersonService";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
    this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.prsioner.androidaidldemo.IPersonService interface,
     * generating a proxy if needed.
     */
    public static com.prsioner.androidaidldemo.IPersonService asInterface(android.os.IBinder obj)
    {
    if ((obj==null)) {
    return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin!=null)&&(iin instanceof com.prsioner.androidaidldemo.IPersonService))) {
    return ((com.prsioner.androidaidldemo.IPersonService)iin);
    }
    return new com.prsioner.androidaidldemo.IPersonService.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
    return this;
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
    java.lang.String descriptor = DESCRIPTOR;
    switch (code)
    {
    case INTERFACE_TRANSACTION:
    {
    reply.writeString(descriptor);
    return true;
    }
    case TRANSACTION_savePersonInfo:
    {
    data.enforceInterface(descriptor);
    com.prsioner.androidaidldemo.Person _arg0;
    if ((0!=data.readInt())) {
    _arg0 = com.prsioner.androidaidldemo.Person.CREATOR.createFromParcel(data);
    }
    else {
    _arg0 = null;
    }
    this.savePersonInfo(_arg0);
    reply.writeNoException();
    return true;
    }
    case TRANSACTION_getAllPerson:
    {
    data.enforceInterface(descriptor);
    java.util.List<com.prsioner.androidaidldemo.Person> _result = this.getAllPerson();
    reply.writeNoException();
    reply.writeTypedList(_result);
    return true;
    }
    default:
    {
    return super.onTransact(code, data, reply, flags);
    }
    }
    }
    private static class Proxy implements com.prsioner.androidaidldemo.IPersonService
    {
    private android.os.IBinder mRemote;
    Proxy(android.os.IBinder remote)
    {
    mRemote = remote;
    }
    @Override public android.os.IBinder asBinder()
    {
    return mRemote;
    }
    public java.lang.String getInterfaceDescriptor()
    {
    return DESCRIPTOR;
    }
    @Override public void savePersonInfo(com.prsioner.androidaidldemo.Person person) throws android.os.RemoteException
    {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
    _data.writeInterfaceToken(DESCRIPTOR);
    if ((person!=null)) {
    _data.writeInt(1);
    person.writeToParcel(_data, 0);
    }
    else {
    _data.writeInt(0);
    }
    mRemote.transact(Stub.TRANSACTION_savePersonInfo, _data, _reply, 0);
    _reply.readException();
    }
    finally {
    _reply.recycle();
    _data.recycle();
    }
    }
    @Override public java.util.List<com.prsioner.androidaidldemo.Person> getAllPerson() throws android.os.RemoteException
    {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    java.util.List<com.prsioner.androidaidldemo.Person> _result;
    try {
    _data.writeInterfaceToken(DESCRIPTOR);
    mRemote.transact(Stub.TRANSACTION_getAllPerson, _data, _reply, 0);
    _reply.readException();
    _result = _reply.createTypedArrayList(com.prsioner.androidaidldemo.Person.CREATOR);
    }
    finally {
    _reply.recycle();
    _data.recycle();
    }
    return _result;
    }
    }
    static final int TRANSACTION_savePersonInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_getAllPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }
    public void savePersonInfo(com.prsioner.androidaidldemo.Person person) throws android.os.RemoteException;
    public java.util.List<com.prsioner.androidaidldemo.Person> getAllPerson() throws android.os.RemoteException;
    }
    

    IInterface接口: 所有用Binder传输数据的接口都必须继承这个接口

    Stub: 继承自Binder 实现我们定义的aidl类接口IPersonService,其实就是作为服务端的一个binder对象
    Stub 中有一个DESCRIPTOR,它是Binder的唯一标识,其中两个int常量是用来标识我们在接口中定义的方法的

    asInterface()方法 用于将服务端的Binder对象转换为客户端所需要的接口对象,该过程区分进程,如果进程一样,
    就返回服务端Stub对象本身,否则呢就返回封装后的Stub.Proxy对象(服务端在客户度的代理对象)

    onTransact() 方法 是运行在服务端的Binder线程中的,当客户端发起远程请求后,在底层封装后会交由此方法来处理。
    通过code来区分客户端请求的方法

    Proxy代理对象类我们主要看一下我们定义的方法savePersonInfo()和getAllPerson()就可以了,这两个方法都是运行在客户端,
    当客户端发起远程请求时,_data会写入参数,然后调用transact方法发起RPC(远程过程调用)请求,同时挂起当前线程,
    然后服务端的onTransact方法就会被调起,直到RPC过程返回后,当前线程继续执行,并从_reply取出返回值(如果有的话),并返回结果

    最后附上示例代码地址:https://github.com/prsioner/androidAIDLDemo

    相关文章

      网友评论

        本文标题:android IPC机制

        本文链接:https://www.haomeiwen.com/subject/xwhigqtx.html