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/