RK3568 Android11 使用AIDL添加Hal层binder通讯
前言
我们通过一个简单的例子来详细说明怎么使用一个AIDL binder服务,并通过init进程解析rc文件启动,并且给系统App提供上层接口调用服务。
第一步添加一个AIDL接口
在RK3568/rk_android11.0_sdk/vendor/rockchip/hardware/interfaces目录新建一个文件夹projectormanager,在这个文件夹里添加aidl、C++代码和编译配置文件。在projectormanager下新建如下文件夹和文件
整体的文件结构如下:
projectormanager/
├── binder/ # 【接口定义层】定义跨进程通信规范
│ ├── aidl_api/ # 存放冻结的 API 版本快照(用于版本兼容性)这个文件夹后面讲
│ ├── com/
│ │ └── appo/
│ │ ├── IProjectorCallback.aidl # 异步回调接口
│ │ └── IProjectorManager.aidl # 主控制接口
│ └── Android.bp # 定义 aidl_interface 模块
├── default/ # 【实现集成层】具体业务逻辑及系统配置
│ ├── com/
│ │ └── appo/
│ │ ├── main.cpp # 服务进程入口(注册 Service)
│ │ ├── ProjectorManagerService.cpp # AIDL 接口的具体 C++ 实现
│ │ └── ProjectorManagerService.h # 实现类头文件
│ ├── Android.bp # 定义 cc_binary (HAL 进程)
│ ├── manifest_projector.xml # VINTF 节点声明 (告知系统该 HAL 的存在)
│ ├── projectormanager.rc # Android Init 启动脚本
│ └── framework_compatibility_matrix.xml # 框架兼容性矩阵配置 这个也后面会讲

我们先来写上图2个AIDL接口如下:
IProjectorCallback.aidl定义如下:
aidl
package com.appo;
@VintfStability
interface IProjectorCallback{
void onStatusChanged(int status);
}
IProjectorManager.aidl定义如下:
aidl
package com.appo;
import com.appo.IProjectorCallback;
@VintfStability
interface IProjectorManager {
void init();
int getPictureMode(int sourceId);
void addCallback(in IProjectorCallback callBack);
void removeCallback(in IProjectorCallback callBack);
void uInit();
}
然后在binder目录下新建一个编译文件Android.bp,如下:
bp
aidl_interface {
name: "com.appo.IProjectorManager",
vendor_available: true,
srcs: [
"com/appo/IProjectorCallback.aidl",
"com/appo/IProjectorManager.aidl",
],
stability: "vintf",
owner: "appo",
local_include_dir: ".",
backend: {
cpp: {
enabled: true,
},
java: {
enabled: true,
platform_apis: true,
},
ndk: {
enabled: true,
},
},
versions: ["1"],
}
如果是新建的aidl.写完编译是编译不过了的,因为有vintf认证,所以我们需要先在Android.bp同级目录即binder目录下新建aidl_api/com.appo.IProjectorManager/1文件夹
然后再编译运行
mk
source build/envsetup.sh
lunch your target ##需要根据自己的实际情况进行选择
m com.appo.IProjectorManager-update-api
执行成功后会在与1同级目录生出current目录,这时删除1目录和bp文件里的versions属性
再次执行以下命令:
mk
m com.appo.IProjectorManager-update-api
#执行完再执行下面的
m com.appo.IProjectorManager-freeze-api
系统会生出1的目录,并在bp文件里的自动生成versions属性
以后需要更新添加aidl接口重复这时删除1目录和bp文件里的versions属性,然后执行:
m com.appo.IProjectorManager-update-api
#执行完再执行下面的
m com.appo.IProjectorManager-freeze-api
执行成功后会在out目录下生成对应的包,如下:

添加服务端实现
在projectormanager目录下新建default目录,并在其下编写相关文件,我们先来写binder服务端代码,目录如下:

现在开始编译相关代码:
main.cpp
cpp
#undef LOG_TAG
#define LOG_TAG "ProjectorManager"
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include "ProjectorManagerService.h"
#include <utils/Log.h>
using aidl::com::appo::ProjectorManagerService;
using ndk::SharedRefBase;
int main() {
// 1. 设置 Binder 线程池最大线程数
ALOGI("ProjectorManagerService (NDK) is starting...");
ABinderProcess_setThreadPoolMaxThreadCount(0);
// 2. 创建服务实例 (注意使用 SharedRefBase::make)
std::shared_ptr<ProjectorManagerService> service = SharedRefBase::make<ProjectorManagerService>();
// 3. 准备实例名称
// descriptor 通常自动生成为 "com.appo.IProjectorManager"
const std::string instance = "com.appo.IProjectorManager.IProjectorManager/default";
// 4. 注册服务到 ServiceManager
binder_status_t status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
if (status != STATUS_OK) {
ALOGE("Failed to register service, status: %d", status); // 打印 Erro
return -1;
}
ALOGI("ProjectorManagerService (NDK) is running...");
// 5. 加入线程池循环
ABinderProcess_joinThreadPool();
return 0;
}
ProjectorManagerService.h
cpp
#ifndef ANDROID_PROJECTOR_MANAGER_SERVICE_H
#define ANDROID_PROJECTOR_MANAGER_SERVICE_H
// 注意:头文件路径由 <com/appo/...> 变为 <aidl/com/appo/...>
#include <aidl/com/appo/BnProjectorManager.h>
#include <aidl/com/appo/IProjectorCallback.h>
#include <vector>
#include <mutex>
#include <memory>
namespace aidl {
namespace com {
namespace appo {
// 继承自 aidl::com::appo::BnProjectorManager
class ProjectorManagerService : public BnProjectorManager {
public:
ProjectorManagerService();
// 返回值变为 ndk::ScopedAStatus,参数使用 std::shared_ptr
::ndk::ScopedAStatus init() override;
::ndk::ScopedAStatus uInit() override;
::ndk::ScopedAStatus getPictureMode(int32_t in_sourceId, int32_t* _aidl_return) override;
::ndk::ScopedAStatus addCallback(const std::shared_ptr<::aidl::com::appo::IProjectorCallback>& in_callback) override;
::ndk::ScopedAStatus removeCallback(const std::shared_ptr<::aidl::com::appo::IProjectorCallback>& in_callback) override;
private:
std::mutex mLock;
std::vector<std::shared_ptr<::aidl::com::appo::IProjectorCallback>> mCallbacks;
};
} // namespace appo
} // namespace com
} // namespace aidl
#endif
ProjectorManagerService.cpp
cpp
#undef LOG_TAG
#define LOG_TAG "ProjectorManager"
#include "ProjectorManagerService.h"
#include <utils/Log.h>
namespace aidl {
namespace com {
namespace appo {
ProjectorManagerService::ProjectorManagerService() {
ALOGI("ProjectorManagerService (NDK) created");
}
::ndk::ScopedAStatus ProjectorManagerService::init() {
ALOGI("Starting projector...");
std::lock_guard<std::mutex> lock(mLock);
for (auto& cb : mCallbacks) {
if (cb) cb->onStatusChanged(1);
}
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus ProjectorManagerService::uInit() {
ALOGI("Stopping projector...");
std::lock_guard<std::mutex> lock(mLock);
for (auto& cb : mCallbacks) {
if (cb) cb->onStatusChanged(0);
}
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus ProjectorManagerService::getPictureMode(int32_t in_sourceId, int32_t* _aidl_return) {
if (_aidl_return == nullptr) return ::ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
*_aidl_return = 2;
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus ProjectorManagerService::addCallback(const std::shared_ptr<IProjectorCallback>& in_callback) {
if (in_callback) {
std::lock_guard<std::mutex> lock(mLock);
mCallbacks.push_back(in_callback);
}
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus ProjectorManagerService::removeCallback(const std::shared_ptr<IProjectorCallback>& in_callback) {
if (!in_callback) return ::ndk::ScopedAStatus::ok();
std::lock_guard<std::mutex> lock(mLock);
auto it = std::remove_if(mCallbacks.begin(), mCallbacks.end(),
[&](const std::shared_ptr<IProjectorCallback>& cb) {
// NDK 中直接比较智能指针或其绑定的 Binder
return cb->asBinder().get() == in_callback->asBinder().get();
});
mCallbacks.erase(it, mCallbacks.end());
return ::ndk::ScopedAStatus::ok();
}
} // namespace appo
} // namespace com
} // namespace aidl
在default目录下编写编译配置文件
Android.bp
bp
cc_binary {
name: "projectormanager",
srcs: [
"com/appo/ProjectorManagerService.cpp",
"com/appo/main.cpp",
],
vendor:true,
relative_install_path: "hw", // 实际路径 /vendor/bin/hw/projectormanager
shared_libs: [
"libbase",
"libbinder_ndk",
"libutils",
"liblog",
"libcutils",
"libdl",
"com.appo.IProjectorManager-ndk_platform", // 引用上面自动生成的 C++ 库
],
vintf_fragments: ["manifest_projector.xml"],//vintf配置文件
init_rc: ["projectormanager.rc"], // 将 rc 文件关联进来
}
projectormanager.rc文件内容如下:
rc
service projector_manager /vendor/bin/hw/projectormanager
class hal
user system
group system
这个rc文件编译的时候会自动拷贝到系统镜像里的vendor/etc/init目录下,init进程会去解析这个文件并且启动projectormanager进程
manifest_projector.xml文件内容如下:
<manifest version="1.0" type="device">
<hal format="aidl" optional="true">
<name>com.appo.IProjectorManager</name>
<interface>
<name>IProjectorManager</name>
<instance>default</instance>
</interface>
</hal>
</manifest>
采取aidl接口写法,需要注意name需要和aidl 模块名一样, 然后其表示的aidl 服务名称为:
com.appo.IProjectorManager.IProjectorManager/default
注册和获取服务的时候使用这个名称
下面就可以开始编译这个projectormanager模块了
mk
m projectormanager
添加Selinux权限、添加框架兼容性矩阵配置并且打包进系统
在device/rockchip目录对应型号下的sepolicy添加相关selinux权限,我的是:
rk_android11.0_sdk/device/rockchip/rk356x/sepolicy_vendor目录下
在file_contexts文件添加
mk
/vendor/bin/hw/projectormanager u:object_r:projectormanager_exec:s0
在service_contexts文件下添加,如果没有这个文件自己新建一个
mk
com.appo.IProjectorManager/default u:object_r:projectormanager_service:s0
新建一个projectormanager.te文件
te
# =========================================================
# 1. 类型定义
# =========================================================
# 定义服务标签 (必须包含 service_manager_type 和 vendor_service)
type projectormanager_service, service_manager_type, vendor_service;
# 定义进程域和执行文件标签
type projectormanager, domain;
type projectormanager_exec, exec_type, vendor_file_type, file_type;
# =========================================================
# 2. 基础域切换与环境权限
# =========================================================
# 允许 init 进程启动二进制并切换到 projectormanager 域
init_daemon_domain(projectormanager)
# 允许作为 Binder 服务端与 servicemanager 通信
allow projectormanager servicemanager:binder { call transfer };
allow projectormanager binder_device:chr_file rw_file_perms;
# =========================================================
# 3. AIDL 服务注册 (核心)
# =========================================================
# 允许向 ServiceManager 注册你自定义的 AIDL 接口
add_service(projectormanager, projectormanager_service)
接下来添加框架兼容性矩阵配置文件,这个文件放在如下目录:

framework_compatibility_matrix.xml里面内容为:
xml
<compatibility-matrix version="1.0" type="framework">
<hal format="aidl" optional="true">
<name>com.appo.IProjectorManager</name>
<interface>
<name>IProjectorManager</name>
<instance>default</instance>
</interface>
</hal>
</compatibility-matrix>
把这个文件路径添加到系统里,添加到你编译的型号的BoardConfig.mk 配置中
我的路径是在/Study/RK3568/rk_android11.0_sdk/device/rockchip/rk356x下的BoardConfig.mk
添加下面这句:
mk
DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE += \
vendor/rockchip/hardware/interfaces/projectormanager/framework_compatibility_matrix.xml
加这个是为了告知系统白名单(Framework Matrix)需要这个接口,不然是非法的,编译系统会失败。
再接下来需要projectormanager可执行程序添加进系统:需要添加到对应型号的device.mk中
我的是/Study/RK3568/rk_android11.0_sdk/device/rockchip/rk356/device.mk
中找到PRODUCT_PACKAGES ,后面追加:
mk
PRODUCT_PACKAGES += \
projectormanager \
com.appo.IProjectorManager
到这里就可以编译系统了,回到系统源码根目录执行编译android
./build.sh -Au
App调用
需要是系统App,不然没有权限
添加 上面编译好的jar包到app中,App添加如下代码就可以调用了,如下:
java
IBinder iBinder= ServiceManager.getService("com.appo.IProjectorManager.IProjectorManager/default");
Log.d(TAG,"iBinder=="+iBinder);
if(iBinder!=null){
IProjectorManager projectorManager=IProjectorManager.Stub.asInterface(iBinder);
Log.d(TAG,"projectorManager=="+projectorManager);
if(projectorManager!=null){
try {
projectorManager.init();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
try {
int mode= projectorManager.getPictureMode(2);
Log.d(TAG,"mode=="+mode);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}
到此就完成了一个AIDL调用的demo,需要注意的是,我们使用了libbinder_ndk库编译,这里可执行文件虽然在vendor目录下,但binder服务其实注册还是在servicemanager,不在vndservicemanager中。