AndroidAndroid开发

Android进程间通信(一)——Binder机制和AIDL的理

2021-07-02  本文已影响0人  Boahui

Android 进程间通信

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

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

Android 进程间通信机制

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

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

Binder进程间通信基本框架

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

Binder到底是什么

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


Binder机制代码结构

如何理解AIDL

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

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

项目结构

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



客户端进程发送一个字符串给服务端,服务端进程接收到将字符显示到界面上。项目中没有用到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生成相关类,进行进程间通信

加入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抽象类是由服务端实现,接收处理客户端数据的

上一篇下一篇

猜你喜欢

热点阅读