android进程间传递文件描述符原理
在Linux中,进程打开一个文件,返回一个整数的文件描述符,然后就可以在这个文件描述符上对该文件进行操作。那么文件描述符和文件到底是什么关系?进程使用的是虚拟地址,不同进程间是地址隔离的,如何在两个进程中传递文件描述符,然后指向同一文件(binder传递文件描述符)?
linux打开文件过程
下图是linux内核中打开文件的结构体之间的关系图(只是大概,细节可以参考各种内核书籍):
内核中每个进程都使用task_struct结构体表示,其成员files是一个files_struct结构体,表示该进程打开的所有文件相关信息;
files_struct结构体中的fd_array数组(上层应用程序返回的文件描述符其实就是这个数组的下标),是个struct file,内核对打开的文件都用file结构体描述,而成员fdt是个struct fdtable,其成员fd代表数组fd_array的起始地址;
struct file中的f_dentry表示文件的dentry结构,而dentry中包含了文件唯一的inode,即d_inode,d_inode唯一表示了该文件(每个具体文件只有一个inode结构,而多个dentry可以指向同一个inode,例如软链接)。
下面简要分析下代码。
上层:应用程序调用c库中(实现依赖使用的c库)的open()函数打开一个文件,open()返回一个文件描述符;
内核:上层open调用系统调用open函数,
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)
{ret = do_sys_open(AT_FDCWD, filename, flags, mode);return ret;
}
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
实际调用的是
long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
{struct open_flags op;int lookup = build_open_flags(flags, mode, &op);char *tmp = getname(filename);int fd = PTR_ERR(tmp);if (!IS_ERR(tmp)) {//①//获取进程中未使用的fd,就是从0开始的整数,使用一个往上+1fd = get_unused_fd_flags(flags);if (fd >= 0) {//②//构建file结构体struct file *f = do_filp_open(dfd, tmp, &op, lookup);if (IS_ERR(f)) {put_unused_fd(fd);fd = PTR_ERR(f);} else {fsnotify_open(f);//③//将fd和file结构体建立关系fd_install(fd, f);}}putname(tmp);}return fd;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
void fd_install(unsigned int fd, struct file *file)
{//当前进程的files_struct结构struct files_struct *files = current->files;struct fdtable *fdt;spin_lock(&files->file_lock);//获取files_struct中的fdt结构体fdt = files_fdtable(files);BUG_ON(fdt->fd[fd] != NULL);//将fdt->fd[fd],也就是fd_array[fd],赋值为file,rcu_assign_pointer(fdt->fd[fd], file);spin_unlock(&files->file_lock);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
do_sys_open主要就完成了上面注释的3步:
获取进程中未使用的fd,就是从0开始的整数,使用一个往上+1;
根据文件的路径,构建file结构体,即构建其中的dentry等;
将fd、file结构体同本进程task_struct结构体建立关系。
经过上面的分析,我们可以得到一个结论:
内核用struct file描述文件,在单个进程中,打开的文件都保存在进程结构体task_struct中files_struct结构体中的fd_array数组中,而上层返回的文件描述符就是这个数组的下标,用来和struct file保持对应关系。因此在不同的进程中打开同一文件,内核都会创建一个新的file结构用来和实际文件关联(但是同一文件在不同进程中的file结构体主要内容是相同的,都描述了所指向的实际文件),然后给上层返回不同的文件描述符。
那么如何将不同进程中的文件描述符关联为同一文件?下面我们看看Android binder通过传递文件描述符如何实现同一文件描述符的共享。
android binder传递文件描述符
下面是内核binder_transaction函数中的一部分,
static void binder_transaction(struct binder_proc *proc,struct binder_thread *thread,struct binder_transaction_data *tr, int reply)
{
case BINDER_TYPE_FD: {int target_fd;struct file *file//通过本进程的fd,获取对应的file结构体file = fget(fp->handle);//获取目标进程未使用的文件描述符target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);//将file结构和目标进程的fd等联系起来task_fd_install(target_proc, target_fd, file);fp->handle = target_fd;} break;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
上述主要工作和前面open函数的实现类似,只不过是去获取目标进程的未使用文件描述符,然后将本进程的file结构体去和目标进程挂钩(file结构体主要内容描述的都是具体文件相关的,例如dentry,所以不同进程间可以共享,因为都是指向同一实际文件),这样binder驱动就悄无声息的帮我们在内核中在目标进程中新建了文件描述符,并将原进程的file结构与之挂钩,就像在目标进程中打开了原进程中的该文件一样,只不过返回给目标进程上层的描述符是新的target_fd。
android进程间传递文件描述符原理相关推荐
- Linux高级进程编程———在任意两个进程间传递文件描述符:使用 sendmsg 和 recvmsg 实现
进程间传递打开的文件描述符,并不是传递文件描述符的值.那么在传递时究竟传递了什么?我们要先搞明白这个问题. 1.文件描述符 文件描述符的值与文件没有任何联系,只是该文件在进程中的一个标识,所以同一文件 ...
- Linux 进程间传递文件描述符
文章目录 文件描述符 文件数据结构 共享文件 UNIX域socket实现传递文件描述符 进程间传递打开的文件描述符,并不是传递文件描述符的值.先说一下文件描述符. 文件描述符 对内核来说,所有打开的文 ...
- Linux中进程间传递文件描述符的方法
在进行fork调用后,由于子进程会拷贝父进程的资源,所以父进程中打开的文件描述符在子进程中仍然保持着打开,我们很容易的就将父进程的描述符传递给了子进程.但是除了这种情况下,如果想将某个父进程在子进程创 ...
- 进程间传递文件描述符--sendmsg,recvmsg(可用)
UNIX域套接字可以在同一台主机上各进程之间传递文件描述符. 下面先来看两个函数: #include <sys/types.h> #include <sys/socket.h> ...
- 不相干进程之间传递文件描述符
#include <sys/socket.h> #include <fcntl.h> #include <stdio.h> #include <unistd. ...
- 线程共享的环境包括:进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。 进程拥有这
线程共享的环境: 进程代码段.进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯).进程打开的文件描述符.信号的处理器.进程的当前目录和进程用户ID与进程组ID. 进程拥有这许多共性的 ...
- Linux的辅助数据和传递文件描述符
简介 首先,明确传递文件描述符的意义.一般来说,在多进程网络编程中,我们设置一个主进程用于监听新来的连接,设置一个进程池,用于处理这些连接.但是,与线程池不同,进程池各个进程之间的空间是独立的,直接共 ...
- FORK()子进程对父进程打开的文件描述符的处理
总的来说,子进程将复制父亲进程的数据段,BSS段,代码段,堆空间,栈空间和文件描述符.而对于文件技术符关联内核文件表项(即STRUCT FILE结构),则是采取了共享的方式. 下面代码说明. I值分离 ...
- fork()子进程与父进程之间的文件描述符问题
在C程序中,文件由文件指针或者文件描述符表示.ISO C的标准I/0库函数(fopen, fclose, fread, fwrite, fscanf, fprintf等)使用文件指针,UNIX的I/O ...
最新文章
- R语言tidyr包spread()函数实战详解:数据裂变、从窄表到宽表
- 【python】一个简单的贪婪爬虫
- Pimple - 一个简单的 PHP 依赖注入容器
- 汇编语言转成c语言,如何把汇编语言转换成C语言
- hadoop小型集群_小型Hadoop集群的Ganglia配置和一些故障排除
- 埃及分数问题(带乐观估计函数的迭代加深搜索算法-IDA*)
- html三列布局和两列布局,CSS 常见两列布局、三列布局
- UVA10063 Knuth‘s Permutation【排列组合】
- 原生JS大揭秘—事件循环机制Event Loop
- OSPF协议配置命令解析
- Knockoutjs开发指南
- educator计算机技术基础答案,计算机教育技术基础,technical basis of computer education,音标,读音,翻译,英文例句,英语词典...
- 计算机图片组合快捷键,电脑高手常用的组合快捷键
- 【考研政治】1. 导论和基本哲学问题
- 关于统计分析软件Spss统计个案数和实际数据的个案数不一致问题
- 大龄程序员找工作,为什么这么难?能力与年龄不匹配
- 基于jsp+mysql+Spring的SSM在线蛋糕商城销售网站项目设计和实现
- 南极大冒险/零下八度/南极物语/8只雪橇犬
- 基于Java毕业设计房屋租赁平台源码+系统+mysql+lw文档+部署软件
- 微信小程序canvas画布新接口type为2D时drawImage方法的使用以及注意事项
热门文章
- Beyond Compare可以进行二进制比较
- 发布 学习进度条 博客要求
- Nuget 管理报repositories.config 访问路径被拒绝 解决办法
- Programmer Competency Matrix
- JBox - 模态窗口,工具提示和消息 jQuery 插件
- 《How to Reshape Input Data for Long Short-Term Memory Networks in Keras》学习笔记
- 【参数辨识】永磁同步电机的参数辨识
- mysql 联合索引 range_MySQL 联合索引使用情况
- oracle函数 power(x,y)
- linux下的文档处理及tar命令