首页>资讯>正文
Android Q 打通应用层到 HAL 层 -- ( JNI 服务和 AIDL 服务实现)
2023-03-05 08:42:06    来源:程序员客栈

先回顾一下上一篇关于 HIDL 的内容:


(相关资料图)

什么是HIDL

HIDL 全称为HAL interface definition language(发音为“hide-l”)是用于指定 HAL 和其用户之间的接口的一种接口描述语言 (IDL),Android O开始引入了HIDL这个概念。

HIDL和应用层AIDL差不多,AIDL常用于连接App和Framework,HIDL则是用来连接Framework和HAL,AIDL使用Binder通信,HIDL则使用HwBinder通信,他们都是通过Binder驱动完成通信,只不过两个Binder域不一样

为什么需要 HIDL

目前Android系统生态是几乎每年google都会出一个Android大版本,而普通手机用户一部手机一般要用两三年,所以你会发现尽管Android系统已经升级到了10,马上11出来了,然后还是有很多用户依然使用的是Android 5,6,7等版本。

对普通用户来说如果不更换手机就很难跟上Android版本,这是因为OEM厂商在同一设备上进行系统升级需要花费时间金钱成本很高,导致他们不愿意升级,成本高的原因是Android O之前Android Framework的升级需要OEM将HAL也进行对应升级,Framework和HAL是一起被编译成system.img,它们存在高耦合。

针对这种情况google在Android O中引入了Treble计划,Treble的目的就是解耦Framework和HAL,就是通过HIDL来实现,Framework不再直接调用HAL,而是通过HIDL来间接使用HAL模块,每个HAL模块都可以对应一个HIDL服务,Framework层通过HwBinder创建HIDL服务。

通过HIDL服务来获取HAL相关模块继而打开HAL下的设备,而最终HAL也从system.img中分离,被编进一个单独的分区vendor.img,从而简化了Android系统升级的影响与难度。

这篇文章要写的是JNI服务和framework层AIDL服务实现,由AIDL服务调用JNI层的服务的函数,为了提供给上层APP使用。

JNI 服务和 AIDL 服务实现

同样我们参照系统其他服务的方式来写,来到frameworks/base/services/core/jni目录下,这下面有许多JNI的服务,创建cpp文件com_android_server_am_HelloService.cpp,为什么要叫这个名字,因为等下我们实现的AIDL服务包名为"com.android.server.am"

#include#include#include#include#includeusingandroid::sp;usingandroid::hardware::hello_hidl::V1_0::IHello;namespaceandroid{sphw_device;staticvoidandroid_server_am_HelloService_nativeInit(JNIEnv*/*env*/,jobject/*clazz*/){ALOGW("hello...android_server_am_HelloService_nativeInit.....");hw_device=IHello::getService();if(hw_device==nullptr){ALOGW("hello...failedtogetIHelloservice");return;}ALOGW("hello...successtogetIHelloservice");}staticjintandroid_server_am_HelloService_nativeAdd(JNIEnv*env,jobject/*clazz*/,jinta,jintb){ALOGW("hello...android_server_am_HelloService_nativeAdd.....");uint32_ttotal=hw_device->addition_hidl(a,b);returnreinterpret_cast(total);}staticconstJNINativeMethodgMethods[]={{"nativeAdd","(II)I",(void*)android_server_am_HelloService_nativeAdd},{"nativeInit","()V",(void*)android_server_am_HelloService_nativeInit},};intregister_android_server_am_HelloService(JNIEnv*env){returnjniRegisterNativeMethods(env,"com/android/server/am/HelloService",gMethods,NELEM(gMethods));}};//namespaceandroid

这个JNI服务中定义两个函数,android_server_am_HelloService_nativeAdd 和android_server_am_HelloService_nativeInit,这两个函数是提供给framework层AIDL服务调用的,添加了一些log方便后面验证,对应等下要实现的AIDL服务中的nativeAdd和nativeInit

android_server_am_HelloService_nativeInit函数作用是获取我们上一篇文章实现的HIDL服务IHello

android_server_am_HelloService_nativeAdd函数作用是调用HIDL服务中定义的addition_hidl函数

JNI服务中的函数想要被framework调用还需要通过register_android_server_am_HelloService函数进行注册,"com/android/server/am/HelloService"这个是等下我们要实现的framework层的AIDL服务

接着需要将这个自定义JNI服务添加到onload.cpp中开机注册,打开frameworks/base/services/core/jni/onload.cpp,添加如下代码:

在这里插入图片描述

接着需要修改Android.bp文件,打开frameworks/base/services/core/jni/Android.bp,添加如下代码:

在这里插入图片描述
主要就是将新增文件添加进编译和添加hello_hidl的依赖库,JNI服务已经创建好了,接着,需要创建framework层AIDL服务

首先到frameworks/base/core/java/android/app/目录下创建IHelloService.aidl文件:

packageandroid.app;interfaceIHelloService{intadd(inta,intb);}

想要编译这个文件还需要修改Android.bp,在frameworks/base/Android.bp中添加如下代码:

在这里插入图片描述
然后就可以编译了,mmm frameworks/base
在这里插入图片描述
编译成功后我们可以去out目录下看看IHelloService.aidl编出来的IHelloService.java文件:

/**Thisfileisauto-generated.DONOTMODIFY.*/packageandroid.app;publicinterfaceIHelloServiceextendsandroid.os.IInterface{/**DefaultimplementationforIHelloService.*/publicstaticclassDefaultimplementsandroid.app.IHelloService{@Overridepublicintadd(inta,intb)throwsandroid.os.RemoteException{return0;}@Overridepublicandroid.os.IBinderasBinder(){returnnull;}}/**Local-sideIPCimplementationstubclass.*/publicstaticabstractclassStubextendsandroid.os.Binderimplementsandroid.app.IHelloService{privatestaticfinaljava.lang.StringDESCRIPTOR="android.app.IHelloService";/**Constructthestubatattachittotheinterface.*/publicStub(){this.attachInterface(this,DESCRIPTOR);}/***CastanIBinderobjectintoanandroid.app.IHelloServiceinterface,*generatingaproxyifneeded.*/publicstaticandroid.app.IHelloServiceasInterface(android.os.IBinderobj){if((obj==null)){returnnull;}android.os.IInterfaceiin=obj.queryLocalInterface(DESCRIPTOR);if(((iin!=null)&&(iininstanceofandroid.app.IHelloService))){return((android.app.IHelloService)iin);}returnnewandroid.app.IHelloService.Stub.Proxy(obj);}@Overridepublicandroid.os.IBinderasBinder(){returnthis;}/**@hide*/publicstaticjava.lang.StringgetDefaultTransactionName(inttransactionCode){switch(transactionCode){caseTRANSACTION_add:{return"add";}default:{returnnull;}}}/**@hide*/publicjava.lang.StringgetTransactionName(inttransactionCode){returnthis.getDefaultTransactionName(transactionCode);}@OverridepublicbooleanonTransact(intcode,android.os.Parceldata,android.os.Parcelreply,intflags)throwsandroid.os.RemoteException{java.lang.Stringdescriptor=DESCRIPTOR;switch(code){caseINTERFACE_TRANSACTION:{reply.writeString(descriptor);returntrue;}caseTRANSACTION_add:{data.enforceInterface(descriptor);int_arg0;_arg0=data.readInt();int_arg1;_arg1=data.readInt();int_result=this.add(_arg0,_arg1);reply.writeNoException();reply.writeInt(_result);returntrue;}default:{returnsuper.onTransact(code,data,reply,flags);}}}privatestaticclassProxyimplementsandroid.app.IHelloService{privateandroid.os.IBindermRemote;Proxy(android.os.IBinderremote){mRemote=remote;}@Overridepublicandroid.os.IBinderasBinder(){returnmRemote;}publicjava.lang.StringgetInterfaceDescriptor(){returnDESCRIPTOR;}@Overridepublicintadd(inta,intb)throwsandroid.os.RemoteException{android.os.Parcel_data=android.os.Parcel.obtain();android.os.Parcel_reply=android.os.Parcel.obtain();int_result;try{_data.writeInterfaceToken(DESCRIPTOR);_data.writeInt(a);_data.writeInt(b);boolean_status=mRemote.transact(Stub.TRANSACTION_add,_data,_reply,0);if(!_status&&getDefaultImpl()!=null){returngetDefaultImpl().add(a,b);}_reply.readException();_result=_reply.readInt();}finally{_reply.recycle();_data.recycle();}return_result;}publicstaticandroid.app.IHelloServicesDefaultImpl;}staticfinalintTRANSACTION_add=(android.os.IBinder.FIRST_CALL_TRANSACTION+0);publicstaticbooleansetDefaultImpl(android.app.IHelloServiceimpl){if(Stub.Proxy.sDefaultImpl==null&&impl!=null){Stub.Proxy.sDefaultImpl=impl;returntrue;}returnfalse;}publicstaticandroid.app.IHelloServicegetDefaultImpl(){returnStub.Proxy.sDefaultImpl;}}publicintadd(inta,intb)throwsandroid.os.RemoteException;}

其实这个文件和我们用Android Studio创建AIDL服务生成的中间文件差不多的,都是统一的AIDL框架:有一个Stub抽象类,继承IBinder,实现IHelloService,还有一个代理类Proxy继承IHelloService,通过asInterface方法来获取

了解了IHelloService.aidl生成的一个中间文件,我们再实现HelloService.java的时候就清晰了,在frameworks/base/services/core/java/com/android/server/am/目录下创建HelloService.java文件:

packagecom.android.server.am;importandroid.app.IHelloService;publicclassHelloServiceextendsIHelloService.Stub{publicHelloService(){android.util.Log.d("dongjiao","StartHelloService...");nativeInit();}@Overridepublicintadd(inta,intb){android.util.Log.d("dongjiao","HelloServiceadd()...a=:"+a+",b=:"+b);returnnativeAdd(a,b);}privatestaticnativevoidnativeInit();privatestaticnativeintnativeAdd(inta,intb);}

这个HelloService继承自IHelloService.Stub,它作为Binder的具体实现端,里面定义了两个native方法,这两个方法和之前创建的JNI服务中的那两个函数一一对应,HelloService构造方法中调用nativeInit,add方法提供给外界访问,它里面调用nativeAdd

好了这个AIDL服务已经创建好了,接着我们到SystemServer中去添加开机注册此服务的代码,打开frameworks/base/services/java/com/android/server/SystemServer.java随便在其他某个服务下添加如下代码:

在这里插入图片描述
SystemServer启动时就会将HelloService添加到ServiceManager,名字自定义为”helloService“,代码已经添加完毕,总的修改就是如下部分:
在这里插入图片描述

开始进行编译 mmm frameworks/base/

编译成功后需要将/system/framework/下所有文件push进手机 adb push out/target/product/TOKYO_TF_arm64/system/framework/ /system/

另外定义的JIN服务相关代码会被编译到libandroid_servers.so这个so中,还需push这个so adb push out/target/product/TOKYO_TF_arm64/system/lib64/libandroid_servers.so /system/lib64/

重启手机发现了如下错误:

在这里插入图片描述
这是因为缺少了SELinux权限,实际开发中添加自定义AIDL,HIDL服务都需要SELinux权限,我们这里重点不在SELinux,所以采用规避方案,直接将SELinux关闭adb shell setenforce 0,这需要root权限

我们发现如下log,这是因为我的HIDL服务还没启动

在这里插入图片描述

启动一下前一篇文章实现的HIDL服务:

在这里插入图片描述
我们重新将SystemServer杀掉,为了再看一遍log:
在这里插入图片描述

04-1423:58:58.76092799279E:hello_hidlserviceisinitsuccess…04-1423:58:58.76192799279IServiceManagement:Registeredandroid.hardware.hello_hidl@1.0::IHellodefault(startdelayof52ms)04-1423:58:58.76292799279IServiceManagement:Removingnamespacefromprocessnameandroid.hardware.hello_hidl@1.0-servicetohello_hidl@1.0-service.04-1423:58:58.76292799279Iandroid.hardware.hello_hidl@1.0-service:Registrationcompleteforandroid.hardware.hello_hidl@1.0::IHellodefault.

这一段代表的是HIDL服务的启动注册

04-1423:59:38.881328328IServiceManager:service‘helloService’died04-1423:59:41.5821403714037W:JNI_OnLoad…hello…04-1423:59:41.5941403714037W:register_android_server_am_HelloService…04-1423:59:44.9781403714037Ddongjiao:SystemServer…addService(helloService)…04-1423:59:44.9781403714037Ddongjiao:StartHelloService…04-1423:59:44.9781403714037W:HelloService…nativeInit…04-1423:59:44.9801403714037W:successtogetIHelloservice"

这一段代表AIDL服务的启动注册

可以看到关闭了SELinux权限之后,HIDL和AIDL服务都注册成功了,并且在AIDL服务初始化时也能成功通过JNI服务获取到HIDL服务了,后面如果调用HIDL的addition_hidl函数也应该是很简单了。

其实整个调用逻辑还是比较清晰的,从AIDL到JNI到HIDL,在AIDL服务初始化中调用JNI服务的nativeInit函数,JNI服务的nativeInit函数中获取到HIDL服务,之后就可以随意调用HIDL的函数了。

原文链接: https://blog.csdn.net/qq_34211365/article/details/105642229

关键词: 插入图片 这是因为 中间文件

【聚看点】香港国安法实施至今,已有260人被拘捕

据大湾区之声官博消息,香港警方国家安全处(国安处)今日(3日)举行2023-07-03

外交部:提醒在法中国公民密切关注当地治安形势,谨慎外出

外交部发言人汪文斌主持今天(3日)举行的例行记者会。汪文斌表示,近2023-07-03

河西学院开展“七一”走访慰问活动

中国甘肃网7月3日讯(西北角·中国甘肃网记者常伟通讯员褚建霞)6月282023-07-03

海通证券:MTBE价差持续扩大 相关企业有望受益

智通财经获悉,海通证券发布研究报告称,MTBE是高辛烷值汽油添加剂,主2023-07-03

《咒术回战:战华双乱》公布 系列首部2vs2对战新游|当前资讯

万代南梦宫宣布,经典动漫《咒术回战》系列首部家用主机游戏《咒术回战2023-07-03

世界今热点:皮衣护理剂_皮衣护理

1、皮衣如何护理2、要避免皮衣接触油污、酸性和碱性等物质,脱下时把皮2023-07-03

世界热文:五芳斋:小型社区店发展良好

五芳斋在接受机构调研时表示,伴随着今年的新环境与新机遇,公司在持续2023-07-03

当前快看:儋州市社保2023年缴费标准 儋州市个人社保最低多少钱一个月

儋州市社保缴费标准怎么计算的呢?以单位买全社保为准,计算如下所示:2023-07-03

基金“中考”放榜:市场行情极度分化,新能源和医药“两头挨打”

在极度分化行情下,买对行业就是牛市,买错行业就是熊市。TMT行情自启2023-07-03

热点吐槽:基金“中考”成绩出炉!顶流基金迎"尴尬时刻",持有三年还没“回本”?!_全球速读

高考中考成绩纷纷出炉的当下,随着火热6、7月的交接,这不,基金经理的2023-07-03

美元存款值得“上车”吗?投资者需警惕市场风险_全球微动态

  近期,多家大行已下调美元定期存款利率。记者梳理银行美元存款产品2023-07-03

A股“甜味剂冲击波”溯源

另一方面,中信证券研报指出目前阿斯巴甜的全球市场规模约为30亿元人2023-07-03

地平线与安波福及风河开展深度战略合作-全球独家

据地平线7月3日消息,地平线与安波福及风河开展深度战略合作。此次合作2023-07-03

「走基层 找问题 想办法 促发展」党员干部深入百街千巷、百村千组、百业千企——“行走浏阳”解难题 环球快看

华声在线全媒体记者王文通讯员胡吉星时下,浏阳市李畋路-高坪镇连接线2023-07-03

今热点:陕西12岁小孩抚养费怎么给

1 有条件的,可以一次性给付;2 暂时不具备条件的,可以按月或定期给付2023-07-03

誉辰智能公布网上发行中签率

誉辰智能7月2日晚间公布网上申购情况及中签率,公司此次网上定价发行有2023-07-03

每日快讯!现代三大发明是什么 现代三大发明介绍

1、机械理想内燃发动机:由于机械理想内燃机的发明,人类在21世纪从中2023-07-03

让人才活力充分奔流在英雄城市|长江评论

长江日报评论员鲁珊首届中国学位与研究生教育大会即将开幕,我们对来到2023-07-03

热讯:prior是什么_PRIOR是什么意思呢

想必现在有很多小伙伴对于PRIOR是什么意思呢方面的知识都比较想要了解2023-07-03

AUTO设区 | 前卫不被理解 奔驰EQS勇敢突破“设计怪圈”

用经典三厢轿车的审美作为评价标准,并不能凸显EQS的设计与美感。2023-07-03

江苏卫视全部节目时间表 江苏卫视二季度创新

hello大家好,我是大学网网小航来为大家解答以上问题,江苏卫视全部节2023-07-03

著名商标查询官方网站_著名商标查询 全球今热点

1、一般可以上你们省工商局网站查询,上面都会有著名商标的名单,在搜2023-07-03

三星 A54 5G 对比谷歌 Pixel 7a,各项评价谁赢?-每日聚焦

点击上方播放视频来自ZEALERApp创作者【电獭少女】,本期视频主要是三2023-07-03

世界消息!宣布的宣字拼音怎么写_宣布的宣字组成语

想必现在有很多小伙伴对于宣布的宣字组成语方面的知识都比较想要了解,2023-07-02

查到了!镇坪县应急管理综合执法大队变“执法犬队”是10岁儿童干的-当前最新

陕西省安康市镇坪县发布:关于网络反映镇坪县应急管理综合执法大队标牌2023-07-02