首页>资讯>正文
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

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

Android Q 打通应用层到 HAL 层 -- ( JNI 服务和 AIDL 服务实现)

先回顾一下上一篇关于HIDL的内容:什么是HIDLHIDL全称为HALinterfacedefinitionlanguage(发音为“hide-l”2023-03-05

我伪装的很简单强悍强然听天由命的是什么歌名 天天即时看

1、伪装-大壮2、词:大壮 一博3、曲:大壮 一博4、心事会让人觉得累5、放的旧了很疲惫6、若即若离的纠结7、哪如干脆82023-03-04

【天天速看料】背靠背反败为胜!勇士队升至第五熬到库里回归,季后赛形势明朗了

背靠背反败为胜!勇士队升至第五熬到库里回归,季后赛形势明朗了,勇士队,汤普森,麦科勒姆,美国篮球,湖人主场,新奥尔良鹈鹕,斯蒂芬·库里2023-03-04

台北最重要地标建筑:小巨蛋

小巨蛋在台北文化中可谓是举足轻重,最常听说的就是某某歌星又要开演唱会了,歌星们可是把小巨蛋作为演唱会场地而感到光荣,最近又有好几场演2023-03-04

个人所得税怎么扣除的_个人所得税怎么交税款_微资讯

1 个人所得税的计算公式为:应纳税额=应纳税所得税率-速算扣除。2 个人所得税的起征点是5000元。应纳税所得额=月收入2023-03-04

特斯拉没招了还是马斯克的饼不香了

“故事大王”马斯克这次似乎没新故事可讲了。北京时间3月2日凌晨5点,特斯拉投资者日开始了同步直播。在这场直播上,特斯拉公布了“秘密宏图”2023-03-04

星文村_对于星文村简单介绍

1、星文村隶属于甸南镇海虹行政村,属于坝区。2、距离村委会0 50公里,距离镇3 00公里。3、国土面积0 36平方公里2023-03-04

2023中国环塔(国际)拉力赛将于5月发车-每日讯息

2023中国环塔(国际)拉力赛将于5月发车,赛车,戈壁,越野2023-03-02

快资讯丨123新手卡之家

1、123新手卡之家以敏锐的市场嗅觉,以玩家需求为根本,在新游戏推出之时,在第一时间与网游厂商洽谈合作,配合网游厂商2023-03-02

【天天聚看点】控制76个账户操纵股价 非法荐股吸金2400万!大V易伟被罚没近1亿

微博大V易伟控制76个账户操纵股价、非法荐股吸金2400万元,最终被罚没近1亿元。证监会日前对易伟操纵北京三夫户外用品股份有限公司(简称“三夫2023-03-02

4-0复仇!阿森纳豪取3连胜,5分优势领先曼城,马丁内利梅开二度 最资讯

4-0复仇!阿森纳豪取3连胜,5分优势领先曼城,马丁内利梅开二度,英超,曼城,阿森纳,埃弗顿,马丁内利,恩凯蒂亚,里卡多·马蒂内利2023-03-02

华南虎和东北虎体型_华南虎东北虎体型对比

1、1、皮毛的颜色和体型能看出来;就像爪哇虎的皮毛颜色纹路和体型一眼就看出来了。2、以上就是【华南虎和东北虎体型,华2023-03-02

梨花树下美人卧_焦点热闻

1、《梨花树下美人卧》是连载于红袖添香的一部古代言情类网络小说,作者是澖意。2、。2023-03-02

微型隔膜真空泵|天天热闻

1、微型隔膜真空泵。2、是指隔膜式的微型真空泵。本文到此分享完毕,希望对大家有所帮助。2023-03-01

世界观天下!赛力斯:2月塞力斯销量同比增长230%

每经AI快讯,3月1日,赛力斯公告,2月新能源汽车销量6577辆,同比增长103 69%;其中塞力斯销量3505辆,同比2023-03-01

游泳三不要_游泳四不要 全球要闻

1、六不准:2、不准私自下水游泳;不准擅自与他人结伴游泳;不准在无家长或老师带队的情况下游泳;不准到不熟悉的水域游泳;不2023-03-01

2023长春购车补贴政策最新(市+区)

2023长春购车补贴政策最新【市级】长春市3000万元汽车消费券申领时间:2023年2月21日-3月31日活动规定:消费者在参与活动的净月区限上汽车销售2023-03-01

当前信息:佛山照明子公司佛照科技与中国农机院签署合作协议

近日,佛山照明子公司佛照(海南)科技有限公司(简称:佛照科技)与中国农业机械化科学研究院(简称:中国农机院)在北京围绕渔业水产养殖产业某重2023-03-01

Bread+618 欧亚卖场店

1、Bread+618(欧亚卖场店)是一家蛋糕西点店,位于长春市开运街5178号欧亚卖场8号门(近东海大街)。2、。2023-03-01

消息!墨西哥副外长:特斯拉将投资近50亿美元在墨建“全球最大电动汽车工厂”

墨西哥副外长:特斯拉将投资近50亿美元在墨建“全球最大电动汽车工厂”,工厂,马斯克,电动车,电动汽车,德尔加多,墨西哥副外长,特斯拉(公司)2023-03-01

2023年,烟台将实施35个重点交通项目,年度计划投资291亿元

01短镜头一最后的85孔“还剩最后的85孔!”潍烟高铁芝罘段,易明伟仰望着头顶上错综的铁路轨道,挥手给同事们鼓劲儿:“还2023-03-01

月销是Model Y的两倍多,比亚迪又一款SUV崛起!

月销是ModelY的两倍多,比亚迪又一款SUV崛起!2023-03-01

如何测试手机硬件信息_手机硬件信息要怎么检测

手机硬件信息的检测方法是通过360官网或91手机助手下载安装“360优化大师”应用软件。点击手机进入“360优化大师”进2023-03-01

焦点播报:四川省人事考试网_四川人事考试网二级建造师

1、看你网上报的地方是什么地方,一般都是在成都,成都又分两处,以成都本地考场名义的一个地方,如果是以省内考场名义又一个地2023-03-01

有机农产品的市场前景_有机农业的市场前景

1、中国有机农业发展前景中国的有机食品具有巨大的国际市场和潜在的国内市场。2、首先,国际上对中国有机食品的2023-03-01