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

这篇具有很好参考价值的文章主要介绍了Android 13(T) - binder阅读(1)- binder driver。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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。

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


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)
{
	// 1. 创建一个binder_proc指针并为其开辟空间
	struct binder_proc *proc, *itr;
	struct binder_device *binder_dev;
	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);
	// 2. 获取binder driver里的binder_device
	binder_dev = container_of(filp->private_data, struct binder_device, miscdev);
	refcount_inc(&binder_dev->ref);
	// 将binder_proc中的binder_context指向binder驱动的binder_context
	proc->context = &binder_dev->context;
	// 3. 初始化binder_alloc
	binder_alloc_init(&proc->alloc);
	// 4. 记录当前调用进程的pid
	proc->pid = current->group_leader->pid;
	INIT_LIST_HEAD(&proc->delivered_death);
	INIT_LIST_HEAD(&proc->waiting_threads);
	// 5. 将binder_proc记录到fd当中
	filp->private_data = proc;
	// 6. 将binder_proc加入到全局链表binder_procs当中
	hlist_add_head(&proc->proc_node, &binder_procs);
	return 0;
}

我这里删除了很多代码内容,只留下了我认为比较重要的步骤:

  1. 为调用进程创建一个binder_proc对象,binder驱动会为每个进程都创建这样一个对象
  2. 获取binder驱动中的binder_device,该对象是属于binder设备的,于binder_init中创建并初始化。这里获取binder_device是因为它里面存储有一个binder_context成员,这个成员就是ServiceManager,这个后面会讲到;
  3. binder_proc初始化成员binder_alloc,后续mmap分配的内存将会记录在该成员中;
  4. 将当前进程pid记录到binder_proc,有了它binder驱动就可以从茫茫进程中找到目标进程了;
  5. binder_proc记录到fd当中,后续每次iotcl都会通过该fd获取到binder_proc
  6. binder_proc加入到全局链表binder_procs当中;

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;
	}
	// 执行cmd
	switch (cmd) {
		......
	}

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


到这里binder驱动就初步了解结束,我认为这篇笔记比较重要的点在于理解binder_proc的作用:binder驱动会为每个调用进程(无论是源进程还是目标进程)都创建一个binder_proc,并且记录到全局变量当中,后续可以通过binder_proc中的pid实现目标进程的查找。

可能这里对新同学来说还比较抽象,不过不要着急,后面我们慢慢看。

根据MediaServer的调用顺序,打开binder驱动后,会去获取ServiceManager,所以接下来我们先去了解ServiceManager的创建,获取以及调用。文章来源地址https://www.toymoban.com/news/detail-509542.html

到了这里,关于Android 13(T) - binder阅读(1)- binder driver的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Android】Binder(一)Binder的介绍和AIDL使用Binder的实例

    Android 中的 Binder 是一个进程间通信机制,它允许不同进程之间相互调用方法和传递数据。Binder 主要用于实现系统服务和应用程序之间的通信,以及实现 IPC(Inter-Process Communication,进程间通信)。 Binder 的核心是 Binder 驱动程序,它负责管理不同进程之间的通信。每个进程都可

    2024年02月07日
    浏览(27)
  • 【Android】深入Binder拦截

    ☞ Github ☜ ☞ Gitee ☜ Binder 作为 Android 系统跨进程通信的核心机制。网上也有很多深度讲解该机制的文章,如: Android跨进程通信详解Binder机制原理 Android系统核心机制Binder【系列】 这些文章和系统源码可以很好帮助我们理解Binder的实现原理和设计理念,为拦截做准备。借助

    2024年02月03日
    浏览(26)
  • Android Binder小结

    Binder是Android中一种跨进程通信方式,Binder也是一个虚拟设备,对于客户端来说Bidner是一个可以跨进程通信的一个类 Android底层是Linux,但是Linux已有的跨进程通信方式都不能满足Android移动设备的需求,在Android中跨进程通信方式,要求是CS的一对多的架构、需要保证安全,并且

    2023年04月08日
    浏览(25)
  • Android 进阶——Binder IPC之Binder IPC架构及原理概述(九)

    前面几篇文章,为我们学习Binder IPC通信机制提供了扎实的理论基础,接下来将正式进入Binder IPC通信架构及原理的解读。 Binder 是基于 C/S 架构的,由一系列的组件组成,包括 Client进程、Server进程、Service Manager进程、Binder 驱动。其中 Client进程、Server进程、Service Manager进程运行

    2023年04月09日
    浏览(31)
  • Android 基础技术——Binder 机制

    笔者希望做一个系列,整理 Android 基础技术,本章是关于Binder 机制 什么是Binder 机制:Binder 是一种进程间通信机制 驱动:Binder 是一个虚拟物理设备驱动 应用层:Binder 是一个能发起通信的 Java 类 为什么要使用Binder 图解析: 性能上:  binder小于共享内存 优于其他ipc 共

    2024年02月19日
    浏览(24)
  • 浅谈 Android Binder 监控方案

    在 Android 应用开发中,Binder 可以说是使用最为普遍的 IPC 机制了。我们考虑监控 Binder 这一 IPC 机制,一般是出于以下两个目的: 卡顿优化:IPC 流程完整链路较长,且依赖于其他进程,耗时不可控,而 Binder 调用本身通常又是以 RPC 形式对外提供能力的,使得我们在使用时更容

    2024年02月11日
    浏览(61)
  • Android 面试笔记整理-Binder机制

    作者:浪人笔记 面试可能会问到的问题 从IPC的方式问到Binder的优势 为什么zygote跟其他服务进程的通讯不使用Binder Binder线程池和Binder机制 等等这些问题都是基于你对Binder的理解还有对其他IPC通讯的理解 IPC方式有多少种 传统的IPC方式有Socket、共享内存、管道、信号量等 安卓

    2024年02月12日
    浏览(27)
  • [DEMO] Android Binder 的使用

    The Android binderfs Filesystem — The Linux Kernel documentation Android Binder 是一种 IPC 机制,IPC 键值/标识 是一个字符串,收发双方通过 键值/标识 建立通讯路径。 Binder 是通过模板类实现的,因此使用起来并不是那么简明通俗,如果没有demo可以参考的话是需要琢磨好一阵子。 class IInt

    2024年02月13日
    浏览(23)
  • Android Framework——Binder 监控方案

    作者:低性能JsonCodec 在 Android 应用开发中,Binder 可以说是使用最为普遍的 IPC 机制了。我们考虑监控 Binder 这一 IPC 机制,一般是出于以下两个目的: 卡顿优化:IPC 流程完整链路较长,且依赖于其他进程,耗时不可控,而 Binder 调用本身通常又是以 RPC 形式对外提供能力的,

    2024年02月04日
    浏览(24)
  • Android Binder通信原理(一):简介

    源码基于: Android R 在Linux 系统中现有的进程间通信(IPC)方式: 管道(PIPE): 在创建时分配一个page大小的内存,缓存区大小比较有限; 命名管道(FIFO): 考虑 PIPE_BUF 和原子操作; 消息队列: 信息复制两次,额外的CPU消耗;不合适频繁或信息量大的通信; 共享内存:  无须

    2024年02月10日
    浏览(24)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包