4

JAVA层HIDL服务的注册原理-Android10.0 HwBinder通信原理(八)

 1 year ago
source link: https://blog.csdn.net/yiranfeng/article/details/108037698
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

摘要:本节主要来讲解Android10.0 JAVA层HIDL服务的注册原理

阅读本文大约需要花费22分钟。

文章首发微信公众号:IngresGe

专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢!

欢迎关注我的公众号!

20200113052246361.jpg

[Android取经之路] 的源码都基于Android-Q(10.0) 进行分析

[Android取经之路] 系列文章:

《系统启动篇》

《日志系统篇》

《Binder通信原理》

  《HwBinder通信原理》

《编译原理》

前面我们学习了Native层 HIDL服务的注册获取原理,这一节我们来看看JAVA层HIDL服务的注册原理。

1.概述

  上一节中,我们了解了Native层的HIDL服务注册和获取流程,HAL服务的注册和获取,其实就是从HwServiceManager的mServiceMap中,插入和获取对应的hidl服务。通常情况下,HAL的服务都是在Native层,Client可以在Native也可以在framework、应用层。但是Android新引入的HIDL是支持JAVA侧的服务创建和Client验证的,这一节,我们深度分析JAVA层的HAL服务的注册和获取。

     JAVA层的HIDL服务注册和获取流程和Native层类似,只是在JAVA到Native层的过渡中,采用了JNI的机制来进行Native层的相关接口转换。

2.JAVA层的HwBinder架构

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

  HwBinder通信原理:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

3.HwBinder-JNI

    当Init进程启动后,孵化Zygote进程时,会有一个虚拟机注册过程,在这个过程中完成了JNI的注册,我们现在不需要深入去理解JNI的原理,现在我们只要知道 JAVA和Native侧的函数对应关系在哪里即可。

       HwBinder的JNI中有个一个HwBinder的映射数组:gMethods。

     我们在撸代码时,是要根据JAVA的函数入口找到JNI的函数调用即可,暂时不要太追求细枝末节,等流程理顺后,再专攻细节分析。

       Zygote进程启动时,JNI的注册调用栈如下所示:

2020081616132852.png

其中gRegJNI保存了我们不同JNI的入口,里面就包含我们HwBinder的JNI入口

3.1 register_android_os_HwBinder()

HwBinder JAVA层和Native层的JNI接口对应关系

我们本节主要分析的就是 注册服务:registerService 和 获取服务getService

4.IDemo服务注册

  JAVA层的HIDL服务注册流程如下图所示:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

4.1 服务注册调用栈

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

4.2 main()

步骤如下:

1.启动HwBinder线程池

2.注册HIDL服务

3.把当前的进程加入HwBinder的线程池进行循环

4.3 registerAsService()

  IDemo服务中注册最终调用的是HwBinder的registerService,接着通过JNI,走到了Native层进行服务注册

4.4 JHwBinder_native_registerService()

       1.通过GetNativeBinder获取一个JHwBinder对象,父类为HwBinder

       2.创建一个BpHwBase来包装JHwBinder

       3.拿到HwServiceManager对象

       4.将BpHwBase注册到hwservicemanager中,参数为:服务名称和对象

4.4.1 JHwBinder::GetNativeBinder()

  获取一个JHwBinder 对象

4.4.2 hidl::base::V1_0::BpHwBase(binder) 

  从HwBinder的成员变量mNativeContext中得到JHwBinderHolder的对象指针,然后调用其get函数得到JHwBinder对象。然后将JHwBinder封装为BpHwBase对象

4.4.3 defaultServiceManager

defaultServiceManager1_2()是用来拿到HwServiceManager的代理对象--BpHwServiceManager

 至此,我们可以看到JAVA-JNI-Native,三层共有三个对象的转换:HwBinder、JHwBinderHolder、JHwBinder。

  它们的类继承如下图所示:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

它们的对象关系如下图所示:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

4.5 BpHwServiceManager::add()

  调用BpHwServiceManager::_hidl_add的方法进行服务注册

4.6 BpHwServiceManager::_hidl_add()

_hidl_add的主要步骤如下:

1.准备两个Parcel结构-- _hidl_data,_hidl_reply

2.组装Parcel数据

3.写入RPC头信息"[email protected]::IServiceManager"

4.写入服务名称,如果没有配置的话,name为"default"

5.写入服务的实体对象--new Demo()

6.调用remote的transact,发送 12 /* addWithChain */ 的命令进行服务的注册

7.得到返回的reply数据

::android::hardware::Return<bool> BpHwServiceManager::_hidl_add(::android::hardware::IInterface *_hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor, const ::android::hardware::hidl_string& name, const ::android::sp<::android::hidl::base::V1_0::IBase>& service) {

BpHwBinder::transact调用后,会把组装的Parcel数据传到/dev/hwbinder,HwServiceManager发现hwbinder有数据变化,进行数据读取,最终根据传入的code=2,找到_hidl_add,进行服务注册

调用栈如下:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

4.7 BnHwServiceManager::_hidl_add

_hidl_add()主要步骤如下:

1.读取注册的Service Name

2. 读取注册的hidl_binder

3.通过hidl_binder,转换得到,注册时的服务实体

4.调用ServiceManager::add(),进行服务注册

5.向_hidl_reply中写入OK

6.把服务注册的结构,写入_hidl_reply

7.返回replay数据

_hidl_add的调用栈如下:

20200816162352133.png

4.7.2 ServiceManager::addImpl()

  获取当前binder调用的pid、sid 上下文信息后,开始注册服务,即把Demo对象注册到mServiceMap中

  在过程中,要进行selinux检查,确认该进程有权限添加service后,再检查是否有重复注册,而且如果子类在父类上注册,则注销它,

  排除一切问题后,把需要注册的服务,注册到mServiceMap中,最后建立一个死亡连接,当服务挂掉时会接收到通知,做一些清理工作。

4.8 PackageInterfaceMap::insertService()

  把传入的hidlservice插入到mInstanceMap 中,即 mServiceMap的value--PackageInterfaceMap 中

HwServiceManager中hidl服务的管理map:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

至此,我们JAVA层的IDemo服务注册完成,对象转换如下图所示

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lpcmFuZmVuZw==,size_16,color_FFFFFF,t_70

注册步骤分为以下几个步骤:

1.服务进程先通过JNI注册得到一个JHwBinder对象

2.获取HwServiceManager的代理对象HwBpServiceManager,主要通过new BpHwBinder(0)得到。

3.调用HwBpServiceManager的_hidl_add,组装一个Parce数据,传入服务名称、服务实体对象--BHwBinder、执行2 /* add */

4.先通过IPCThreadThread的writeTransactionData()把上面的Parcel数据写入mOut,用来进行发送

5.通过IPCThreadThread的talkWithDriver()与HwBinder驱动通信,传递语义BINDER_WRITE_READ

6.HwServiceManager有个for循环,调用epoll_wait()监控hwbinder的变化

7.waitForResponse()收到BR_TRANSACTION响应码后,最终后调用executeCommand()进行命令执行,根据逻辑处理,最终会调用到BnHwServiceManager::onTransact(),根据传入的code=12,调用addWithChain,最终把服务名称和实体对象插入到mServiceMap这个map中

8.注册成功后,把注册结果写入reply,返回reply信息

9.最终完成服务的注册流程

下一节,我们一起来看看《JAVA层HIDL服务的获取原理》

我的微信公众号:IngresGe

20200113052246361.jpg

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK