android binder相关

米夕
2023-12-01

为了解android如何在不同进程间传递fd,搜索了一下资料。

在binder内核代码中,对BINDER_TYPE_FD,会先

fget(fp->handle);

然后:

target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);

task_fd_install(target_proc, target_fd, file);

这样就相当于在新的进程理重新打开该文件,但得到的fd的值可能与原进程不一样。

 

http://dev.10086.cn/cmdn/wiki/index.php?doc-view-6363.html

1.文件描述符是如何在进程之间传递的?

我们知道文件描述符,就像虚拟内存的地址一样,是进程私有的资源。在一个进程中文件描 述符,在另外一个进程中,可能是无效的,也可能是对应另外一个文件。Android却可以把文件描述符从一个进程传到另外一个进程。第一次发现这种情况时,让我感到很惊奇,所以花了点时间去研究。看明白之后,发现其实现也 很简单:

Java代码:

  1. Java代码
    1. status_t Parcel::writeFileDescriptor(int fd)
    2. {
    3. flat_binder_object obj;
    4. obj.type = BINDER_TYPE_FD;
    5. obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    6. obj.handle = fd;
    7. obj.cookie = (void*)0;
    8. return writeObject(obj, true);
    9. }



在对文件描述符打包时,把对象的类型设置为BINDER_TYPE_FD。
在binder的内核模块binder_transaction函数中,我们可以看:

Java代码:

  1. Java代码
    1. case BINDER_TYPE_FD: {
    2. int target_fd;
    3. struct file *file;
    4. if (reply) {
    5. if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {
    6. binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n",
    7. proc->pid, thread->pid, fp->handle);
    8. return_error = BR_FAILED_REPLY;
    9. goto err_fd_not_allowed;
    10. }
    11. } else if (!target_node->accept_fds) {
    12. binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n",
    13. proc->pid, thread->pid, fp->handle);
    14. return_error = BR_FAILED_REPLY;
    15. goto err_fd_not_allowed;
    16. }
    17. file = fget(fp->handle);
    18. if (file == NULL) {
    19. binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n",
    20. proc->pid, thread->pid, fp->handle);
    21. return_error = BR_FAILED_REPLY;
    22. goto err_fget_failed;
    23. }
    24. target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
    25. if (target_fd < 0) {
    26. fput(file);
    27. return_error = BR_FAILED_REPLY;
    28. goto err_get_unused_fd_failed;
    29. }
    30. task_fd_install(target_proc, target_fd, file);
    31. binder_debug(BINDER_DEBUG_TRANSACTION,
    32. " fd %ld -> %d\n", fp->handle, target_fd);
    33. /* TODO: fput? */
    34. fp->handle = target_fd;
    35. } break;




这里如果是文件描述符,就在目标进程中重新打开同一个文件了(虽然打开的是同一个文件,但目标进程拿到的文件描述符可能不相同)。

2.Receiver是如何工作的?

大家对Service的工作原理应该比较熟悉,先通过服务名称从 ServiceManager获取一个Binder,然后通过Binder去调用服务相应的函数。由客户端主动发起请求,这是典型是C/S模型。而 Receiver则是服务端反过来调用客户端函数,这就看起来有点让人感到迷惑了。

其实Receiver更简单,所有Broadcast都是从 ActivityManagerService发出的,所以只需要让 ActivityManagerService知道你的Receiver就行了,这是通过 ActivityManagerNative.registerReceiver完成的。实现自己的Receiver时都是实现 BroadcastReceiver接口,BroadcastReceiver本身并不是可以跨进程调用的,这是由 ActivityThread.PackageInfo.ReceiverDispatcher来包装的。

这里值得注意的是Receiver都是在ActivityThread里处理的,而不是在Binder线程里处理的,主要目的可能为了避免不必要的加锁操作吧。

 

 

搜索了几篇blog:

http://blog.csdn.net/black_berry/article/details/6618307

http://blog.csdn.net/black_berry/article/details/6621297

http://blog.csdn.net/black_berry/article/details/6621318

http://blog.csdn.net/black_berry/article/details/6621327

http://blog.csdn.net/black_berry/article/details/6621391

http://blog.csdn.net/black_berry/article/details/6621411

http://blog.csdn.net/black_berry/article/details/6621435

 

 http://www.21876.com/project/Android/71246.html

http://blog.csdn.net/t80t90s/article/details/7704375

 http://hi.baidu.com/woodyqt/item/3a5362d97982613b48e1ddab

http://www.redwolf-blog.com/?p=902

 http://blog.csdn.net/lihui130135/article/details/7372282

 http://w.hudong.com/3fdeadabfa514f1faf372c589632f692.html

 http://www.blogjava.net/mixer-a/archive/2012/04/17/374989.html

 

这个人的blog也不错

http://blog.csdn.net/t80t90s/article/category/1145236/3

 类似资料: