zoukankan      html  css  js  c++  java
  • system_service进程里 调用SystemManager.getService("activity") 直接返回ams的引用?

    我们知道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
    ",
                            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
    ",
                             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)
    ",
                             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。

  • 相关阅读:
    go语言练习:go实现md5
    go语言练习:结构体
    go语言练习:指针
    go语言练习:数组
    DEL: MySQL Learning
    EV: Notepad++: Insert Timestamp -- Using Python
    EV: 文件共享的问题
    EV: Ruby: 安装和运行rails
    EV: MySQL Clear Screen
    EV: Ubuntu 的root用户password问题
  • 原文地址:https://www.cnblogs.com/hushpa/p/6652797.html
Copyright © 2011-2022 走看看