两个与Android IPC有关的问题
2011-01-25 17:59
211 查看
1.文件描述符是如何在进程之间传递的?
我们知道文件描述符,就像虚拟内存的地址一样,是进程私有的资源。在一个进程中文件描述符,在另外一个进程中,可能是无效的,也可能是对应另外一个文件。 Android却可以把文件描述符从一个进程传到另外一个进程。第一次发现这种情况时,让我感到很惊奇,所以花了点时间去研究。看明白之后,发现其实现也很简单:
在对文件描述符打包时,把对象的类型设置为BINDER_TYPE_FD。
在binder的内核模块binder_transaction函数中,我们可以看:
这里如果是文件描述符,就在目标进程中重新打开同一个文件了(虽然打开的是同一个文件,但目标进程拿到的文件描述符可能不相同)。
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线程里处理的,主要目的可能为了避免不必要的加锁操作吧。
这里通过消息把Receiver的动作执行放到了mActivityThread线程里。
我们知道文件描述符,就像虚拟内存的地址一样,是进程私有的资源。在一个进程中文件描述符,在另外一个进程中,可能是无效的,也可能是对应另外一个文件。 Android却可以把文件描述符从一个进程传到另外一个进程。第一次发现这种情况时,让我感到很惊奇,所以花了点时间去研究。看明白之后,发现其实现也很简单:
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函数中,我们可以看:
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线程里处理的,主要目的可能为了避免不必要的加锁操作吧。
public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky) { if (DEBUG_BROADCAST) { int seq = intent.getIntExtra("seq", -1); Slog.i(TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq + " to " + mReceiver); } Args args = new Args(); args.mCurIntent = intent; args.mCurCode = resultCode; args.mCurData = data; args.mCurMap = extras; args.mCurOrdered = ordered; args.mCurSticky = sticky; if (!mActivityThread.post(args)) { if (mRegistered && ordered) { IActivityManager mgr = ActivityManagerNative.getDefault(); try { if (DEBUG_BROADCAST) Slog.i(TAG, "Finishing sync broadcast to " + mReceiver); mgr.finishReceiver(mIIntentReceiver, args.mCurCode, args.mCurData, args.mCurMap, false); } catch (RemoteException ex) { } }
这里通过消息把Receiver的动作执行放到了mActivityThread线程里。
相关文章推荐
- Android IPC有关的问题
- Android-与Android IPC有关的问题
- Unity3D 和 Android 交互时遇到的常见的两个问题
- 有关两个select内容互相移动问题
- Android中两个APP间跳转导致的异常问题及解决办法
- 有关outlook的两个小问题
- Android中一个Activity两个ListView的显示错误问题
- 有关Java中两个整数的交换问题
- 升级Android支持库版本遇到的两个问题
- Android----- MD5加密(登录注册得到与IOS相同的加密值,并且解决两个平台汉字加密不相同问题)
- android的ndk下,解决两个so相互调用的问题
- Android程序调试时出现的两个问题
- 有关asp.net获取android端上传的图片问题
- 两个有关数组的变量名和其地址的问题?
- 升级Android支持库版本遇到的两个问题
- Android WebView 文本框获取焦点后自动放大有关问题
- android有关内存消耗的问题
- 关于Android开发中有关权限的问题
- 关于android创建快捷方式会启动两个应用的问题
- nor current process has android.permission.WRITE_APN_SETTINGS Proxy andriod,代理上网,wap网络请求有关问题