size_t IN = mIn.dataAvail(); if (IN < sizeof(int32_t)) continue; cmd = mIn.readInt32(); IF_LOG_COMMANDS() {
alog << \ << getReturnString(cmd) << endl; }
result = executeCommand(cmd); } ... while(...);
这个函数在循环中重复执行下列动作:
talkWithDriver 通过ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)读取请求和写回结果。
executeCommand 执行相应的请求
在IPCThreadState::executeCommand(int32_t cmd)函数中:
对于控制对象生命周期的请求,像BR_ACQUIRE/BR_RELEASE直接做了处理。 对于BR_TRANSACTION请求,它调用被请求对象的transact函数。 按下列方式调用实际的对象: if (tr.target.ptr) {
sp
const status_t error = b->transact(tr.code, buffer, &reply, 0); if (error < NO_ERROR) reply.setError(error); } else {
const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0); if (error < NO_ERROR) reply.setError(error);
}
如果tr.target.ptr不为空,就把tr.cookie转换成一个Binder对象,并调用它的transact函数。如果没有目标对象,就调用 the_context_object对象的transact函数。奇怪的是,根本没有谁对the_context_object进行初始化,the_context_object是空指针。原因是context_mgr的请求发给了ServiceManager,所以根本不会走到else语句里来。
o 内核模块
android使用了一个内核模块binder来中转各个进程之间的消息。模块源代码放在binder.c里,它是一个字符驱动程序,主要通过binder_ioctl与用户空间的进程交换数据。其中BINDER_WRITE_READ用来读写数据,数据包中有一个cmd域用于区分不同的请求:
binder_thread_write用于发送请求或返回结果。 binder_thread_read用于读取结果。
从binder_thread_write中调用binder_transaction中转请求和返回结果,binder_transaction的实现如下:
对请求的处理:
通过对象的handle找到对象所在的进程,如果handle为空就认为对象是context_mgr,把请求发给context_mgr所在的进程。
把请求中所有的binder对象全部放到一个RB树中。 把请求放到目标进程的队列中,等待目标进程读取。
如何成为context_mgr呢?内核模块提供了BINDER_SET_CONTEXT_MGR调用: static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { ...
case BINDER_SET_CONTEXT_MGR: if (binder_context_mgr_node != NULL) {
printk(KERN_ERR \set\\n\
ret = -EBUSY; goto err; }
if (binder_context_mgr_uid != -1) {
if (binder_context_mgr_uid != current->euid) { printk(KERN_ERR \ \ current->euid,
binder_context_mgr_uid); ret = -EPERM; goto err; } } else
binder_context_mgr_uid = current->euid;
binder_context_mgr_node = binder_new_node(proc, NULL, NULL); if (binder_context_mgr_node == NULL) { ret = -ENOMEM; goto err; }
binder_context_mgr_node->local_weak_refs++; binder_context_mgr_node->local_strong_refs++; binder_context_mgr_node->has_strong_ref = 1; binder_context_mgr_node->has_weak_ref = 1; break;
ServiceManager(frameworks/base/cmds/servicemanager)通过下列方式成为了context_mgr进程:
int binder_become_context_manager(struct binder_state *bs) {
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); }
int main(int argc, char **argv) {
struct binder_state *bs;
void *svcmgr = BINDER_SERVICE_MANAGER;
bs = binder_open(128*1024);
if (binder_become_context_manager(bs)) {
LOGE(\ return -1; }
svcmgr_handle = svcmgr; binder_loop(bs, svcmgr_handler); return 0; }
o 如何得到服务对象的handle
服务提供者通过defaultServiceManager得到ServiceManager对象,然后调用addService向服务管理器注册。
服务使用者通过defaultServiceManager得到ServiceManager对象,然后调用getService通过服务名称查找到服务对象的handle。
o 如何通过服务对象的handle找到服务所在的进程
0表示服务管理器的handle,getService可以查找到系统服务的handle。这个handle只是代表了服务对象,内核模块是如何通过handle找到服务所在的进程的呢?
对于ServiceManager: ServiceManager调用了binder_become_context_manager使用自己成为context_mgr,所有handle为0的请求都会被转发给ServiceManager。
相关推荐: