美文网首页工作生活
Binder进程间通信机制

Binder进程间通信机制

作者: feifei_fly | 来源:发表于2019-07-03 11:47 被阅读0次

    一、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配置在一个新的进程中

    
    <service android:name = "org.qhyuan.binder.ComputeService"
        android:process=":remote"/>
    

    客户端程序:

    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进程间通信机制

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