一文分析Binder机制和AIDL的理解

作者: 愿天堂没Android | 来源:发表于2022-03-04 16:35 被阅读0次

    为什么要去理解Android的进程间通信机制

    对于Android开发工程师来说,如果不去理解进程间通信机制也可以使用系统提供的API完成应用开发,但如果想要达到更高的层级,那么就不能简单只会调用API。无论是工作中遇到一些疑难问题,还是想要学习源码的一些功能实现,或者是想要提升APP的性能等,这些工作都需要我们去看系统的源码,而系统的源码中进程间通信无处不在,如果不理解进程间通信机制,那么很难看懂系统源码,而且容易迷失在大量的代码中。

    Android 进程间通信机制

    为什么使用Binder作为Android进程间通信机制

    主要是为了弥补Linux中其他进程间通信方式得性能和安全性不足。当然Binder机制也并非是谷歌为了Android原创技术,Binder机制源于OpenBinder,OpenBinder要早于Android系统出现。所以如果想要立即Android得进程间通信,主要就是理解Binder机制。

    Binder进程间通信基本框架

    img

    在Android中,2个应用或者进程之间的通信都需要经过Binder代理,二者不能直接通信,同样APP在使用系统服务时也需要跨进程通信,比如我们最常用的ActivityManagerService(AMS)也是一个系统服务进程,此外APP使用WIFI 、定位、媒体服务等都是系统进程,APP想要使用这些系统服务的功能一定要通过Binder进行通信。

    Binder到底是什么

    我们一直在说利用Binder机制进行进程间通信,那么Binder具体是什么?是一个Java类,还是一个底层驱动?通常我们说Binder机制是Android系统不同层Binder相关代码组成的一套跨进程通信功能。Binder机制相关代码从最底层的驱动层到最顶层的应用层都有,所以要读懂Binder机制,就需要我们耐心的逐层进行分析。

    img

    Binder机制代码结构

    如何理解AIDL

    我们从上图没有看到任何AIDL相关的信息,也就是说Binder机制是与AIDL无关的,那么我们日常中如果要跨进程都要写一个AIDL类然后由AS生成一些Java类,我们使用这些类实现进程间通信,这么做的目的其实是由AS帮我们生成一些模板代码,减少我们的工作和出错概率,其实不用AIDL我们也可以实现Binder通信,并且可以更好的理解Binder机制。下面我写一个Demo进程,这个Demo中有AIDL文件并生成相关代码,但我们不用,只是用来作为对比,我们用最少的代码实现Binder通信,并通过对比我们写的代码和AIDL生成的代码来更好的理解AIDL生成的代码的作用。代码Github

    不使用ADIL,手动实现进程间通信

    img

    项目结构

    代码中client为客户端,server为服务端

    img img

    客户端进程发送一个字符串给服务端,服务端进程接收到将字符显示到界面上。项目中没有用到AIDL为我们生成Binder通信类,而是用最简单的方式实现Binder通信,因而我们可以看清Binder通信最关键的地方。首先我们要知道,实现了IBinder接口的类的对象是可以跨进程传递的。

    服务端

    1.服务端RemoteService继承Service 2.创建一个继承Binder的类ServerBinder,并覆写onTransact方法,用于处理Client的调用,Binder实现了IBinder接口 3.服务端覆写Service的onBind方法,返回一个ServerBinder对象(这个ServerBinder对象是最终传递给Client端)

    public class RemoteService extends Service {
        public static final int TRANSAVTION_showMessage = IBinder.FIRST_CALL_TRANSACTION;
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return new ServerBinder();
        }
    
        static class ServerBinder extends Binder   {
            public ServerBinder() {
            }
    
            @Override
            protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
    
                switch (code) {
                    case TRANSAVTION_showMessage:
                        String message = data.readString();
                        Log.d("ServerBinder", "showMessage " + message);
                        if (ServerMainActivity.tvShowMessage != null) {//显示收到数据逻辑
                            new Handler(Looper.getMainLooper()).post(new Runnable() {
                                @Override
                                public void run() {
                                    ServerMainActivity.tvShowMessage.setText(message);
                                }
                            });
                        }
                        if (reply != null) {
                            reply.writeNoException();
                        }
                        return true;
                }
                return super.onTransact(code, data, reply, flags);
            }
    
    
        }
    }
    

    客户端

    1.客户端创建一个ServiceConnection对象,用于与服务端建立连接,并获取到服务端的IBinder对象 2.客户端通过bindService与服务端的RemoteService建立连接

    public class ClientMainActivity extends AppCompatActivity {
        private Button mSendString;
        private EditText mStingEditText;
        public static final int TRANSAVTION_showMessage = IBinder.FIRST_CALL_TRANSACTION;
        private IBinder mServer;//服务端的Binder对象
        private boolean isConnection = false;
    
        private ServiceConnection serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                
                isConnection = true;
                mServer = service;//建立连接成功,保存服务端进程的IBinder对象
                Log.d("Client"," onServiceConnected success");
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                isConnection = false;
            }
        };
    
        //与服务端进程中RemoteService建立连接
        private void attemptToBindService() {
            Intent intent = new Intent();
            intent.setClassName("com.binder.server", "com.binder.server.RemoteService");
            bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
        }
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mSendString = findViewById(R.id.btn_send_string);
            mStingEditText = findViewById(R.id.et_string);
            mSendString.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (!isConnection) {
                        attemptToBindService();
                        return;
                    }
                    //发送数据给服务端进程
                    Parcel data = Parcel.obtain();
                    Parcel replay = Parcel.obtain();
                    if (mServer != null) {
                        try {
                            data.writeString(mStingEditText.getText().toString());
                            Log.d("Client"," mServer.transact call");
                          //发送数据到服务端进程
                            mServer.transact(TRANSAVTION_showMessage, data, replay, 0);
                            replay.readException();
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        } finally {
                            replay.recycle();
                            data.recycle();
                        }
                    }
    
    
                }
            });
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            if (!isConnection) {
                attemptToBindService();
            }
        }
    

    从上面的代码来看Binder的跨进程通信核心就是客户端获取到服务端的IBinder对象,然后调用这个对象的transact方法发送数据,实现进程间通信。

    使用ADIL生成相关类,进行进程间通信

    img

    加入AIDL文件

    interface IShowMessageAidlInterface {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
       void showMessage(String msg);
    }
    

    修改Client端代码

    public class ClientMainActivityUseAidl extends AppCompatActivity {
        private Button mSendString;
        private EditText mStingEditText;
        private IShowMessageAidlInterface mServer;//服务端的Binder对象代理
        private boolean isConnection = false;
    
        private ServiceConnection serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                isConnection = true;
                //调用IShowMessageAidlInterface.Stub.asInterface静态方法,将service转换为一接口
                mServer = IShowMessageAidlInterface.Stub.asInterface(service);
                Log.d("Client"," onServiceConnected success");
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                isConnection = false;
            }
        };
        private void attemptToBindService() {
            Intent intent = new Intent();
            intent.setClassName("com.binder.server", "com.binder.server.RemoteServiceUseAidl");
            bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
        }
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mSendString = findViewById(R.id.btn_send_string);
            mStingEditText = findViewById(R.id.et_string);
            mSendString.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (!isConnection) {
                        attemptToBindService();
                        return;
                    }
                    try {
                      //直接调用接口的showMessage方法
                        mServer.showMessage(mStingEditText.getText().toString());
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            if (!isConnection) {
                attemptToBindService();
            }
        }
    

    1.客户端利用 IShowMessageAidlInterface生成类中的Stub内部类将接受到的IBinder对象转换为一个接口 2.在发送数据时,直接调用IShowMessageAidlInterface接口的showMessage方法

    asInterface方法

       public static com.binder.server.IShowMessageAidlInterface asInterface(android.os.IBinder obj)
       {
         if ((obj==null)) {
           return null;
         }
       //查询obj对象是否是本地接口,也就是是不是在同一个进程
         android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
         if (((iin!=null)&&(iin instanceof com.binder.server.IShowMessageAidlInterface))) {
           如果是同一个进程直接返回
           return ((com.binder.server.IShowMessageAidlInterface)iin);
         }
     //如果是不同进程,则将IBinder对象利用Proxy封装一层
         return new com.binder.server.IShowMessageAidlInterface.Stub.Proxy(obj);
       }
    

    Proxy类

     private static class Proxy implements com.binder.server.IShowMessageAidlInterface
        {
          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;
          }
          /**
               * Demonstrates some basic types that you can use as parameters
               * and return values in AIDL.
               */
          //代理对象做的工作是把AIDL接口中定义的方法中的数据进行封装,方便进行跨进程传输
          @Override public void showMessage(java.lang.String msg) throws android.os.RemoteException
          {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            try {
              _data.writeInterfaceToken(DESCRIPTOR);
              _data.writeString(msg);
              boolean _status = mRemote.transact(Stub.TRANSACTION_showMessage, _data, _reply, 0);
              if (!_status && getDefaultImpl() != null) {
                getDefaultImpl().showMessage(msg);
                return;
              }
              _reply.readException();
            }
            finally {
              _reply.recycle();
              _data.recycle();
            }
          }
          public static com.binder.server.IShowMessageAidlInterface sDefaultImpl;
        }
    

    所以我们可以知道,客户端用到了AIDL文件生成Stub类中的asInterface方法,把接收到的远程IBinder转换为IShowMessageAidlInterface接口,而这个接口的具体实现其实是Proxy类,代理类对方法传入数据进行封装,然后发送给mRemote 服务端。

    修改服务端代码

    public class RemoteServiceUseAidl extends Service {
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return new IShowMessageAidlInterface.Stub() {
                @Override
                public void showMessage(String msg) throws RemoteException {
                    if (ServerMainActivity.tvShowMessage != null) {
                        new Handler(Looper.getMainLooper()).post(new Runnable() {
                            @Override
                            public void run() {
                                ServerMainActivity.tvShowMessage.setText(msg);
                            }
                        });
                    }
                }
            };
        }
    }
    
    
    

    服务端的 onBind方法返回AIDL生成的Stub类的对象,Stub是个抽象类,其中待实现的方法为AIDL中定义的showMessage方法。

     public static abstract class Stub extends android.os.Binder implements com.binder.server.IShowMessageAidlInterface
      {
        private static final java.lang.String DESCRIPTOR = "com.binder.server.IShowMessageAidlInterface";
        static final int TRANSACTION_showMessage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        /** Construct the stub at attach it to the interface. */
        public Stub()
        {
          this.attachInterface(this, DESCRIPTOR);
        }
        @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_showMessage:
            {
              data.enforceInterface(descriptor);
              java.lang.String _arg0;
              _arg0 = data.readString();
              this.showMessage(_arg0);
              reply.writeNoException();
              return true;
            }
            default:
            {
              return super.onTransact(code, data, reply, flags);
            }
          }
        }
       
      }
    
    
    

    可以看到Sub抽象类中继承自Binder,也就是客端最终拿到的是这个Stub IBinder对象,客户端调用tansact方法最终会调用到Stub类的onTransact进行处理,Stub的onTransact方法根据code确定客端户调用了哪个方法,然后对接收到的data数据进行读取解析,将处理好的数据交给IShowMessageAidlInterface中对应的方法。

    总结: 1.AIDL生成的类中Stub的静态方法asInterface和Proxy类是给客户端用于发送数据的 2.Stub抽象类是由服务端实现,接收处理客户端数据的

    相关文章

      网友评论

        本文标题:一文分析Binder机制和AIDL的理解

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