Android12 AIDL native层实现

本文主要是讲解如何实现一个完整的AIDL HAL层的例子,包括aidl文件的编写、service的实现、测试用例的实现、开机启动以及编译过程中和运行时的错误如何解决。此文不讲解AIDL的原理,具体原理的了解请参考官方资料:https://source.android.com/docs/core/architecture/aidl?hl=zh-cn

生成中间库

创建code路径:vendor/xxxx/proprietary/hardware/interfaces/helloworld

在上面的目录下创建子路径:aidl/vendor/hardware/helloworld

创建Android.bp和IHelloWorld.aidl,文件位置如下:

1.	vendor/xxxx/proprietary/hardware/interfaces/helloworld$ tree  
2.	.  
3.	└── aidl  
4.	    ├── Android.bp  
5.	    └── vendor  
6.	        └── hardware  
7.	            └── helloworld  
8.	                └── IHelloWorld.aidl  

Android.bp内容:

1.	aidl_interface {  
2.	    name: "vendor.hardware.helloworld",  
3.	    vendor_available: true,  
4.	    srcs: ["vendor/hardware/ helloworld /*.aidl"],  
5.	    stability: "vintf",  
6.	    owner: "yezhiqiang",  
7.	    backend: {  
8.	        java: {  
9.	            enabled: true,  
10.	            platform_apis: true,  
11.	        },  
12.	        ndk: {  
13.	            enabled: true,  
14.	        },  
15.	        cpp: {  
16.	            enabled: true,  
17.	        },  
18.	    },  
19.	}  

IHelloWorld.aidl内容:

1.	package vendor.hardware.helloworld;  
2.	  
3.	@VintfStability  
4.	interface IHelloWorld {  
5.	        void sayWhat(String what);  
6.	}  

尝试编译:mmm vendor/xxxx/proprietary/hardware/interfaces/helloworld/aidl/

发生错误如下:

FAILED: out/soong/.intermediates/vendor/xxxx/proprietary/hardware/interfaces/helloworld/aidl/vendor.hardware.helloworld-api/checkapi_current.timestamp  
echo "API dump for the current version of AIDL interface vendor.hardware.helloworld does not exist." && echo Run "m vendor.hardware.helloworld-update-api", or add "unstable: true" to the build rule for the interface if it does not need to be versioned && false # hash of input list: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  
API dump for the current version of AIDL interface vendor.hardware.helloworld does not exist.  
Run m vendor.hardware.helloworld-update-api, or add unstable: true to the build rule for the interface if it does not need to be versioned  

虽然出错,但此时已经在out目录下创建了部分目录:

1.	//out/soong/.intermediates/vendor/xxxx/proprietary/hardware/interfaces/helloworld/aidl/  
2.	vendor.hardware.helloworld-api/  
3.	vendor.hardware.helloworld-V1-java/  

根据提示,需要执行命令:m vendor.hardware.helloworld-update-api

成功时打印如下信息:

[100% 13/13] //vendor/xxxx/proprietary/hardware/interfaces/helloworld/aidl:vendor.hardware.helloworld-api Making AIDL API of vendor.hardware.helloworld as version c  

此时,会在aidl_api/vendor.hardware.helloworld/目录下生成current及其内部的内容。

回过头来,再次执行:

mmm vendor/xxxx/proprietary/hardware/interfaces/helloworld/aidl/,编译成功。

此时发现out目录下生成了很多目录:

那么执行到这一步,其实在out目录下已经生成了binder的各种类型的源文件以及各种IBinder库了。

编写services

创建default目录及相应服务程序,文件列表如下:

vendor/xxxx/proprietary/hardware/interfaces/helloworld/aidl/default$ tree  
.  
├── Android.bp  
├── HelloWorld.cpp  
├── HelloWorld.h  
├── service.cpp  
├── vendor.hardware.helloworld-service.rc  
└── vendor.hardware.helloworld-service.xml  

Android.bp内容:

1.	cc_binary {  
2.	    name: "vendor.hardware.helloworld-service",  
3.	    relative_install_path: "hw",  
4.	    init_rc: ["vendor.hardware.helloworld-service.rc"],  
5.	    vintf_fragments: ["vendor.hardware.helloworld-service.xml"],  
6.	    vendor: true,  
7.	    srcs: [  
8.	        "service.cpp",  
9.	        "HelloWorld.cpp",  
10.	    ],  
11.	    shared_libs: [  
12.	        "vendor.hardware.helloworld-V1-ndk_platform",  
13.	         "liblog",  
14.	        "libbase",  
15.	        "libbinder_ndk",  
16.	    ],  
17.	}  

HelloWorld.h内容:

1.	#pragma once  
2.	  
3.	#include <aidl/vendor/hardware/helloworld/BnHelloWorld.h>  
4.	  
5.	namespace aidl {  
6.	namespace vendor {  
7.	namespace hardware {  
8.	namespace helloworld {  
9.	class HelloWorld : public BnHelloWorld {  
10.	public:  
11.	    HelloWorld() = default;  
12.	  
13.	    ::ndk::ScopedAStatus  sayWhat(const std::string& in_what);  
14.	};  
15.	  
16.	  
17.	}  // namespace helloworld  
18.	}  // namespace hardware  
19.	}  // namespace vendor  
20.	}  // namespace aidl  

HelloWorld.cpp内容:

1.	#include "HelloWorld.h"  
2.	#include <iostream>  
3.	#include <log/log.h>
4.	  
5.	namespace aidl {  
6.	namespace vendor {  
7.	namespace hardware {  
8.	namespace helloworld {  
9.	  
10.	::ndk::ScopedAStatus HelloWorld::sayWhat(const std::string& in_what) {  
11.	    ALOGI("client say:%s.", in_what.c_str());
12.	
13.	    return ::ndk::ScopedAStatus::ok();
14.	}  
15.	  
16.	}  // namespace helloworld  
17.	}  // namespace hardware  
18.	}  // namespace vendor  
19.	}  // namespace aidl  

service.cpp内容:

1.	#include <android-base/logging.h>  
2.	#include <android/binder_manager.h>  
3.	#include <android/binder_process.h>  
4.	  
5.	#include "HelloWorld.h"  
6.	  
7.	using ::aidl::vendor::hardware::helloworld::HelloWorld;  
8.	  
9.	int main() {  
10.	    ABinderProcess_setThreadPoolMaxThreadCount(0);  
11.	    std::shared_ptr<HelloWorld> hello = ndk::SharedRefBase::make<HelloWorld>();  
12.	  
13.	    const std::string instance = std::string() + HelloWorld::descriptor + "/default";  
14.	    binder_status_t status = AServiceManager_addService(hello->asBinder().get(), instance.c_str());  
15.	    CHECK(status == STATUS_OK);  
16.	  
17.	    ABinderProcess_joinThreadPool();  
18.	    return -1; // Should never be reached  
19.	}  

vendor.hardware.helloworld-service.rc内容:

1.	service vendor_helloworld_default /vendor/bin/hw/vendor.hardware.helloworld-service  
2.	    class hal  
3.	    user root  
4.	    group root  

vendor.hardware.helloworld-service.xml内容:

1.	<manifest version="1.0" type="device">  
2.	    <hal format="aidl">  
3.	        <name>vendor.hardware.helloworld</name>  
4.	        <version>1</version>  
5.	        <interface>  
6.	            <name>IHelloWorld</name>  
7.	            <instance>default</instance>  
8.	        </interface>  
9.	    </hal>  
10.	</manifest>  

解决启动问题

验证service能否正常启动,将如下文件分别push入系统:

1.	//push to vendor/lib/  
2.	vendor.hardware.helloworld-V1-ndk_platform.so  
3.	//push to vendor/etc/vintf/manifest  
4.	vendor.hardware.helloworld-service.xml  
5.	//push to vendor/etc/init/  
6.	vendor.hardware.helloworld-service.rc  
7.	//push to vendor/bin/hw/  
8.	vendor.hardware.helloworld-service  

手动执行./vendor/bin/hw/vendor.hardware.helloworld-service,报错如下:

1.	05-16 10:10:34.484   208   208 E servicemanager: Could not find vendor.hardware.hw.IHelloWorld/default in the VINTF manifest.  
2.	05-16 10:10:34.484  4696  4696 F vendor.hardware.helloworld-service: Check failed: status == STATUS_OK   
3.	--------- beginning of crash  
4.	05-16 10:10:34.484  4696  4696 F libc    : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 4696 (vendor.hardware), pid 4696 (vendor.hardware)  
5.	05-16 10:10:34.500  4701  4701 I crash_dump32: obtaining output fd from tombstoned, type: kDebuggerdTombstoneProto  
6.	05-16 10:10:34.501   258   258 I tombstoned: received crash request for pid 4696  
7.	05-16 10:10:34.501  4701  4701 I crash_dump32: performing dump of process 4696 (target tid = 4696)  
8.	05-16 10:10:34.520  4701  4701 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***  
9.	05-16 10:10:34.520  4701  4701 F DEBUG   : Build fingerprint: 'Xxxxx/xx_evb_xxxx/xx_evb_xxxx:12/SQ1D.220205.004/eng.E00023.20240314.110003:userdebug/release-keys'  
10.	05-16 10:10:34.520  4701  4701 F DEBUG   : Revision: '0'  
11.	05-16 10:10:34.520  4701  4701 F DEBUG   : ABI: 'arm'  
12.	05-16 10:10:34.520  4701  4701 F DEBUG   : Timestamp: 2024-05-16 10:10:34.503272142+0800  
13.	05-16 10:10:34.521  4701  4701 F DEBUG   : Process uptime: 0s  
14.	05-16 10:10:34.521  4701  4701 F DEBUG   : Cmdline: ./vendor.hardware.helloworld-service  
15.	05-16 10:10:34.521  4701  4701 F DEBUG   : pid: 4696, tid: 4696, name: vendor.hardware  >>> ./vendor.hardware.helloworld-service <<<  
16.	05-16 10:10:34.521  4701  4701 F DEBUG   : uid: 0  
17.	05-16 10:10:34.521  4701  4701 F DEBUG   : signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------  
18.	05-16 10:10:34.521  4701  4701 F DEBUG   : Abort message: 'Check failed: status == STATUS_OK '  
19.	05-16 10:10:34.521  4701  4701 F DEBUG   :     r0  00000000  r1  00001258  r2  00000006  r3  ffa26c50  
20.	05-16 10:10:34.521  4701  4701 F DEBUG   :     r4  ffa26c64  r5  ffa26c48  r6  00001258  r7  0000016b  
21.	05-16 10:10:34.521  4701  4701 F DEBUG   :     r8  ffa26c50  r9  ffa26c60  r10 ffa26c80  r11 ffa26c70  
22.	05-16 10:10:34.521  4701  4701 F DEBUG   :     ip  00001258  sp  ffa26c20  lr  f41fee69  pc  f41fee7c  
23.	05-16 10:10:34.521  4701  4701 F DEBUG   : backtrace:  
24.	05-16 10:10:34.521  4701  4701 F DEBUG   :       #00 pc 00038e7c  /apex/com.android.runtime/lib/bionic/libc.so (abort+172) (BuildId: 6fe5d03094b6a4257b4dce75d0d315fe)  
25.	05-16 10:10:34.521  4701  4701 F DEBUG   :       #01 pc 000048fb  /system/lib/liblog.so (__android_log_default_aborter+6) (BuildId: 7e7368d7d9eae3d9600145f485b59ddc)  
26.	05-16 10:10:34.522  4701  4701 F DEBUG   :       #02 pc 0000ef17  /apex/com.android.vndk.v31/lib/libbase.so (android::base::LogMessage::~LogMessage()+238) (BuildId: 817e26a81d950aec834317a5a87d17db)  
27.	05-16 10:10:34.522  4701  4701 F DEBUG   :       #03 pc 000021f5  /vendor/bin/hw/vendor.hardware.helloworld-service (main+360) (BuildId: 7e9de488a3879701621129888c474439)  
28.	05-16 10:10:34.522  4701  4701 F DEBUG   :       #04 pc 0003244b  /apex/com.android.runtime/lib/bionic/libc.so (__libc_init+54) (BuildId: 6fe5d03094b6a4257b4dce75d0d315fe)  

出现上述问题的根本原因是:未将我们生成的接口添加入兼容性矩阵中。找到vendor自己客制化的兼容性矩阵文件:manifest.xml或compatibility_matrix.xml。

例如:

1.	device/xxxx/common/products/tv/manifest/manifest.xml  
2.	或
3.	device/xxxx/yyyy/manifest/compatibility_matrix.xml  
4.	device/xxxx/yyyy/manifest/manifest.xml  

将如下内容添加到xml文件中:

1.	<!-- device/xxxx/common/products/tv/manifest/manifest.xml -->  
2.	    <hal format="aidl">  
3.	        <name>vendor.hardware.helloworld</name>  
4.	        <version>1</version>  
5.	        <interface>  
6.	            <name>IHelloWorld</name>  
7.	            <instance>default</instance>  
8.	        </interface>  
9.	    </hal>  

整编系统,重新烧写super img。再次运行service即可正常启动。

开机自启动service

创建domain,否则开机不会被init进程启动。

在device/xxxx/common/sepolicy/目录下创建:hal_helloworld_default.te文件,添加内容如下:

1.	//device/xxxx/common/sepolicy/hal_helloworld_default.te  
2.	type hal_helloworld_default, domain;  
3.	type hal_helloworld_default_exec, exec_type, vendor_file_type, file_type;  
4.	init_daemon_domain(hal_helloworld_default)  

在file_context文件中添加内容:

1.	//device/xxxx/common/sepolicy/file_contexts  
2.	/vendor/bin/hw/vendor\.hardware\.helloworld-service    u:object_r:hal_helloworld_default_exec:s0  

整编系统,重新烧写super img。重新启动系统抓取log,检查并解决剩余的selinux问题。Log中会有如下错误:

1.	Line 4765: 08-08 16:08:21.780   353   353 W vendor.hardware: type=1400 audit(0.0:6): avc: denied { call } for scontext=u:r:hal_helloworld_default:s0 tcontext=u:r:servicemanager:s0 tclass=binder permissive=0  
2.	Line 4766: 08-08 16:08:21.784   353   353 W vendor.hardware: type=1400 audit(0.0:7): avc: denied { call } for scontext=u:r:hal_helloworld_default:s0 tcontext=u:r:servicemanager:s0 tclass=binder permissive=0  

针对上述错误为hal_helloworld_default添加访问规则:

1.	//device/xxxx/common/sepolicy/hal_helloworld_default.te  
2.	type hal_helloworld_default, domain;  
3.	type hal_helloworld_default_exec, exec_type, vendor_file_type, file_type;  
4.	init_daemon_domain(hal_helloworld_default)  
5.	
6.	allow hal_helloworld_default servicemanager:binder { call };

解决完上述selinux问题后,又会出现其他selinux错误,例如:

1.	Line 5117: 08-08 16:08:21.908   356   356 W vendor.hardware: type=1400 audit(0.0:6): avc: denied { transfer } for scontext=u:r:vendor_helloworld_default:s0 tcontext=u:r:servicemanager:s0 tclass=binder permissive=0  
2.	08-08 16:08:21.958   207   207 E SELinux : avc:  denied  { add } for pid=358 uid=0 name=vendor.hardware.hw.IHelloWorld/default scontext=u:r:vendor_helloworld_default:s0 tcontext=u:object_r:default_android_service:s0 tclass=service_manager permissive=0

按部就班继续添加规则即可,最终内容如下:

1.	//device/xxxx/common/sepolicy/hal_helloworld_default.te  
2.	hal_attribute(helloworld);
3.	
4.	type hal_helloworld_default, domain;
5.	hal_server_domain(hal_helloworld_default, hal_helloworld)
6.	
7.	type hal_helloworld_default_exec, exec_type, vendor_file_type, file_type;  
8.	init_daemon_domain(hal_helloworld_default)  
9.	
10.	allow hal_helloworld_default servicemanager:binder { call transfer };
11.	add_service(hal_helloworld_default, hal_helloworld_service);
12.	
13.	//device/xxxx/common/sepolicy/file_contexts
14.	/vendor/bin/hw/vendor\.hardware\.helloworld-service     u:object_r:hal_helloworld_default_exec:s0
15.	
16.	//device/xxxx/common/sepolicy/service_contexts  
17.	vendor.hardware.helloworld.IHelloWorld/default      u:object_r:hal_helloworld_service:s0  
18.	
19.	//device/xxxx/common/sepolicy/service.te  
20.	type hal_helloworld_service, vendor_service, service_manager_type;  

整编系统,重新烧写super img,push入系统,可以看到vendor.hardware.helloworld-service已经可以自启动了。

编写测试程序

在目录中分别创建文件:

1.	//vendor/xxxx/proprietary/hardware/interfaces/helloworld/aidl/test  
2.	.  
3.	├── Android.bp  
4.	└── main.cpp  

Android.bp内容:

1.	//vendor/xxxx/proprietary/hardware/interfaces/helloworld/aidl/test/Android.bp  
2.	cc_binary {  
3.	    name: "helloworld-test",  
4.	    vendor: true,  
5.	    srcs: [  
6.	        "main.cpp",  
7.	    ],  
8.	    shared_libs: [  
9.	        "vendor.hardware.helloworld-V1-ndk_platform",  
10.	        "libutils",  
11.	        "libcutils",  
12.	        "liblog",  
13.	        "libbase",  
14.	        "libbinder_ndk",  
15.	    ],  
16.	} 

main.cpp内容:

1.	//vendor/xxxx/proprietary/hardware/interfaces/helloworld/aidl/test/main.cpp  
2.	#include <iostream>  
3.	  
4.	#include <android/binder_manager.h>  
5.	#include <android/binder_process.h>  
6.	#include <aidl/vendor/hardware/helloworld/IHelloWorld.h>  
7.	  
8.	using aidl::vendor::hardware::helloworld::IHelloWorld;  
9.	  
10.	int main() {  
11.	    std::cout << "client: hello world test begin =>" << std::endl;  
12.	  
13.	    std::shared_ptr<IHelloWorld> hello = IHelloWorld::fromBinder(::ndk::SpAIBinder(AServiceManager_getService("vendor.hardware.helloworld.IHelloWorld/default")));  
14.	    if (hello == nullptr) {  
15.	        std::cout << "client: get service error..." << std::endl;  
16.	        return -1;  
17.	    }  
18.	  
19.	    std::cout << "client: say 'hello China.'" << std::endl;  
20.	    hello->sayWhat("hello China");  
21.	  
22.	    std::cout << "client: hello world test end <=" << std::endl;  
23.	    return 0;  
24.	}  

编译测试模块push入系统并执行。

Client shell端口打印如下:

Server的log通过logcat抓取,可以看到:

  • 28
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android中,可以使用AIDLAndroid Interface Definition Language)来定义跨进程通信的接口。如果要让Java客户端调用本地实现AIDL服务,可以使用JNI来实现。以下是实现步骤: 1.编写本地服务代码:使用C或C++编写本地服务的代码,并将其编译成本地库,例如.dll文件(Windows平台)或.so文件(Linux平台)。 2.编写AIDL接口:在Android中,使用AIDL定义接口。你需要编写一个AIDL文件来定义服务的接口。 3.编写Java代码:在Java中编写客户端代码,并使用JNI调用本地库。你需要将AIDL接口转换为Java接口,并使用JNI调用本地实现。 4.将本地库加载到Java中:使用System.loadLibrary()方法将本地库加载到Java中。 5.连接到服务:在Java代码中连接到AIDL服务。 以下是一个简单的示例代码: C/C++本地服务代码: ```c #include <jni.h> JNIEXPORT jstring JNICALL Java_com_example_MyService_nativeMethod(JNIEnv *env, jobject obj) { return (*env)->NewStringUTF(env, "Hello from native method!"); } ``` AIDL接口: ```aidl interface IMyService { String sayHello(); } ``` Java客户端代码: ```java public class MyService extends Service { // 定义本地方法 private native String nativeMethod(); // 实现AIDL接口 private final IMyService.Stub mBinder = new IMyService.Stub() { @Override public String sayHello() throws RemoteException { return nativeMethod(); // 调用本地方法 } }; @Override public IBinder onBind(Intent intent) { return mBinder; // 返回AIDL接口 } static { System.loadLibrary("mylib"); // 加载本地库 } } ``` 注意:这只是一个简单的示例,实际情况可能更加复杂。你需要仔细阅读JNI和AIDL文档,并且确保你的本地代码和Java代码之间的交互是正确的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值