在编写 AIDL HAL 服务时开发者并不需要完全弄懂所有底层类的实现但必须清楚以下几个核心类/函数的作用和使用方式。这里提炼一份精简的“开发者必备知识表”覆盖了你将反复打交道的 C 实体。一、你直接编写/继承的类类/概念手写还是自动生成你必须知道的事HelloTest手写你的业务实现类必须继承BnHelloTest覆写 AIDL 定义的所有方法。IHelloTest自动生成AIDL 接口的“抽象面孔”。客户端用它获得代理并调用方法。你通常不需要继承它服务端用BnHelloTest。BnHelloTest自动生成服务端 Stub帮你处理 binder 解包/打包。你只需继承它实现纯虚函数如getTestOne无需关心通讯细节。BpHelloTest自动生成隐藏客户端代理IHelloTest::fromBinder实际返回它的实例。开发者不直接使用但调用service-method()时就是它在 binder 发请求。编写服务端时你只需要写这样的类class HelloTest : public BnHelloTest { public: ndk::ScopedAStatus getTestOne(int32_t in, const std::string name, int32_t* _return) override; };然后实现方法并在_return指针里填入业务结果。二、服务注册与发现你必须调用的 NDK 函数函数/类作用用法要点AServiceManager_addService将服务对象注册到vndservicemanager参数(AIBinder*, 服务名)。服务名格式接口全限定名/default例如android.hardware.testtld.IHelloTest/defaultAServiceManager_waitForService阻塞等待并获取服务 binder返回AIBinder*需要包装为ndk::SpAIBinder。超时返回nullptr。IHelloTest::fromBinder把原始 binder 转为类型化接口代理返回std::shared_ptrIHelloTest失败返回nullptr。HelloTest::descriptor静态字符串值为接口全限定名用于构造服务名descriptor /default服务端注册示例在service.cpp中auto service ndk::SharedRefBase::makeHelloTest(); std::string name HelloTest::descriptor /defaults; AServiceManager_addService(service-asBinder().get(), name.c_str());客户端获取示例auto binder ndk::SpAIBinder(AServiceManager_waitForService(android.hardware.testtld.IHelloTest/default)); auto service IHelloTest::fromBinder(binder); if (service) service-getTestOne(...);三、Binder 基础设施进程与线程管理函数/类作用注意事项android::ProcessState::initWithDriver(/dev/vndbinder)绑定 vendor binder 域服务端必须调用且必须用/dev/vndbindervendor HAL 专用。客户端通常不需要手动调用由 shell 或 init 提供。ABinderProcess_setThreadPoolMaxThreadCount(0)设置最大线程数0 为自动在startThreadPool之前调用。ABinderProcess_startThreadPool()启动 binder 线程池允许处理并发 binder 请求。ABinderProcess_joinThreadPool()将当前线程加入线程池阻塞等待请求服务端最后调用进入服务循环。ndk::SpAIBinder智能指针管理AIBinder*自动增减 binder 引用计数避免泄漏。通常用于包装waitForService的返回值。 客户端获取服务的完整流程客户端获取服务的过程可以分为以下步骤创建 Binder 代理对象 (BpBinder)客户端首先通过ServiceManager获取到服务端的 Binder 代理对象 (BpBinder)。这个过程看似简单但 Binder 驱动在底层做了大量工作如引用计数管理等。封装为业务代理对象 (BpHelloTest)拿到底层的BpBinder后不能直接使用。需要将其进一步封装创建业务层的代理对象也就是 AIDL 自动生成的BpHelloTest。这个对象是关键它的内部保存了BpBinder的引用并且实现了IHelloTest接口。但它不写任何业务逻辑它的职责非常纯粹——将你的每一次函数调用如getTestOne及其参数打包成一个数据包Parcel然后调用内部BpBinder的transact()方法将数据包交给 Binder 驱动最终发送给服务端。客户端调用fromBinder方法你需要手动调用的IHelloTest::fromBinder(binder)方法正是完成第二步转换的关键API。它的内部会精确地执行这个封装过程返回给你一个可以像本地调用一样使用的HelloTest代理对象。// 伪代码展示IHelloTest::fromBinder的内部逻辑 static std::shared_ptrIHelloTest fromBinder(const ndk::SpAIBinder binder) { // 1. 检查传入的binder是否为空 if (!binder) return nullptr; // 2. 验证binder的服务端接口描述符是否匹配 // ...验证逻辑... // 3. 创建并返回业务代理对象 return std::make_sharedBpHelloTest(binder); } 客户端与服务的完整通信图客户端进程 内核空间 服务进程 ┌─────────────────┐ ┌─────────┐ ┌──────────────────────┐ │ test_aidl_hal │ │ │ │ android.hardware. │ │ │ │ │ │ testtld-service │ │ getTestOne(1, │ -- 打包数据-- │ Binder │ -- 解包-- │ │ │ hello, │ │ 驱动 │ │ HelloTest:: │ │ result) │ -- 打包结果--│ │ -- 打包-- │ getTestOne(...) │ │ │ │ │ │ │ │ result 2 │ │ │ │ return ok; │ └─────────────────┘ └─────────┘ └──────────────────────┘✅ 客户端开发自查清单AIDL 定义一致确保客户端链接的 AIDL 库版本与服务端严格一致接口签名不匹配是常见的运行时错误。线程池与同步/异步明确你的客户端是同步调用还是异步调用。如果涉及回调需要确保客户端进程也配置了 binder 线程池来处理服务端的反向调用。️服务名称AServiceManager_waitForService中使用的服务名称例如android.hardware.testtld.IHelloTest/default必须与服务端注册时使用的名称完全一致。死亡通知 (Death Recipient)对于需要长期保持连接的服务建议注册死亡通知监听器。这能让客户端在服务异常退出时进行优雅处理避免调用失败时无响应。四、方法签名与返回值你每次都要写的项目说明ndk::ScopedAStatus每个 AIDL 方法必须返回该类型表示通信状态。调用成功返回ndk::ScopedAStatus::ok()。输出参数_aidl_returnAIDL 方法的实际返回值通过指针传递。你在服务端需要给它赋值如*_aidl_return 2;。输入参数按照 AIDL 定义的类型使用如int32_t in_event,const std::string in_name。它们由 binder 从客户端序列化而来。五、对象创建与生命周期函数/类用途为什么用它ndk::SharedRefBase::makeT(args...)创建 HAL 服务对象返回std::shared_ptrT且对象支持 binder 跨进程引用计数。绝不用new或std::make_shared。std::shared_ptrHelloTest智能指针自动管理对象生命周期当本地和所有 binder 客户端都释放后自动析构对象。六、日志输出调试必备宏输出目标查看命令ALOGD(tag, ...)logd main 缓冲区logcat -s YourTagALOGE(...)同上优先级 ERROR更容易在大量日志中凸显printf(...)stdout直接显示在终端适合测试小工具不建议用于最终 HAL 服务推荐在最终 HAL 服务中用ALOGD/ALOGE临时测试时用printf加速调试。七、必须遵守的硬规则服务端必须使用/dev/vndbinder不能是/dev/binder。服务名必须精确匹配接口全限定名 /default客户端用同一个字符串查找。必须先启动线程池再注册服务否则addService可能失败。实现类HelloTest的命名空间必须与 AIDL 生成的接口完全一致aidl::android::hardware::testtld。不要手动 delete 服务对象交给shared_ptr和 binder 引用计数管理。八、一张图汇总操作流程编写 .aidl 文件 ↓ 编译生成: IHelloTest, BnHelloTest, BpHelloTest, descriptor ↓ 手写 HelloTest.cpp (继承 BnHelloTest, 实现方法) 手写 service.cpp (初始化 vndbinder, 创建实例, 注册, join) ↓ 编译出 testtld-service 可执行文件 ↓ 在 init.rc 中配置自动启动 ↓ 客户端通过 AServiceManager_waitForService IHelloTest::fromBinder 获取服务并调用