Android 13(T) - binder阅读(1)- binder driver

news2024/9/22 1:28:54

1 总览

想要使用binder完成进程间通信(IPC)或者完成远程过程调用(RPC),那么我们需要有如下三个要素:

  1. 源:即调用者(Client)
  2. 目的:即服务提供者(Server)。这里会有一个问题,client怎么知道我要向哪里发送数据呢?这里就需要用到ServiceManager,Server需要先注册到ServiceManager中,Client再向ServiceManager查询服务获得一个handle。
  3. 数据:Client想要调用Server的哪个方法,传输什么参数,返回什么结果,需要事先约定好协议,放在一个Buffer当中。

我绘制了一张Client、Server、ServiceManager以及Binder Driver四者的关系图,图中虚线都是RPC调用,实际都是通过ioctl与binder驱动进行交互,实现Client和Server通讯的功能。从图上可以看到,ServiceManager与Server/Client之间的调用也是虚线,也就说ServiceManager也是一个binder service,只不过是一个特殊的service。

请添加图片描述


2 Binder Driver

从上面可以看到,client和server之间的通讯都是通过与binder驱动的交互来完成的,所以如果不了解binder驱动,那么是很难理解binder的。binder驱动相关的代码参考 binder.c。

const struct file_operations binder_fops = {
	.owner = THIS_MODULE,
	.poll = binder_poll,
	.unlocked_ioctl = binder_ioctl,
	.compat_ioctl = compat_ptr_ioctl,
	.mmap = binder_mmap,
	.open = binder_open,
	.flush = binder_flush,
	.release = binder_release,
};

我们在用户态调用的mmapopeniotcl实际调用的是binder.c中定义的binder_mmapbinder_openbinder_ioctl

接下来我们将以MediaServer为例,初步了解与binder驱动相关的系统调用。MediaServer的代码参考 main_mediaserver.cpp

int main(int argc __unused, char **argv __unused)
{
	// 1. 打开binder驱动,mmap
    sp<ProcessState> proc(ProcessState::self());
    // 2. 获取servicemanager
    sp<IServiceManager> sm(defaultServiceManager());
    // 3. 注册到servicemanager
    MediaPlayerService::instantiate();
    // 4. 开始监听
    ::android::hardware::configureRpcThreadpool(16, false);
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    ::android::hardware::joinRpcThreadpool();
}

2.1 binder_open

创建ProcessState单例对象时,会先调用open打开binder驱动,代码可以参考 ProcessState.cpp

int fd = open(driver, O_RDWR | O_CLOEXEC);

这里就会进入内核态调用binder驱动的binder_open方法。

static HLIST_HEAD(binder_procs);

static int binder_open(struct inode *nodp, struct file *filp)
{
	// 创建一个binder_proc指针并为其开辟空间
	struct binder_proc *proc, *itr;
	proc = kzalloc(sizeof(*proc), GFP_KERNEL);
	// 初始化binder_proc的成员
	get_task_struct(current->group_leader);
	proc->tsk = current->group_leader;
	proc->cred = get_cred(filp->f_cred);
	INIT_LIST_HEAD(&proc->todo);
	// 初始化binder_alloc
	binder_alloc_init(&proc->alloc);
	// 记录当前调用进程的pid
	proc->pid = current->group_leader->pid;
	INIT_LIST_HEAD(&proc->delivered_death);
	INIT_LIST_HEAD(&proc->waiting_threads);
	filp->private_data = proc;
	// 将binder_proc加入到全局链表binder_procs当中
	hlist_add_head(&proc->proc_node, &binder_procs);
	return 0;
}

我这里删除了很多代码内容,只留下了binder_proc的创建和初始化。我认为binder_open最重要的工作之一就是为当前的调用进程创建一个binder_proc对象,该对象中存有进程的pid,有了它binder驱动就可以从茫茫进程中找到目标进程了,至于如何寻找的我们后面再了解。

2.2 binder_mmap

执行完binder_open之后,ProcessState会用回传的fd执行mmap

mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,opened.value(), 0);

这里就会进入内核态调用binder驱动的binder_mmap方法。

static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
	struct binder_proc *proc = filp->private_data;
	if (proc->tsk != current->group_leader)
		return -EINVAL;
	vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP;
	vma->vm_flags &= ~VM_MAYWRITE;
	vma->vm_ops = &binder_vm_ops;
	vma->vm_private_data = proc;
	// 核心工作
	return binder_alloc_mmap_handler(&proc->alloc, vma);
}

binder_mmap的核心工作在binder_alloc_mmap_handler中完成,由于比较复杂,我对驱动也不了解,所以就不贴代码了。

我们要了解的是通过binder_mmap可以为当前进程开辟一块共享内存,可由用户态和内核态共享,每个进程都会有这样一块内存,内存信息存储在binder_procbinder_alloc成员中,通过这块内存可以完成其他博文中所说的一次拷贝的功能,如何拷贝的我们后面再看。

2.3 binder_ioctl

通过binder_ioctl,用户态就可以与binder驱动实现通信了。

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	int ret;
	// 找到当前进程的binder_proc
	struct binder_proc *proc = filp->private_data;
	struct binder_thread *thread;
	unsigned int size = _IOC_SIZE(cmd);
	void __user *ubuf = (void __user *)arg;
	if (ret)
		goto err_unlocked;
	// 获取到线程,这里不在本次阅读的重点中,暂时忽略
	thread = binder_get_thread(proc);
	if (thread == NULL) {
		ret = -ENOMEM;
		goto err;
	}
	switch (cmd) {
		......
	}

binder驱动会根据传入的fd、cmd以及对应的参数来执行对应的操作,这里暂时不去看里面具体执行了什么。


到这里binder driver就初步了解结束,我认为这篇比较重要的点在于,一个进程打开binder driver,driver就会为该进程创建一个binder_proc对象,有了它就可以找到目标进程。

接下来我们先去了解ServiceManager,这篇先到这边。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

win10 64位系统下载、安装nodejs(图文教程)

windows电脑下载、安装nodejs是很容易的&#xff0c;参考下面的图文教程&#xff0c;很快就能搞定下载安装. 1&#xff0c;下载nodejs 下载地址&#xff1a;https://nodejs.org/en/download/ 2&#xff0c;安装nodejs 点击安装包&#xff0c;一路下一步 3&#xff0c;验证…

设计模式—责任链模式

一、待解决问题&#xff1a; 减少代码中 if else 语句&#xff0c;降低代码圈复杂度或深度&#xff0c;增强可读性。 1、需求背景&#xff1a; 采购订单创建&#xff0c;需要验证采购员、物料、供应商、供应商的银行账号等信息。如采购员权限到期、或供应商失效等问题&#xff…

python机器学习——机器学习相关概念 特征工程

目录 机器学习特征工程1.特征抽取2.特征处理2.1 归一化&#xff1a;传统精确小数据2.2 标准化&#xff1a;大多数情况 3.数据降维3.1特征选择3.2主成分分析PCA 案例&#xff1a;超市订单分析 机器学习 监督学习&#xff1a;输入数据有特征有标签&#xff0c;即有标准答案 分类&…

chatgpt赋能python:Python求累加求和指南

Python求累加求和指南 Python是一种简单而强大的编程语言&#xff0c;从事编程工作的人大多都对它有一定的了解。它具有开发复杂应用程序的强大功能&#xff0c;同时也可以被用作数据处理和分析等用途。其中一个最常见的任务就是累加求和&#xff0c;今天我们将介绍如何在Pyth…

Redis 集合相关命令

Redis 支持多种数据结构&#xff0c;比如 字符串、列表、集合、有序集合 和 哈希 等数据结构。本次我整理了关于 集合 相关的命令&#xff0c;也就是关于 Sets 相关的命令&#xff0c;如下图。 上图中用红色圈中的部分&#xff0c;就是关于 集合 相关的命令。如果想要在 Redis …

JDBC小记——基础入门

目录 JDBC概念 JDBC入门 1. 导入数据库的驱动jar包 2. 加载驱动jar包 3. 获取连接对象 4. 获取操作对象 5.执行SQL语句 6.释放资源 IDEA连接数据库 结果集对象 登录练习 JDBC概念 Java DataBase Connectivity 即 Java数据库连接 JDBC&#xff0c;其实就是Java定义…

第7章 Scala集合

第7章 Scala集合 7.1 简介 ​ ​ scala.collection.immutable ​ scala.collection.mutable ​ 7.2 数组 ​ 不可变数组 package chapter07object Test01_ImmutableArray {def main(args: Array[String]): Unit {// 1. 创建数组val arr: Array[Int] new Array[Int](10…

【AUTOSAR】AUTOSAR开发工具链(二)----TASKING库的封装

1、集成工程 步骤&#xff1a; 拷贝模块代码&#xff1a; 将源工程的所有模块代码拷贝到库工程&#xff0c;将源工程拷贝一份&#xff0c;并删除不必要的文件作为释放工程&#xff0c;完成结果如下图&#xff1a; 源工程&#xff08;左&#xff09;VS库工程&#xff08;中&am…

[CUDA][Ubuntu]如何卸载cuda和cudnn和nvidia driver

百度有很多牛鬼蛇神的办法&#xff0c;试了一晚上&#xff0c;都不行。 包括&#xff1a;通过安装方式卸载&#xff0c;我tm根本不知道当初这个机器是怎么安装的cuda&#xff0c;我怎么卸载&#xff1f;&#xff1f;&#xff1f; 通过删除文件夹和自带uninstall程序&#xff…

安卓蓝牙协议数据包格式

本文解析蓝牙传输的数据包格式&#xff0c;目的是对蓝牙的各个层次的协议有更深的理解。 bit数据流格式 在讲数据报文之前&#xff0c;必须了解协议中对数据的BIT排序的规定&#xff0c;在协议中规定数据包或者PDU都是以Little Endian format(小端模式)存放&#xff0c;也就是…

数据库信息速递 - 将可观测性带到现代数据堆栈 (译)

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

Layui基础入门

一、引言 1.1 介绍 官网&#xff1a;<https://www.layui.com/ > 这个不维护了 看下面这个 https://www.layuiweb.com/ 在官网首页&#xff0c;可以很方便的下载LayUI LayUI 是一款经典模块化前端 UI 框架&#xff0c;我们只需要定义简单的HTML、CSS、JS即可实现很复杂的前…

小鲜肉语录

马上端午放假了&#xff0c;今天不聊技术&#xff0c;聊点轻松的。 一、 和老公、小鲜肉周末出去玩&#xff0c;路上闲聊。老公提到小鲜肉在他们班成绩大概是第四名。 我说&#xff1a;我小学五年级的时候我们我们班60个人我排第四。你们班不到30个人。这么算你成绩不如我小时候…

Qt编写跨平台的推流工具(支持win/linux/mac/嵌入式linux/安卓等)

一、前言 跨平台的推流工具当属OBS最牛逼&#xff0c;功能也是最强大的&#xff0c;唯一的遗憾就是多路推流需要用到插件&#xff0c;而且CPU占用比较高&#xff0c;默认OBS的规则是将对应画布中的视频画面和设定的音频一起重新编码再推流&#xff0c;意味着肯定占用不少CPU资…

【解决】笔记本电脑wifi无法访问网站的各种情况

本文适用于 mac 以及 windows 等操作系统 场景 手机可以连接wifi&#xff0c;电脑连接却无法访问左下角wifi图标为小地球可以使用app&#xff0c;无法访问网站其他 方式一 Win10任务栏中的网络变成小地球&#xff0c;无WIFI列表显示&#xff0c;应该&#xff1a; winR , 输入…

MATLAB计算程序运行所需的时间

在使用MATLAB进行计算时&#xff0c;用户有时需要了解程序运行所花费的四件&#xff0c;以此来评价程序的执行效率&#xff0c;从而对代码进行优化 可以使用3种方法来得到程序运行所需要的时间 1.使用tic和toc命令 将tic和toc命令相结合来得到程序的运行时间 ①tic命令&…

SAP CAP篇六:为CAP添加Fiori Elements程序(3)

本文目录 本系列之前的文章本篇之前的运行效果修改pom.xml添加新的Dependency更新plugin 添加新的Controller创建index目录添加UiIndexContentProviderFactory.java 添加resources运行结果更新UiIndexContentProviderFactory 代码库 (Gitcode) 本系列之前的文章 本系列之前的文…

文学创作的数学原理——5年文学阅读的思考

作者 | gongyouliu 编辑 | gongyouliu 我从2019年初开始阅读文学作品&#xff0c;到今年差不多5年了&#xff0c;至少也阅读了50本以上的世界名著了&#xff08;如果算「得到」听书上的文学作品&#xff0c;那么至少也有200本以上了&#xff09;&#xff0c;这里面绝大多数都是…

python(10):批量修改文件名

文章目录 1. 使用Python的字符串操作来去除文件名高位的多余零说明代码示例 2. 将文件夹中的文件重命名为递增的数字加上原始文件名的后缀代码运行前后&#xff1a; 1. 使用Python的字符串操作来去除文件名高位的多余零 说明 一个目录下的文件名是6位数字序号加上后缀的格式&…

PaddleSeg在Windows上的配置及人像分隔使用

PaddleSeg是基于飞桨PaddlePaddle开源的端到端图像分割套件&#xff0c;提供语义分割、交互式分割、Matting、全景分割四大分割能力。源代码地址&#xff1a;https://github.com/PaddlePaddle/PaddleSeg&#xff0c;license为Apache-2.0&#xff0c;最新发布版本为2.8。 Window…