Binder系统-C程序示例_框架分析

news/2024/4/18 14:10:09/文章来源:https://blog.csdn.net/qq_34888036/article/details/129232207

IPC:进程间的通信,远程调用,比如我们的A进程需要打开LED灯,调用led_open/led_ctl方法,但是他是没有权限去操作的,所以进程A通过:1.首先构造一些数据,2.通过IPC发送数据到进程B,然后B进程:1.取出数去,2.调用本地的led_open/led_ctl。表面看起来,我们是通过进程A直接操控LED。

我们可以分析出框架大致如下:
数据的传输有三大要素,分别为源,目的已经数据。找上述的例子中可以如下描述:
源(进程A):发送数据,A向serviceManager查询led服务,获取一个handle(对硬件操作的服务),该handle指向进程B。
目的(进程B):B向serviceManager注册LED服务,以便A进程获取
数据:点亮,或者熄灭闪烁等。在这里插入图片描述
源码总体分析
相关问价你主要集中在SDK/frameworks\native\cmds\servicemanager目录下,其中存在文件service_manager.c,bctest.c(半成品),binder.c(封装好的C库)。根据前面的框图,我们分别来了解client,servicemanager,service分别做了,或者需要做什么。前面提到需要注册服务,那么肯定最先运行的是servicemanager,其主做了以下工作:

在这里插入图片描述
首先先打开驱动,并且告诉驱动他是servicemanager,这样他就有了驱动的操作权限,并且他是是一个while(1)循环,不停的读取数据,解释数据,如果有需要注册服务,则保存注册的服务到链表中,如果有需要获取服务,则从链表查询服务返回,在没有事情做的时候会处于休眠状态。

下面我们看看service:
在这里插入图片描述
最后我们在来看看client:
在这里插入图片描述
首先也是open打开驱动,然后向servicemanager查询获取服务,最后向handle(service服务)发送数据。

从上面简单的分析可以看出,service在注册服务的时候没事需要向进程servicemanage发送消息的,client也会向servicemanage进程发送消息获取服务,那么他们怎么知道哪个是servicemanage呢?在servicemanage分析中,他会告诉驱动他是servicemanage(上面已经提及过)。下面我们开始追踪andriod源码,也就是上面提到的那几个文件,看到具体是怎么回事

源码追踪
首先我们打开SDK\frameworks\native\cmds\servicemanager\service_manager.c,我们找到最末尾的main函数:

service_manager.c
service_manager.c(从main函数开始分析):

//txn->code参数是一个编码,这个编码包含呢很多信息,比如是查找,还是添加服务等等信息,都包含在这个编码中。
svcmgr_handler(struct binder_state *bs,struct binder_transaction_data *txn,struct binder_io *msg,struct binder_io *reply)handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);//根据传入的txn->code,在链表中查找服务,查找到之后返回服务do_add_service(bs, s, len, handle, txn->sender_euid,allow_isolated, txn->sender_pid) //如果传入的是注册服务,则加入本地链表main()binder_open(128*1024); open("/dev/binder", O_RDWR | O_CLOEXEC); //打开驱动binde(前面提到过,进程间的通信都是通过binder)binder_become_context_manager(bs); //告诉驱动他是service_managerbinder_loop(bs, svcmgr_handler); //一个循环,读取处理数据,其中的svcmgr_handler为服务处理函数ioctl(bs->fd, BINDER_WRITE_READ, &bwr);  //读取数据binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func); //解析数据func(bs, txn, &msg, &reply);//处理数据,此处的func就是前面的传入的svcmgr_handler

bctest.c
bctest.c中主要实现了两个功能,注册服务和获取服务,首先我们来看看他的注册服务,我们依旧从main函数开始

main()binder_open(128*1024);open("/dev/binder", O_RDWR | O_CLOEXEC); //打开驱动binde(前面提到过,进程间的通信都是通过binder)svcmgr_publish(bs, svcmgr, argv[1], &token);/*注册服务,其中的svcmgr = BINDER_SERVICE_MANAGER(0),打开驱动binde,进行进程间的通信,那么你当然需要告诉binder你是和谁通信,要发给谁,这里的BINDER_SERVICE_MANAGER即为service_manager进程,前面的ervice_manager告诉binder他是service_manager就起到了作用*/binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE) //构建数据之后,调用该函数,msg:含有服务的名字,reply:service_manager返回的数据 ,target:service_manager进程(0),SVC_MGR_ADD_SERVICE添加服务

以上是注册服务的过程,下面分获取服务过程:

main()binder_open(128*1024);handle = svcmgr_lookup(bs, svcmgr, "alt_svc_mgr");binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE) /*构造数据之后调用该函数,msg:含有服务的名字,reply:service_manager返回的数据(即提供服务的进程) ,target:service_manager进程(0),SVC_MGR_CHECK_SERVICE:获取服务*/

分析了注册服务和获取服务的大致过程,我们现在来分析其细致原理,即分析binder_call与之前提到svcmgr_handler函数参数txn中的txn->code,binder_call函数时在binder.c中提供的。

binder.c
我们打开binder.c文件,对binder_call进行分析;

int binder_call(struct binder_state *bs,struct binder_io *msg, struct binder_io *reply,uint32_t target, uint32_t code)

在这里插入图片描述
binder_call为远程调用,那么我们至少要知道调用那个进程,向那个价进程发送数据,调用那个函数,传递什么参数 ,返回值信息保存在哪里。在上图中已经进行了描述。

那我们这个函数怎么用呢?

1. 构造参数:放在buf中,这buf使用struct binder_io *msg进行描述2. 调用ioctl发送数据:res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);/*其中bwr:struct binder_write_read bwr;struct binder_io{char *data;            /* pointer to read/write from */binder_size_t *offs;   /* array of offsets */size_t data_avail;     /* bytes available in data buffer */size_t offs_avail;     /* entries available in offsets array */char *data0;           /* start of data buffer */binder_size_t *offs0;  /* start of offsets buffer */uint32_t flags;uint32_t unused;};*/3. ioctl也会接受数据,收到一个binder_write_read。

不知道大家发现一个问题没有,我们构建的是struct binder_io,但是ioctl需要的是struct binder_write_read bwr,那么他们之间是怎么进行转换的呢?那么他们肯定有一个转换过程。

这些都是大致的一个过程,下面我们开始分析源码:

svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name)//bctest.c文件bio_init(&msg, iodata, sizeof(iodata), 4);bio_put_uint32(&msg, 0);  // strict mode headerbio_put_string16_x(&msg, SVC_MGR_NAME);bio_put_string16_x(&msg, name);binder_call(struct binder_state *bs,struct binder_io *msg, 	struct binder_io *reply,uint32_t target, uint32_t code)------------------------------------------------------//对writebu进行构造writebuf.cmd = BC_TRANSACTION;writebuf.txn.target.handle = target;writebuf.txn.code = code;writebuf.txn.flags = 0;writebuf.txn.data_size = msg->data - msg->data0;writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0);writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0;writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0;----------------------------------------------------------------------------------------------------------------struct binder_write_read bwr;bwr.write_size = sizeof(writebuf);bwr.write_consumed = 0;bwr.write_buffer = (uintptr_t) &writebuf;--------------------------------------------------------

我们发现调用了很多bio_put去构建&msg,放入使用bio_put,那个获取我们可以使用bio_get。构建好msg然后调用binder_call,在该函数中从把msg中的相关成员赋值给writebuf,最后在让bwr.write_buffer指向writebuf,这样就完成了binder_io ms msg到binder_write_read bwr之间的转换,就能通过ioctl驱动binder。
其中write_buffer定义如下:

struct {uint32_t cmd;struct binder_transaction_data txn;} __attribute__((packed)) writebuf;//其中txn包括了:handle,code,参数。

小节结语
分析其内部机制之后,我们归纳一下,应该如何去写应用程序,实现进程之间的通信。

client:a.binder_open打开驱动,b.获取服务handle,c.构造参数binder_io,d.调用binder_call(handle,code,binder_io),e.分析返回的binder_io,取出返回值。
server:a.binder_open打开驱动,b.注册服务(service)c.ioctrl(read)d.解析数据binder_write_read,其中存在成员readbuf.binder_transaction_data.txn(前面提到其中包含handle,code,参数)e.根据code,决定调用哪个函数,从binder_io取出需要传递的参数,f.把返回值转换为binder_io发送给client。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_74664.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【分布式系统】MinIO之Multi-Node Multi-Drive架构分析

文章目录架构分析节点资源硬盘资源服务安装安装步骤创建系统服务新建用户和用户组创建环境变量启动服务负载均衡代码集成注意最近打算使用MinIO替代原来使用的FastDFS,所以一直在学习MinIO的知识。这篇文章是基于MinIO多节点多驱动的部署进行研究。 架构分析 节点资…

SpringBoot配置文件(properties yml)

查看官网更多系统配置项:https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties 1.配置⽂件作⽤ 整个项⽬中所有重要的数据都是在配置⽂件中配置的,⽐如:数据库的连接信息&am…

怎么把音乐传到苹果手机上?如何将铃声导入iphone

很多人肯定都有这样的经验—比起电脑,使用iPhone和iPad播放音乐能获得更好的声音体验。 因此,现在有越来越多的用户将音乐传输到iPhone/iPad上播放。怎么把音乐传到苹果手机上?把音乐导入苹果手机,主要有2种方法:一种是…

vue中的百度地图的搜索定位功能

效果图 申请百度地图AK 前往 百度地图开放平台控制台 ,登录百度账号,创建应用即得。 封装loadBMap.js文件 /*** 动态加载百度地图api函数* param {String} ak 百度地图AK,必传*/ export default function loadBMap(ak) {return new Promise…

Python曲线肘部点检测-膝部点自动检测

文章目录一. 术语解释二. 拐点检测肘部法则是经常使用的法则。很多时候,可以凭人工经验去找最优拐点,但有时需要自动寻找拐点。最近解决了一下这个问题,希望对各位有用。一. 术语解释 **肘形曲线(elbow curve)**类似人胳膊状的曲线&#xff…

【ArcGIS Pro二次开发】(10):属性表字段(field)的修改

在ArcGIS Pro中,经常会遇到用字段计算器对要素的属性表进行计算。下面以一个例子演示如何在ArcGIS Pro SDK二次开发中实现。 一、要实现的功能 如上图所示的要素图层,要实现如下功能: 当字段【市级行政区】的值为【泉州市】时,将…

服务网格领域的百花齐放

服务网格是一种技术架构,它用于管理微服务系统中各个服务之间的通信,旨在处理微服务间的流量(也称为东西向流量)。 ​ 在云原生应用中,一个应用的背后可能存在着成百上千个服务,各个服务可能又有着若干个实…

【论文速递】EMNLP 2020 - 将事件抽取作为机器阅读理解任务

【论文速递】EMNLP 2020 - 将事件抽取作为机器阅读理解任务 【论文原文】:Event Extraction as Machine Reading Comprehension 【作者信息】:Jian Liu and Yubo Chen and Kang Liu and Wei Bi and Xiaojiang Liu 论文:https://aclantholo…

[音视频] wav 格式

wav 格式结构 WAV文件遵循RIFF规则,其内容以区块(chunk)为最小单位进行存储。WAV文件一般由3个区块组成:RIFF chunk、Format chunk和Data chunk。另外,文件中还可能包含一些可选的区块,如:Fact…

算法leetcode|38. 外观数列(多语言实现)

文章目录38. 外观数列:样例 1:样例 2:提示:分析:题解:rustgocpythonjava38. 外观数列: 给定一个正整数 n ,输出外观数列的第 n 项。 「外观数列」是一个整数序列,从数字…

异步交互的关键——Ajax

文章目录1,Ajax 概述1.1 作用1.2 同步和异步1.3 案例1.3.1 分析1.3.2 后端实现1.3.3 前端实现2,axios2.1 基本使用2.2 快速入门2.2.1 后端实现2.2.2 前端实现2.3 请求方法别名最后说一句1,Ajax 概述 AJAX (Asynchronous JavaScript And XML):异步的 Jav…

C语言--指针进阶2

目录前言函数指针函数指针数组指向函数指针数组的指针回调函数前言 本篇文章我们将继续学习指针进阶的有关内容 函数指针 我们依然用类比的方法1来理解函数指针这一全新的概念,如图1 我们用一段代码来验证一下: int Add(int x, int y) {return xy;…

少走弯路,来自HR自动化实践者5条忠告 | RPA铺第4期

安东尼与巴克利共同撰写的《“无人力”的人力资源?自动化、人工智能及机器学习时代的产业演变》一书中指出,到2030年,全球8.5%的制造业劳动力(约2000万工人)将会被自动化机器人取代。 因自动化、人工智能、机器学习带…

大数据之Phoenix基本介绍

文章目录前言一、Phoenix简介二、Phoenix入门(一)创建表语法(二)查看表信息(三)删除表(四)大小写问题前言 #博学谷IT学习技术支持# 上篇文章介绍了Phoenix环境搭建,点击…

【C语言进阶】指针与数组、转移表详解

前言 大家好我是程序猿爱打拳,我们在学习完指针的基本概念后知道了指针就是地址,我们可以通过这个地址并对它进行解引用从而改变一些数据。但只学习指针的基础是完全不够的,因此学习完指针的基础后我们可以学习关于指针的进阶,其中…

计算机网络高频知识点(一)

目录 一、http状态码 二、浏览器怎么数据缓存 三、强缓存与协商缓存 1、强缓存 2、协商缓存 四、简单请求与复杂请求 五、PUT 请求类型 六、GET请求类型 七、GET 和 POST 的区别 八、跨域 1、什么时候会跨域 2、解决方式 九、计算机网络的七层协议与五层协议分别指…

线上研讨会报名 | Perforce、中手游、星思半导体专家邀您一起畅聊如何通过数字资产管理与版本控制赋能大规模研发

全球领先的数字资产管理与DevSecOps工具厂商Perforce联合中国授权合作伙伴龙智举办的Perforce on Tour网络研讨会将于2月28日下午2:00举行。 本次研讨会以“赋能‘大’研发,助力‘快’交付”为主题,龙智董事长何明、Perforce高级顾问Robert Cowham&…

Spring中的FactoryBean 和 BeanFactory、BeanPostProcessor 和BeanFactoryPostProcessor解析

文章目录FactoryBean 和 BeanFactory后置处理器BeanPostProcessor 和 BeanFactoryPostProcessorBeanPostProcessorBeanFactoryPostProcessorFactoryBean 和 BeanFactory BeanFactory接⼝是容器的顶级接⼝,定义了容器的⼀些基础⾏为,负责⽣产和管理Bean的…

2.26selenium常用api

一.等待1.线程强制等待Thread.sleep()2.隐式等待driver.manage().timeouts().implicitlyWait(Duration.ofSeconds())3.显式等待WebDriverWait foo new WebDriverWait(driver,Duration.ofSeconds(10));foo.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector()…

Spring Boot整合Kaptcha实现验证码功能

目录一、前言1.Kaptcha 简介2.Kaptcha 详细配置表二、实现1.整合kaptcha,创建kaptcha的工具类1.1 添加依赖1.2 创建KaptchaConfig工具类2 编写接口,在接口中使用 kaptcha 工具类来生成验证码图片(验证码信息)并返回3 登录时从sess…