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
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。