您的位置:首页 > 移动开发 > Android开发

Android IPC有关的问题

2012-07-04 13:59 148 查看
1.文件描述符是如何在进程之间传递的?

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

Java代码:

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);

}

复制代码

在对文件描述符打包时,把对象的类型设置为BINDER_TYPE_FD。

在binder的内核模块binder_transaction函数中,我们可以看:

Java代码:

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);

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;

} 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线程里处理的,主要目的可能为了避免不必要的加锁操作吧。

Java代码:

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);

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;

} break;

复制代码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: