hal深入剖析之aidl实战-android framework车机车载手机系统开发

1、创建相关的目录hal目录及aidl存放目录

~/nx563j_xiaomi$ mkdir hardware/interfaces/mytest
~/nx563j_xiaomi$ cd hardware/interfaces/mytest/

这个是hal工程根目录

接下来要创建aidl的文件存放目录

test@test:~/nx563j_xiaomi/hardware/interfaces/mytest$ mkdir aidl
test@test:~/nx563j_xiaomi/hardware/interfaces/mytest$ cd aidl/
test@test:~/nx563j_xiaomi/hardware/interfaces/mytest/aidl$ mkdir -p  android/hardware/mytest

注意mkdir -p android/hardware/mytest其实就是包名目录,即模块包名就是android.hardware.mytest.

提示:这个如果为了项目的更加好的维护性建议到自己项目目标的vendor下面进行,目前只是为了演示方便,直接在system的hardware下面

2、创建定义对应aidl文件

创建最重要的aidl接口文件,需要在第一步创建的目录下

test@test:~/nx563j_xiaomi/hardware/interfaces/mytest/aidl/android/hardware/mytest$ touch IMyTest.aidl
test@test:~/nx563j_xiaomi/hardware/interfaces/mytest/aidl/android/hardware/mytest$ touch MyTestObj.aidl
test@test:~/nx563j_xiaomi/hardware/interfaces/mytest/aidl$ tree
.
`-- android
    `-- hardware
        `-- mytest
            |-- IMyTest.aidl
            `-- MyTestObj.aidl

编写aidl内容:

IMyTest.aidl

package android.hardware.mytest; 
import android.hardware.mytest.MyTestObj; 
@VintfStability 
interface IMyTest { MyTestObj test();
}

MyTestObj.aidl

package android.hardware.mytest; 
@VintfStability 
parcelable MyTestObj { String key;
    int value;
}

其实和普通的aidl基本一样,唯一差别就是要多一些稳定性的声明比如@VintfStability这个注解官方解释如下:

VintfStability
VintfStability declares that a user-defined type (interface, parcelable, and enum) can be used across the system and vendor domains.

还是就是parcelable都是需要进行结构化,成员属性写清楚到aidl

3、编写顶层aidl的Android.bp

最开始的aidl目录创建一个Android.bp

test@test:~/nx563j_xiaomi/hardware/interfaces/mytest/aidl$ touch Android.bp

Android.bp

aidl_interface { name: "android.hardware.mytest",
    vendor_available: true,
    srcs: ["android/hardware/mytest/*.aidl"],
    stability: "vintf",
    owner:"qianli.ma",
    backend: { cpp: { enabled: false,
        },
        java: { sdk_version: "module_current",
        },
    },
}

需要注意以下几个点:

1、要写aidl_interface目标

2、设置成 vendor_available: true即代表vendor和system都可以用,不是vendor独享

3、stability: “vintf” stability保证接口是稳定的属性,目前只支持vintf

4、backend 这里的后端有4个,C++/JAVA/NDK/RUST, 我们将使用NDK和java,因此将CPP声明为false,为啥不使用c++呢?为啥出来个ndk呢?这个google官方给出了解释

https://source.android.google.cn/docs/core/architecture/aidl/aidl-hals#choosing-runtime

Building against the AIDL runtime
AIDL has three different backends: Java, NDK, CPP. To use Stable AIDL, you must always use the system copy of libbinder at system/lib*/libbinder.so and talk on /dev/binder. For code on the vendor image, this means that libbinder (from the VNDK) cannot be used: this library has an unstable C++ API and unstable internals. Instead, native vendor code must use the NDK backend of AIDL, link against libbinder_ndk (which is backed by system libbinder.so), and link against the -ndk_platform libraries created by aidl_interface entries.

大概意思就是一般aidl的vendor和system跨进程中不使用libbinder的包,因为一般vendor使用是vndk下面的包,故无法访问dev/binder,访问其实是dev/vndbinder,所有一般使用是NDK

4、编译接口文件

编译命令:

test@test:~/nx563j_xiaomi$ mmm hardware/interfaces/mytest

但是出现如下错误

[ 62% 200/319] echo "API dump for the current version of AIDL interface android.hardware.mytest does not exist." && echo Run "m android.hardware.mytest-update-api", or add "unstable: true" to the build r
FAILED: out/soong/.intermediates/hardware/interfaces/mytest/aidl/android.hardware.mytest-api/checkapi_current.timestamp
echo "API dump for the current version of AIDL interface android.hardware.mytest does not exist." && echo Run "m android.hardware.mytest-update-api", or add "unstable: true" to the build rule for the int
erface if it does not need to be versioned && false # hash of input list: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
API dump for the current version of AIDL interface android.hardware.mytest does not exist.
Run m android.hardware.mytest-update-api, or add unstable: true to the build rule for the interface if it does not need to be versioned
12:38:45 ninja failed with: exit status 1
#### failed to build some targets (01:04 (mm:ss)) ####

大概意思我们的接口是不存在的需要更新api执行:

m android.hardware.mytest-update-api

下面执行新的编译命令:

m android.hardware.mytest-update-api

成功后如下打印

out/soong/Android-lineage_nx563j.mk was modified, regenerating...
[100% 190/190] //hardware/interfaces/mytest/aidl:android.hardware.mytest-api Updating AIDL API dump version current for android.hardware.mytest (see hardware/interfaces/mytest/aidl/aidl_api/android.hardw
#### build completed successfully (06:57 (mm:ss)) ####

此时的目录已经被生成了aidl_api目录

test@test:~/nx563j_xiaomi/hardware/interfaces/mytest$ tree
.
`-- aidl
    |-- Android.bp
    |-- aidl_api
    |   `-- android.hardware.mytest
    |       `-- current
    |           `-- android
    |               `-- hardware
    |                   `-- mytest
    |                       |-- IMyTest.aidl
    |                       `-- MyTestObj.aidl
    `-- android
        `-- hardware
            `-- mytest
                |-- IMyTest.aidl
                `-- MyTestObj.aidl

然后在进行刚才的编译

test@test:~/nx563j_xiaomi$ mmm hardware/interfaces/mytest

成功后会有如下打印

============================================
[100% 128/128] Install: out/target/product/nx563j/system/framework/android.hardware.mytest-V1-java.jar
#### build completed successfully (03:20 (mm:ss)) ####

这里主要是在编译相关目录生成相关接口代码和库,具体路径如下:

test@test:~/nx563j_xiaomi/out/soong/.intermediates/hardware/interfaces/mytest/aidl$ ls -l
total 20
drwxrwxr-x  3 test test 4096 Dec 12 13:07 android.hardware.mytest-V1-java
drwxrwxr-x  3 test test 4096 Dec 12 13:07 android.hardware.mytest-V1-java-source
drwxrwxr-x 16 test test 4096 Dec 12 13:07 android.hardware.mytest-V1-ndk
drwxrwxr-x  3 test test 4096 Dec 12 13:07 android.hardware.mytest-V1-ndk-source
drwxrwxr-x  3 test test 4096 Dec 12 13:07 android.hardware.mytest-api
test@test:~/nx563j_xiaomi/out/soong/.intermediates/hardware/interfaces/mytest/aidl$ 

因为bp中backend只对ndk和java有开放,c++已经关闭了

android.hardware.mytest-V1-ndk 代表aidl相关的库

android.hardware.mytest-V1-ndk-source 代表aidl相关的源文件比如一些头文件或者bp,bn文件

有了上面的生成代码和库,我们就可以写一个服务端的程序了

5、编写服务端程序代码

准备好相关的源文件和xml,rc配置文件

test@test:~/nx563j_xiaomi/hardware/interfaces/mytest/aidl/default$ tree
.
|-- Android.bp
|-- MyTestImpl.cpp
|-- MyTestImpl.h
|-- android.hardware.mytest.rc
|-- main.cpp
`-- mytest-default.xml
0 directories, 6 files

分为两部分:

源码部分

MyTestImpl.cpp —Binder服务端的具体实现部分cpp

#define LOG_TAG "MyTestImpl"
#define LOG_NDEBUG 0
#include "MyTestImpl.h"
#include #include namespace aidl::android::hardware::mytest { ::ndk::ScopedAStatus MyTestImpl::test(::aidl::android::hardware::mytest::MyTestObj* _aidl_return) { *_aidl_return = mObj;
        ALOGE(" MyTestImpl::test ok");
        return ::ndk::ScopedAStatus::ok();
}
}  // namespace aidl::android::hardware::mytest

MyTestImpl.h—Binder服务端的具体实现部分头文件

#ifndef ANDROID_HARDWARE_MYTESTIMPL_H
#define ANDROID_HARDWARE_MYTESTIMPL_H
#include 
namespace aidl::android::hardware::mytest {class MyTestImpl : public BnMyTest { public:
    ::aidl::android::hardware::mytest::MyTestObj  mObj = {"hello",1};
    ::ndk::ScopedAStatus test(::aidl::android::hardware::mytest::MyTestObj* _aidl_return) override;
};
}  // namespace aidl::android::hardware::mytest
#endif 

main.cpp ----主程序入口cpp

#include "MyTestImpl.h"
#define LOG_TAG "MyTestImpl"
#define LOG_NDEBUG 0
#include #include 
#include 
#include 
#include using aidl::android::hardware::mytest::MyTestImpl;
int main() { ABinderProcess_setThreadPoolMaxThreadCount(0);
    std::shared_ptr test = ::ndk::SharedRefBase::make();
    const std::string instance = std::string() + MyTestImpl::descriptor + "/default";
    printf("MyTestImpl instance =%s  sde =%p \n", instance.c_str(),test->asBinder().get());
    binder_status_t status =
          AServiceManager_addService(test->asBinder().get(), instance.c_str());
    CHECK_EQ(status, STATUS_OK);
    printf("MyTestImpl AServiceManager_addService status=%d \n", status);
    fflush(stdout);
    ABinderProcess_joinThreadPool();
    return EXIT_FAILURE;  // should not reach
}
bp和配置文件部分

Android.bp --编译可执行文件的bp

cc_binary { name: "android.hardware.mytest.example",
    relative_install_path: "hw",
    vendor: true,
    init_rc: ["android.hardware.mytest.rc"],
    vintf_fragments: ["mytest-default.xml"],
    shared_libs: [
        "android.hardware.mytest-V1-ndk", 
        "liblog",
        "libbase",
        "libcutils",
        "libutils",
        "libbinder_ndk",
    ],
    srcs: [
        "main.cpp",
        "MyTestImpl.cpp",
    ],
}

android.hardware.mytest.rc --开机自启动

service vendor.mytest-default /vendor/bin/hw/android.hardware.mytest.example
    class hal
    user root
    group root

mytest-default.xml ----声明接口到vintf中

  android.hardware.mytest 1  IMyTest default  

然后再执行编译命令:

 mmm hardware/interfaces/mytest/

出现如下成功提示:

aservices
============================================
[100% 10/10] Install: out/target/product/nx563j/vendor/bin/hw/android.hardware.mytest.example
#### build completed successfully (5 seconds) ####

到此基本上aidl业务模块就完成了,一个简单接口实现就好了

6、模块加入到兼容性矩阵中

应该添加到的目录即文件

hardware/interfaces/compatibility_matrices

test@test:~/nx563j_xiaomi/hardware/interfaces/compatibility_matrices$ ll
total 188
drwxrwxr-x  4 test test  4096 Dec 12 11:39 ./
drwxrwxr-x 54 test test  4096 Dec 12 11:43 ../
-rw-rw-r--  1 test test  2764 Mar  4  2023 Android.bp
-rw-rw-r--  1 test test  4860 Mar  4  2023 Android.mk
-rw-rw-r--  1 test test  2440 Mar  4  2023 CleanSpec.mk
drwxrwxr-x  2 test test  4096 Mar  4  2023 build/
-rw-rw-r--  1 test test   942 Mar  4  2023 clear_vars.mk
-rw-rw-r--  1 test test 15448 Mar  4  2023 compatibility_matrix.3.xml
-rw-rw-r--  1 test test 16709 Mar  4  2023 compatibility_matrix.4.xml
-rw-rw-r--  1 test test 18568 Mar  4  2023 compatibility_matrix.5.xml
-rw-rw-r--  1 test test 21273 Mar  4  2023 compatibility_matrix.6.xml
-rw-rw-r--  1 test test 26116 Dec 12 11:39 compatibility_matrix.7.xml
-rw-rw-r--  1 test test 26380 Dec 12 11:39 compatibility_matrix.current.xml
-rw-rw-r--  1 test test    56 Mar  4  2023 compatibility_matrix.empty.xml
-rw-rw-r--  1 test test  5349 Mar  4  2023 compatibility_matrix.mk
drwxrwxr-x  3 test test  4096 Mar  4  2023 exclude/
-rw-rw-r--  1 test test    41 Mar  4  2023 manifest.empty.xml

这里应该选数字最大的7和current两个xml文件

compatibility_matrix.7.xml

compatibility_matrix.current.xml

2个文件加入如下内容:

  android.hardware.mytest 1  IMyTest default  

7、增加对应selinux权限

这里直接做成了一个patch方便大家直接apply

到system/sepolicy/然后apply下面这个patch

add-selinux.patch

commit 7b459a68fe188b9f051850ac0629c868a31de2c2
Author: Your Name Date:   Sun Oct 8 10:03:22 2023 +0800
    add selinux for hal mytest
    
    Change-Id: I5feeec2aa30cd7fe0d306922225d512c10a0725e
diff --git a/prebuilts/api/33.0/private/hwservice_contexts b/prebuilts/api/33.0/private/hwservice_contexts
index 4a44dc58b..8092f0485 100644
--- a/prebuilts/api/33.0/private/hwservice_contexts
+++ b/prebuilts/api/33.0/private/hwservice_contexts
@@ -6,6 +6,7 @@ android.frameworks.schedulerservice::ISchedulingPolicyService   u:object_r:fwk_s
 android.frameworks.sensorservice::ISensorManager                u:object_r:fwk_sensor_hwservice:s0
 android.frameworks.stats::IStats                                u:object_r:fwk_stats_hwservice:s0
 android.hardware.atrace::IAtraceDevice                          u:object_r:hal_atrace_hwservice:s0
+android.hardware.mytest::IMyTest                                u:object_r:hal_mytest_hwservice:s0
 android.hardware.audio.effect::IEffectsFactory                  u:object_r:hal_audio_hwservice:s0
 android.hardware.audio::IDevicesFactory                         u:object_r:hal_audio_hwservice:s0
 android.hardware.authsecret::IAuthSecret                        u:object_r:hal_authsecret_hwservice:s0
diff --git a/prebuilts/api/33.0/private/service_contexts b/prebuilts/api/33.0/private/service_contexts
index 72fa16629..936638f18 100644
--- a/prebuilts/api/33.0/private/service_contexts
+++ b/prebuilts/api/33.0/private/service_contexts
@@ -15,6 +15,7 @@ android.hardware.contexthub.IContextHub/default                      u:object_r:
 android.hardware.drm.IDrmFactory/clearkey                            u:object_r:hal_drm_service:s0
 android.hardware.drm.ICryptoFactory/clearkey                         u:object_r:hal_drm_service:s0
 android.hardware.dumpstate.IDumpstateDevice/default                  u:object_r:hal_dumpstate_service:s0
+android.hardware.mytest.IMyTest/default                  	     u:object_r:hal_mytest_service:s0
 android.hardware.gnss.IGnss/default                                  u:object_r:hal_gnss_service:s0
 android.hardware.graphics.allocator.IAllocator/default               u:object_r:hal_graphics_allocator_service:s0
 android.hardware.graphics.composer3.IComposer/default                u:object_r:hal_graphics_composer_service:s0
diff --git a/private/hwservice_contexts b/private/hwservice_contexts
index 4a44dc58b..8092f0485 100644
--- a/private/hwservice_contexts
+++ b/private/hwservice_contexts
@@ -6,6 +6,7 @@ android.frameworks.schedulerservice::ISchedulingPolicyService   u:object_r:fwk_s
 android.frameworks.sensorservice::ISensorManager                u:object_r:fwk_sensor_hwservice:s0
 android.frameworks.stats::IStats                                u:object_r:fwk_stats_hwservice:s0
 android.hardware.atrace::IAtraceDevice                          u:object_r:hal_atrace_hwservice:s0
+android.hardware.mytest::IMyTest                                u:object_r:hal_mytest_hwservice:s0
 android.hardware.audio.effect::IEffectsFactory                  u:object_r:hal_audio_hwservice:s0
 android.hardware.audio::IDevicesFactory                         u:object_r:hal_audio_hwservice:s0
 android.hardware.authsecret::IAuthSecret                        u:object_r:hal_authsecret_hwservice:s0
diff --git a/private/service_contexts b/private/service_contexts
index 72fa16629..936638f18 100644
--- a/private/service_contexts
+++ b/private/service_contexts
@@ -15,6 +15,7 @@ android.hardware.contexthub.IContextHub/default                      u:object_r:
 android.hardware.drm.IDrmFactory/clearkey                            u:object_r:hal_drm_service:s0
 android.hardware.drm.ICryptoFactory/clearkey                         u:object_r:hal_drm_service:s0
 android.hardware.dumpstate.IDumpstateDevice/default                  u:object_r:hal_dumpstate_service:s0
+android.hardware.mytest.IMyTest/default                  	     u:object_r:hal_mytest_service:s0
 android.hardware.gnss.IGnss/default                                  u:object_r:hal_gnss_service:s0
 android.hardware.graphics.allocator.IAllocator/default               u:object_r:hal_graphics_allocator_service:s0
 android.hardware.graphics.composer3.IComposer/default                u:object_r:hal_graphics_composer_service:s0
diff --git a/vendor/file_contexts b/vendor/file_contexts
index 392a750fd..b87914600 100644
--- a/vendor/file_contexts
+++ b/vendor/file_contexts
@@ -105,6 +105,7 @@
 /(vendor|system/vendor)/bin/hw/wpa_supplicant                                 u:object_r:hal_wifi_supplicant_default_exec:s0
 /(vendor|system/vendor)/bin/install-recovery\.sh                              u:object_r:vendor_install_recovery_exec:s0
 /(vendor|system/vendor)/bin/vndservicemanager                                 u:object_r:vndservicemanager_exec:s0
+/(vendor|system/vendor)/bin/hw/android\.hardware\.mytest\.example         	 u:object_r:hal_mytest_default_exec:s0
 
 #############################
 # Same process HALs installed by platform into /vendor
diff --git a/vendor/hal-aidl-mytest.te b/vendor/hal-aidl-mytest.te
new file mode 100644
index 000000000..378df3826
--- /dev/null
+++ b/vendor/hal-aidl-mytest.te
@@ -0,0 +1,39 @@
+# type hal_mytest, domain;
+# type hal_mytest_service, vendor_service, service_manager_type;
+# type hal_mytest_hwservice, hwservice_manager_type, protected_hwservice;
+# type hal_mytest_default_exec, exec_type, vendor_file_type, file_type;
+# init_daemon_domain(hal_mytest);
+
+
+
+# get_prop(hal_mytest, hwservicemanager_prop)
+# add_hwservice(hal_mytest, hal_mytest_hwservice)
+# hwbinder_use(hal_mytest);
+
+
+# allow platform_app hal_mytest_hwservice:hwservice_manager { find };
+# allow platform_app hal_mytest:binder {call};
+
+
+hal_attribute(mytest);
+type hal_mytest_default, domain, mlstrustedsubject;
+hal_server_domain(hal_mytest_default, hal_mytest);
+type hal_mytest_default_exec, exec_type, vendor_file_type, file_type;
+init_daemon_domain(hal_mytest_default);
+
+#Allow hwbinder call form hal client to server
+binder_call(hal_mytest_client, hal_mytest_default_exec)
+
+#add hwservice related rules
+type hal_mytest_service, vendor_service, service_manager_type;
+type hal_mytest_hwservice, hwservice_manager_type, protected_hwservice;
+get_prop(hal_mytest, hwservicemanager_prop)
+add_service(hal_mytest_default, hal_mytest_service)
+add_hwservice(hal_mytest_server, hal_mytest_hwservice)
+allow hal_mytest_client hal_mytest_hwservice:hwservice_manager find;
+hal_client_domain(system_server, hal_mytest)
+hwbinder_use(hal_mytest);
+
+allow hal_mytest_default servicemanager:binder { call transfer };
+allow { platform_app shell } hal_mytest_hwservice:hwservice_manager { find };
+allow { platform_app shell } hal_mytest:binder {call};

8、编写一个测试模块,来测试一下aidl的hal是否正常运行

aidl目录下创建一个test_hal目录:

test_hal/
|-- Android.bp
`-- main.cpp

Android.bp

cc_binary { name: "test-hal-mytest",
    shared_libs: [
        "android.hardware.mytest-V1-ndk", 
        "liblog",
        "libbase",
        "libcutils",
        "libutils",
        "libbinder_ndk",
    ],
    srcs: [
        "main.cpp",
    ],
}

主要就是需要引入 “android.hardware.mytest-V1-ndk”, 这个依赖库

main.cpp

#define LOG_TAG "Test-HAL"
#define LOG_NDEBUG 0
#include #include #include 
#include 
#include 
#include using aidl::android::hardware::mytest::IMyTest;
int main() { printf("test hal mytest main 1\n");
    std::shared_ptr service = IMyTest::fromBinder(ndk::SpAIBinder(AServiceManager_getService("android.hardware.mytest.IMyTest/default")));
    printf("test hal mytest service = %p\n",service.get());
    ALOGE("Test hal  MyTest");
    if (service == nullptr) { return -1;
    }
    ::aidl::android::hardware::mytest::MyTestObj obj;
    service->test(&obj);
    printf("test hal mytest main  test result  %s %d \n",obj.key.c_str(),obj.value);
    fflush(stdout);
    return EXIT_FAILURE;  // should not reach
} 

9、device下面加入相关的程序进入编译到整机

device/nubia/nx563j/device.mk文件中加入如下:

PRODUCT_PACKAGES += \
    android.hardware.mytest \
    android.hardware.mytest.example \
    test-hal-mytest \

10、测试部分

测试方法

1、先看看是否mytest的hal服务是否开机自启动了

2、执行test-hal-mytest看看是否输出正常

本文章对应视频手把手教你学framework:

https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg

私聊作者+v(androidframework007)

点击这里 https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw

视频:https://www.bilibili.com/video/BV1wc41117L4/