RK3568 Android11 使用AIDL添加Hal层binder通讯

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中。

相关推荐
henysugar1 天前
Android studio编译aidl若干问题记录
android·ide·android studio·aidl
消失的旧时光-19432 天前
Binder 是如何贯穿 ART / Native / Kernel 的?
binder
灵感菇_2 天前
全面解析Android Binder机制
android·binder
似霰6 天前
AIDL Hal 开发笔记7----AIDL HAL 的升级
android·framework·hal
似霰9 天前
AIDL Hal 开发笔记5----实现AIDL HAL
android·framework·hal
似霰9 天前
AIDL Hal 开发笔记6----添加硬件访问服务
android·framework·hal
似霰16 天前
AIDL Hal 开发笔记4----驱动开发
android·驱动开发·framework·hal
似霰17 天前
AIDL Hal 开发笔记2----AIDL HAL 实例分析light hal
android·framework·hal
似霰17 天前
AIDL Hal 开发笔记1----AIDL HAL 整体架构
android·framework·hal
似霰19 天前
HIDL Hal 开发笔记10----添加硬件访问服务(Java 层调用 HIDL)
android·framework·hal