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