RK3568 Android11 增加HAL层的AIDL

参考文章:

AIDL for HALs实战_hidl会被aidl代替-优快云博客

Android 11 创建自定义AIDL HAL-优快云博客

Native AIDL (与hal通信)_hidl转aidl-优快云博客

Android的自启动_android 自启动-优快云博客

1. 定义HAL接口

创建对应的模块目录:/vendor/rockchiip/hardware/interfaces/helloworld/aidl/
创建aidl文件:

/vendor/rockchiip/hardware/interfaces/helloworld/aidl/vendor/rockchip/hardware/testaidl/helloworld/IHelloworld.aidl

package vendor.rockchip.hardware.testaidl.helloworld;
@VintfStability
interface IHelloworld {
	void sayHello(in String name);
}

 注意: 每个类型定义都必须使用@VintfStability进行注释。

2. 配置Android.bp

创建Android.bp:/vendor/rockchiip/hardware/interfaces/helloworld/aidl/Android.bp

aidl_interface {
    name: "vendor.rockchip.hardware.testaidl.helloworld",
    vendor_available: true,
    srcs: [
        "vendor/rockchip/hardware/testaidl/helloworld/*.aidl",
    ],
    stability: "vintf",
    owner: "tld",
    backend: {
        cpp: {
            enabled: true,
        },
        java: {
            platform_apis: true,
        },
        ndk: {
            enabled: true,
        },
    },
    versions: [
        "1",
    ],
}

  注意: 将owner设置为组织名称。此处正常不用加versions属性,我这个版本编译不加报错,先手动加上并创建相应的目录到1的文件夹,后面需要生成的时候在删除版本属性和目录,在aidl目录下创建如下目录: aidl_api/vendor.rockchip.hardware.testaidl.helloworld/1

backend: 服务的后端,AIDL支持四种后端,分别是C++/JAVA/NDK/RUST, 我们将使用NDK(谷歌推荐),这里都加上会生成相应接口代码,因为后面C++和JAVA要调用。

3. 编译模块

首先前版本没有这个接口,需要更新下API,在项目跟目录下执行:

source build/envsetup.sh
lunch your target ##需要根据自己的实际情况进行选择
m android.hardware.testaidl.helloworld-update-api

 执行成功后会在与1同级目录生出current目录,这时删除1目录和bp文件里的versions属性。

source build/envsetup.sh
lunch your target ##需要根据自己的实际情况进行选择
mm vendor.rockchip.hardware.testaidl.helloworld-update-api

再次执行命令,系统会生出1的目录,并在bp文件里的自动versions属性。

source build/envsetup.sh
lunch your target ##需要根据自己的实际情况进行选择
mm android.hardware.automotive.helloworld-freeze-api

4. 实现HAL 接口

在aidl目录下添加default目录及实现代码 , 目录结构如下

default
    ├── Android.bp
    ├── Helloworld.h
    │── Helloworld.cpp
    └── service.cpp
    └── Helloworld-default.rc
    └── Helloworld-default.xml
      

aidl/default/Helloworld.h

 
#include <aidl/vendor/rockchip/hardware/testaidl/helloworld/BnHelloworld.h>
#include <android-base/expected.h>
#include <android-base/thread_annotations.h>
#include <android/binder_auto_utils.h>

namespace vendor {

namespace rockchip {

namespace hardware {

namespace testaidl {

namespace helloworld {

class Helloworld final : public aidl::vendor::rockchip::hardware::testaidl::helloworld::BnHelloworld {
public:
    ndk::ScopedAStatus sayHello(
        const std::string& name)
        override;
};

}  // namespace helloworld

}  // namespace testaidl

}  // namespace hardware

}  // namespace rockchip

}  // namespace vendor

 

aidl/default/Helloworld.cpp

#define ATRACE_TAG ATRACE_TAG_HAL
#define LOG_TAG "voendor.rockchip.hardware.testaidl.Helloworld@1.0-service"
#include <Helloworld.h>
#include <android-base/result.h>
#include <android-base/stringprintf.h>
#include <android/binder_ibinder.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
#include <utils/Trace.h>
#include <android-base/logging.h>
#include <log/log.h>
#include <inttypes.h>
#include <set>
#include <unordered_set>

namespace vendor {

namespace rockchip {

namespace hardware {

namespace testaidl {

namespace helloworld {

namespace {

using ::android::base::Error;
using ::android::base::expected;
using ::android::base::Result;
using ::android::base::StringPrintf;

using ::ndk::ScopedAIBinder_DeathRecipient;
using ::ndk::ScopedAStatus;

}  // namespace

ndk::ScopedAStatus Helloworld::sayHello(const std::string& name) {
         ALOGD("======sayHello====");
        ALOGD("%s: this = %p, name = %s ", __FUNCTION__, this, &name);
    return ScopedAStatus::ok();
}

}  // namespace helloworld

}  // namespace testaidl

}  // namespace hardware

}  // namespace rockchip

}  // namespace vendor

aidl/default/service.cpp


#define LOG_TAG "vendor.rockchip.hardware.testaidl.helloworld@1.0-service"

#include <unistd.h>

#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>

#include <Helloworld.h>

using ::aidl::vendor::rockchip::hardware::testaidl::helloworld::IHelloworld;
using ::vendor::rockchip::hardware::testaidl::helloworld::Helloworld;
using ::ndk::ScopedAStatus;
using ::ndk::SharedRefBase;

const static char kHelloworldServiceName[] = "default";

int main() {
    ABinderProcess_setThreadPoolMaxThreadCount(0);
    LOG(INFO) << "Helloworld service is starting";
    std::shared_ptr<Helloworld> helloworldHal = SharedRefBase::make<Helloworld>();

    const std::string instance =
            std::string() + IHelloworld::descriptor + "/" + kHelloworldServiceName;

    binder_status_t status =
            AServiceManager_addService(helloworldHal->asBinder().get(), instance.c_str());
    if (status == STATUS_OK) {
        LOG(INFO) << "Service " << kHelloworldServiceName << " is ready";
        ABinderProcess_joinThreadPool();
    } else {
        LOG(ERROR) << "Could not register service " << kHelloworldServiceName
                   << ", status: " << status;
    }

    // In normal operation, we don't expect the thread pool to exit.
    LOG(ERROR) << "Helloworld service is shutting down";
    return 1;
}

aidl/default/Android.bp

cc_binary {
    name: "vendor.rockchip.hardware.testaidl.helloworld@1.0-service",
    init_rc: ["Helloworld-default.rc"],
    vintf_fragments: ["Helloworld-default.xml"],
    relative_install_path: "hw",
    vendor: true,
    srcs: [
        "service.cpp",
        "Helloworld.cpp",
    ],
    shared_libs: [
        "libbase",
        "libbinder_ndk",
        "libutils",
        "liblog",
        "libcutils",
        "libdl",
        "vendor.rockchip.hardware.testaidl.helloworld-ndk_platform",
    ],
}

到  /vendor/rockchiip/hardware/interfaces/helloworld 下,运行:

source build/envsetup.sh
lunch your target ##需要根据自己的实际情况进行选择
mm -j8
或者根目录下执行
mmm /vendor/rockchiip/hardware/interfaces/helloworld -j8

将会在 /out/target/product/trout_arm64/vendor/bin/hw 目录生成如下文件:

vendor.rockchip.hardware.testaidl.helloworld@1.0-service

5. 编写服务启动的rc脚本

aidl/default/Helloworld-default.rc

service vendor.helloworld-1-0 /vendor/bin/hw/vendor.rockchip.hardware.testaidl.helloworld@1.0-service
    class hal
    user system
    group system

6. 声明VINTF AIDL 接口

aidl/default/Helloworld-default.xml

<manifest version="1.0" type="device">
    <hal format="aidl">
        <name>vendor.rockchip.hardware.testaidl.helloworld</name>
        <version>1.0</version>
        <fqname>IHelloworld/default</fqname>
    </hal>
</manifest>

7. 将模块加入系统中

/device/rockchip/common/device.mk

# test HAL AIDL
PRODUCT_PACKAGES += \
    vendor.rockchip.hardware.testaidl.helloworld \
    vendor.rockchip.hardware.testaidl.helloworld@1.0-service

8. 将模块添加到兼容性矩阵中

# (选下标最新的那个) hardware/interfaces/compatibility_matrices/compatibility_matrix.5.xml
     <hal format="aidl" optional="true">
        <name>vendor.rockchip.hardware.testaidl.helloworld</name>
        <version>1.0</version>
        <interface>
            <name>IHelloworld</name>
            <instance>default</instance>
        </interface>
    </hal>

 9.解决Selinux权限

hwservice.te

type hal_helloworld_hwservice, hwservice_manager_type, protected_hwservic

hwservice_contexts

vendor.rockchip.hardware.testaidl.helloworld::IHelloworld       u:object_r:hal_helloworld_hwservice:s0

file_contexts

/vendor/bin/hw/vendor\.rockchip\.hardware\.testaidl\.helloworld@1\.0-service   u:object_r:hal_helloworld_exec:s0

hal_helloworld.te

type hal_helloworld, domain;
type hal_helloworld_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(hal_helloworld)

 29.0.ignore.cil 按需求修改忽略文件,增加如下内容

    hal_helloworld_hwservice
    hal_helloworld_exec

修改的目录为如下图:

10.调用测试

整体进行编译,更设备镜像查看,通过adb shell 查看服务是否启动,有就成功了,执行命令service list 查看服务列表多新增的如下:

vendor.rockchip.hardware.testaidl.helloworld.IHelloworld/default: [vendor.rockchip.hardware.testaidl.helloworld.IHelloworld]

查看vendor/bin/hw/目录下会有vendor.rockchip.hardware.testaidl.helloworld@1.0-service

调用是基于framework层的CPP和JAVA调用

JNI的CPP调用需要引入生成的文件,文件地址

frameworks/base/services/core/jni/Android.bp


cc_defaults {
    name: "libservices.core-libs",
    shared_libs: [
        ........
        "libbinder_ndk",
        "vendor.rockchip.hardware.testaidl.helloworld-ndk_platform",
        ........
    ],

调用文件frameworks/base/services/core/jni/com_android_server_SystemTestJni.cpp

#define LOG_TAG "SystemTestJniCpp"
#include <cutils/log.h>
#include <cutils/properties.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <jni.h>
#include <linux/netlink.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/socket.h>
#include <pthread.h>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
#include <aidl/vendor/rockchip/hardware/testaidl/helloworld/IHelloworld.h>
#include <binder/Binder.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <utils/RefBase.h>
#include <android-base/properties.h>
#include <future>
#include <unistd.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>

using aidl::vendor::rockchip::hardware::testaidl::helloworld::IHelloworld;
using ::ndk::ScopedAStatus;
using ::ndk::SharedRefBase;

namespace android {
static JavaVM *g_VM;
static jobject g_obj;

static void nativeSetTestOne(JNIEnv *env, jobject obj, jint flag) {
    ALOGD("----run nativeTestOne----flag:%d", flag);
        //通过ServiceManager获得aidl服务
        ndk::SpAIBinder binder(
                   AServiceManager_checkService("vendor.rockchip.hardware.testaidl.helloworld.IHelloworld/default"));
        if (binder.get() == nullptr) {
            ALOGE("---- AIDL is not present---");
        } else {
              ALOGE("---- AIDL is  present---");
              std::string mName="def";
             IHelloworld::fromBinder(binder)->sayHello(mName);
        }
     ALOGW("------success to get IHello service-----");
}

JNI的JAVA调用需要引入生成的文件,文件地址

frameworks/base/services/core/Android.bp

    static_libs: [
        ....
        "vendor.rockchip.hardware.testaidl.helloworld-java",
        .....
    ],

调用文件frameworks/base/services/core/java/com/android/server/SystemTestJni.java

package com.android.server;
import android.os.ServiceManager;
import android.content.Context;
import android.os.RemoteException;
import android.util.Slog;
import android.app.SystemTestManager;
import vendor.rockchip.hardware.testaidl.helloworld.IHelloworld;

public class SystemTestJni {
    private final String TAG = "SystemTestJni";
    private SystemTestManager mManager;
    public static native void nativeSetTestOne(int flag);

    public SystemTestJni() {

    }
        public void setTestOne(int flag) throws RemoteException {
            try {
                Slog.d(TAG, "------setTestOne--------flag:" + String.valueOf(flag));
                try {
                    Slog.d(TAG, "----Trying to get AIDL service----");
                    ///通过ServiceManager获得aidl服务
                    IHelloworld serviceAidl =
                    IHelloworld.Stub.asInterface(
                                    ServiceManager.getService("vendor.rockchip.hardware.testaidl.helloworld.IHelloworld/default"));
                    if (serviceAidl != null) {
                        Slog.d(TAG, "-----success to get Helloworld AIDL service--111---");
                        serviceAidl.sayHello("abc");
                        Slog.d(TAG, "-----success to get Helloworld AIDL service--222---");
                    }
                } catch (Exception eAidl) {
                    Slog.e(TAG, "-----Failed to get Helloworld AIDL service-----", eAidl);
                }

                nativeSetTestOne(flag);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

APP 调用 

app的libs引入jar包vendor.rockchip.hardware.helloworld-java.jar,导入方式implementaion ,同时引入framework.jar方式compileOnly。

jar位置:out/soong/.intermediates/vendor/rockchip/hardware/interfaces/helloworld/aidl/vendor.rockchip.hardware.helloworld-java/android_common/javac目录下

调用代码同Framework  的JNI 的JAVA调用一致

package xxxxxx;
import android.util.Log;
import android.os.ServiceManager;
import vendor.rockchip.hardware.testaidl.helloworld.IHelloworld;

public class Test{

        public void setTestOne()   {
     
                try {
                    Log.d(TAG, "----Trying to get AIDL service----");
                    ///通过ServiceManager获得aidl服务
                    IHelloworld serviceAidl =
                    IHelloworld.Stub.asInterface(
                                    ServiceManager.getService("vendor.rockchip.hardware.testaidl.helloworld.IHelloworld/default"));
                    if (serviceAidl != null) {
                        Log.d(TAG, "-----success to get Helloworld AIDL service--111---");
                        serviceAidl.sayHello("abc");
                        Log.d(TAG, "-----success to get Helloworld AIDL service--222---");
                    }
                } catch (Exception eAidl) {
                    Log.e(TAG, "-----Failed to get Helloworld AIDL service-----", eAidl);
                }  
        }

再需要补充APP调用权限,修改hal_helloworld.tet添加下面内容即可或者关闭SELinux。

allow hal_helloworld servicemanager:binder { call transfer };
allow {  platform_app system_app shell } hal_helloworld_hwservice:hwservice_manager { find };
allow {  platform_app system_app shell } hal_helloworld:binder {call};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值