android binderfs 介绍

284 阅读15分钟

android BinderFS 是 Android 操作系统中用于管理 Binder 设备的新型文件系统。 BinderFS 设计用于动态管理 Binder 设备节点。它主要解决了传统 Binder 设备管理中的一些局限性,提供了更灵活和动态的设备节点管理方式。

主要特点

  1. 动态创建设备节点:BinderFS 可以在运行时动态创建和销毁 Binder 设备节点,而不需要预先在设备文件系统(如 /dev/binder)中创建这些节点。
  2. 命名空间支持:BinderFS 支持 Linux 命名空间,允许每个命名空间有自己的 Binder 设备集合。
  3. 简化管理:通过一个简单的文件系统接口,可以更方便地管理 Binder 设备节点,而不需要直接操作设备节点的权限和属性。

为了更好理解这篇文件可以先查看

Linux 内核驱动开发介绍

Linux VFS API 介绍

初始化

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 文件系统

image.png

binder 文件系统创建的文件 202404260642082.png

三个链接文件

image.png