我们知道ActivityManager是运行在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"):
  Client首先与ServiceManager进程通信
  Client端先构造一个handle为0的binder引用(灰色曲线四边形),
  通过这个引用向内核发送数据(包含servcie的名字"activity"),
  在内核空间创建一个ServiceManager的biner引用(灰色六边形),
  找到ServiceManager的binder实体(灰色矩形),
  然后唤醒ServiceManager进程,
  通过binder实体中的ServiceManager实例,调用它的getService方法,
  ServiceManager通过名字"activity"找到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 = ;
fp->handle = new_ref->desc;
fp->cookie = ;
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进程和要获取AMS的进程是否是同一个,
如果是,则改写fp->type为BINDER_TYPE_BINDER,设fp->binder = ref->node->ptr;
后续把AMS的binder实体中的实例引用返回给请求者,

所以通过SystemManager.getService("name")在同一进程获取服务,会直接返回这个服务实例的引用,这是binder驱动支持的。 当然在一个进程里有更直接的办法来获取,但是在某些特殊情况用这种办法也可以,只是效率稍低,因为经历了一次与serviceManager的ipc。

最新文章

  1. js类型检测
  2. HTTP 错误 403.14–Forbidden错误解决
  3. PowerDesigner之PDM(物理概念模型)
  4. 2011 Asia Fuzhou Regional Contest
  5. 使用java求高精度除法,要求保留N位小数
  6. WindowsForm 增 删 查 改
  7. WebBrowser脚本错误的完美解决方案
  8. Object-c中间initialize 与 辛格尔顿
  9. js实现ajax的post请求步骤
  10. 51Nod 1632 B君的连通(递归,快速幂)
  11. 【Shell脚本学习指南笔记】重定向文件描述符 2>&1
  12. Git 版本退回commit
  13. error:org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
  14. Java转PHP的心路历程
  15. CentOS6.9下离线部署Django项目
  16. PEP8中文翻译(转)
  17. PHPWord插件详解
  18. 如何解决ORA-28002 the password will expire within 7 days问题(密码快过期)
  19. Java设计模式之五 ----- 外观模式和装饰器模式
  20. python数据结构之树(二分查找树)

热门文章

  1. MySQL的高可用实现方案之mysql-mmm
  2. [转]TabControl Style in WPF
  3. 移动端video视频播放问题
  4. IIS发布web应用程序之再折腾
  5. rdf(资源描述框架)
  6. 【DM8168学习笔记5】EZSDK目录结构
  7. 一、初识asyncio协程
  8. mysql知识点回顾与梳理
  9. 浅谈Python小数据池
  10. 初探.NET CORE WEB API(RESTful风格)