标签:pre ipc color style 技术 error cli 获取 bug
AMS运行在system_service进程里, 最近看代码发现在这个进程的其他服务线程里为了获取AMS直接调用:
ActivityManagerService am = (ActivityManagerService)ServiceManager.getService("activity");
验证了下,返回的am直接就是AMS的实例,没问题,这个是为什么?
我们一般用ServiceManager.getService在其他进程中获取AMS服务,返回的一个是远端binder代理,
如果用在同一进程中会怎样? 为了解释这个问题,首先要复习下binder通信知识,由于太复杂,这里只能概述下基本原理
Binder IPC模型
Binder在内核中两种形式: Binder实体(binder_node), Binder引用(binder_ref)
binder_node:
{
binder_proc* proc; //service进程信息
void__user* ptr; //service实例指针
}
binder_ref:
{
binder_proc* proc; //service进程信息
binder_node* node; //指向Binder实体
unit32_t desc; //service handle值,唯一标识一个service
}
两个典型流程
1. service在ServiceManager注册:
在内核创建一个binder实体(橙色矩形),一个binder引用(蓝色六边形),
在ServiceManager里用map保存这个service的名字和binder引用(蓝色曲线四边形)。
2. Client通过ServiceManager getService("activity")的case,
Client首先与ServiceManager进程通信
Client端先构造一个handle为0的binder引用(灰色曲线四边形),
通过这个引用向内核发送数据(包含servcie的名字"activity"),
在内核空间创建一个ServiceManager的biner引用(灰色六边形),
为其找到ServiceManager的binder实体(灰色矩形),
然后唤醒ServiceManager进程,
通过binder实体中的ServiceManager实例,调用它的getService方法,
ServiceManager通过名字找到ActivityManagerService服务的binder引用,
在内核为Client进程创建一个ActivityManagerService binder引用(蓝色六边形)
并且返回binder的handle值给Client,在Client创建一个app端的binder引用(蓝色曲线四边形)
然后Client可以通过这个app端的binder引用与AMS进行通信。
在app-service通信中,binder内核驱动担任dns的功能,也就是通过binder引用,找对应服务的binder实体
回到开始问题:
上面的步骤是在Client端请求AMS服务,这里Client与AMS在两个不同进程,
而如果在同一进程,AMS运行在system_server进程中,如果其他服务线程通过SystemManager.getService("activity")请求AMS服务,
那么这个接口将直接返回 ActivityManagerService实例的引用。原因是什么?
主要是在case 2步骤中蓝色部分,binder驱动会进行检查:
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; ... } }
红色代码
首先判断ref->node->proc == target_proc,即注册的进程和现在获取AMS的进程是否是同一个,
如果是,则改写fp->type为BINDER_TYPE_BINDER,设fp->binder = ref->node->ptr;
后续过程会把AMS的binder实体中的实例引用返回给请求者,
所以在获取同一进程服务,会直接返回这个实例的引用。 当然在一个进程里有更直接的办法来获取,但是在某些特殊情况用这种办法也可以,只是效率较低,因为经历了一次与serviceManager的ipc
system_service进程里 调用SystemManager.getService("activity") 直接返回ams的引用?
标签:pre ipc color style 技术 error cli 获取 bug
原文地址:http://www.cnblogs.com/hushpa/p/6652797.html