一.概述

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)相关推荐

  1. 为 Kerberos 连接注册服务主体名称

    为 Kerberos 连接注册服务主体名称 SQL Server 2012 引自:http://technet.microsoft.com/zh-cn/library/ms191153.aspx 若要 ...

  2. Consul入门03 - 注册服务

    在前面的步骤,我们运行了第一个代理,看到了集群的成员,并且查询了节点信息.在这篇指南里,我们将注册我们第一个服务并且查询这个服务. 定义一个服务 一个服务能够通过提供一个服务定义或者调用适当的HTTP ...

  3. linux 查询注册服务,window下注册服务的命令小结

    1. 描述:     SC 是用于与服务控制管理器通信的命令行程序 . 用法: sc [command] [service name] ... 选项 的格式为 可以键入 "sc [comma ...

  4. Dubbo使用Zooker注册服务

    一.安装配置Zooker 1.下载Zooker 在apache mirros上下载Zooker :https://mirror.bit.edu.cn/apache/zookeeper/,下载后解压到指 ...

  5. .net core grpc consul 实现服务注册 服务发现 负载均衡(二)

    在上一篇 .net core grpc 实现通信(一) 中,我们实现的grpc通信在.net core中的可行性,但要在微服务中真正使用,还缺少 服务注册,服务发现及负载均衡等,本篇我们将在 .net ...

  6. Windows安装Apache注册服务出现(OS 5)拒绝访问。 : AH00369: Failed to open the Windows service manager,

    windows安装Apache,注册服务出现"(OS 5)拒绝访问. : AH00369: Failed to open the WinNT service manager..." ...

  7. Cloudflare推出域名注册服务:不赚利润只收取成本费

    9月27日,Cloudflare官方博客宣布推出域名注册服务,承诺只收取成本费,不赚取利润. Cloudflare在2010年9月成立,在那之前就有Cloudflare的早期测试版客户问:" ...

  8. datasnap——动态注册服务类

    datasnap--动态注册服务类 在DataSnap的应用程序时,我们首先需要注册的服务器类,以提供访问客户端应用程序的服务器方法.通常的做法是使用DSServerClass组件,但有些时候,我们要 ...

  9. Spring Boot快速注册服务脚本

    前言 Spring Boot项目通过JAR打包部署的时候,一般我们所采取的措施是将其注册为服务,并通过service命令管理项目.但注册服务的过程相对繁琐,不如写一个脚本来快速注册(入门Shell). ...

最新文章

  1. 前端基础---HTML
  2. vbs脚本读写INI文件
  3. c# 使用GDAL处理大图
  4. 新款iPhone SE并未搭载U1超宽带芯片,后续恐不支持AirTag
  5. UI素材|让设计有愉悦的体验,app交互动效的重要性!
  6. html3d变形,深入理解CSS变形transform(3d) - 小火柴的蓝色理想
  7. 计算机电路基础 - 1,计算机电路基础1.1(4页)-原创力文档
  8. Flash--提高flash的使用寿命(1)
  9. ASUS主板ALC887声卡,RTL81XX网卡,黑苹果驱动安装
  10. CAD虚线不显示怎么办
  11. 搭建帮助中心无方法,Baklib帮你轻松解决
  12. ssm+redis整合(通过cache方式)
  13. wx python 基本控件
  14. 解决下载github-production-release-asset-2e65be.s3.amazonaws.com上release文件慢的问题
  15. python文件的两种编译方法
  16. 移植 SOEM 到嵌入式平台 STM32F767
  17. textarea 禁止拖拽
  18. PowerDesigner 画类图
  19. 使用JLink、OpenOCD通过JTAG调试树莓派4
  20. Selenium Tips - CSS定位元素

热门文章

  1. 布尔值_Python基础知识点手册——布尔值及布尔运算
  2. wince车机可以连接电脑吗_想在WinCE车机上运行凯立德实时路况版吗?那就进来看看,让你一键傻瓜式联网...
  3. sqlanyshere转mysql_【SQL】Oracle和Mysql的分页、重复数据查询(limit、rownum、rowid)
  4. angular 触发 enter事件
  5. C++中常用的字符串函数
  6. java 从mysql 导出到excel_JAVA实现在数据库导出到EXCEL并下载
  7. 区块链教程Fabric1.0源代码分析Peer peer channel命令及子命令实现
  8. Ansible 基础-介绍
  9. Mybatis 通用 Mapper 使用 ①
  10. js 查找树节点 数组去重