千里马Android Framework实战开发-binder驱动常见binder_open,binder_mmap介绍

想掌握-Binder-机制?驱动核心源码详解和Binder超系统学习资源,想学不会都难! 简历首选内推方式,速度快,效率高啊!然后可以在拉钩,boss,脉脉,大街上看看。简历上写道熟悉什么技术就一定要去熟悉它,不然被问到不会很尴尬!做过什么项目,即使项目体量不大,但也一定要熟悉实现原理!不是你负责的部分,也可以看看同事是怎么实现的,换你来做你会怎么做?做过什么,会什么是广度问题,取决于项目内容。但做过什么,达到怎样一个境界,这是深度问题,和个人学习能力和解决问题的态度有关了。大公司看深度,小公司看广度。大公司面试你会的,小公司面试他们用到的你会不会,也就是岗位匹配度。 阅读详情
AI摘要

本文深入探讨Android Binder驱动,解析binder_open和binder_mmap两个关键函数,揭示Binder如何实现进程间通信。binder_open主要用于初始化binder_proc结构体,而binder_mmap则涉及用户空间与内核空间的内存映射,动态分配物理页并建立映射关系。通过对vm_area_struct的理解,阐述了Binder驱动如何处理内存分配和管理。

csdn在线学习课程,课程咨询答疑和新课信息:QQ交流群:422901085进行课程讨论

android跨进程通信实战视频课程(加群获取优惠)

背景知识:

大家经常听到的驱动驱动,是不是一般都会有与一个具体的硬件设备相关,比如说wifi驱动,触摸屏驱动等。binder驱动是不是也是会有一个对应的一个硬件设备呢?哈哈,这里要告诉大家是没有的,因为binder本身只是用于操作系统进程间一个通讯而已,只涉及一些内存的拷贝,并不需要额外的硬件来支持,和linux常见的socket,共享内存,等一样哈。所以binder驱动不是实体的硬件驱动。
方法映射关系:
binder驱动代码是在内核层,而普通进程的都是通过一些常见的系统调用才可以到达内核层,所以肯定会有如下的一些应用层的系统调用方法和内核驱动代码的方法映射关系:
open ---->binder_open
mmap -->binder_mmap
ioctl -->binder_ioctl
这个大家记住就行哈,暂时不用深究,就行java到jni一样。。就是一种规则

1.binder_open

static int binder_open(struct inode *nodp, struct file *filp)
{
	struct binder_proc *proc;//声明binder_proc指针
	struct binder_device *binder_dev;
	//开始真正内核中开辟binder_proc 空间
	proc = kzalloc(sizeof(*proc), GFP_KERNEL);
	//初始化todo队列
	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);
	//初始化waiting_threads队列
	INIT_LIST_HEAD(&proc->waiting_threads);
	//proc赋值给private_data 方便后面的使用
	filp->private_data = proc;
	//把proc->proc_node加入binder_procs的list中
	hlist_add_head(&proc->proc_node, &binder_procs);

	return 0;
}

可以看出这里open中主要是做了binder_proc这个结构体的初始化和赋值操作,这里面只是对部分的成员做了赋值,其实binder_proc有很多关键的元素:

struct binder_proc {
	struct hlist_node proc_node;
	//rb_root 其实是红黑树,red black, threads 是binder_proc 进程内用于处理用户请求的线程
	struct rb_root threads;
	// nodes树 代表binder_proc 进程内创建的binder实体对象
	struct rb_root nodes;
	//表示一个binder_ref红黑树,但变了访问获取是通过desc
	struct rb_root refs_by_desc;
	//表示一个binder_ref红黑树,但变了访问获取是通过node
	struct rb_root refs_by_node;
	struct list_head waiting_threads;
	int pid;
	struct task_struct *tsk;
	struct files_struct *files;
	struct mutex files_lock;
	struct hlist_node deferred_work_node;
	int deferred_work;
	bool is_dead;

	struct list_head todo;
	struct binder_stats stats;
	struct list_head delivered_death;
	int max_threads;
	int requested_threads;
	int requested_threads_started;
	int tmp_ref;
	struct binder_priority default_priority;
	struct dentry *debugfs_entry;
	struct binder_alloc alloc;
	struct binder_context *context;
	spinlock_t inner_lock;
	spinlock_t outer_lock;
};

2、binder_mmap

binder.c

static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
	int ret;
	struct binder_proc *proc = filp->private_data;
    //..省略
	//判断申请内存大小是否超过4M如果超过就最多只给4M
	if ((vma->vm_end - vma->vm_start) > SZ_4M)
		vma->vm_end = vma->vm_start + SZ_4M;
	//..省略
	vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE;
	vma->vm_ops = &binder_vm_ops;
	vma->vm_private_data = proc;

	ret = binder_alloc_mmap_handler(&proc->alloc, vma);
   //..省略
}


这里是不是参数里面有个vm_area_struct和vm_struct 结构体,感觉比较陌生?
vm_area_struct 用于表示0~3G的空间中一段连续的虚拟地址空间,是给user space的process使用.
vm_struct 是kernel space 除low memory中用于表示连续的虚拟地址空间,常用于vmalloc/vfree的操作
大家就可以简单理解为vm_area_struct 就是用户空间的虚拟内存描述结构体,vm_struct 是kernel中的虚拟内存描述结构体。
所以这里大参数是用户空间传递来的虚拟内存结构体。
这里binder_mmap除了判断限制了申请内存最大为4M,其他真正业务都是在binder_alloc_mmap_handler方法中,同时把proc的binder_alloc传递类进去,及用户空间的vm_area_struct 也传递了进去
binder_alloc.c

int binder_alloc_mmap_handler(struct binder_alloc *alloc,
			      struct vm_area_struct *vma)
{
	int ret;
	struct vm_struct *area;
	const char *failure_string;
	struct binder_buffer *buffer;
	//根据用户空间的vm_area_struct 虚拟地址大小,同样子内核也申请一个虚拟地址结构体
	area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
	//让binder_alloc指向内核申请的虚拟地址
	alloc->buffer = area->addr;
	//通过用户空间虚拟地址起始位与内核虚拟地址起始相减得出与内核与虚拟地址的偏移,这个比较关键哦 
	alloc->user_buffer_offset =
		vma->vm_start - (uintptr_t)alloc->buffer;
	//配置物理页的指针数组,数组大小为 vma 的等效 page 个数
	alloc->pages = kzalloc(sizeof(alloc->pages[0]) *
				   ((vma->vm_end - vma->vm_start) / PAGE_SIZE),
			       GFP_KERNEL);
	alloc->buffer_size = vma->vm_end - vma->vm_start;
	//构造出binder_buffer结构体,而且让buffer->data指向的是alloc->buffer
	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
	buffer->data = alloc->buffer;
	//把bufferbuffer->entry加入到alloc->buffers
	list_add(&buffer->entry, &alloc->buffers);
	buffer->free = 1;
	binder_insert_free_buffer(alloc, buffer);
	//异步空闲空间为正常的1/2
	alloc->free_async_space = alloc->buffer_size / 2;
	..省略
	//把应用空间的vma赋值给binder_alloc 的vma
	alloc->vma = vma;
	alloc->vma_vm_mm = vma->vm_mm;
	..省略
}

上面都有详细注释,这里大家是不是会看到好像整个mmap都只是在构造出对应结构体和物理页数据,没有看到真实的内存申请,这个因为改进版本变成你需要内存时候再给你动态分配多少,而不是一开始系统就分配好1M -8K的内存,真正申请内存是按物理页为单位进行申请,具体申请内存方法看如下:
binder_alloc.c

static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
				    void *start, void *end)
{
	void *page_addr;
	unsigned long user_page_addr;
	struct binder_lru_page *page;
	struct vm_area_struct *vma = NULL;
	struct mm_struct *mm = NULL;
	bool need_mm = false;

	。。省略
	//根据start和end区域大小,计算申请对应的内存页
	for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
		page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
		//判断这个物理页是否已经申请,如果没有申请则need_mm = true;就从这一页开始申请分配物理内存
		if (!page->page_ptr) {
			need_mm = true;
			break;
		}
	}

	/* Same as mmget_not_zero() in later kernel versions */
	if (need_mm && atomic_inc_not_zero(&alloc->vma_vm_mm->mm_users))
		mm = alloc->vma_vm_mm;

	if (mm) {
		down_write(&mm->mmap_sem);
		vma = alloc->vma;
	}
//又一次遍历。。其实好像和上面的代码有点重复遍历,可以考虑是否可以优化这里减少遍历次数
	for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
	
		index = (page_addr - alloc->buffer) / PAGE_SIZE;
		page = &alloc->pages[index];
		//page->page_ptr不为null说明已经被使用,只能继续遍历
		if (page->page_ptr) {
		   //lru优化。。。暂时不理会
			on_lru = list_lru_del(&binder_alloc_lru, &page->lru);
			continue;
		}
		//遍历到了没有被申请使用的,那就开始真正page内存页申请
		page->page_ptr = alloc_page(GFP_KERNEL |
					    __GFP_HIGHMEM |
					    __GFP_ZERO);
		。。省略
		page->alloc = alloc;
		//把内核虚拟地址page_addr与真实的页内存进行映射
		ret = map_kernel_range_noflush((unsigned long)page_addr,
					       PAGE_SIZE, PAGE_KERNEL,
					       &page->page_ptr);
		flush_cache_vmap((unsigned long)page_addr,
				(unsigned long)page_addr + PAGE_SIZE);
		//根据原来的内核和用户空间地址偏移,可以直接得出用户空间的虚拟地址
		user_page_addr =
			(uintptr_t)page_addr + alloc->user_buffer_offset;
		////把用户空间虚拟地址user_page_addr与真实的页内存进行映射
		ret = vm_insert_page(vma, user_page_addr, page[0].page_ptr);
	

		if (index + 1 > alloc->pages_high)
			alloc->pages_high = index + 1;
	}
	
	。。省略
}

具体map_kernel_range_noflush和flush_cache_vmap源码可以参考https://www.cnblogs.com/arnoldlu/p/8251333.html

深入解析luckyExcel处理xlsx与xls文件的实战技巧 本文深入解析了使用luckyExcel库在前端处理.xlsx与.xls文件的实战技巧。针对.xlsx文件,可直接调用API转换;对于老旧的.xls格式,则需结合SheetJS进行预处理。文章详细介绍了核心API的使用、两种格式的处理流程、数据提取方法以及性能优化建议,为开发在线Excel编辑应用提供了完整解决方案。 阅读详情

相关推荐

【NLP】文献翻译4——CH-SIMS:中文多模态情感分析数据集与细粒度的模态注释

CH-SIMS: A Chinese Multimodal Sentiment Analysis Dataset with Fine-grained Annotations of Modality摘要1. 介绍2. 相关工作2.1 多模态数据集2.2 多模态情感分析2.3 多任务学习3. CH-SIMS 数据集3.1 数据获取3.2 标注3.3 特征提取4. 多模式多任务学习框架4.1 单模态子网4.2 特征融合网络4.3 优化目标5. 实验5.1 基准5.2 实验的细节5.3 结果和讨论5.3.1 与

YoungSeng's Blog 1万+

binder驱动分析

相关源码文件: /drivers/android/binder.c /drivers/staging/android/binder.c 1.binder_init 用户态的程序调用 Kernel 层方法需要陷入内核态,进行系统调用(syscall),打开 Binder 驱动方法的调用链为: open-> __open() -> binder_open()。 open() 为用户空间的方法,__open() 便是系统调用中相应的处理方法,内部通过查找会找到对应的内核 binder 驱动的 bin

qq_34888036的博客 944

基于PI双闭环解耦控制的三相SVPWM电压型逆变器(1)--数学模型

三相电压型逆变器、双PI控制、SVPWM、解耦

weixin_58670090的博客 1万+

android onserviceconnected_Android进程间通信详解

由于android系统中应用程序之间不能共享内存。因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些。进程间通信(ipc)IPC方法总是产生客户/服务端模式的调用,也即是客户端组件(Activity/Service)持有服务端Service的组件,只能是客户端主动调用服务端的方法,服务端无法反过来调用客户端的方法,因为IPC的另一端Service无法获取客户端的对象。binde...

weixin_39968801的博客 1406

Python赋能,洞见先机:构建基于异步爬虫与流处理的实时舆情监控系统

我们将从核心概念入手,逐步搭建一个集。.option("es.resource", "public-opinion-%s" % time.strftime("%Y-%m-%d")) \ # 按日期分索引。| 数据采集层 |----->| 消息队列层 |----->| 流处理与分析层 |----->| 存储与可视化层 |:使用Spark Streaming的状态操作或Flink的CEP库,检测更复杂的模式,如“某关键词的负面舆情在1小时内激增500%”。

2201_76125261的博客 434

Neo4j LLM知识图谱构建器使用教程

是一个开源应用程序,旨在将非结构化数据(如PDF、文档、文本、YouTube视频、网页等)转换为存储在Neo4j中的知识图谱。该项目利用大型语言模型(如OpenAI、Gemini等)从文本中提取节点、关系及其属性,并通过Langchain框架创建结构化的知识图谱。

u013250861的博客 541

理解Android Binder机制(1/3):驱动篇

http://qiangbo.space/2017-01-15/AndroidAnatomy_Binder_Driver/ Binder的实现是比较复杂的,想要完全弄明白是怎么一回事,并不是一件容易的事情。 这里面牵涉到好几个层次,每一层都有一些模块和机制需要理解。这部分内容预计会分为三篇文章来讲解。本文是第一篇,首先会对整个Binder机制做一个架构性的讲解,然后会将大部分精力用

zdy0_2004的专栏 2994

Python在振动信号处理中的应用(一):振动信号消除多项式趋势项

文章目录一、概述二、最小二乘法去除趋势项原理三、python模块介绍3.1 scikitlearn简介(1)转化器(Transformer)(2)估计器(Estimator)3.2 线性回归LinearRegression3.3 多项式PolynomialFeatures3.4 工作流Pipeline四、python代码实现4.1 构造模拟信号4.2 编写去除趋势项主代码4.3 展示算法效果五、TIPS 一、概述   在振动测试过程中,传感器或采集设备由于自身性能问题或受环境干扰(如温度、供电等影响),容易

白银时代的博客 8578

Android进程间通信之一:Binder机制学习

Binder机制学习Binder驱动Binder核心APILinux 使用两级保护机制:0 级供系统内核使用,3 级供用户程序使用。Linux 下的传统 IPC 通信原理Linux 下的传统 IPC 通信原理Binder通信过程ServiceManager进程启动MMAP Binder驱动 binder驱动在以misc设备进行注册,作为虚拟字符设备,没有直接操作硬件,只是对设备内存的处理。 主要是驱动设备的初始化(binder_init),打开 (binder_open),映射(binder_mmap)

北洋的博客 9037

【AI应用实战-claude】在飞书上接入claudecode进行远程使用(十三)

本文介绍了三种将ClaudeCode接入飞书的方案,包括官方飞书CLI工具(推荐)、cc-connect中转工具和MCP协议集成。官方飞书CLI适合自动化办公场景,通过简单配置即可实现消息发送和文档管理;cc-connect适用于远程调用Claude功能,通过飞书群聊触发响应;MCP协议则适合开发者构建复杂工作流。文章提供了详细的操作步骤,并针对不同使用场景给出了选择建议。

1013

政务帮办新范式:基于检索增强与多智能体协同的智能系统实践

本文提出了一种多智能体协同的智能政务系统架构,突破传统方案在状态管理、职责过载和感知闭环方面的局限。系统由中央规划智能体、对话引导智能体、参数提取智能体和执行状态分析智能体组成,通过职责分离与显式状态管理实现高效协同。核心创新在于中央决策引擎的确定性逻辑,采用基于规则的状态机设计,确保系统可靠可控。该架构支持自然语言交互、参数自动提取、业务系统操作和视觉闭环验证,能够真正实现"帮办"功能,显著提升政务服务的智能化水平。

469

千里马Android Framework实战开发视频-binder驱动的简单核心方法及原理介绍

binder驱动的简单核心方法及原理介绍 1、linux操作系统用户空间和内核空间简单介绍 一般内核空间1GB,用户空间是3GB 2. 为什么要分为内核空间和用户空间 cpu在不同的工作模式下可以访问的寄存器是不一样的,所以为了保护我们的操作系统,避免用户程序将内核搞崩,所以进行了内核空间和用户空间的划分。 3.用户空间想要访问内核空间怎么办? 只能通过系统调用和硬件中断完成,常见就是系统调用 4、binder驱动中涉及的系统调用有哪些? ioctl mmap 5、为什么内核态情况下就是进程间是可以互通的

learnframework的博客 1032

基于深度学习的水质预测:多参数监测与预测

首先,我们需要收集水质监测的多参数数据。收集到的数据应包括不同时间点的水质参数值以及相应的水质等级标签,用于训练和评估深度学习模型。同时,数据的质量和数量对于模型的性能也有重要影响,因此在实际应用中需要充分考虑数据的采集和处理过程。总之,基于深度学习的水质预测可以通过收集水质监测的多参数数据并使用适当的深度学习模型进行训练和预测来实现。通过以上的深度学习模型,我们可以利用水质监测的多参数数据进行水质预测。这种基于深度学习的方法可以提高水质预测的准确性和稳定性,为水质监测和环境保护提供有力支持。

web_bug407的博客 1103

打开Binder设备 -- binder_open

一 binder设备打开的函数实现 binder_open 路径:kernel/drivers/android/binder.c static int binder_open(struct inode *nodp, struct file *filp) { struct binder_proc *proc; binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n", current->group

zhanshenwu的专栏 438

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Binder 驱动源码分析

app 进入 loop,并阻塞读。其中 write_buffer 前面四个字节表示 binder 命令:BC_REPLY其中 BC_TRANSACTION、BC_REPLY 会触发进程间数据交换。从上述代码可知,此命令只是修改了 thread 的 looper 状态为 BINDER_LOOPER_STATE_ENTERED。thread 是从哪里定义的呢?

朝花夕拾 1366

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

binder学习笔记

device_initcall(binder_init) binder_open static int binder_open(struct inode *nodp, struct file *filp) proc = kzalloc(sizeof(*proc), GFP_KERNEL); //此处主要分配了binder_proc结构体,管理数据结构体,每个进程都有独立的记录 proc->tsk = current->group_leader; ...

HZero 1179

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Binder进程间通信机制(图文解析)

前言本来想洋洋洒洒写一篇形象生动的Binder原理的文章,再配上我这个灵魂画手的图画,但是再经过了1个多星期的学习后,我决定了,我自首,我这太年少了 我,太懵懂了,我没成想这Binder机制这么厉害!作为一名Android开发,常年使用java开发的人来说,C实在是太不友好了…..但是Binder机制对于整个Android系统来说,你难道没有感觉到,Binder是多么地重要~~所以我作为一名Andr...

omyrobin的专栏 1万+

Android系统之Binder 机制

转:https://blog.youkuaiyun.com/litao55555/article/details/80597677 写在前面:看过很多大牛写的Binder详解,因为讲得太过晦涩难懂,所以对于新手好像不太友好,为了让新手对于Binder有一个大概的认识,故准备了半个月写了这篇博客,博客的大概流程应该是正确的,希望看过的新手能够有一些收获。本文主要讲解了三个部分:ServiceManager 启动...

老鹰不捉小鸡 309

Binder驱动之打开设备----binder_open

一 binder设备打开的函数实现binder_open 路径:kernel/drivers/android/binder.c static int binder_open(struct inode *nodp, struct file *filp) { struct binder_proc *proc; binder_debug(BINDER_DEBUG_OPEN_CL...

私房菜 1644

Android mmap+Binder机制

1.Binder ①Binder是什么? 机制:Binder是一种进程间通信的机制 驱动:Binder是一个虚拟物理设备驱动 应用层:Binder是一个能发起进程间通信的JAVA类 Binder就是Android中的血管,在Android中使用Activity、Service等组件时都需要和AMS(system_server)进行通信,这种跨进程的通信都是通过Binder完成。 Activity、Service等组件和AMS不是同一个进程,其实也是多进程通信。 ②为什么要用多进程? 虚拟机给

zenmela2011的专栏 3306

binder机制详解

很全:亲,耐心看完会有收获的 1.Binder通信机制介绍 这篇文章会先对比Binder机制与Linux的通信机制的差别,了解为什么Android会另起炉灶,采用Binder。接着,会根据Binder的机制,去理解什么是Service Manager,在C/S模型中扮演什么角色。最后,会从一次完整的通信活动中,去理解Binder通信的过程。 1.1 Android与Linux

西红柿炒土豆 5398

Binder框架探究之binder驱动

通过Binder框架图示,对于Binder的整体流程有了一个基本的认知后,接下来就可以深入每一个部分进行逐一的探究,首先先来探究:Binder的所谓一次拷贝究竟是什么?这个一次拷贝又是发生在何处? 1 一次拷贝的原理解析 1.1 内核空间和用户空间的数据交互 如上篇 binder-框架认知 中 3.1章节 所陈述的,在Linux中,用户进程和内核空间是隔离的,而内核空间和用户空间之间的相互访问只能通过系统调用(System Call)进行,对于用户空间和内核空间之间的数据交互,常用的是以下的几个函数:.

super_marie的博客 874

【Android】Binder(二)内存划分和Binder实现一次拷贝

内存划分和Binder实现一次拷贝

每天不是在写bug就是在写bug的路上 1802

千里马2024年终总结-android framework实战

心里焦虑加大了,需要调节好平常心面对创业以来最大感受就是“创业艰难”,原本预想的很美好,终于可以有勇气为了理想和兴趣奋斗了,一定是每天满怀激情的干。实际情况是:当自己的兴趣与谋生的收入挂钩时候,一切变得不那么理想和美好。每天还是会有担心自己课程的销售情况,必然就会有焦虑,这种心态和上班兼职搞完全不是一回事。所以心态上确实是相比以前有焦虑一些,这个部分做的不够好。时间不够用创业初期,也没有很多资金搞团队,大部分工作都落到我的头上,比如一些售前咨询,课程研发录制,答疑服务等。

learnframework的博客 2003
上一篇: 千里马Android Framework实战开发-跨进程通信专题博客总结
下一篇: 千里马Android Framework-Binder通信总结流程图
千里马学框架
博客等级 码龄6年 1万+粉丝 650原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值