如何在 Android 系统中通过 Native(C++)代码调用 Java 编写的 Binder 服务

260 阅读2分钟

这篇文章详细讲解了如何在 Android 系统中通过 Native(C++)代码调用 Java 编写的 Binder 服务。我们可以用两种方式实现,以下用通俗的语言分步解释:


​核心概念​

​Binder​​ 是 Android 的跨进程通信(IPC)机制,类似「快递员」在不同进程间传递数据。

  • ​服务端​​(Java)提供功能(如计算器)
  • ​客户端​​(C++)调用服务端的功能

​方法一:手动操作(底层方式)​

1. ​​获取服务​

cpp
Copy
sp<IServiceManager> sm = defaultServiceManager();  // 拿到系统服务管理器
sp<IBinder> ibinder = sm->getService(String16("hello")); // 查找名为"hello"的服务

就像在快递站问:"有没有叫'hello'的快递员?"

2. ​​打包数据​

cpp
Copy
Parcel data, reply;  // 准备发送和接收的包裹
data.writeInterfaceToken(descriptor); // 告诉服务端你要调用的接口

3. ​​发送请求​

cpp
Copy
ibinder->transact(代码, data, &reply, 0); // 发送包裹,等待回复

类似告诉快递员:"用第一个业务代码(FIRST_CALL_TRANSACTION)把包裹送给服务端"。

4. ​​处理结果​

cpp
Copy
int result = reply.readInt32(); // 拆包裹读取结果
ALOGI("结果: %d", result); 

​方法二:自动生成(AIDL方式)​

1. ​​定义接口​

用 .aidl 文件声明服务接口(如 IHelloService.aidl),工具会自动生成 C++ 和 Java 代码。

2. ​​生成代码​

bash
Copy
aidl-cpp IHelloService.aidl  # 生成 C++ 代理类

这会生成类似 IHello.h/cpp 的代码,封装了底层 Binder 操作。

3. ​​调用服务​

cpp
Copy
// 直接调用生成的类方法,就像本地函数!
IHello::getService()->hello(); 
IHello::getService()->sum(3, 4);

​关键对比​

方式优点缺点
手动操作灵活,适合简单场景代码复杂,容易出错
AIDL生成代码自动处理打包/解包,代码简洁需要提前定义接口,生成代码步骤

​实战步骤​

  1. ​编译代码​​:用 mm 命令编译 Native 客户端。
  2. ​推送文件​​:将生成的 CppClient 和服务端 Jar 包推送到设备。
  3. ​启动服务​​:在 Android Shell 中运行 Java 服务端。
  4. ​运行客户端​​:执行 C++ 客户端,查看日志验证结果。

​总结​

  • ​底层方式​​:直接操作 Binder 的 transact(),适合临时需求或学习原理。
  • ​AIDL方式​​:通过接口定义自动生成代码,更规范、安全,推荐实际开发使用。

两种方法殊途同归,最终都实现了跨语言(C++ ↔ Java)的进程间通信,体现了 Android Binder 的强大灵活性。