第三节-Android10.0 Binder通信原理(三)-ServiceManager篇

2023-11-23 04:52

本文主要是介绍第三节-Android10.0 Binder通信原理(三)-ServiceManager篇,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、概述

        在Android中,系统提供的服务被包装成一个个系统级service,这些service往往会在设备启动之时添加进Android系统,当某个应用想要调用系统某个服务的功能时,往往是向系统发出请求,调用该服务的外部接口。在上一节我们了解到,这种外部接口,我们通常称之为代理接口,也就是我们要拿到目标服务对应的代理对象。
    //TODO

    在Android8.0后,谷歌引入Treble机制,binder机制增加了hwbinder和vndbinder,其中vndbinder的守护进程为vndservicemanager。
    vndservicemanager和service共用同一份代码,只是传入的参数和宏控制的流程有部分差异。
    vndservicemanager会传入参数“/dev/vndbinder”,servicemanager使用默认的“/dev/binder”。
    servicemanager主要做了以下几件事:
    1、打开binder驱动,申请了128k的内存空间
    2、然后调用binder_become_context_manager()让自己成为整个系统中唯一的上下文管理器,其实也就是service管理器
    3、调用binder_loop()进入无限循环,不断监听并解析binder驱动发来的命令


2、Binder架构

//TODO

3、servicemanager的启动

//TODO

4、service_manager调用栈:

//TODO

5、源码分析

    5.1 主程序启动main()

         //TODO

    5.2 binder_open()

        servicemanager启动后,先通过binder_open()来打开“/dev/binder”,代码如下:
        

binder_open()的工作也比较简单,分为以下几步:

1、通过系统调用open()来打开“/dev/binder”,获得一个句柄信息,在Binder驱动重对应的是函数binder_open()

2、通过ioctl获取binder的版本信息,比较binder协议版本是否相同,不同则跳出,在Binder驱动重对应的是函数binder_ioctl()

3、通过mmap内存映射128k的内存空间,即把binder驱动文件的128K字节映射到了内存空间,这128K内存空间的servicemanager使用,在Binder驱动重对应的是函数binder_mmap()。

其他的binder服务进程会映射BINDER_VM_SIZE((1*1024*1024)-sysconf(SC_PAGE_SIZE)*2)的内存空间,SC_PAGE_SIZE表示一个page页的大小,通常情况下为4K,即(1M-4K*2)=(1M-7K)

这个page的大小,不同厂家有时候也会调整大小,一般有1M,64K,4K,1KB,通常为4K。

ServiceManager进程mmap的内存大小可以通过adb shell命令得出:

其中0x7457b61000 -0x745d41000=0x20000,转成10进制,即为128K

ARM32内存映射:

虚拟空间的低3GB部分从0-0XBFFFFFFF的虚拟线性地址,用户态和内核态都可以寻址,这部分也是每个进程的独立空间。

虚拟空间的高1G部分从0XC00000000到0XFFFFFFFF的虚拟地址,只有内核态的进程才能访问,这种限制由页目录和页眉描述符的权限标示位决定,通过MML启动控制

ARM64内存映射:

默认情况下,32位系统默认只能支持4G的内存,在打开PAE后,最大可以扩展到64G的内存,随着物理硬件的不断升级,现在的内存越来越大,因此基本上都切换到了64位系统。

理论上讲,64位的地址总线可以支持高达16EB(2^64)的内存。

2^64次方太大了,Linux内核只采用了64bits的一部分(开启CONFIG_ARM64_64K_PAGES时使用42bits,页大小是4K时使用39bits),该文假设使用的页大小是4K(VA_BITS=39)

ARM64有足够的虚拟地址,用户空间和内核空间可以有各自的2^39=512GB的虚拟地址。

需要注意到,32位应用仍然拥有512GB的内核虚拟地址空间,并且不与内核共享自己的4GB空间,但在ARM32上,32位应用只有3GB的地址空间。

ARM32和ARM64内存地址比较:


    5.3 binder_become_context_manager()

binder_become_context_manager()的作用是让servicemanager成为整个系统中唯一的上下文管理器,其实也就是service管理器,这样我们就可以把ServiceManager称之为守护进程。

对应的binder驱动中操作如下:

从用户空间拷贝ioctl的参数,调用binder_ioctl_set_ctx_mgr()进行设置

BINDER_SET_CONTEXT_MGR_EXT带参数,BINDER_SET_CONTEXT_MGR不带参数

binder_ioctl_set_ctx_mgr()的流程也比较简单

1、先检查当前进程是否具有注册Context Manager的SEAndroid安全权限

2、如果具有SELinux权限,会为整个系统的上下管理器专门生成一个binder_node节点,便该节点的强弱应用加1

3、新创建的binder_node节点,记入context->binder_context_mgr_node,即ServiceManager进程的context binder节点,使之成为serviceManager的binder管理实体


    5.4 binder_loop()

        下一步进行守护进程的循环处理,binder_loop()会先向binder驱动发出了BC_ENTER_LOOPER命令,告诉binder驱动“本线程要进入循环状态了”,接着进入一个for循环不断调用ioctl()读取发来的数据,接着解析这些数据

其中最重要的一个结构体是binder_write_read,它用来记录Binder buffer中读和写的数据信息结构体如下:

    5.5 binder_parse()

        在binder_loop()进入for循环之后,核心处理流程就是ioctl和binder_parse(),即不停的从Binder驱动接收读写数据,进行binder解析后,进行处理。

在binder_loop()中声明了一个128字节的栈内存-readbuf,用BINDER_WRITE_READ命令从驱动读取一些内容,并传入binder_parse(),binder_parse()根据binder驱动传来的“BR_XXX”协议码,进行相关的逻辑处理,最重要的有三个“BR_XXX”协议:

BR_TRANSACTION:事务处理,解析binder_transaction_data的数据,调用回调函数svcmgr_handler()进行服务的注册,获取等操作

BR_REPLY:消息回复

BR_DEAD_BINDER:死亡通知

只要binder_parse()解析正常,binder_loop()就会一直执行下去,ServiceManager进程不退出。

binder_parse()解析binder驱动传来的readbuf的内存,readbuf拥有128字节的栈内存,每次可以只处理一个cmd,也可以有多个cmd,所以存在一个while循环,可以同时解析多个cmd,多个cmd的结构体如下图所示:

        5.5.1 BR_XXX 协议码分析

        BR_XXX码,也称为Binder响应码,这里介绍了ServiceManager处理的一些响应码的作用:

        5.5.2 BR_TRANSACTION解析

        我们这里单独分析下BR_TRANSACTION的流程,这也是我们常用的一个流程,这是Binder驱动向Server端发送请求数据。

从readbuf中解析出binder_transaction_data的数据,最后对接收和发送数据进行了封装,传递给svcmgr_handler()做详细处理

从上main的逻辑看,我们重点关注的是binder_transaction_data这个结构,binder_transaction_data说明了transaction到底在传输什么语义,而语义码就记录在其code成员中,不同语义码需要携带的数据也是不同的,这些数据由data指定。

结构体说明如下:

从上面binder_transaction_data的结构可以看出,data可存入的数据很少,主要采用了数据其实地址和数据偏移量,根据代码上下文可知,调用了bio_init_from_txn(),从txn.transaction_data解析出binder_io的信息,存入msg

        5.5.2.1 bio_init_from_txn()

bio_init_from_txn()的作用就是把binder_transaction_data的“数据起始地址”,“偏移量”,“data数据的总大小”和“偏移数组中可用的条目”:

binder_transaction_data和binder_io的关联

初始化完binder_io的replay,并把transaction_data转换成了binder_io的msg后,调用回调函数svcmgr_handler()进行最终逻辑处理

    5.6 svcmgr_handler()

        在BR_TRANSACTION的命令解析后,就把binder_transaction_data_secctx的数据传给回调函数svcmgr_handler()进行处理。

根据不同的传输语义码(txn->code)来进行相应的操作:查询服务,注册服务,以及列举所服务

源码如下:

    5.7 ServiceManager是如何管理service信息的?

        //TODO

    5.8 注册服务

        根据传入的code:SVC_MGR_ADD_SERVICE得知,本次binder流程想要进行服务注册。

步骤:

从binder_io msg中获取服务名称和长度

从binder_io msg中获取handle

检查该服务是否有注册的selinx权限

查询服务列表svclist是否存在该handle,如果有handle,就更新该服务的handle信息,通过这个handle我们最终就能找到远端的service实体

如果svclist不存在该服务,申请一个svcinfo的空间,把服务名,长度,handle等信息存入其中

把svcinfo进入svclist的链表中

再以BC_ACQUIRE命令,handle为目标的信息,通过ioctl发送给binder驱动

最后以BC_REQEST_DEATH_NOTIFICATION命令的信息,通过ioctl发送给binder驱动,主要用于清理内存等收尾工作        

    5.9 查找服务

        //TODO

6、总结

        //TODO

这篇关于第三节-Android10.0 Binder通信原理(三)-ServiceManager篇的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/415486

相关文章

从原理到实战深入理解Java 断言assert

《从原理到实战深入理解Java断言assert》本文深入解析Java断言机制,涵盖语法、工作原理、启用方式及与异常的区别,推荐用于开发阶段的条件检查与状态验证,并强调生产环境应使用参数验证工具类替代... 目录深入理解 Java 断言(assert):从原理到实战引言:为什么需要断言?一、断言基础1.1 语

MySQL中的表连接原理分析

《MySQL中的表连接原理分析》:本文主要介绍MySQL中的表连接原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、表连接原理【1】驱动表和被驱动表【2】内连接【3】外连接【4编程】嵌套循环连接【5】join buffer4、总结1、背景

深度解析Spring AOP @Aspect 原理、实战与最佳实践教程

《深度解析SpringAOP@Aspect原理、实战与最佳实践教程》文章系统讲解了SpringAOP核心概念、实现方式及原理,涵盖横切关注点分离、代理机制(JDK/CGLIB)、切入点类型、性能... 目录1. @ASPect 核心概念1.1 AOP 编程范式1.2 @Aspect 关键特性2. 完整代码实

Java Stream的distinct去重原理分析

《JavaStream的distinct去重原理分析》Javastream中的distinct方法用于去除流中的重复元素,它返回一个包含过滤后唯一元素的新流,该方法会根据元素的hashcode和eq... 目录一、distinct 的基础用法与核心特性二、distinct 的底层实现原理1. 顺序流中的去重

Spring @Scheduled注解及工作原理

《Spring@Scheduled注解及工作原理》Spring的@Scheduled注解用于标记定时任务,无需额外库,需配置@EnableScheduling,设置fixedRate、fixedDe... 目录1.@Scheduled注解定义2.配置 @Scheduled2.1 开启定时任务支持2.2 创建

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

Python中使用uv创建环境及原理举例详解

《Python中使用uv创建环境及原理举例详解》uv是Astral团队开发的高性能Python工具,整合包管理、虚拟环境、Python版本控制等功能,:本文主要介绍Python中使用uv创建环境及... 目录一、uv工具简介核心特点:二、安装uv1. 通过pip安装2. 通过脚本安装验证安装:配置镜像源(可

Mysql的主从同步/复制的原理分析

《Mysql的主从同步/复制的原理分析》:本文主要介绍Mysql的主从同步/复制的原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录为什么要主从同步?mysql主从同步架构有哪些?Mysql主从复制的原理/整体流程级联复制架构为什么好?Mysql主从复制注意

Nacos注册中心和配置中心的底层原理全面解读

《Nacos注册中心和配置中心的底层原理全面解读》:本文主要介绍Nacos注册中心和配置中心的底层原理的全面解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录临时实例和永久实例为什么 Nacos 要将服务实例分为临时实例和永久实例?1.x 版本和2.x版本的区别

RabbitMQ工作模式中的RPC通信模式详解

《RabbitMQ工作模式中的RPC通信模式详解》在RabbitMQ中,RPC模式通过消息队列实现远程调用功能,这篇文章给大家介绍RabbitMQ工作模式之RPC通信模式,感兴趣的朋友一起看看吧... 目录RPC通信模式概述工作流程代码案例引入依赖常量类编写客户端代码编写服务端代码RPC通信模式概述在R