news 2026/10/19 2:11:27

Binder双向通信

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Binder双向通信

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。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/19 2:07:34

《驾驭你的AI同事:WorkBuddy深度精通》041:5.4 自定义 MCP 实操(mcp.json)

《驾驭你的AI同事:WorkBuddy深度精通》041:5.4 自定义 MCP 实操(mcp.json) 本文是《唤醒你的 AI 同事:WorkBuddy 全栈指南》系列 卷二(深度精通) 的第 41 篇。前面几篇我们讲了 MCP 协议、开发环境、接入现有服务器。这一篇落到最实用的一招:用一份 mcp.json,把任何&q…

作者头像 李华
网站建设 2026/10/19 2:07:32

AI测试效率翻倍:告别返工半小时,掌握8个Agent Skill让AI懂你的规矩!

本文分享了作者使用AI生成测试用例后遭遇的返工困境&#xff0c;并提出通过创建8个Agent Skill来规范AI工作流程&#xff0c;从而大幅提升测试效率。文章详细介绍了这些Skills的设计思路和应用场景&#xff0c;覆盖从需求澄清到测试复盘的全链路&#xff0c;帮助测试人员将AI工…

作者头像 李华
网站建设 2026/10/19 2:07:09

122. 2016年蓝桥杯省赛 - 四平方和(困难)- 暴力枚举

122. 四平方和&#xff08;暴力枚举&#xff09; 2016年蓝桥杯省赛 - 四平方和&#xff08;困难&#xff09; 标签&#xff1a;2016 省赛 暴力枚举 题目描述 四平方和定理&#xff0c;又称拉格朗日定理&#xff1a;每个正整数都可以表示为至多 4 个正整数的平方和。把 0 也算进…

作者头像 李华
网站建设 2026/10/19 2:06:55

红同电子线束工厂百问百答|传感器线束IP65公母对接装配注意事项

1. 引言传感器线束在工业设备、汽车电子和自动化控制中承担着信号传输的关键作用&#xff0c;而IP65防护等级的公母对接结构&#xff0c;则决定了线束在潮湿、粉尘等恶劣环境下的长期可靠性。上海红同电子有限公司&#xff08;www.hongtongsh.com&#xff09;深耕电子高低压线束…

作者头像 李华
网站建设 2026/10/19 2:06:29

Pip实用命令全解析:从安装到升级一网打尽

#技术派的书架#引言是一个关于包管理的工具, 它最常见的用来安装软件包的用途, 除了这个以外还有一些别的很有用的命令, 这些命令可能很多读者朋友并不怎么清楚, 接下来我们要对它们做个简单的说明。1. 更新 pippython -m pip install --upgrade pip2. 把软件包进行安装, 这个动…

作者头像 李华