我们知道ActivityManager是运行在system_service进程里的,但是最近看代码发现在这个进程的其他服务线程里为了获取AMS调用: ActivityManagerService am = (ActivityManagerService)ServiceManager.getService("activity"); 验证了下,返回的am确实是AMS的实例,没问题 我们一般用ServiceManager.getService在其他进程中获取AMS服务,返回的一个是远端binder代理, 如果用在同一进程中会怎样? 为了解释这个问题,首先要复习下binder通信知识
Binder在内核中两种形式: Binder实体(binder_node), Binder引用(binder_ref)
两个典型流程 1. service在ServiceManager注册: 然后Client可以通过这个app端的binder引用与AMS进行通信。
回到开始问题: 上面的步骤是在Client端请求AMS服务,这里Client与AMS在两个不同进程,
static void binder_transaction(struct binder_proc *proc, struct binder_thread *thread, struct binder_transaction_data *tr, int reply) { switch (fp->type) { ... case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { struct binder_ref *ref = binder_get_ref(proc, fp->handle, fp->type == BINDER_TYPE_HANDLE); if (ref == NULL) { binder_user_error("%d:%d got transaction with invalid handle, %d\n", proc->pid, thread->pid, fp->handle); return_error = BR_FAILED_REPLY; goto err_binder_get_ref_failed; } if (ref->node->proc == target_proc) { if (fp->type == BINDER_TYPE_HANDLE) fp->type = BINDER_TYPE_BINDER; else fp->type = BINDER_TYPE_WEAK_BINDER; fp->binder = ref->node->ptr; fp->cookie = ref->node->cookie; binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL); trace_binder_transaction_ref_to_node(t, ref); binder_debug(BINDER_DEBUG_TRANSACTION, " ref %d desc %d -> node %d u%016llx\n", ref->debug_id, ref->desc, ref->node->debug_id, (u64)ref->node->ptr); } else { struct binder_ref *new_ref; new_ref = binder_get_ref_for_node(target_proc, ref->node); if (new_ref == NULL) { return_error = BR_FAILED_REPLY; goto err_binder_get_ref_for_node_failed; } fp->binder = 0; fp->handle = new_ref->desc; fp->cookie = 0; binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL); trace_binder_transaction_ref_to_ref(t, ref, new_ref); binder_debug(BINDER_DEBUG_TRANSACTION, " ref %d desc %d -> ref %d desc %d (node %d)\n", ref->debug_id, ref->desc, new_ref->debug_id, new_ref->desc, ref->node->debug_id); } } break; ... } }
看红色代码 所以通过SystemManager.getService("name")在同一进程获取服务,会直接返回这个服务实例的引用,这是binder驱动支持的。 当然在一个进程里有更直接的办法来获取,但是在某些特殊情况用这种办法也可以,只是效率稍低,因为经历了一次与serviceManager的ipc。 |
|