进程间通讯基本原理

  • 内存划分

    图片1.png

    1.内存空间不能直接访问,但是内核空间是一整块的

    2.一般来说32位操作系统的内核空间是1GB用户空间是3GB

    3.如果需要A访问B的内村空间(用户空间)就可以通过内核空间来访问

  • Binder 是什么?

    1.Binder 与传统 IPC 对比


    图片2.png

    从图中看共享内存的性能是最好的,其次是Binder,然后是Socket

    2.传统 IPC 传输数据

    图片3.png

    这张图跟送快递是一样的我们发快递需要打个包然后在送到指定地点,进程之间也是这样的,进程A访问进程B无非就是访问它的方法或成员变量

    3.Binder 传输数据

    图片4.png

    因为用户空间和内核空间都属于虚拟内存而我们使用的时候使用的是物理内存,通过mmap内存映射机制把用户空间和内核空间都映射到同一块物理内存,s端直接从物理内存中取数据。

    4.内存共享

    图片56.png

    无须拷贝就是内核与服务端通过mmap进行了映射,而客户端也而映射到了与内核和服务端映射的同一个物理空间这样就不需要拷贝了(因为涉及到同一块物理空间就需要使用同步机制,还有可能会出现数据不同步的现象)

  • 什么时候需要用到进程间通信?

  • 为什么要多进程?

  • 进程间通信为什么要用到Binder机制?

    1.从性能上考虑Binder不是最快的,内存共享是最快的,Socket在这三者之中是最慢的

    2.从有点上考虑Binder的易用性高,内存共享的易用性差控制起来比较复杂,Socket的传输效率低开销大(一般用于靠网络的进程间通信,如说是用在本机上的也是一个低速的进程间通讯)

    3.安全性考虑Bindle为每个APP分配UID同时支持实名和匿名(如果是恶意软件的话可以轻松查出来),内存共享依和Socket赖于上层协议PID(进程的ID也是唯一标识)当我们把客户端的数据发送给服务端的时候需要打包而PID是放在包里面的然后发送给对方,PID是由进程告诉系统的不是系统通过某种机制获取的这就可能会造成PID造假行为,访问接入点是开放的谁都可以知道接入点不安全

  • 源码分析

1.客户端如何获取到AIDL的句柄的?

    private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.e(TAG, "onServiceConnected: success");
        iLsAidl = ILeoAidl.Stub.asInterface(service);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.e(TAG, "onServiceDisconnected: success");
        iLeoAidl = null;
    }
};

通过ServiceConnection 获取连接后通过onServiceConnected方法中的service参数获取到ILeoAidl.Stub.asInterface(service),获取AIDL对象的方法

AIDL代码

 interface ILsaidl {
   void addPerson(in Person person);
 List getPersonList();
}

生成的代码

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.ls.demo.myclient;

public interface ILsaidl extends android.os.IInterface {
/**
 * Default implementation for ILsaidl.
 */
public static class Default implements com.ls.demo.myclient.ILsaidl {
    @Override
    public void addPerson(com.ls.demo.myclient.Person person) throws android.os.RemoteException {
    }

    @Override
    public java.util.List getPersonList() throws android.os.RemoteException {
        return null;
    }

    @Override
    public android.os.IBinder asBinder() {
        return null;
    }
}

/**
 * Local-side IPC implementation stub class.
 */
public static abstract class Stub extends android.os.Binder implements com.ls.demo.myclient.ILsaidl {
    private static final java.lang.String DESCRIPTOR = "com.ls.demo.myclient.ILsaidl";

    /**
     * Construct the stub at attach it to the interface.
     */
    public Stub() {
        this.attachInterface(this, DESCRIPTOR);
    }

    /**
     * Cast an IBinder object into an com.ls.demo.myclient.ILsaidl interface,
     * generating a proxy if needed.
     */
    public static com.ls.demo.myclient.ILsaidl asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof com.ls.demo.myclient.ILsaidl))) {
            return ((com.ls.demo.myclient.ILsaidl) iin);
        }
        return new com.ls.demo.myclient.ILsaidl.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_addPerson: {
                data.enforceInterface(descriptor);
                com.ls.demo.myclient.Person _arg0;
                if ((0 != data.readInt())) {
                    _arg0 = com.ls.demo.myclient.Person.CREATOR.createFromParcel(data);
                } else {
                    _arg0 = null;
                }
                this.addPerson(_arg0);
                reply.writeNoException();
                return true;
            }
            case TRANSACTION_getPersonList: {
                data.enforceInterface(descriptor);
                java.util.List _result = this.getPersonList();
                reply.writeNoException();
                reply.writeTypedList(_result);
                return true;
            }
            default: {
                return super.onTransact(code, data, reply, flags);
            }
        }
    }

    private static class Proxy implements com.ls.demo.myclient.ILsaidl {
        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 addPerson(com.ls.demo.myclient.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);
                }
                boolean _status = mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
                if (!_status && getDefaultImpl() != null) {
                    getDefaultImpl().addPerson(person);
                    return;
                }
                _reply.readException();
            } finally {
                _reply.recycle();
                _data.recycle();
            }
        }

        @Override
        public java.util.List getPersonList() throws android.os.RemoteException {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            java.util.List _result;
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                boolean _status = mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
                if (!_status && getDefaultImpl() != null) {
                    return getDefaultImpl().getPersonList();
                }
                _reply.readException();
                _result = _reply.createTypedArrayList(com.ls.demo.myclient.Person.CREATOR);
            } finally {
                _reply.recycle();
                _data.recycle();
            }
            return _result;
        }

        public static com.ls.demo.myclient.ILsaidl sDefaultImpl;
    }

    static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

    public static boolean setDefaultImpl(com.ls.demo.myclient.ILsaidl impl) {
        if (Stub.Proxy.sDefaultImpl == null && impl != null) {
            Stub.Proxy.sDefaultImpl = impl;
            return true;
        }
        return false;
    }

    public static com.ls.demo.myclient.ILsaidl getDefaultImpl() {
        return Stub.Proxy.sDefaultImpl;
    }
}

public void addPerson(com.ls.demo.myclient.Person person) throws android.os.RemoteException;

public java.util.List getPersonList() throws android.os.RemoteException;
}

当我们写好AIDL后系统会为我们生成

 public void addPerson(com.ls.demo.myclient.Person person) throws android.os.RemoteException;
public java.util.List getPersonList() throws android.os.RemoteException;

从源码中可以看出Stub是一个抽象类它继承了Binder然后又实现了AIDL,因为它要实现接口的方法。
Proxy是一个实体类它也实现了AIDL接口,因为它也要实现 void addPerson(in Person person);
List getPersonList();这两个方法。

asInterface 首先它会判断服务是不是null如果是直接返回null,然后通过 android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);查询本地的接口,DESCRIPTOR是一个描述符它是全类名。
是通过

        public Stub() {
        this.attachInterface(this, DESCRIPTOR);
        }

传过去的然后保存到本地再通过queryLocalInterface去判断Stub传过来的DES是否和queryLocalInterface里面参数的DES是否相同,从表面上看是一样的但是服务端的DES先初始化而客户端的DES并不会被初始化。
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);在这里比较的原因就是当Activity和Service在同一个进程的时候就不需要使用Binder了,然后判断如果是在同一个进程就返回否则就返回Proxy然后就可以调用Proxy对象里面的方法去发送数据,这些方法就是实现AILD的方法的实现。addPerson方法里面有两个包android.os.Parcel _data和android.os.Parcel _reply,_data发送到服务器的数据_reply服务端返回的数据。

boolean _status = mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);客户端通过调用transact后就会把客户端的线程挂起来,直到服务端返回后客户端的线程才会继续运行,然后通过调用_reply.readException()读取服务端返回的数据,Stub.TRANSACTION_addPerson参数代表你要调用那个方法,通过AIDL可以知道对应的方法,0代表可以返回数据,如果是1代表不可以。

到了mRemote.transact后然后就到了Binder然后经过处理到服务端,服务端调用onTransact()方法,以上是客户端

到了服务端后在Stub里面的onTransact接收数据处理。之后通过 onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)里面的code判断你是调用的那个方法,onTransact里面的 this.addPerson(_arg0);调用的是服务里面的IBinder iBinder = new ILsAidl.Stub()里面的addPerson()。
这样的话就完成了一个客户端到服务端的一个调用

public interface ILsAidl extends android.os.IInterface {
/**
 * Local-side IPC implementation stub class.
 */
public static abstract class Stub extends android.os.Binder implements com.ls.demo.ls_service.ILsAidl {
    private static final java.lang.String DESCRIPTOR = "com.ls.demo.ls_service.ILsAidl";

    /**
     * Construct the stub at attach it to the interface.
     */
    public Stub() {
        this.attachInterface(this, DESCRIPTOR);
    }

    /**
     * Cast an IBinder object into an com.ls.demo.ls_service.ILsAidl interface,
     * generating a proxy if needed.
     */
    public static com.ls.demo.ls_service.ILsAidl asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof com.ls.demo.ls_service.ILsAidl))) {
            return ((com.ls.demo.ls_service.ILsAidl) iin);
        }
        return new com.ls.demo.ls_service.ILsAidl.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 {
        switch (code) {
            case INTERFACE_TRANSACTION: {
                reply.writeString(DESCRIPTOR);
                return true;
            }
            case TRANSACTION_addPerson: {
                data.enforceInterface(DESCRIPTOR);
                com.ls.demo.ls_service.Person _arg0;
                if ((0 != data.readInt())) {
                    _arg0 = com.ls.demo.ls_service.Person.CREATOR.createFromParcel(data);
                } else {
                    _arg0 = null;
                }
                this.addPerson(_arg0);
                reply.writeNoException();
                return true;
            }
            case TRANSACTION_getPersonList: {
                data.enforceInterface(DESCRIPTOR);
                java.util.List _result = this.getPersonList();
                reply.writeNoException();
                reply.writeTypedList(_result);
                return true;
            }
        }
        return super.onTransact(code, data, reply, flags);
    }

    private static class Proxy implements com.ls.demo.ls_service.ILsAidl {
        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 addPerson(com.ls.demo.ls_service.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_addPerson, _data, _reply, 0);
                _reply.readException();
            } finally {
                _reply.recycle();
                _data.recycle();
            }
        }

        @Override
        public java.util.List getPersonList() throws android.os.RemoteException {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            java.util.List _result;
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
                _reply.readException();
                _result = _reply.createTypedArrayList(com.ls.demo.ls_service.Person.CREATOR);
            } finally {
                _reply.recycle();
                _data.recycle();
            }
            return _result;
        }
    }

    static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}

public void addPerson(com.ls.demo.ls_service.Person person) throws android.os.RemoteException;

public java.util.List getPersonList() throws android.os.RemoteException;

}

ADIL的调用流程图

ADIL的调用流程图.png

最后返回是通过_reply.readException()返回的

AIDL的结构

AIDL的结构.png

由Stub和proxy组成

图片7.png

A APP 的Proxy将数据发送到内核里面的Binder中然后B APP的Stub接收数据

源码流程

你可能感兴趣的:(进程间通讯基本原理)