从0到1学Binder-Binder驱动初始化

文章目录

  • 1. binder_alloc_shrinker_init
  • 2. debugfs_create_dir/debugfs_create_file
  • 3. init_binder_device
  • 4. init_binderfs

我的微信公众号“ZZH的Android”,还有更多 Android 系统源码解析的干货文章等着你,欢迎关注加入交流群。

binder驱动启动入口如下

// android-kernel/common/drivers/android/binder.c
device_initcall(binder_init);

device_initcall是Binder驱动的入口,其最终调用的是__define_initcall(fn, 6),这里的fn就是传入的函数binder_init。

这里稍微拓展一下驱动的启动内容,不同的驱动启动顺序是不同的,系统会按照优先级依次启动。
不同的调用入口调用代表了不同的启动顺序,其定义如下:

// android-kernel/common/include/linux/init.h
/** A "pure" initcall has no dependencies on anything else, and purely* initializes variables that couldn't be statically initialized.** This only exists for built-in code, not for modules.* Keep main.c:initcall_level_names[] in sync.*/
#define pure_initcall(fn)		__define_initcall(fn, 0)#define core_initcall(fn)		__define_initcall(fn, 1)
#define core_initcall_sync(fn)		__define_initcall(fn, 1s)
#define postcore_initcall(fn)		__define_initcall(fn, 2)
#define postcore_initcall_sync(fn)	__define_initcall(fn, 2s)
#define arch_initcall(fn)		__define_initcall(fn, 3)
#define arch_initcall_sync(fn)		__define_initcall(fn, 3s)
#define subsys_initcall(fn)		__define_initcall(fn, 4)
#define subsys_initcall_sync(fn)	__define_initcall(fn, 4s)
#define fs_initcall(fn)			__define_initcall(fn, 5)
#define fs_initcall_sync(fn)		__define_initcall(fn, 5s)
#define rootfs_initcall(fn)		__define_initcall(fn, rootfs)
#define device_initcall(fn)		__define_initcall(fn, 6)
#define device_initcall_sync(fn)	__define_initcall(fn, 6s)
#define late_initcall(fn)		__define_initcall(fn, 7)
#define late_initcall_sync(fn)		__define_initcall(fn, 7s)

上面定义了0-7一共8个等级,数值越小越先启动,binder驱动使用的是device_initcall(fn) ,属于启动比较晚的了。

下面开始分析binder_init函数。

// android-kernel/common/drivers/android/binder.c
static int __init binder_init(void)
{int ret;char *device_name, *device_tmp;struct binder_device *device;struct hlist_node *tmp;char *device_names = NULL;// 1ret = binder_alloc_shrinker_init();if (ret)return ret;atomic_set(&binder_transaction_log.cur, ~0U);atomic_set(&binder_transaction_log_failed.cur, ~0U);// 2binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);if (binder_debugfs_dir_entry_root) {const struct binder_debugfs_entry *db_entry;binder_for_each_debugfs_entry(db_entry)debugfs_create_file(db_entry->name,db_entry->mode,binder_debugfs_dir_entry_root,db_entry->data,db_entry->fops);binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",binder_debugfs_dir_entry_root);}// 3if (!IS_ENABLED(CONFIG_ANDROID_BINDERFS) &&strcmp(binder_devices_param, "") != 0) {/** Copy the module_parameter string, because we don't want to* tokenize it in-place.*/device_names = kstrdup(binder_devices_param, GFP_KERNEL);if (!device_names) {ret = -ENOMEM;goto err_alloc_device_names_failed;}device_tmp = device_names;while ((device_name = strsep(&device_tmp, ","))) {ret = init_binder_device(device_name);if (ret)goto err_init_binder_device_failed;}}// 4ret = init_binderfs();if (ret)goto err_init_binder_device_failed;return ret;err_init_binder_device_failed:hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) {misc_deregister(&device->miscdev);hlist_del(&device->hlist);kfree(device);}kfree(device_names);err_alloc_device_names_failed:debugfs_remove_recursive(binder_debugfs_dir_entry_root);binder_alloc_shrinker_exit();return ret;
}

1. binder_alloc_shrinker_init

该函数的作用是在 Android 系统中的 Binder 驱动程序中初始化一个 shrinker 结构,用于内存管理和内存回收。下面是对其作用的详细解释:

内存管理:Binder 是 Android 系统中用于进程间通信(IPC)的机制,它涉及到内核空间和用户空间之间的数据传输。在这个过程中,会涉及到内存的分配和释放。binder_alloc_shrinker_init 函数的主要作用是帮助管理 Binder 驱动程序中的内存分配和释放。

shrinker 结构:shrinker 结构是 Linux 内核中用于内存回收的一种机制。当系统内存不足时,内核会调用 shrinker 结构中的回调函数来释放一些不必要的内存,以便为系统提供更多可用内存。binder_alloc_shrinker_init 函数初始化了一个 shrinker 结构,使其能够在需要时被内核调用。

内存回收:通过初始化 shrinker 结构,binder_alloc_shrinker_init 函数为 Binder 驱动程序提供了一种内存回收的机制。当系统内存不足时,内核可以调用 Binder 驱动程序中的 shrinker 结构来释放一些不必要的内存,从而帮助系统更好地管理内存资源,提高系统的稳定性和性能。

总结成一句话就是,向Linux的内存管理模块shrinker注册回调函数,当内存不足时能够收到系统的回调并进行内存的释放和回收处理。

2. debugfs_create_dir/debugfs_create_file

下面这段代码在 debugfs 文件系统中创建了一个名为 “binder” 的目录,并在该目录下创建了一些调试文件和一个名为 “proc” 的子目录。这些文件和目录用于导出 Binder 驱动的调试信息,方便内核开发人员进行调试和分析。这些调试信息可以包括但不限于事务日志、性能统计和状态信息。

// 创建binder目录
binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
if (binder_debugfs_dir_entry_root) {const struct binder_debugfs_entry *db_entry;// 在binder目录下创建各种文件binder_for_each_debugfs_entry(db_entry)debugfs_create_file(db_entry->name,db_entry->mode,binder_debugfs_dir_entry_root,db_entry->data,db_entry->fops);// 在binder目录下创建proc目录binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",binder_debugfs_dir_entry_root);
}

可以关注一下binder_for_each_debugfs_entry的实现

// 其实就是个for循环
#define binder_for_each_debugfs_entry(entry)	\for ((entry) = binder_debugfs_entries;	\(entry)->name;			\(entry)++)       

下面就是在binder目录下创建的文件信息:

const struct binder_debugfs_entry binder_debugfs_entries[] = {{.name = "state",.mode = 0444,.fops = &state_fops,.data = NULL,},{.name = "stats",.mode = 0444,.fops = &stats_fops,.data = NULL,},{.name = "transactions",.mode = 0444,.fops = &transactions_fops,.data = NULL,},{.name = "transaction_log",.mode = 0444,.fops = &transaction_log_fops,.data = &binder_transaction_log,},{.name = "failed_transaction_log",.mode = 0444,.fops = &transaction_log_fops,.data = &binder_transaction_log_failed,},{} /* terminator */
};

调试信息的作用

**调试和开发:**开发人员可以通过这些调试文件查看和分析 Binder 驱动的运行状态,找出潜在的问题或优化点。

**性能监控:**通过这些文件,可以监控 Binder 驱动的性能指标,确保其在高负载下的稳定性和效率。

**故障诊断:**在系统发生故障时,这些调试信息可以帮助快速定位和解决问题。

但是我们在设备里面却发现,/sys/kernel/debug/目录是空的。原因是debugfs文件系统没有被挂载,执行如下命令进行挂载即可。

mount -t debugfs none /sys/kernel/debug

然后就能看到上面创建的文件信息了

vsoc_x86_64:/sys/kernel/debug/binder # ls -lh
total 0
-r--r--r-- 1 root root 0 2024-06-05 18:29 failed_transaction_log
drwxr-xr-x 2 root root 0 2024-06-05 18:39 proc
-r--r--r-- 1 root root 0 2024-06-05 18:29 state
-r--r--r-- 1 root root 0 2024-06-05 18:29 stats
-r--r--r-- 1 root root 0 2024-06-05 18:29 transaction_log
-r--r--r-- 1 root root 0 2024-06-05 18:29 transactions

3. init_binder_device

从代码里可以看到,如果没有配置CONFIG_ANDROID_BINDERFS,并且binder_devices_param不为空的话,就会执行init_binder_device来注册binder设备。

if (!IS_ENABLED(CONFIG_ANDROID_BINDERFS) &&strcmp(binder_devices_param, "") != 0) {/** Copy the module_parameter string, because we don't want to* tokenize it in-place.*/device_names = kstrdup(binder_devices_param, GFP_KERNEL);if (!device_names) {ret = -ENOMEM;goto err_alloc_device_names_failed;}device_tmp = device_names;while ((device_name = strsep(&device_tmp, ","))) {ret = init_binder_device(device_name);if (ret)goto err_init_binder_device_failed;}
}

binder_devices_param的定义

// android-kernel/common/drivers/android/binder.c
char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES;
// android-kernel/common/kernel/configs/android-base.config
CONFIG_ANDROID_BINDER_DEVICES=binder,hwbinder,vndbinder

这里看到会初始化三个binder驱动设备dev/binder,dev/hwbinder,dev/vnbinder,那么这三者有何不同呢?

binder是system分区的进程间通过binder通信的binder设备;

hwbinder是system分区进程和vendor分区进程间通过binder通信的binder设备;

vnbinder是vendor分区的进程间通过binder通信的binder设备;

核心函数是init_binder_device

static int __init init_binder_device(const char *name)
{int ret;struct binder_device *binder_device;binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL);if (!binder_device)return -ENOMEM;// binder_fops为binder设备操作函数binder_device->miscdev.fops = &binder_fops;binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;binder_device->miscdev.name = name;refcount_set(&binder_device->ref, 1);binder_device->context.binder_context_mgr_uid = INVALID_UID;binder_device->context.name = name;mutex_init(&binder_device->context.context_mgr_node_lock);// 注册为一个杂项设备ret = misc_register(&binder_device->miscdev);if (ret < 0) {kfree(binder_device);return ret;}hlist_add_head(&binder_device->hlist, &binder_devices);return ret;
}

4. init_binderfs

之前我们看到在执行init_binder_device时有一个宏判断CONFIG_ANDROID_BINDERFS。

CONFIG_ANDROID_BINDERFS 是一个内核配置选项,用于启用 BinderFS 文件系统,这是 Android 的 Binder IPC 机制的一部分。BinderFS 提供了一种新的方法来管理和使用 Binder 设备文件。

作用与背景

Binder机制:
Android 的 Binder 是一个用于进程间通信(IPC)的机制,允许不同应用程序和系统服务之间进行高效、安全的数据交换。

传统的 Binder 设备管理:
传统上,Binder 设备文件(如 /dev/binder)在设备节点上管理。每个 Binder 设备文件都对应一个具体的设备,设备文件通常由 init 脚本或类似机制创建。

BinderFS 的引入:
BinderFS 是一个文件系统,用于管理和简化 Binder 设备文件的创建和使用。它为 Binder 设备文件提供了一个文件系统抽象,使得这些设备文件更容易管理和隔离。
BinderFS 通过挂载一个特殊的文件系统来动态创建 Binder 设备文件,而不是依赖静态的设备节点配置。

优点

隔离性:
BinderFS 提供了一种隔离不同 Binder 设备文件的方法。通过将不同的 Binder 设备文件挂载在不同的 BinderFS 文件系统上,可以实现更好的隔离性和安全性。

动态管理:
BinderFS 允许在运行时动态创建和删除 Binder 设备文件,而不需要修改 init 脚本或其他静态配置文件。

简化配置:
通过文件系统抽象,BinderFS 简化了 Binder 设备文件的管理,不需要预先定义所有设备文件。

如下代码可以看到,如果没有启用CONFIG_ANDROID_BINDERFS,则init_binderfs就是个空实现。

// android-kernel/common/drivers/android/binder_internal.h
#ifdef CONFIG_ANDROID_BINDERFS
extern int __init init_binderfs(void);
#else
static inline int __init init_binderfs(void)
{return 0;
}
#endif

如果启用了,则代码实现如下

// android-kernel/common/drivers/android/binderfs.c
int __init init_binderfs(void)
{int ret;const char *name;size_t len;/* Verify that the default binderfs device names are valid. */name = binder_devices_param;for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) {if (len > BINDERFS_MAX_NAME)return -E2BIG;name += len;if (*name == ',')name++;}/* Allocate new major number for binderfs. */ret = alloc_chrdev_region(&binderfs_dev, 0, BINDERFS_MAX_MINOR,"binder");if (ret)return ret;ret = register_filesystem(&binder_fs_type);if (ret) {unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR);return ret;}return ret;
}

binder驱动初始化就先讲到这里,只是说了个大概,后面章节介绍通信实现流程时继续讲解。

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

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

相关文章

蓝桥杯物联网竞赛_STM32L071KBU6_第十五届蓝桥杯物联网竞赛国赛代码解析

目录 前言&#xff1a;1、配置及代码&#xff1a;(1) A板&#xff1a;[1] CUBMX配置&#xff1a;[2] keil5代码&#xff1a; (2) B板&#xff1a;[1] CUBMX配置&#xff1a;[2] keil5代码&#xff1a; 2、代码解析&#xff1a; 前言&#xff1a; 这届国赛是目前为止最难一届&am…

计算机发展史 | 从起源到现代技术的演进

computer | Evolution from origins to modern technology 今天没有参考资料哈哈 PPT&#xff1a;&#xff08;评论区&#xff1f;&#xff09; 早期计算工具 算盘 -算盘是一种手动操作的计算辅助工具&#xff0c;起源于中国&#xff0c;迄今已有2600多年的历史&#xff0c;是…

实验9 静态路由配置

实验9 静态路由配置 一、 原理描述二、 实验目的三、 实验内容四、 实验配置五、 实验步骤 一、 原理描述 网络中的每个路由器都会维护一张路由表或转发表。路由表的表项记录着目的网络信息以及下一跳I 地址。路由表可以手动配置&#xff0c;也可以通过路由算法动态生成。静态…

使用 MDC 实现日志链路跟踪,包教包会!

在微服务环境中&#xff0c;我们经常使用 Skywalking、Spring Cloud Sleut 等去实现整体请求链路的追踪&#xff0c;但是这个整体运维成本高&#xff0c;架构复杂&#xff0c;本次我们来使用 MDC 通过 Log 来实现一个轻量级的会话事务跟踪功能&#xff0c;需要的朋友可以参考一…

小世界网络生成及其分析

研究背景: 小世界网络是一种介于规则网络和随机网络之间的网络模型,具有短平均路径和高聚集性的特点。这种网络模型被广泛应用于社交网络、互联网、生物网络等领域的研究中。研究小世界网络的生成和分析可以帮助我们理解和揭示复杂网络的结构和特性,以及网络中信息传播、动力…

数据驱动的未来:数据融合与平台化应用的探索

随着大数据时代的到来&#xff0c;数据驱动的决策制定已成为企业与组织的核心。本文探讨了数据驱动的概念&#xff0c;数据融合的技术及其重要性&#xff0c;并分析了平台化应用如何促进数据的有效利用和价值创造。 数据驱动的决策制定 在信息化时代的浪潮中&#xff0c;数据已…

Flutter之旅:探索安卓与跨平台开发的无限可能

随着移动互联网的飞速发展,移动应用开发已成为企业竞争的重要战场。在众多开发框架中,Flutter凭借其高效的性能和出色的跨平台能力,正引领着一场安卓与跨平台开发的奇幻之旅。本文将从Flutter的起源、特点、优势以及未来展望等方面,深入探讨Flutter在移动应用开发领域的无限…

su和sudu、三剑客中的sed、awk命令

一、用户授权 如果普通用户需要执行特殊操作&#xff0c;有两种方法&#xff1a; su -root 切换到root账户进行特殊操作&#xff0c;然后再回到普通用户 sudo 命令 su命令&#xff1a; 优点&#xff1a;使用简单 缺点&#xff1a;root密码容易泄露 普通用户执行操作不可控 su…

官宣!2024 MongoDB Developer Day来了!北上深三场等你集结!

北上深开发者 专为你们打造的 MongoDB Developer Day 来了&#xff01; 动手实操工作坊➕模型设计优化专场 学习 NoSQL 数据建模的最佳实践 深入探索 MongoDB 的各种可能性 和开发者同行和 MongoDB 技术专家 一起度过充实的一天&#xff01; 北京&#xff08;6/22&…

HBuilderx uniapp启动微信小程序报错[error] Error: Fail to open IDE

1、打开微信呢开发者工具&#xff0c;添加项目 创建小程序--目录&#xff08;目录选择自己小程序项目下的dist/dev/mp-weixin&#xff09;点击确定之后微信开发者工具会自己去编译&#xff0c;等待一会便好&#xff0c;查看微信开发者工具控制台是否有报错日志 如果发现[插件 w…

Yshop框架的小程序登录

1配置 根据请求头去判断&#xff0c;走小程序&#xff0c;还是Pc端。 #jwt jwt:header: Authorization#小程序前缀 请求头mini-program-header: MiAuthorization# 令牌前缀token-start-with: Bearersecret: k09BQnaF# 必须使用最少88位的Base64对该令牌进行编码base64-secret…

6.13 CO-RE(Compile Once – Run Everywhere)简介

写在前面 BPF CO-RE 即Compile Once – Run Everywhere,编译一次——到处运行。BPF CO-RE是为了解决BPF的可移植性而存在,也就是说编写一个BPF程序,该程序能够成功编译、通过内核验证,并且能够在不同的内核版本上正确运行,而无需为每个特定的内核重新编译。 一,BPF可移…

科技与环保

科技与环保之间存在着密不可分的关系&#xff0c;两者相互影响、相互促进&#xff0c;共同推动着社会的可持续发展。以下是对科技与环保关系的详细分析&#xff1a; 一、科技进步对环保的积极作用 提供技术手段和解决方案&#xff1a;科技进步为环境保护提供了强有力的技术支…

maven项目中报错 could not find class that it depends on找不到所依赖的类

maven工程在程序编译时报错&#xff0c;could not find class that it depends on找不到所依赖的类。 能够引起这种错误的原因&#xff1a;jar包缺失、jar包冲突、jar包不完整、IDE工具问题。 本次解决方案&#xff1a;删除本地仓库中的maven项目&#xff0c;重新install项目&a…

Vue05-数据绑定

一、数据绑定 1-1、v-bind指令 1-2、v-model指令 1、单项数据绑定&#xff1a; 2、双向数据绑定 注意&#xff1a; 表单元素&#xff0c;必须要有属性&#xff1a;value&#xff01;&#xff01;&#xff01; 1-3、小结

【数据库系统概论】触发器

【数据库系统概论】触发器 概述 在数据库系统中&#xff0c;触发器&#xff08;Trigger&#xff09;是一种特殊的存储过程&#xff0c;当特定事件在数据库表上发生时&#xff0c;会自动执行。触发器主要用于确保数据的完整性、一致性和实现复杂的业务规则。触发器是由用户定义…

电拖基础JIAOXUE

1.最简单的TT马达&#xff0c;实际就是一个减速电机&#xff1a; 减速箱的内部包含了一组齿轮。在实际的使用中&#xff0c;绝大部分的电动机都要和减速箱配合使用&#xff0c;因为一般的电机转速都在每分钟几千转甚至1万转以上&#xff0c;而在实际的使用中并不需要这么快的转…

PSO-LSSVM-Adaboost分类模型,粒子群算法优化基于最小二乘支持向量机结合Adaboost的数据分类-附代码

PSO-LSSVM-Adaboost是一种结合PSO-LSSVM和AdaBoost两种机器学习技术的方法&#xff0c;旨在提升模型的性能和鲁棒性。具体来说&#xff0c;AdaBoost是一种集成学习方法&#xff0c;通过组合多个弱分类器来形成一个强分类器&#xff0c;每个分类器针对不同的数据集和特征进行训练…

测试记录3:WLS2运行Linux界面

1.WLS1转到WLS2 &#xff08;1&#xff09;根据自己的平台&#xff0c;下载WLS2安装包 x64: https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi arm64: https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_arm64.msi &#xff08;2&…

Oracle和Random Oracle

Oracle和Random Oracle 在计算机理论里面经常可以看到oracle&#xff0c;这个oracle可以是一个程序 一片代码 一个算法 一个机器 也可以是一个函数 甚至是一个关系。但我们只能知道这个oracle能做什么&#xff0c;不清楚他是怎么做的。所以经常讲其称为黑箱。推广一点&#xf…