Binder机制和AIDL的理解
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抽象类是由服务端实现,接收处理客户端数据的
作者:传道士
链接:https://juejin.cn/post/7069013946929250311