简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!
优质专栏:Audio工程师进阶系列【原创干货持续更新中...... 】🚀
优质专栏:多媒体系统工程师系列【原创干货持续更新中...... 】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课【原创干货持续更新中......】🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮
🍉🍉🍉文章目录🍉🍉🍉
-
- 🌻1.前言
- 🌻2.Linux内核之binder_update_page_range介绍
-
- [🐓2.1 功能概述](#🐓2.1 功能概述)
- [🐓2.2 技术细节](#🐓2.2 技术细节)
- [🐓2.3 安全性考虑](#🐓2.3 安全性考虑)
- [🐓2.4 总结](#🐓2.4 总结)
- 🌻3.代码实例
🌻1.前言
本篇目的:Linux内核之binder_update_page_range实例用法
🌻2.Linux内核之binder_update_page_range介绍
- Android Binder是Android系统中用于进程间通信(IPC)的一种机制。Binder驱动程序负责实现Binder机制的核心功能,包括数据的传递、线程的管理等。在Binder驱动程序中,
binder_update_page_range
函数是一个重要的函数,用于处理内存映射的相关操作。
🐓2.1 功能概述
binder_update_page_range
函数主要处理Binder内存映射的更新。在Binder通信中,客户端与服务端通过Binder机制进行数据交换,这些数据通常存储在内核空间的内存中。为了减少数据复制,Binder机制采用了内存映射的方式,将内核空间的内存直接映射到用户空间的内存。binder_update_page_range
函数在这个过程中起到了关键作用,它负责更新内存映射的范围,确保数据的一致性和安全性。
🐓2.2 技术细节
- 当Binder驱动需要更新内存映射的范围时,它会调用
binder_update_page_range
函数。这个函数接收四个参数:
proc
:指向当前进程的Binder进程结构体。vma
:指向内存区域的结构体,代表了用户空间的虚拟内存区域。start
:需要更新的内存区域的起始地址。end
:需要更新的内存区域的结束地址。
- 函数首先会检查传递的参数是否有效。如果参数无效,函数会直接返回错误代码。
- 接下来,函数会遍历
proc
中的buffers
链表,查找与start
和end
地址匹配的内存缓冲区。对于找到的每个缓冲区,函数会执行以下操作:
- 如果缓冲区是写缓冲区(
is_buffer
为真),并且当前进程有写权限,则设置相应的页面为可写。 - 如果缓冲区是读缓冲区(
is_buffer
为假),则设置相应的页面为只读。 - 如果
end
地址在缓冲区的范围内,但start
地址不在,则设置end
地址对应的页面为只读。
- 在更新页面权限的过程中,函数会使用
vm_insert_page
和vm_set_page_range
等函数来操作虚拟内存区域。
🐓2.3 安全性考虑
binder_update_page_range
函数在更新内存映射时,会根据进程的权限来设置页面的读写权限。这样可以防止没有权限的进程修改其他进程的数据,从而保证了数据的安全性和一致性。
🐓2.4 总结
binder_update_page_range
函数是Binder驱动程序中一个关键的函数,它负责更新Binder内存映射的范围,确保数据的一致性和安全性。通过合理的参数检查和页面权限设置,该函数有效地管理了Binder通信过程中的内存映射,提高了Android系统的稳定性和可靠性。
🌻3.代码实例
cpp
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#define PAGE_SIZE 4096
struct binder_lru_page {
void *page_ptr;
struct list_head lru;
struct binder_alloc *alloc;
};
struct binder_alloc {
int pid; // 进程ID
unsigned char buffer[PAGE_SIZE]; // 缓冲区
struct binder_lru_page *pages; // 内存页面列表
struct vm_area_struct *vma; // 进程的虚拟内存区域
struct mm_struct *vma_vm_mm; // 进程的内存描述符
size_t pages_high; // 分配的页面数量
};
// 模拟 binder_update_page_range 函数,这里简单返回 0 表示成功
static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
void __user *start, void __user *end)
{
printk(KERN_INFO "Binder update page range called\n");
return 0;
}
static int __init my_module_init(void)
{
void __user *start_addr = (void *)0x10000000; // 虚拟地址起始位置
void __user *end_addr = (void *)(0x10000000 + PAGE_SIZE); // 虚拟地址结束位置
struct binder_alloc alloc;
int ret;
printk(KERN_INFO "Module init\n");
// 初始化Binder分配器
alloc.pid = 1; // 设置进程ID
alloc.pages = kmalloc(sizeof(struct binder_lru_page), GFP_KERNEL);
if (!alloc.pages) {
printk(KERN_ERR "Failed to allocate memory for pages\n");
return -ENOMEM;
}
// 调用binder_update_page_range()函数分配内存页面并建立映射
ret = binder_update_page_range(&alloc, 1, start_addr, end_addr);
if (ret < 0) {
printk(KERN_ERR "Failed to map virtual address to physical space\n");
kfree(alloc.pages);
return ret;
}
printk(KERN_INFO "Mapped virtual address to physical space\n");
return 0;
}
static void __exit my_module_exit(void)
{
printk(KERN_INFO "Module exit\n");
}
module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");
-
binder_update_page_range 函数是 Android Binder 驱动中的一个关键部分,用于管理 Binder 缓冲区的内存分配和映射。它的作用包括:
-
1.分配或释放用户空间和内核空间之间的内存页面。
-
2.在用户空间和内核空间之间建立内存页面的映射。
-
3.管理内存页面的LRU(最近最少使用)列表,以便在需要时可以快速访问。
-
binder_update_page_range数的主要功能:
接收参数 alloc,它是一个指向 binder_alloc 结构体的指针,包含了内存分配器的信息。
接收参数 allocate,用于指示是分配内存页面还是释放内存页面。
接收参数 start 和 end,表示用户空间的虚拟地址范围。
遍历指定范围内的每个页面,检查是否已经分配了相应的页面,如果没有,则进行分配。 -
对于分配的页面,将其映射到用户空间。
-
对于释放的页面,将其重新加入到LRU列表中以便重复使用。
-
最后,根据需要释放锁和资源,并返回适当的错误码。