注册服务(addService)
一.概述
1.1 media服务注册
media入口函数是main_mediaserver.cpp中的main()方法,代码如下:
过程说明:
获取ServiceManager: 讲解了defaultServiceManager()返回的是BpServiceManager对象, 用于跟servicemanager进程通信;
理解Binder线程池的管理, 讲解了startThreadPool和joinThreadPool过程.
本文的重点就是讲解Native层服务注册的过程.
1.2 类图
在Native层的服务以media服务为例,来说一说服务注册过程,先来看看media的整个的类关系图
图解:
蓝色代表的是注册MediaPlayerService服务所涉及的类
绿色代表的是Binder架构中与Binder驱动通信过程中的最为核心的两个类;
紫色代表的是注册服务和获取服务的公共接口/父类;
1.3 时序图
先通过一幅图来说说,media服务启动过程是如何向servicemanager注册服务的。
二. ProcessState
2.1 ProcessState::self
获得ProcessState对象: 这也是单例模式,从而保证每一个进程只有一个ProcessState对象。其中gProcess和gProcessMutex是保存在Static.cpp类的全局变量。
2.2 ProcessState初始化
ProcessState的单例模式的惟一性,因此一个进程只打开binder设备一次,其中ProcessState的成员变量mDriverFD记录binder驱动的fd,用于访问binder设备。
BINDER_VM_SIZE = (110241024) - (4096 *2), binder分配的默认内存大小为1M-8k。
DEFAULT_MAX_BINDER_THREADS = 15,binder默认的最大可并发访问的线程数为16。
2.3 open_driver
open_driver作用是打开/dev/binder设备,设定binder支持的最大线程数。关于binder驱动的相应方法,见文章Binder Driver初探。
ProcessState采用单例模式,保证每一个进程都只打开一次Binder Driver。
2.4 mmap
参数说明:
addr: 代表映射到进程地址空间的起始地址,当值等于0则由内核选择合适地址,此处为0;
size: 代表需要映射的内存地址空间的大小,此处为1M-8K;
prot: 代表内存映射区的读写等属性值,此处为PROT_READ(可读取);
flags: 标志位,此处为MAP_PRIVATE(私有映射,多进程间不共享内容的改变)和 MAP_NORESERVE(不保留交换空间)
fd: 代表mmap所关联的文件描述符,此处为mDriverFD;
offset:偏移量,此处为0。
mmap()经过系统调用,执行binder_mmap过程。
三. 服务注册
3.1 instantiate
注册服务MediaPlayerService:由defaultServiceManager()返回的是BpServiceManager,同时会创建ProcessState对象和BpBinder对象。 故此处等价于调用BpServiceManager->addService。其中MediaPlayerService位于libmediaplayerservice库.
3.2 BpSM.addService
服务注册过程:向ServiceManager注册服务MediaPlayerService,服务名为”media.player”;
3.2.1 writeStrongBinder
3.2.2 flatten_binder
将Binder对象扁平化,转换成flat_binder_object对象。
对于Binder实体,则cookie记录Binder实体的指针;
对于Binder代理,则用handle记录Binder代理的句柄;
关于localBinder,代码见Binder.cpp。
3.2.3 finish_flatten_binder
3.2.3 finish_flatten_binder
将flat_binder_object写入out。
3.3 BpBinder::transact
Binder代理类调用transact()方法,真正工作还是交给IPCThreadState来进行transact工作。先来 看看IPCThreadState::self的过程。
3.3.1 IPCThreadState::self
\TLS是指Thread local storage(线程本地储存空间),每个线程都拥有自己的TLS,并且是私有空间,线程之间不会共享。通过pthread_getspecific/pthread_setspecific函数可以获取/设置这些空间中的内容。从线程本地存储空间中获得保存在其中的IPCThreadState对象。
3.3.2 IPCThreadState初始化
每个线程都有一个IPCThreadState,每个IPCThreadState中都有一个mIn、一个mOut。成员变量mProcess保存了ProcessState变量(每个进程只有一个)。
mIn 用来接收来自Binder设备的数据,默认大小为256字节;
mOut用来存储发往Binder设备的数据,默认大小为256字节。
3.4 IPC::transact
IPCThreadState进行transact事务处理分3部分:
errorCheck() //数据错误检查
writeTransactionData() // 传输数据
waitForResponse() //f等待响应
3.5 IPC.writeTransactionData
其中handle的值用来标识目的端,注册服务过程的目的端为service manager,此处handle=0所对应的是binder_context_mgr_node对象,正是service manager所对应的binder实体对象。binder_transaction_data结构体是binder驱动通信的数据结构,该过程最终是把Binder请求码BC_TRANSACTION和binder_transaction_data结构体写入到mOut。
transact过程,先写完binder_transaction_data数据,其中Parcel data的重要成员变量:
mDataSize:保存再data_size,binder_transaction的数据大小;
mData: 保存在ptr.buffer, binder_transaction的数据的起始地址;
mObjectsSize:保存在ptr.offsets_size,记录着flat_binder_object结构体的个数;
mObjects: 保存在offsets, 记录着flat_binder_object结构体在数据偏移量;
接下来执行waitForResponse()方法。
3.6 IPC.waitForResponse
在waitForResponse过程, 首先执行BR_TRANSACTION_COMPLETE;另外,目标进程收到事务后,处理BR_TRANSACTION事务。 然后发送给当前进程,再执行BR_REPLY命令。
3.7 IPC.talkWithDriver
binder_write_read结构体用来与Binder设备交换数据的结构, 通过ioctl与mDriverFD通信,是真正与Binder驱动进行数据读写交互的过程。 主要是操作mOut和mIn变量。
ioctl()经过系统调用后进入Binder Driver.
四. Binder Driver
ioctl -> binder_ioctl -> binder_ioctl_write_read
4.1 binder_ioctl_write_read
4.2 binder_thread_write
4.3 binder_transaction
注册服务的过程,传递的是BBinder对象,故[小节3.2.1]的writeStrongBinder()过程中localBinder不为空, 从而flat_binder_object.type等于BINDER_TYPE_BINDER。
服务注册过程是在服务所在进程创建binder_node,在servicemanager进程创建binder_ref。 对于同一个binder_node,每个进程只会创建一个binder_ref对象。
向servicemanager的binder_proc->todo添加BINDER_WORK_TRANSACTION事务,接下来进入ServiceManager进程。
4.3.1 binder_get_node
从binder_proc来根据binder指针ptr值,查询相应的binder_node。
4.3.2 binder_new_node
4.3.3 binder_get_ref_for_node
handle值计算方法规律:
每个进程binder_proc所记录的binder_ref的handle值是从1开始递增的;
所有进程binder_proc所记录的handle=0的binder_ref都指向service manager;
同一个服务的binder_node在不同进程的binder_ref的handle值可以不同;
五. ServiceManager
由Binder系列3—启动ServiceManager已介绍其原理,循环在binder_loop()过程, 会调用binder_parse()方法。
5.1 binder_parse
[-> servicemanager/binder.c]
5.2 svcmgr_handler
[-> service_manager.c]
5.3 do_add_service
[-> service_manager.c]
\svcinfo记录着服务名和handle信息,保存到svclist列表。
5.4 binder_send_reply
[-> servicemanager/binder.c]
binder_write进入binder驱动后,将BC_FREE_BUFFER和BC_REPLY命令协议发送给Binder驱动, 向client端发送reply.
六. 总结
服务注册过程(addService)核心功能:在服务所在进程创建binder_node,在servicemanager进程创建binder_ref。 其中binder_ref的desc再同一个进程内是唯一的:
每个进程binder_proc所记录的binder_ref的handle值是从1开始递增的;
所有进程binder_proc所记录的handle=0的binder_ref都指向service manager;
同一个服务的binder_node在不同进程的binder_ref的handle值可以不同;
Media服务注册的过程涉及到MediaPlayerService(作为Client进程)和Service Manager(作为Service进程),通信流程图如下所示:
过程分析:
MediaPlayerService进程调用ioctl()向Binder驱动发送IPC数据,该过程可以理解成一个事务binder_transaction(记为T1),执行当前操作的线程binder_thread(记为thread1),则T1->from_parent=NULL,T1->from = thread1,thread1->transaction_stack=T1。其中IPC数据内容包含:
Binder协议为BC_TRANSACTION;
Handle等于0;
RPC代码为ADD_SERVICE;
RPC数据为”media.player”。
Binder驱动收到该Binder请求,生成BR_TRANSACTION命令,选择目标处理该请求的线程,即ServiceManager的binder线程(记为thread2),则 T1->to_parent = NULL,T1->to_thread = thread2。并将整个binder_transaction数据(记为T2)插入到目标线程的todo队列;
Service Manager的线程thread2收到T2后,调用服务注册函数将服务”media.player”注册到服务目录中。当服务注册完成后,生成IPC应答数据(BC_REPLY),T2->form_parent = T1,T2->from = thread2, thread2->transaction_stack = T2。
Binder驱动收到该Binder应答请求,生成BR_REPLY命令,T2->to_parent = T1,T2->to_thread = thread1, thread1->transaction_stack = T2。 在MediaPlayerService收到该命令后,知道服务注册完成便可以正常使用。
整个过程中,BC_TRANSACTION和BR_TRANSACTION过程是一个完整的事务过程;BC_REPLY和BR_REPLY是一个完整的事务过程。 到此,其他进行便可以获取该服务,使用服务提供的方法
注册服务(addService)相关推荐
- 为 Kerberos 连接注册服务主体名称
为 Kerberos 连接注册服务主体名称 SQL Server 2012 引自:http://technet.microsoft.com/zh-cn/library/ms191153.aspx 若要 ...
- Consul入门03 - 注册服务
在前面的步骤,我们运行了第一个代理,看到了集群的成员,并且查询了节点信息.在这篇指南里,我们将注册我们第一个服务并且查询这个服务. 定义一个服务 一个服务能够通过提供一个服务定义或者调用适当的HTTP ...
- linux 查询注册服务,window下注册服务的命令小结
1. 描述: SC 是用于与服务控制管理器通信的命令行程序 . 用法: sc [command] [service name] ... 选项 的格式为 可以键入 "sc [comma ...
- Dubbo使用Zooker注册服务
一.安装配置Zooker 1.下载Zooker 在apache mirros上下载Zooker :https://mirror.bit.edu.cn/apache/zookeeper/,下载后解压到指 ...
- .net core grpc consul 实现服务注册 服务发现 负载均衡(二)
在上一篇 .net core grpc 实现通信(一) 中,我们实现的grpc通信在.net core中的可行性,但要在微服务中真正使用,还缺少 服务注册,服务发现及负载均衡等,本篇我们将在 .net ...
- Windows安装Apache注册服务出现(OS 5)拒绝访问。 : AH00369: Failed to open the Windows service manager,
windows安装Apache,注册服务出现"(OS 5)拒绝访问. : AH00369: Failed to open the WinNT service manager..." ...
- Cloudflare推出域名注册服务:不赚利润只收取成本费
9月27日,Cloudflare官方博客宣布推出域名注册服务,承诺只收取成本费,不赚取利润. Cloudflare在2010年9月成立,在那之前就有Cloudflare的早期测试版客户问:" ...
- datasnap——动态注册服务类
datasnap--动态注册服务类 在DataSnap的应用程序时,我们首先需要注册的服务器类,以提供访问客户端应用程序的服务器方法.通常的做法是使用DSServerClass组件,但有些时候,我们要 ...
- Spring Boot快速注册服务脚本
前言 Spring Boot项目通过JAR打包部署的时候,一般我们所采取的措施是将其注册为服务,并通过service命令管理项目.但注册服务的过程相对繁琐,不如写一个脚本来快速注册(入门Shell). ...
最新文章
- 前端基础---HTML
- vbs脚本读写INI文件
- c# 使用GDAL处理大图
- 新款iPhone SE并未搭载U1超宽带芯片,后续恐不支持AirTag
- UI素材|让设计有愉悦的体验,app交互动效的重要性!
- html3d变形,深入理解CSS变形transform(3d) - 小火柴的蓝色理想
- 计算机电路基础 - 1,计算机电路基础1.1(4页)-原创力文档
- Flash--提高flash的使用寿命(1)
- ASUS主板ALC887声卡,RTL81XX网卡,黑苹果驱动安装
- CAD虚线不显示怎么办
- 搭建帮助中心无方法,Baklib帮你轻松解决
- ssm+redis整合(通过cache方式)
- wx python 基本控件
- 解决下载github-production-release-asset-2e65be.s3.amazonaws.com上release文件慢的问题
- python文件的两种编译方法
- 移植 SOEM 到嵌入式平台 STM32F767
- textarea 禁止拖拽
- PowerDesigner 画类图
- 使用JLink、OpenOCD通过JTAG调试树莓派4
- Selenium Tips - CSS定位元素
热门文章
- 布尔值_Python基础知识点手册——布尔值及布尔运算
- wince车机可以连接电脑吗_想在WinCE车机上运行凯立德实时路况版吗?那就进来看看,让你一键傻瓜式联网...
- sqlanyshere转mysql_【SQL】Oracle和Mysql的分页、重复数据查询(limit、rownum、rowid)
- angular 触发 enter事件
- C++中常用的字符串函数
- java 从mysql 导出到excel_JAVA实现在数据库导出到EXCEL并下载
- 区块链教程Fabric1.0源代码分析Peer peer channel命令及子命令实现
- Ansible 基础-介绍
- Mybatis 通用 Mapper 使用 ①
- js 查找树节点 数组去重