为了让两个进程共享内存,也就是让他们共享同一打开的文件,这个是在binder驱动里面做的事情,当我们希望binder Client和Service端共享句柄时传递参数时必须要调用writeFileDescriptor readFileDescriptor来标识这是一个句柄值,这样binder驱动会对其做进一步的处理
看一下writeFileDescriptor
status_t Parcel::writeFileDescriptor(int fd)
{
flat_binder_object obj;
obj.type = BINDER_TYPE_FD;
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
obj.handle = fd;
obj.cookie = (void*)0;
return writeObject(obj, true);
}
其实也就是写入了一个flat_binder_object结构,这样在驱动里面就需要处理这个binder
对于我们前面一个例子,client端从Service端获取fd,所以这个writeFileDescriptor是在Serivce端调用的,同样fd也是它创建的,看一下它在驱动里面相应的处理
case BINDER_TYPE_FD: {
int target_fd;
struct file *file;
if (reply) {
if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {
binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fd_not_allowed;
}
} else if (!target_node->accept_fds) {
binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fd_not_allowed;
}
file = fget(fp->handle);//文件描述符的值就保存在fp->handle中
if (file == NULL) {
binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fget_failed;
}
target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);//在目标进程中获得一个空闲的文件描述符
if (target_fd < 0) {
fput(file);
return_error = BR_FAILED_REPLY;
goto err_get_unused_fd_failed;
}
task_fd_install(target_proc, target_fd, file);//把这个文件描述符和这个打开文件结构关联起来
binder_debug(BINDER_DEBUG_TRANSACTION,
" fd %ld -> %d\n", fp->handle, target_fd);
/* TODO: fput? */
fp->handle = target_fd;// 由于这个Binder对象最终是要返回给目标进程的,所以还要修改fp->handle的值
} break
这里主要就是为其在目标进程中分配一个未使用的文件描述符,并调用task_fd_install把它和这文件关系起来。
这样,两个进程就可以共享这个文件了。