RK3576 Android14 增加HAL层的AIDL

Source

 参考文章:

AIDL for HALs实战_hidl会被aidl代替-CSDN博客

Android 11 创建自定义AIDL HAL-CSDN博客

Native AIDL (与hal通信)_hidl转aidl-CSDN博客

Android的自启动_android 自启动-CSDN博客

1. 定义HAL接口

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

hardware/interfaces/testtld/aidl/android/hardware/testtld/IHelloTest.aidl

package android.hardware.testtld;

 
@VintfStability
interface IHelloTest {
    int getTestOne(in int event, in String name);
}

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

2. 配置Android.bp

创建Android.bp:/hardware/interfaces/testtld/aidl/Android.bp

package {
    // See: http://go/android-license-faq
    // A large-scale-change added 'default_applicable_licenses' to import
    // all of the 'license_kinds' from "hardware_interfaces_license"
    // to get the below license kinds:
    //   SPDX-license-identifier-Apache-2.0
    default_applicable_licenses: ["hardware_interfaces_license"],
}

aidl_interface {
    name: "android.hardware.testtld",
    vendor_available: true,
    srcs: ["android/hardware/testtld/*.aidl"],
    stability: "vintf",
    owner: "tld",
    backend: {
        cpp: {
            enabled: true,
        },
       java: {
            sdk_version: "module_current",
        },        
        ndk: {
            enabled: true,
        },
    },

    frozen: false,

}

  注意: 将owner设置为组织名称,此处不用加versions_with_info属性,后面编译完会自动生成,frozen会自动变成true 。vendor_available属性一定不能改成vendor,不然so文件不会在system文件下生成,只是在vendor下就引用不到了。

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

3. 编译模块

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

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

 执行成功后会生出current目录。

source build/envsetup.sh
lunch your target ##需要根据自己的实际情况进行选择
mmm hardware/interfaces/testtld

再次执行命令,系统会生出1的目录,并在bp文件里的自动添加版本属性frozen变成true。

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

4. 实现HAL 接口

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

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

aidl/default/HelloTest.h

#include <aidl/android/hardware/testtld/BnHelloTest.h>

namespace aidl {

namespace android {

namespace hardware {

namespace testtld {



class HelloTest  : public BnHelloTest {
public:
    ndk::ScopedAStatus getTestOne(int32_t in_event, const std::string& in_name, int32_t* _aidl_return);
};


}  // namespace testtld

}  // namespace hardware

}  // namespace android

}  // namespace aild

aidl/default/HelloTest.cpp

#define LOG_TAG "android.hardware.testtld-service"

#include <utils/Log.h>
#include <log/log.h>
#include <iostream>
#include <HelloTest.h>

namespace aidl {

namespace android {

namespace hardware {

namespace testtld {

ndk::ScopedAStatus HelloTest::getTestOne(int32_t in_event, const std::string& in_name, int32_t* _aidl_return) {
    ALOGD("======getTestOne====1");
    std::int32_t ret = in_event;
    std::string name = in_name;
    *_aidl_return = 2;
     ALOGD("======getTestOne====2===in_event:%d",ret);
    ALOGD("%s: this = %p, name = %s ", __FUNCTION__, this, name.c_str());
    return ndk::ScopedAStatus::ok();
}


}  // namespace testtld

}  // namespace hardware

}  // namespace android

}  // namespace aidl

aidl/default/service.cpp

#define LOG_TAG "android.hardware.testtld-service"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include "HelloTest.h"

using aidl::android::hardware::testtld::HelloTest;
using std::string_literals::operator""s;

int main() {
    // Enable vndbinder to allow vendor-to-venfor binder call
    android::ProcessState::initWithDriver("/dev/vndbinder"); //使用vnbinder的配置

    ABinderProcess_setThreadPoolMaxThreadCount(0); // vnbinder的线程池独立,需要单独配置 
    ABinderProcess_startThreadPool();

    std::shared_ptr<HelloTest> helloTest = ndk::SharedRefBase::make<HelloTest>();
    const std::string desc = HelloTest::descriptor + "/default"s;

    if (helloTest != nullptr) {
        if(AServiceManager_addService(helloTest->asBinder().get(), desc.c_str()) != STATUS_OK) {
            ALOGE("Failed to register IHelloTest service");
            return -1;
        }
    } else {
        ALOGE("Failed to get IHelloTest instance");
        return -1;
    }

    ALOGD("IHelloTest service starts to join service pool");
    ABinderProcess_joinThreadPool();

    return EXIT_FAILURE;  // should not reached
}

aidl/default/Android.bp

cc_binary {
    name: "android.hardware.testtld-service",
    init_rc: ["HelloTest-default.rc"],
    vintf_fragments: ["HelloTest-default.xml"],
    relative_install_path: "hw",
    vendor: true,
    srcs: [
        "service.cpp",
        "HelloTest.cpp",
    ],
    shared_libs: [
        "libbase",
        "libbinder",
        "libbinder_ndk",
        "libutils",
        "liblog",
        "libcutils",
        "libutils",
        "libdl",
        "android.hardware.testtld-V1-ndk",
    ],
    cflags: [
        "-Wall",
        "-Werror",
    ],
}

到  /hardware/interfaces/testtld/ 下,运行:

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

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

android.hardware.testtld-service

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

aidl/default/HelloTest-default.rc

service android.hardware.testtld-service /vendor/bin/hw/android.hardware.testtld-service
    class hal
    user system
    group system

6. 声明VINTF AIDL 接口

aidl/default/HelloTest-default.xml

<manifest version="1.0" type="device">
    <hal format="aidl">
        <name>android.hardware.testtld</name>
        <version>1</version>
        <fqname>IHelloTest/default</fqname>
    </hal>
</manifest>

7. 将模块加入系统中

/device/rockchip/common/device.mk

# test AIDL
PRODUCT_PACKAGES += \
    android.hardware.testtld \
    android.hardware.testtld-service

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

# 查看对应的API级别文件对应的兼容矩阵文件
# device/rockchip/common/manifests/compatibility_matrix_level_34.xml
# device/rockchip/common/manifests/manifest_level_34.xml
hardware/interfaces/compatibility_matrices/compatibility_matrix.8.xml
    <hal format="aidl" optional="true">
        <name>android.hardware.testtld</name>
        <version>1</version>
        <interface>
            <name>IHelloTest</name>
            <instance>default</instance>
        </interface>
    </hal>

 9.解决Selinux权限

hwservice.te

type hal_hellotest_hwservice, hwservice_manager_type, protected_hwservice;

hwservice_contexts

android.hardware.testtld::IHelloTest                                      u:object_r:hal_hellotest_hwservice:s0

file_contexts

/vendor/bin/hw/android\.hardware\.testtld-service     u:object_r:hal_hellotest_exec:s0

hal_hellotest.te

type hal_hellotest, domain;
type hal_hellotest_exec, vendor_file_type, exec_type, file_type;
init_daemon_domain(hal_hellotest)

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

    hal_hellotest_exec
    hal_hellotest_hwservice

修改的目录为如下:

system/sepolicy/prebuilts/api/34.0/private/compat/29.0/29.0.ignore.cil

system/sepolicy/prebuilts/api/34.0/private/compat/30.0/30.0.ignore.cil

system/sepolicy/prebuilts/api/34.0/private/compat/30.0/30.0.ignore.cil

system/sepolicy/prebuilts/api/34.0/private/compat/32.0/32.0.ignore.cil

system/sepolicy/prebuilts/api/34.0/private/compat/33.0/33.0.ignore.cil

system/sepolicy/prebuilts/api/34.0/private/file_contexts

system/sepolicy/prebuilts/api/34.0/private/hal_hellotest.te

system/sepolicy/prebuilts/api/34.0/private/hal_hellotest.te

system/sepolicy/prebuilts/api/34.0/private/hwservice.te

system/sepolicy/prebuilts/api/34.0/private/hwservice_contexts

system/sepolicy/private/compat/29.0/29.0.ignore.cil

system/sepolicy/private/compat/30.0/30.0.ignore.cil

system/sepolicy/private/compat/31.0/31.0.ignore.cil

system/sepolicy/private/compat/32.0/32.0.ignore.cil

system/sepolicy/private/compat/33.0/33.0.ignore.cil

system/sepolicy/private/file_contexts

system/sepolicy/private/hal_hellotest.te

system/sepolicy/private/hwservice.te

system/sepolicy/private/hwservice_contexts

10.调用测试

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

android.hardware.testtld.IHelloTest/default: [android.hardware.testtld.IHelloTest]

查看vendor/bin/hw/目录下会有android.hardware.testtld-service

so 库文件目录

/system/lib64/android.hardware.testtld-V1-ndk.so 

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

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

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


cc_defaults {
    name: "libservices.core-libs",
    shared_libs: [
        ........
        "libbinder_ndk",
        "android.hardware.testtld-V1-ndk",
        ........
    ],

调用文件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/android/hardware/testtld/IHelloTest.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::android::hardware::testtld::IHelloTest;
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("android.hardware.testtld.IHelloTest/default"));
    if (binder.get() == nullptr) {
        ALOGE("---- AIDL is not present---");
    } else {
            ALOGE("---- AIDL is  present---");
            std::string mName="def";
            std::int32_t in_event =456 ;
            int32_t* aidl_return = new int32_t;
            IHelloTest::fromBinder(binder)->getTestOne(in_event,mName,aidl_return);
            ALOGD("------success to get IHelloTest service----aidl_return:%d", static_cast<int>(*aidl_return));
    }
}

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

frameworks/base/services/core/Android.bp

    static_libs: [
        ....
        "android.hardware.testtld-V1-java", // AIDL
        .....
    ],

调用文件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 android.hardware.testtld.IHelloTest;

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));
                nativeSetTestOne(flag);
                try {
                    Slog.d(TAG, "----Trying to get AIDL service----");
                    ///通过ServiceManager获得aidl服务
                    IHelloTest serviceAidl =
                    IHelloTest.Stub.asInterface(
                                    ServiceManager.getService("android.hardware.testtld.IHelloTest/default"));
                    if (serviceAidl != null) {
                        Slog.d(TAG, "-----success to get IHelloTest AIDL service--111---");
                        int result = serviceAidl.getTestOne(123,"abc");
                        Slog.d(TAG, "-----success to get IHelloTest AIDL service-result:" + result);
                    }
                } catch (Exception eAidl) {
                    Slog.e(TAG, "-----Failed to get IHelloTest AIDL service-----", eAidl);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

APP 调用 

app的libs引入jar包android.hardware.testtld-V1-java.jar,导入方式implementaion ,同时引入framework.jar方式compileOnly。

jar位置:out/soong/.intermediates/hardware/interfaces/testtld/aidl/vandroid.hardware.testtld-V1-java/android_common/javac目录下

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

 
   
package xxxxxx;
import android.util.Log;
import android.os.ServiceManager;
import android.hardware.testtld.IHelloTest;

public class Test{

        public void setTestOne()   {
     
               try {
                Log.d(TAG, "------setTestOne--------flag:" + String.valueOf(flag));
                nativeSetTestOne(flag);
                try {
                    Log.d(TAG, "----Trying to get AIDL service----");
                    ///通过ServiceManager获得aidl服务
                    IHelloTest serviceAidl =
                    IHelloTest.Stub.asInterface(
                                    ServiceManager.getService("android.hardware.testtld.IHelloTest/default"));
                    if (serviceAidl != null) {
                        Log.d(TAG, "-----success to get IHelloTest AIDL service--111---");
                        int result = serviceAidl.getTestOne(123,"abc");
                       Log.d(TAG, "-----success to get IHelloTest AIDL service-result:" + result);
                    }
                } catch (Exception eAidl) {
                    Log.e(TAG, "-----Failed to get IHelloTest AIDL service-----", eAidl);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

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

allow hal_hellotest servicemanager:binder { call transfer };
allow {  platform_app system_app shell } hal_hellotest_hwservice:hwservice_manager { find };
allow {  platform_app system_app untrusted_app_29 shell } hal_hellotest:binder {call};