Binder 是双向的:客户端能调服务端,服务端也能调客户端。修改之前的demo测试下。
新建一个ICallback的aidl文件:
修改 IMyAidlInterface.aidl,加上注册callback和解注册callback的接口:
构建,让 AIDL 重新生成。
生成的IMyAidlInterface.java如下:
/* * This file is auto-generated. DO NOT MODIFY. * Using: C:\\Users\\86186\\AppData\\Local\\Android\\Sdk\\build-tools\\36.0.0\\aidl.exe -pC:\\Users\\86186\\AppData\\Local\\Android\\Sdk\\platforms\\android-36\\framework.aidl -oE:\\android\\projects\\binderdemo\\app\\build\\generated\\aidl_source_output_dir\\debug\\out -IE:\\android\\projects\\binderdemo\\app\\src\\main\\aidl -IE:\\android\\projects\\binderdemo\\app\\src\\debug\\aidl -IC:\\Users\\86186\\.gradle\\caches\\9.1.0\\transforms\\126ef151667daa32756d4a8a1016b441\\workspace\\transformed\\core-1.18.0\\aidl -IC:\\Users\\86186\\.gradle\\caches\\9.1.0\\transforms\\b4877cb6e78f8cd2f0c4778997dbc841\\workspace\\transformed\\versionedparcelable-1.1.1\\aidl -dC:\\Users\\86186\\AppData\\Local\\Temp\\aidl13839983640013265463.d E:\\android\\projects\\binderdemo\\app\\src\\main\\aidl\\com\\example\\binderdemo\\IMyAidlInterface.aidl * * DO NOT CHECK THIS FILE INTO A CODE TREE (e.g. git, etc..). * ALWAYS GENERATE THIS FILE FROM UPDATED AIDL COMPILER * AS A BUILD INTERMEDIATE ONLY. THIS IS NOT SOURCE CODE. */ package com.example.binderdemo; public interface IMyAidlInterface extends android.os.IInterface { /** Default implementation for IMyAidlInterface. */ public static class Default implements com.example.binderdemo.IMyAidlInterface { @Override public int add(int a, int b) throws android.os.RemoteException { return 0; } @Override public java.lang.String getMessage() throws android.os.RemoteException { return null; } @Override public void registerCallback(com.example.binderdemo.ICallback cb) throws android.os.RemoteException { } @Override public void unregisterCallback(com.example.binderdemo.ICallback cb) throws android.os.RemoteException { } @Override public android.os.IBinder asBinder() { return null; } } /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.example.binderdemo.IMyAidlInterface { /** Construct the stub and attach it to the interface. */ @SuppressWarnings("this-escape") public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.binderdemo.IMyAidlInterface interface, * generating a proxy if needed. */ public static com.example.binderdemo.IMyAidlInterface asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.example.binderdemo.IMyAidlInterface))) { return ((com.example.binderdemo.IMyAidlInterface)iin); } return new com.example.binderdemo.IMyAidlInterface.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 { java.lang.String descriptor = DESCRIPTOR; if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) { data.enforceInterface(descriptor); } if (code == INTERFACE_TRANSACTION) { reply.writeString(descriptor); return true; } switch (code) { case TRANSACTION_add: { int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.add(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); break; } case TRANSACTION_getMessage: { java.lang.String _result = this.getMessage(); reply.writeNoException(); reply.writeString(_result); break; } case TRANSACTION_registerCallback: { com.example.binderdemo.ICallback _arg0; _arg0 = com.example.binderdemo.ICallback.Stub.asInterface(data.readStrongBinder()); this.registerCallback(_arg0); reply.writeNoException(); break; } case TRANSACTION_unregisterCallback: { com.example.binderdemo.ICallback _arg0; _arg0 = com.example.binderdemo.ICallback.Stub.asInterface(data.readStrongBinder()); this.unregisterCallback(_arg0); reply.writeNoException(); break; } default: { return super.onTransact(code, data, reply, flags); } } return true; } private static class Proxy implements com.example.binderdemo.IMyAidlInterface { 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 int add(int a, int b) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(a); _data.writeInt(b); boolean _status = mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public java.lang.String getMessage() 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); boolean _status = mRemote.transact(Stub.TRANSACTION_getMessage, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void registerCallback(com.example.binderdemo.ICallback cb) 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.writeStrongInterface(cb); boolean _status = mRemote.transact(Stub.TRANSACTION_registerCallback, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public void unregisterCallback(com.example.binderdemo.ICallback cb) 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.writeStrongInterface(cb); boolean _status = mRemote.transact(Stub.TRANSACTION_unregisterCallback, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_getMessage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_registerCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); static final int TRANSACTION_unregisterCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); } /** @hide */ public static final java.lang.String DESCRIPTOR = "com.example.binderdemo.IMyAidlInterface"; public int add(int a, int b) throws android.os.RemoteException; public java.lang.String getMessage() throws android.os.RemoteException; public void registerCallback(com.example.binderdemo.ICallback cb) throws android.os.RemoteException; public void unregisterCallback(com.example.binderdemo.ICallback cb) throws android.os.RemoteException; }生成的ICallback.java如下:
/* * This file is auto-generated. DO NOT MODIFY. * Using: C:\\Users\\86186\\AppData\\Local\\Android\\Sdk\\build-tools\\36.0.0\\aidl.exe -pC:\\Users\\86186\\AppData\\Local\\Android\\Sdk\\platforms\\android-36\\framework.aidl -oE:\\android\\projects\\binderdemo\\app\\build\\generated\\aidl_source_output_dir\\debug\\out -IE:\\android\\projects\\binderdemo\\app\\src\\main\\aidl -IE:\\android\\projects\\binderdemo\\app\\src\\debug\\aidl -IC:\\Users\\86186\\.gradle\\caches\\9.1.0\\transforms\\126ef151667daa32756d4a8a1016b441\\workspace\\transformed\\core-1.18.0\\aidl -IC:\\Users\\86186\\.gradle\\caches\\9.1.0\\transforms\\b4877cb6e78f8cd2f0c4778997dbc841\\workspace\\transformed\\versionedparcelable-1.1.1\\aidl -dC:\\Users\\86186\\AppData\\Local\\Temp\\aidl2301886493502012606.d E:\\android\\projects\\binderdemo\\app\\src\\main\\aidl\\com\\example\\binderdemo\\ICallback.aidl * * DO NOT CHECK THIS FILE INTO A CODE TREE (e.g. git, etc..). * ALWAYS GENERATE THIS FILE FROM UPDATED AIDL COMPILER * AS A BUILD INTERMEDIATE ONLY. THIS IS NOT SOURCE CODE. */ package com.example.binderdemo; // 注意 oneway 关键字。回调通常是“通知”,不需要客户端返回结果,所以用 oneway 避免服务端 Binder 线程阻塞等客户端。 public interface ICallback extends android.os.IInterface { /** Default implementation for ICallback. */ public static class Default implements com.example.binderdemo.ICallback { @Override public void onResult(int result) throws android.os.RemoteException { } @Override public android.os.IBinder asBinder() { return null; } } /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.example.binderdemo.ICallback { /** Construct the stub and attach it to the interface. */ @SuppressWarnings("this-escape") public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.binderdemo.ICallback interface, * generating a proxy if needed. */ public static com.example.binderdemo.ICallback asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.example.binderdemo.ICallback))) { return ((com.example.binderdemo.ICallback)iin); } return new com.example.binderdemo.ICallback.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 { java.lang.String descriptor = DESCRIPTOR; if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) { data.enforceInterface(descriptor); } if (code == INTERFACE_TRANSACTION) { reply.writeString(descriptor); return true; } switch (code) { case TRANSACTION_onResult: { int _arg0; _arg0 = data.readInt(); this.onResult(_arg0); break; } default: { return super.onTransact(code, data, reply, flags); } } return true; } private static class Proxy implements com.example.binderdemo.ICallback { 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 void onResult(int result) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(result); boolean _status = mRemote.transact(Stub.TRANSACTION_onResult, _data, null, android.os.IBinder.FLAG_ONEWAY); } finally { _data.recycle(); } } } static final int TRANSACTION_onResult = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); } /** @hide */ public static final java.lang.String DESCRIPTOR = "com.example.binderdemo.ICallback"; public void onResult(int result) throws android.os.RemoteException; }再修改RemoteService,服务端要保存回调,并在 add 后调用。RemoteService代码改成如下:
package com.example.binderdemo; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; import android.util.Log; import java.util.ArrayList; import java.util.List; public class RemoteService extends Service { private static final String TAG = "RemoteService"; private final List<ICallback> callbacks = new ArrayList<>(); private final IMyAidlInterface.Stub binder = new IMyAidlInterface.Stub() { @Override public int add(int a, int b) throws RemoteException { Log.d(TAG, "add(" + a + "," + b + ") thread=" + Thread.currentThread().getName() + ", pid=" + Process.myPid()); int result = a + b; // 通知所有已注册的回调 for (ICallback cb : callbacks) { cb.onResult(result); } return result; } @Override public String getMessage() { Log.d(TAG, "getMessage thread=" + Thread.currentThread().getName() + ", pid=" + Process.myPid()); return "Hello from pid=" + Process.myPid() + " , 为人不识陈近南,纵称英雄也枉然。"; } @Override public void registerCallback(ICallback cb) throws RemoteException { Log.d(TAG, "registerCallback cb=" + cb + ", class=" + (cb == null ? "null" : cb.asBinder().getClass().getName())); if (cb != null) { callbacks.add(cb); } } @Override public void unregisterCallback(ICallback cb) throws RemoteException { if (cb != null) { callbacks.remove(cb); } } }; @Override public IBinder onBind(Intent intent) { Log.d(TAG, "onBind thread=" + Thread.currentThread().getName() + ", pid=" + Process.myPid()); return binder; } }修改MainActivity,客户端实现 ICallback.Stub,注册给服务端。如下:
调用add前先注册callBack:
activity销毁时解注册callback:
完整代码如下:
package com.example.binderdemo; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; import android.util.Log; import android.widget.TextView; import androidx.activity.ComponentActivity; import androidx.annotation.Nullable; import static com.example.binderdemo.IMyAidlInterface.DESCRIPTOR; public class MainActivity extends ComponentActivity { private static final String TAG = "ClientMainActivity"; private IMyAidlInterface remote; private final ICallback callback = new ICallback.Stub() { @Override public void onResult(int result) { Log.d(TAG, "onResult result=" + result + ", thread=" + Thread.currentThread().getName() + ", pid=" + Process.myPid()); runOnUiThread(() -> tv.setText("callback result=" + result)); } }; //private IMiniInterface remote; private TextView tv; private boolean bound; private final ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "onServiceConnected thread=" + Thread.currentThread().getName()); // // 这个service类型是android.os.BinderProxy,远端代理,用于跨进程通信。 // // 这里asInterface返回一个客户端Proxy对象,里面的成员变量mRemote就是这个service对象。 // remote = IMyAidlInterface.Stub.asInterface(service); // 手写版 asInterface:跨进程直接返回 Proxy // remote = new MiniProxy(service); // android.os.IInterface iin = service.queryLocalInterface(DESCRIPTOR); // 跨进程通信时,搜索为null // Log.d(TAG, "iin=" + iin); // iin=null remote = IMyAidlInterface.Stub.asInterface(service); try { // 先注册callback remote.registerCallback(callback); Log.d(TAG, "registered callback, callback.asBinder()=" + callback.asBinder().getClass().getName()); // 然后调用add方法 int result = remote.add(1, 2); // String msg = remote.getMessage(); // Log.d(TAG, "add result=" + result + ", msg=" + msg); // tv.setText("result=" + result + "\n" + msg); tv.setText("add result=" + result); Log.d(TAG, "当前客户端进程:"+ Process.myPid()); Log.d(TAG, "remote: " + remote); Log.d(TAG, "service: " + service); } catch (RemoteException e) { e.printStackTrace(); } Log.d(TAG, "client pid=" + Process.myPid()); } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "onServiceDisconnected"); remote = null; } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); tv = new TextView(this); setContentView(tv); Intent intent = new Intent(this, RemoteService.class); // Intent intent = new Intent(this, RemoteService2.class); bound = bindService(intent, conn, BIND_AUTO_CREATE); } @Override protected void onDestroy() { if (bound) { try { if (remote != null) { remote.unregisterCallback(callback); } } catch (RemoteException e) { e.printStackTrace(); } unbindService(conn); bound = false; } super.onDestroy(); } }运行:
看下日志:
看下为啥是这个日志现象。追踪下代码,注册callback:
// IMyAidlInterface.java 生成的 Proxy @Override public void registerCallback(ICallback cb) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeStrongInterface(cb); // 这一行注册callBack mRemote.transact(TRANSACTION_registerCallback, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } }此刻:客户端进程、主线程、Java 层。cb 就是 MainActivity$1,本质是 ICallback.Stub,继承 android.os.Binder。
Parcel的writeStrongInterface方法如下:
public final void writeStrongInterface(IInterface val) { writeStrongBinder(val == null ? null : val.asBinder()); }里面调用了asBinder(), 也就算调用的这里:
可以看出,asBinder还是Stub自身,因为它自身就算继承的Binder, 也就是 CallBack 自己。
继续看下,Parcel.writeStrongBinder:
public final void writeStrongBinder(IBinder val) { nativeWriteStrongBinder(mNativePtr, val); }nativeWriteStrongBinder 是 native 方法。到这里,Java 层调用结束,进入 JNI。
此刻 _data 里写入了两样东西:
writeInterfaceToken(DESCRIPTOR) 写入的接口名字符串。
writeStrongBinder 即将写入的 Binder 引用。
看下jni入口,frameworks/base/core/jni/android_os_Parcel.cpp:
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object) { Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); if (parcel != NULL) { const status_t err = parcel->writeStrongBinder( ibinderForJavaObject(env, object)); // ... } }题外话,为啥nativeWriteStrongBinder调用到了android_os_Parcel_writeStrongBinder?看上去方法签名对应不上。是用的jni动态注册,在frameworks/base/core/jni/android_os_Parcel.cpp这里:
static const JNINativeMethod gParcelMethods[] = { // ... {"nativeWriteStrongBinder", "(J Landroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder}, // ... };android_os_Parcel_writeStrongBinder的作用:
ibinderForJavaObject(env, object) ---- 先把Java 层传下来的 object(这里是callback)转换成 Native 层认识的 IBinder 对象。(注:如果传入的object是Binder 类型,返回一个 JavaBBinder 对象; BinderProxy 类型, 返回一个 BpBinder 对象)
parcel->writeStrongBinder(...) ---- 拿到转换后的 Native IBinder(这里是 JavaBBinder)后,就调用 Native 层 Parcel 的 writeStrongBinder 方法,把它序列化并写入 Parcel 的数据缓冲区里。
再回到demo的场景里:
传入的 object就是 MainActivity$1,本质是 ICallback.Stub,一个 Java 层的 Binder。 ibinderForJavaObject 返回:一个 Native 层的 JavaBBinder,它“指向”那个callback。
writeStrongBinder 写入:Native Parcel 里现在有了一个代表了回调的 Native 对象。接下来 Parcel 被交给 Binder 驱动时,驱动看到这个 Native 对象,就知道这是一个“本地 Binder”,从而在目标进程创建 BinderProxy。
上面涉及到术语,本地Binder意思是,这个 Binder 对象的真实实现,就存在于发送方进程里。比如demo中的callback是发送方进程里的对象。
JavaBBinder 在 Native 层被写成 flat_binder_object,标记为“本地 Binder”。Binder 驱动看到这个标记,发现接收方不是它所属的进程,就把它改写成 handle(handle由 Binder 驱动分配和维护,代表“对方进程里的某个 Binder 对象”),服务端 Java 层再把 handle 包装成 BinderProxy。