android BinderFS 是 Android 操作系统中用于管理 Binder 设备的新型文件系统。 BinderFS 设计用于动态管理 Binder 设备节点。它主要解决了传统 Binder 设备管理中的一些局限性,提供了更灵活和动态的设备节点管理方式。
主要特点
- 动态创建设备节点:BinderFS 可以在运行时动态创建和销毁 Binder 设备节点,而不需要预先在设备文件系统(如 /dev/binder)中创建这些节点。
- 命名空间支持:BinderFS 支持 Linux 命名空间,允许每个命名空间有自己的 Binder 设备集合。
- 简化管理:通过一个简单的文件系统接口,可以更方便地管理 Binder 设备节点,而不需要直接操作设备节点的权限和属性。
为了更好理解这篇文件可以先查看
初始化
device_initcall
宏用于注册设备的初始化函数,这些函数在内核启动过程中会在特定的时间点被调用。这个宏的主要作用是简化设备驱动程序的初始化过程,确保设备在内核启动的适当阶段进行初始化
// Linux 内核中的一个宏,用于标识设备初始化函数
device_initcall(binder_init);
static int __init binder_init(void)
{
int ret;
// ...
ret = init_binderfs(); // 初始化 binder 文件系统
// ...
return ret;
}
int __init init_binderfs(void)
{
int ret;
const char *name;
size_t len;
/* 验证默认的 binder 设备名是否有效. */
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++;
}
/* 为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;
}
// 当文件系统被挂载时会调用 binderfs_init_fs_context 函数
static struct file_system_type binder_fs_type = {
.name = "binder", // 文件系统的名字
.init_fs_context = binderfs_init_fs_context, //初始化文件系统上下文
.parameters = binderfs_fs_parameters, // 文件系统挂载时携带的参数
.kill_sb = kill_litter_super, // 用于销毁文件系统的超级块。
.fs_flags = FS_USERNS_MOUNT, // 文件系统挂载的标识 ,可以由用户命名空间根挂载
};
static const struct constant_table binderfs_param_stats[] = {
{ "global", binderfs_stats_mode_global },
{}
};
// 文件系统挂载时参数配置
static const struct fs_parameter_spec binderfs_fs_parameters[] = {
fsparam_u32("max", Opt_max),
fsparam_enum("stats", Opt_stats_mode, binderfs_param_stats),
{}
};
填充超级块
请注意 binder_devices_param 为 "binder,hwbinder,vndbinder" 创建了三个binder设备文件
static int binderfs_init_fs_context(struct fs_context *fc)
{
struct binderfs_mount_opts *ctx; // binderfs 挂载选项
// 创建 binderfs_mount_opts 对象
ctx = kzalloc(sizeof(struct binderfs_mount_opts), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->max = BINDERFS_MAX_MINOR; // 初始化 max
ctx->stats_mode = binderfs_stats_mode_unset; // 初始化 stats_mode
fc->fs_private = ctx; // binderfs 挂载选项 存储在 fs_private 中
fc->ops = &binderfs_fs_context_ops; // 文件上下文操作
return 0;
}
static const struct fs_context_operations binderfs_fs_context_ops = {
.free = binderfs_fs_context_free,
.get_tree = binderfs_fs_context_get_tree, // 获取文件树
.parse_param = binderfs_fs_context_parse_param, // 解析参数
.reconfigure = binderfs_fs_context_reconfigure,
};
// 解析参数
static int binderfs_fs_context_parse_param(struct fs_context *fc,
struct fs_parameter *param)
{
int opt;
struct binderfs_mount_opts *ctx = fc->fs_private; // 从 fc 取出 binderfs 挂载选项
struct fs_parse_result result;
opt = fs_parse(fc, binderfs_fs_parameters, param, &result); // 解析挂载参数
if (opt < 0)
return opt;
switch (opt) {
// 此参数是为了配置设备号的最大值
case Opt_max:
if (result.uint_32 > BINDERFS_MAX_MINOR)
return invalfc(fc, "Bad value for '%s'", param->key);
ctx->max = result.uint_32;
break;
// 配置为 global 会创建 binder 日志文件
case Opt_stats_mode:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
ctx->stats_mode = result.uint_32;
break;
default:
return invalfc(fc, "Unsupported parameter '%s'", param->key);
}
return 0;
}
static int binderfs_fs_context_get_tree(struct fs_context *fc)
{
// 在内核中创建文件系统的根节点。它通过调用 fill_super 函数来填充文件系统的超级块,
// 并根据超级块的信息创建文件系统的根节点
return get_tree_nodev(fc, binderfs_fill_super);
}
// 填充超级块
static int binderfs_fill_super(struct super_block *sb, struct fs_context *fc)
{
int ret;
struct binderfs_info *info;
struct binderfs_mount_opts *ctx = fc->fs_private;
struct inode *inode = NULL;
struct binderfs_device device_info = {};
const char *name;
size_t len;
sb->s_blocksize = PAGE_SIZE; // PAGE_SIZE 的大小为 4096 字节,即 4KB。
sb->s_blocksize_bits = PAGE_SHIFT;
/*
在非初始用户命名空间中,用户命名空间的根用户可以挂载 binderfs 文件系统。
默认情况下,这种挂载会在超级块的 s_iflags 中设置 SB_I_NODEV 标志,
以防止安全问题,即用户命名空间的根用户可以通过 mknod() 创建任意设备节点,
因为它拥有文件系统挂载。但是,binderfs 不允许创建任何文件,包括设备节点。
创建 binder 设备节点的唯一方式是通过 binder-control 设备,用户命名空间的根用户
被明确允许执行此操作。因此,从 s_iflags 中删除 SB_I_NODEV 标志既是必要的又是安全的。
*/
sb->s_iflags &= ~SB_I_NODEV; // 去除 SB_I_NODEV 标识
sb->s_iflags |= SB_I_NOEXEC; // 添加 SB_I_NOEXEC 标识
sb->s_magic = BINDERFS_SUPER_MAGIC; // binder 文件系统的魔数,值为 0x6c6f6f70
sb->s_op = &binderfs_super_ops; // 超级块的操作
sb->s_time_gran = 1; // 文件系统的访问、修改、创建时间的粒度。表示在文件系统中的时间精度为 1 纳秒
//文件系统特定的私有信息 创建一个 binderfs_info 对象
sb->s_fs_info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL);
if (!sb->s_fs_info)
return -ENOMEM;
info = sb->s_fs_info;
// 表示获取当前进程的 IPC 命名空间
info->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns);
// 用于创建一个内核组 ID(Kerbel GID)的函数调用,并将其存储在 info 结构体中的 root_gid 字段中。
info->root_gid = make_kgid(sb->s_user_ns, 0);
if (!gid_valid(info->root_gid))
info->root_gid = GLOBAL_ROOT_GID;
// 创建一个内核用户 ID(Kerbel UID),并将其存储在 info 结构体中的 root_uid 字段中。
info->root_uid = make_kuid(sb->s_user_ns, 0);
if (!uid_valid(info->root_uid))
info->root_uid = GLOBAL_ROOT_UID;
// 存储挂载选项
info->mount_opts.max = ctx->max;
info->mount_opts.stats_mode = ctx->stats_mode;
// 在超级块中创建一个 inode 对象
inode = new_inode(sb);
if (!inode)
return -ENOMEM;
// 设置 inode 的 inode 号。
inode->i_ino = FIRST_INODE;
// 设置目录 inode 的文件操作函数
inode->i_fop = &simple_dir_operations;
inode->i_mode = S_IFDIR | 0755; // 目录 + 文件权限位
// 初始化目录三个时间
inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
// 设置目录 inode 的操作函数
inode->i_op = &binderfs_dir_inode_operations;
// 设置目录 inode 的硬链接计数为 2,表示该目录有两个链接:一个是自身的链接,另一个是父目录的链接。
set_nlink(inode, 2);
// 创建根目录的 dentry,并将其挂载到超级块(sb)的根目录上
sb->s_root = d_make_root(inode);
if (!sb->s_root)
return -ENOMEM;
// 创建 binder-control 字符设备文件
ret = binderfs_binder_ctl_create(sb);
if (ret)
return ret;
// "binder,hwbinder,vndbinder"
name = binder_devices_param;
for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) {
strscpy(device_info.name, name, len + 1);
// 创建 binder,hwbinder,vndbinder 设备文件
ret = binderfs_binder_device_create(inode, NULL, &device_info);
if (ret)
return ret;
name += len;
if (*name == ',')
name++;
}
// 创建 features 目录
ret = init_binder_features(sb);
if (ret)
return ret;
if (info->mount_opts.stats_mode == binderfs_stats_mode_global)
// 创建 binder_logs 目录
return init_binder_logs(sb);
return 0;
}
/* sb->s_iflags */
#define SB_I_CGROUPWB 0x00000001 /* cgroup-aware writeback enabled */
#define SB_I_NOEXEC 0x00000002 /* Ignore executables on this fs */
#define SB_I_NODEV 0x00000004 /* Ignore devices on this fs */
#define SB_I_STABLE_WRITES 0x00000008 /* don't modify blks until WB is done */
/* sb->s_iflags to limit user namespace mounts */
#define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */
#define SB_I_IMA_UNVERIFIABLE_SIGNATURE 0x00000020
#define SB_I_UNTRUSTED_MOUNTER 0x00000040
#define SB_I_SKIP_SYNC 0x00000100 /* Skip superblock at global sync */
创建 binder-control 文件
// 创建一个新的 binder 控制设备节点,在指定的 binderfs 挂载点(由参数 sb 指定)中创建。
static int binderfs_binder_ctl_create(struct super_block *sb)
{
int minor, ret;
struct dentry *dentry;
struct binder_device *device;
struct inode *inode = NULL;
struct dentry *root = sb->s_root;
struct binderfs_info *info = sb->s_fs_info;
#if defined(CONFIG_IPC_NS)
bool use_reserve = (info->ipc_ns == &init_ipc_ns);
#else
bool use_reserve = true;
#endif
// 创建 binder_device 对象
device = kzalloc(sizeof(*device), GFP_KERNEL);
if (!device)
return -ENOMEM;
/* If we have already created a binder-control node, return. */
if (info->control_dentry) {
ret = 0;
goto out;
}
ret = -ENOMEM;
inode = new_inode(sb);// 创建一个新的 inode
if (!inode)
goto out;
mutex_lock(&binderfs_minors_mutex);
// ida_alloc_max 用于从 IDA(ID Allocator)中分配一个未使用的整数 ID,并指定分配的最大 ID 值
minor = ida_alloc_max(&binderfs_minors,
use_reserve ? BINDERFS_MAX_MINOR :
BINDERFS_MAX_MINOR_CAPPED,
GFP_KERNEL);
mutex_unlock(&binderfs_minors_mutex);
if (minor < 0) {
ret = minor;
goto out;
}
// inode 设置序列号
inode->i_ino = SECOND_INODE;
inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
// 用于初始化特殊文件的 inode。特殊文件包括字符设备、块设备、管道和套接字
init_special_inode(inode, S_IFCHR | 0600, // 字符设备 + 文件权限位
MKDEV(MAJOR(binderfs_dev), minor)); // 设备号
// inode 文件操作函数
inode->i_fop = &binder_ctl_fops;
// 为 inode 设置 uid
inode->i_uid = info->root_uid;
// 为 inode 设置 gid
inode->i_gid = info->root_gid;
// device->ref 初始化引用计数为 1
refcount_set(&device->ref, 1);
//初始化 binder_device 对象
device->binderfs_inode = inode;
device->miscdev.minor = minor;
// 在 binderfs 文件系统中根目录创建一个 binder-control的目录项
dentry = d_alloc_name(root, "binder-control");
if (!dentry)
goto out;
inode->i_private = device;
info->control_dentry = dentry;
// 把 inode 和 dentry 关联起来
d_add(dentry, inode);
return 0;
out:
kfree(device);
iput(inode);
return ret;
}
// binder-control 文件操作
static const struct file_operations binder_ctl_fops = {
.owner = THIS_MODULE,
.open = nonseekable_open,
.unlocked_ioctl = binder_ctl_ioctl,
.compat_ioctl = binder_ctl_ioctl,
.llseek = noop_llseek,
};
创建 binder 文件
请注意 binder_fops 后面打开读写 binder 文件会调用该配置设置的函数指针
// 创建 binder,hwbinder,vndbinder 设备文件
static int binderfs_binder_device_create(struct inode *ref_inode,
struct binderfs_device __user *userp,
struct binderfs_device *req)
{
int minor, ret;
struct dentry *dentry, *root;
struct binder_device *device;
char *name = NULL;
size_t name_len;
struct inode *inode = NULL;
struct super_block *sb = ref_inode->i_sb;
struct binderfs_info *info = sb->s_fs_info;
#if defined(CONFIG_IPC_NS)
bool use_reserve = (info->ipc_ns == &init_ipc_ns);
#else
bool use_reserve = true;
#endif
/*分配次设备号. */
mutex_lock(&binderfs_minors_mutex);
if (++info->device_count <= info->mount_opts.max)
minor = ida_alloc_max(&binderfs_minors,
use_reserve ? BINDERFS_MAX_MINOR :
BINDERFS_MAX_MINOR_CAPPED,
GFP_KERNEL);
else
minor = -ENOSPC;
if (minor < 0) {
--info->device_count;
mutex_unlock(&binderfs_minors_mutex);
return minor;
}
mutex_unlock(&binderfs_minors_mutex);
ret = -ENOMEM;
// 创建 binder_device 对象
device = kzalloc(sizeof(*device), GFP_KERNEL);
if (!device)
goto err;
// 新建一个 inode 对象
inode = new_inode(sb);
if (!inode)
goto err;
inode->i_ino = minor + INODE_OFFSET;
// 设置 inode 文件时间
inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
// 初始化 inode
init_special_inode(inode, S_IFCHR | 0600,
MKDEV(MAJOR(binderfs_dev), minor));
// 设置 inode 的文件操作
inode->i_fop = &binder_fops;
// 设置 inode uid
inode->i_uid = info->root_uid;
// 设置 inode gid
inode->i_gid = info->root_gid;
req->name[BINDERFS_MAX_NAME] = '\0'; /* NUL-terminate */
name_len = strlen(req->name);
/* Make sure to include terminating NUL byte */
name = kmemdup(req->name, name_len + 1, GFP_KERNEL);
if (!name)
goto err;
// device->ref 初始化引用计数为 1
refcount_set(&device->ref, 1);
// 初始化 binder_device 对象
device->binderfs_inode = inode;
device->context.binder_context_mgr_uid = INVALID_UID;
device->context.name = name;
device->miscdev.name = name;
device->miscdev.minor = minor;
mutex_init(&device->context.context_mgr_node_lock);
req->major = MAJOR(binderfs_dev);
req->minor = minor;
if (userp && copy_to_user(userp, req, sizeof(*req))) {
ret = -EFAULT;
goto err;
}
root = sb->s_root;
// 获取 根目录的 inode 对象 并且对 inode 进行同步访问
inode_lock(d_inode(root));
/* 在根目录查找 binder,hwbinder,vndbinder 设备文件 */
dentry = lookup_one_len(name, root, name_len);
/*
当 lookup`操作未找到文件时,仍然返回的一个目录项指针,不过实际上是一个“负向”目录项,它表示了查找失败的结果。
负向目录项允许内核缓存查找失败的结果,以避免在后续查找中重复执行相同的查找操作。
负向目录项的存在对于文件系统的性能是有益的,因为它们减少了对磁盘的访问次数。
当应用程序多次尝试访问不存在的文件时,内核可以快速返回先前的查找失败结果,而无需再次访问磁盘
*/
if (IS_ERR(dentry)) { // 如果是一个错误指针 ,类似 errno
inode_unlock(d_inode(root));
ret = PTR_ERR(dentry);
goto err;
}
// 如果查找到了,说明已经创建过了,报错
if (d_really_is_positive(dentry)) {
/* already exists */
dput(dentry); // 释放 dentry
inode_unlock(d_inode(root));
ret = -EEXIST;
goto err;
}
inode->i_private = device;
// 创建目录项,并且和 inode 关联
d_instantiate(dentry, inode);
// binder文件被创建 向文件系统的监视器发送通知
fsnotify_create(root->d_inode, dentry);
// 解除锁定
inode_unlock(d_inode(root));
return 0;
err:
kfree(name);
kfree(device);
mutex_lock(&binderfs_minors_mutex);
--info->device_count;
ida_free(&binderfs_minors, minor);
mutex_unlock(&binderfs_minors_mutex);
iput(inode);
return ret;
}
// binder,hwbinder,vndbinder 文件操作
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,
};
创建 features 目录 和文件
// 创建 features 目录
static int init_binder_features(struct super_block *sb)
{
struct dentry *dentry, *dir;
// 在 binderfs 创建 features 目录
dir = binderfs_create_dir(sb->s_root, "features");
if (IS_ERR(dir))
return PTR_ERR(dir);
// 在 features 目录 创建 oneway_spam_detection 文件
dentry = binderfs_create_file(dir, "oneway_spam_detection",
&binder_features_fops,
&binder_features.oneway_spam_detection);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
return 0;
}
// 创建目录
static struct dentry *binderfs_create_dir(struct dentry *parent,
const char *name)
{
struct dentry *dentry;
struct inode *new_inode, *parent_inode;
struct super_block *sb;
// 获取 parent 目录项的 inode 对象
parent_inode = d_inode(parent);
// inode 加锁
inode_lock(parent_inode);
// 创建 dentry 对象
dentry = binderfs_create_dentry(parent, name);
if (IS_ERR(dentry))
goto out;
sb = parent_inode->i_sb;
// 创建 inode , 设置 目录 + 文件权限位
new_inode = binderfs_make_inode(sb, S_IFDIR | 0755);
if (!new_inode) {
dput(dentry);
dentry = ERR_PTR(-ENOMEM);
goto out;
}
new_inode->i_fop = &simple_dir_operations;
new_inode->i_op = &simple_dir_inode_operations;
// 设置目录 inode 的硬链接计数为 2,表示该目录有两个链接:一个是自身的链接,另一个是父目录的链接。
set_nlink(new_inode, 2);
// 创建目录项,并且和 inode 关联
d_instantiate(dentry, new_inode);
// 增加 parent_inode 的链接计数
inc_nlink(parent_inode);
// 新目录被创建,向文件系统的监视器发送通知
fsnotify_mkdir(parent_inode, dentry);
out:
inode_unlock(parent_inode);
return dentry;
}
static struct binder_features binder_features = {
.oneway_spam_detection = true,
};
// 创建 inode 方法
static struct inode *binderfs_make_inode(struct super_block *sb, int mode)
{
struct inode *ret;
// 创建一个 inode 对象
ret = new_inode(sb);
if (ret) {
// 初始化 inode 对象
ret->i_ino = iunique(sb, BINDERFS_MAX_MINOR + INODE_OFFSET);
ret->i_mode = mode;
ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret);
}
return ret;
}
// 创建 dentry 方法
static struct dentry *binderfs_create_dentry(struct dentry *parent,
const char *name)
{
struct dentry *dentry;
// 查找名为 name 的目录项
dentry = lookup_one_len(name, parent, strlen(name));
if (IS_ERR(dentry))
return dentry;
/* 如果目录项存在,释放的目录项的指针,返回错误 */
if (d_really_is_positive(dentry)) {
dput(dentry);
return ERR_PTR(-EEXIST);
}
return dentry;
}
// 创建文件
struct dentry *binderfs_create_file(struct dentry *parent, const char *name,
const struct file_operations *fops,
void *data)
{
struct dentry *dentry;
struct inode *new_inode, *parent_inode;
struct super_block *sb;
// 从 dentry 获取 indoe
parent_inode = d_inode(parent);
inode_lock(parent_inode);
//创建 dentry
dentry = binderfs_create_dentry(parent, name);
if (IS_ERR(dentry))
goto out;
// 获取 super_block
sb = parent_inode->i_sb;
// 创建 inode 对象
new_inode = binderfs_make_inode(sb, S_IFREG | 0444);
if (!new_inode) {
dput(dentry);
dentry = ERR_PTR(-ENOMEM);
goto out;
}
// 初始化 inode
new_inode->i_fop = fops;
new_inode->i_private = data;
// 创建目录项,并且和 inode 关联
d_instantiate(dentry, new_inode);
// 文件被创建 向文件系统的监视器发送通知
fsnotify_create(parent_inode, dentry);
out:
inode_unlock(parent_inode);
return dentry;
}
创建 binder_logs 目录和文件
// 创建 binder_logs 目录
static int init_binder_logs(struct super_block *sb)
{
struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir;
const struct binder_debugfs_entry *db_entry;
struct binderfs_info *info;
int ret = 0;
// 创建 binder_logs 目录 dentry对象
binder_logs_root_dir = binderfs_create_dir(sb->s_root,
"binder_logs");
if (IS_ERR(binder_logs_root_dir)) {
ret = PTR_ERR(binder_logs_root_dir);
goto out;
}
// 遍历 binder_debugfs_entries 数组创建文件
binder_for_each_debugfs_entry(db_entry) {
dentry = binderfs_create_file(binder_logs_root_dir,
db_entry->name,
db_entry->fops,
db_entry->data);
if (IS_ERR(dentry)) {
ret = PTR_ERR(dentry);
goto out;
}
}
// 创建 proc 目录 dentry对象
proc_log_dir = binderfs_create_dir(binder_logs_root_dir, "proc");
if (IS_ERR(proc_log_dir)) {
ret = PTR_ERR(proc_log_dir);
goto out;
}
info = sb->s_fs_info;
info->proc_log_dir = proc_log_dir;
out:
return ret;
}
// 要创建的文件数组
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 */
};
extern const struct binder_debugfs_entry binder_debugfs_entries[];
#define binder_for_each_debugfs_entry(entry) \
for ((entry) = binder_debugfs_entries; \
(entry)->name; \
(entry)++)
binderfs 文件系统的挂载
binderfs 文件系统 有 android系统启动时 init 进程解析 init.rc 文件进行挂载的
# 创建目录 /dev/binderfs
mkdir /dev/binderfs
# 挂载 binderfs 文件系统
# 第一个 binder:表示挂载设备的类型,使用 Binder 文件系统。
# 第二个 binder:表示挂载点的名称。
# /dev/binderfs:表示Binder文件系统的挂载点,即文件系统将被挂载到系统的/dev/binderfs目录下
# stats=global:挂载选项,指定了一个参数 ,当 stats 参数为 global 时会创建 binder 日志文件
mount binder binder /dev/binderfs stats=global
#设置 /dev/binderfs 目录权限
chmod 0755 /dev/binderfs
# 创建三个软链接
symlink /dev/binderfs/binder /dev/binder
symlink /dev/binderfs/hwbinder /dev/hwbinder
symlink /dev/binderfs/vndbinder /dev/vndbinder
# 设置三个文件权限
chmod 0666 /dev/binderfs/hwbinder
chmod 0666 /dev/binderfs/binder
chmod 0666 /dev/binderfs/vndbinder
# 启动了三个服务管理器
# Start essential services.
start servicemanager
start hwservicemanager
start vndservicemanager
存在多个服务管理器(servicemanager
, hwservicemanager
, 和 vndservicemanager
),
分别负责不同类型的服务,通过这种分工和隔离,可以实现系统的模块化设计、提高系统的可维护性和稳定性,并且更好地支持硬件抽象层和供应商特定实现
servicemanager
主要用于管理系统进程中的服务,这些服务包括 Activity Manager, Window Manager, Package Manager 等hwservicemanager
主要用于管理硬件抽象层(HAL)服务,这些服务由设备制造商提供,涉及到设备的硬件组件如摄像头、GPS、音频等vndservicemanager
专用于管理供应商分区中的服务,这些服务是在设备制造商实现的特定功能或扩展。
查看 binder 文件系统
使用 df -aih
命令可以看到挂载的 binderfs 文件系统
binder 文件系统创建的文件
三个链接文件