Binder进程间通信机制

一、Binder是什么

Binder是android中用于进程间通信IPC的重要机制。

Binder架构包括服务器接口、Binder驱动、客户端接口三个模块。

image
  • Binder服务端:一个Binder服务端实际上就是Binder类的对象。该对象一旦创建,内部则会启动一个隐藏线程,会接收Binder驱动发送的消息,收到消息后,会执行Binder对象中的onTransact()函数,并按照该函数的参数执行不同的服务器端代码。
    onTransact函数的参数是客户端调用transact函数的输入。
  • Binder驱动:任意一个服务端Binder对象被创建时,同时会在Binder驱动中创建一个mRemote对象,该对象也是一个实现了IBinder接口。客户端访问远程服务端都是通过该mRemote对象。
  • 客户端:获取远程服务在Binder驱动中对应的mRemote引用,然后调用它的transact方法即可向服务端发送消息。

注意:
服务端产生Binder对象有两种方式:
方式一:

Xxx extend Binder
重载onTransact()方法

方式二:

Xxx extend IXXX.Stub
重载onTransact()方法

IXXX.Stub extend Binder implement IXXX

客户端利用mRemote 调用服务端程序,有两种方式:

方式一:直接利用mRemote调用transact()方法,兵传递对应的code,data,replay
mRemote.transact()
方式二:
IXXX ixxx = IXXX.Stub.asInterface(mRemote);//得到IXXX.Proxy对象
IXXX 调用定义的接口方法

二、直接调用mRemote进行进程间通信

服务端代码:

public class ComputeService extends Service {
    
    private IBinder binder = new Binder(){
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            if (code == 1) {
                String _arg0;
                _arg0 = data.readString();
                String _arg1;
                _arg1 = data.readString();
                String _result = this.strcat(_arg0, _arg1);
                reply.writeString(_result);
                return true;
            }
            return super.onTransact(code, data, reply, flags);
        };
        
        public String strcat(String x, String y){
            return x + y;
        }
    };
    
    @Override
    public IBinder onBind(Intent arg0) {
        return binder;
    }
}

将该service配置在一个新的进程中



客户端程序:

public class MainActivity extends Activity {
    private boolean isBound;
    private Button btn_add;
    private IBinder mRemote = null;
    private ServiceConnection serviceConn = new ServiceConnection() {  
        @Override  
        public void onServiceConnected(ComponentName name, IBinder service) {
            mRemote = service;
        }
        @Override  
        public void onServiceDisconnected(ComponentName name) {
        }
    };
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bind();
        btn_add = (Button)findViewById(R.id.btn_add);
        btn_add.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                String result = null;
                try {
                    result = strcat("abc", "def");
                } catch (RemoteException e) {
                    Toast.makeText(MainActivity.this, "error", 0).show();
                    e.printStackTrace();
                }
                Toast.makeText(MainActivity.this, result, 0).show();
            }
        });
    }
    
    private void bind() {
        Intent intent = new Intent(MainActivity.this, ComputeService.class);  
        isBound = bindService(intent, serviceConn, Context.BIND_AUTO_CREATE);
    }
    
    private void unbind() {
        if (isBound) {
            MainActivity.this.unbindService(serviceConn);
            isBound = false;
        }
    }
    
    private String strcat(String x, String y) throws RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        String _result;
        try {
            _data.writeString(x);
            _data.writeString(y);
            mRemote.transact(1, _data, _reply, 0);
            _result = _reply.readString();
        } finally {
            _reply.recycle();
            _data.recycle();
        }
        return _result;
    }
 
    @Override
    protected void onDestroy() {
        unbind();
        super.onDestroy();
    }
}

三、利用AIDL 操作IBider,进程间通信。

使用Binder进行IPC通信的时候代码比较繁琐,尤其是客户端给服务端发送消息的打包过程中要保证顺序的一致性。android也给我们提供了一个比较好的方式,那就是使用android提供的aidl工具。
AIDL(Android Interface Definition Language),编译器通过*.aidl文件的描述信息生成符合通信协议的Java代码,我们不需要自己写这些繁杂的代码,使用非常方便。

1.示例代码:


package org.qhyuan.aidl;
interface ICompute {
    String strcat (String x,String y);

服务端代码变成了:


public class ComputeService extends Service {
    
    private IBinder binder = new ICompute.Stub() {
        @Override
        public String strcat(String x, String y) throws RemoteException {
            return x+y;
        }
    };
    
    @Override
    public IBinder onBind(Intent arg0) {
        return binder;
    }


客户端的代码:


public class MainActivity extends Activity {
    private ICompute compute = null;
    private boolean isBound;
    private Button btn_add;
    private ServiceConnection serviceConn = new ServiceConnection() {  
        @Override  
        public void onServiceConnected(ComponentName name, IBinder service) {
            compute = ICompute.Stub.asInterface(service);
        }
        @Override  
        public void onServiceDisconnected(ComponentName name) {
        }
    };
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bind();
        btn_add = (Button)findViewById(R.id.btn_add);
        btn_add.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                String result = null;
                try {
                    result = compute.strcat("abc", "def");
                } catch (RemoteException e) {
                    Toast.makeText(MainActivity.this, "error", 0).show();
                    e.printStackTrace();
                }
                Toast.makeText(MainActivity.this, result, 0).show();
            }
        });
    }
    
    private void bind() {
        Intent intent = new Intent(MainActivity.this, ComputeService.class);  
        isBound = bindService(intent, serviceConn, Context.BIND_AUTO_CREATE);
    }
    
    private void unbind() {
        if (isBound) {
            MainActivity.this.unbindService(serviceConn);
            isBound = false;
        }
    }
 
    @Override
    protected void onDestroy() {
        unbind();
        super.onDestroy();
    }
}

2. 我们来分析AIDL到底做了什么

AIDL 生成的代码如下:


package org.qhyuan.aidl;
 
public interface ICompute extends android.os.IInterface {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements
            org.qhyuan.aidl.ICompute {
        private static final java.lang.String DESCRIPTOR = "org.qhyuan.aidl.ICompute";
 
        /** Construct the stub at attach it to the interface. */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }
 
        /**
         * Cast an IBinder object into an org.qhyuan.aidl.ICompute interface,
         * generating a proxy if needed.
         */
        public static org.qhyuan.aidl.ICompute asInterface(
                android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof org.qhyuan.aidl.ICompute))) {
                return ((org.qhyuan.aidl.ICompute) iin);
            }
            return new org.qhyuan.aidl.ICompute.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_strcat: {
                data.enforceInterface(DESCRIPTOR);
                java.lang.String _arg0;
                _arg0 = data.readString();
                java.lang.String _arg1;
                _arg1 = data.readString();
                java.lang.String _result = this.strcat(_arg0, _arg1);
                reply.writeNoException();
                reply.writeString(_result);
                return true;
            }
            }
            return super.onTransact(code, data, reply, flags);
        }
 
        private static class Proxy implements org.qhyuan.aidl.ICompute {
            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 java.lang.String strcat(java.lang.String x,
                    java.lang.String y) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.lang.String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(x);
                    _data.writeString(y);
                    mRemote.transact(Stub.TRANSACTION_strcat, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
 
        static final int TRANSACTION_strcat = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }
 
    public java.lang.String strcat(java.lang.String x, java.lang.String y)
            throws android.os.RemoteException;
}

主要涉及到几个类:

interface ICompute extends IInterface
{
    strcat();
 
    static abstract class Stub extends Binder implements ICompute {
        static final int TRANSACTION_strcat;
        static final String DESCRIPTOR;
        static asInterface();
        asBinder();
        onTransact();
 
        static class Proxy implements ICompute {
            IBinder binder;
            asBinder();
            getInterfaceDescriptor();
            strcat();
        }
    }
}

2.1 ICompute 继承IInterface,自定义了方法strcat()
2.2 ICompute.Stub类
    static abstract class Stub extends Binder implements ICompute {
        static final int TRANSACTION_strcat;
        static final String DESCRIPTOR;
        static asInterface();
        asBinder();
        onTransact();
        
    }


继承自Binder类,实现了Icompute接口。
内部实现的方法:
asBinder()
strcat()
onTransact()
asInterface()方法

其中onTransact()方法中,已经实现了IPC的参数拆包、并调用strcat()实现了计算操作。

@Override
        public boolean onTransact(int code, android.os.Parcel data,
                android.os.Parcel reply, int flags)
                throws android.os.RemoteException {
            switch (code) {
            case TRANSACTION_strcat: {
                data.enforceInterface(DESCRIPTOR);
                java.lang.String _arg0;
                _arg0 = data.readString();
                java.lang.String _arg1;
                _arg1 = data.readString();
                java.lang.String _result = this.strcat(_arg0, _arg1);
                reply.writeNoException();
                reply.writeString(_result);
                return true;
            }
            }
            return super.onTransact(code, data, reply, flags);
        }
2.3、ICompute.Stub.Proxy类

内部持有了一个mRemote远程Binder,实现了ICompute接口,重载strcat()方法,重载方法中完成了参数装包,以及利用mRemote向Binder发消息的操作.(mRemoute.transact())

    private static class Proxy implements org.qhyuan.aidl.ICompute {
            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 java.lang.String strcat(java.lang.String x,
                    java.lang.String y) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.lang.String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(x);
                    _data.writeString(y);
                    mRemote.transact(Stub.TRANSACTION_strcat, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
 
        static final int TRANSACTION_strcat = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }
 
2.4、无比重要的方法ICompute.Stub.asInterface()
一个结论:
  • 如何客户端和服务端在同一个进程,则客户端获得的mRemote就是服务端的Binder,可以直接调用服务端程序,无需IPC。
  • 如果客户端和服务端不在同一个进程,则客户端获得的mRemote是BinderDriver中的Binder,需要IPC款进程通信,才能向服务端Binder发消息。
实现原理:

Binder.java


 public void attachInterface(IInterface owner, String descriptor) {
        mOwner = owner;
        mDescriptor = descriptor;
    }
    
  public IInterface queryLocalInterface(String descriptor) {
        if (mDescriptor.equals(descriptor)) {
            return mOwner;
        }
        return null;
    }
public static abstract class Stub extends android.os.Binder implements
            org.qhyuan.aidl.ICompute {
        private static final java.lang.String DESCRIPTOR = "org.qhyuan.aidl.ICompute";
 
        /** Construct the stub at attach it to the interface. */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }
        
        public static org.qhyuan.aidl.ICompute asInterface(
                android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof org.qhyuan.aidl.ICompute))) {
                return ((org.qhyuan.aidl.ICompute) iin);
            }
            return new org.qhyuan.aidl.ICompute.Stub.Proxy(obj);
        }
    }
  • 每一个服务端Binder 都有一个唯一的descriptor字符串,对应其实现的接口。

  • 如果客户端中的mRemoute中的descriptor和服务端Binder中的描述符一致,说明客户端得到的就是服务端的Binder本身,说明client和Server位于同一个个进程,可以直接利用mReoute直接调用服务端程序,无需IPC跨进程通信。

  • 如果客户端中mRemote中的descriptor与服务端Binder的descriptor不一致,则说明mRemote是BinderDriver中的Binder,不是服务端的Binder,需要通过IPC 跨进程通信。此时asInterface()方法中,将mRemte封装成ICompute.Stub.Proxy,在ICompute.Stub.Proxy内部利用mRemote实现IPC。

三、几个重要的类

1、时刻记得使用aidl工具生成那三个类:IXXX、IXXX.Stub和IXXX.Stub.Proxy。

IXXX AIDL 生成的接口

IXXX.Stub - 集成Binder类,重载了onTransact方法, 实现了IXXX接口。服务端Binder继承自该类。

IXXX.Stub.Proxy - 实现了IXXX接口,内部持有一个mRemote。实际的IPC操作在此类进行。客户端通过IXXX.Stub.asInterface(mRemote)获得Proxy类,来进行通信。

2、Android系统服务进程的对比。

Android 系统服务中大量应用了Binder机制,可以与AIDL做一下类比。

拿ServerManager举例:

ServerManager既是系统服务的管理者,同时也是一个系统服务,其基于Binder实现。

  • 与IXXX相对应的类就是IServiceManager类,封装了远程调用的几个主要函数

public interface IServiceManager extends IInterface
{
    public IBinder getService(String name) throws RemoteException;
    public IBinder checkService(String name) throws RemoteException;
    public void addService(String name, IBinder service, boolean allowIsolated)
                throws RemoteException;
    public String[] listServices() throws RemoteException;
    public void setPermissionController(IPermissionController controller)
            throws RemoteException;
    static final String descriptor = "android.os.IServiceManager";
    int GET_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
    int CHECK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
    int ADD_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
    int LIST_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
    int CHECK_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;
    int SET_PERMISSION_CONTROLLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+5;

!
  • .与IXXX.Stub对应的类就是ServiceManagerNative
public abstract class ServiceManagerNative extends Binder implements IServiceManager{
    static public IServiceManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IServiceManager in = (IServiceManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
        return new ServiceManagerProxy(obj);
    }
    
    public ServiceManagerNative() {
        attachInterface(this, descriptor);
    }
    
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags){
        try {
            switch (code) {
            case IServiceManager.GET_SERVICE_TRANSACTION: {
                data.enforceInterface(IServiceManager.descriptor);
                String name = data.readString();
                IBinder service = getService(name);
                reply.writeStrongBinder(service);
                return true;
            }
            case IServiceManager.ADD_SERVICE_TRANSACTION: {
                data.enforceInterface(IServiceManager.descriptor);
                String name = data.readString();
                IBinder service = data.readStrongBinder();
                boolean allowIsolated = data.readInt() != 0;
                addService(name, service, allowIsolated);
                return true;
            }
            // ...
        } catch (RemoteException e) {
        }
        
        return false;
    }
    public IBinder asBinder() {
        return this;
    }
}

  • 与IXXX.Stub.Proxy对应的类ServiceManagerProx
class ServiceManagerProxy implements IServiceManager {
    public ServiceManagerProxy(IBinder remote) {
        mRemote = remote;
    }
    
    public IBinder asBinder() {
        return mRemote;
    }
    
    public IBinder getService(String name) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name);
        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
        IBinder binder = reply.readStrongBinder();
        reply.recycle();
        data.recycle();
        return binder;
    }
    public void addService(String name, IBinder service, boolean allowIsolated) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name);
        data.writeStrongBinder(service);
        data.writeInt(allowIsolated ? 1 : 0);
        mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
        reply.recycle();
        data.recycle();
    }
    // ....
    private IBinder mRemote;
}

观察上面的代码,实际上和使用adil生成的代码没什么两样。仅仅是类命名不一样,将三个类分开写了而已。

四、参考文章:

https://blog.csdn.net/cauchyweierstrass/article/details/50701102

你可能感兴趣的:(Binder进程间通信机制)