Android ActivityManagerService 注

作者: __Y_Q | 来源:发表于2021-06-10 19:30 被阅读0次

    接上一章.

    33.binder_thread_read

    源线程, 即 AMS, 从上一章的第 32 步函数 binder_transaction 返回第 29 步 binder_thread_write 之后, 继续返回到第 28 步 binder_ioctl_write_read 函数中调用 binder_thread_read 函数.

    为什么执行 binder_thread_read, 可见上一章第 27 步中的代码 04-05 处的文字分析

    static int binder_ioctl_write_read(struct file *filp,
                    unsigned int cmd, unsigned long arg,
                    struct binder_thread *thread)
    {
        ...
    
        if (bwr.write_size > 0) {
            ret = binder_thread_write(proc, thread,
                          bwr.write_buffer,
                          bwr.write_size,
                          &bwr.write_consumed);
            trace_binder_write_done(ret);
            ...
        }
        if (bwr.read_size > 0) {
            ret = binder_thread_read(proc, thread, bwr.read_buffer,
                         bwr.read_size,
                         &bwr.read_consumed,
                         filp->f_flags & O_NONBLOCK);
            ...
        }
    ...
    }
    

    执行 binder_thread_read 函数来处理源线程 threadtodo 队列中类型为 BINDER_WORK_TRANSACTION_COMPLETE 的工作项. 下面是 binder_thread_read 代码
    源码路径: kernel 3.18下的 /drivers/staging/android/binder.c

    
    static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed, int non_block)
    {
        ...
        while (1) {
            ...
    01      if (!list_empty(&thread->todo)) {
                w = list_first_entry(&thread->todo, struct binder_work,entry);
            } else if (...) {
                ...
            } else {
                ...
            }
            ...
            switch (w->type) {
            ...
            case BINDER_WORK_TRANSACTION_COMPLETE: {
                cmd = BR_TRANSACTION_COMPLETE;
    02          if (put_user(cmd, (uint32_t __user *)ptr))
                    return -EFAULT;
                ...
            } break;
            ...
        }
        ...
        return 0;
    }
    

    在代码 01 处判断线程 threadtodo队列不为 NULL, 这里命中 if, 取出线程 threadtodo队列中类型为 BINDER_WORK_TRANSACTION_COMPLETE 的工作项保存在 binder_work 结构体 w 中.

    接着在代码 02 处将一个 BR_TRANSACTION_COMPLETE 返回协议写入到用户空间提供的缓冲区中.

    这里可以看出, Binder 驱动程序处理类型为 BINDER_WORK_TRANSACTION_COMPLETE 的工作项的方式就是向相应的进程发送一个 BR_TRANSACTION_COMPLETE 返回协议

    函数 binder_thread_read 执行完之后, 返回到上一章第 27 步的 IPCThreadState.talkWithDriver 中的代码06- 07 处将 Binder 驱动程序发送的返回协议保存在类内部的返回协议缓冲区 mIn 中. 再返回到第 26 步的时候. 就可以通过解析返回协议缓冲区 mIn 的内容来执行相对应的操作了.

    现在返回到第 26步的 IPCThreadState.waitForResponse 中, 处理 Binder 驱动程序为进程发送的 BR_TRANSACTION_COMPLETE 返回协议.

    34. IPCThreadState.waitForResponse

    源码路径: /frameworks/native/libs/binder/IPCThreadState.cpp

    status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
    {
        uint32_t cmd;
        int32_t err;
    
        while (1) {
    01      if ((err=talkWithDriver()) < NO_ERROR) break;
              ...
    02      cmd = (uint32_t)mIn.readInt32();
            
    
            switch (cmd) {
            case BR_TRANSACTION_COMPLETE:
                if (!reply && !acquireResult) goto finish;
                break;
            }
           ...
        }
        return err;
    }
    

    上面所有的步骤都是在代码 01 处完成. 现在代码 01 处已经执行完毕, 并且将 Binder 驱动层发送的返回协议保存在类内部的返回协议缓冲区 mIn 中, 现在接着向下执行.

    在代码 02 处通过返回协议缓冲区 mIn 来获得这个 BR_TRANSACTION_COMPLETE 返回协议.
    这个返回协议的处理较为简单, 就是跳出 switch 语句后, 重新执行外层的 while 循环, 即再次调用 01 处代码与 Binder 驱动程序交互.

    再次进入到 talkWithDriver函数时, 由于 IPCThreadState 类内部的命令协议缓冲区 mOut 中的命令协议, 以及返回缓冲区 mIn 中的返回协议都已经处理完成了, 因此当它再次通过 IO 控制命令 BINDER_WRITE_READ 进入到 Binder 驱动程序的函数 binder_ioctl 时, 就会直接调用函数 binder_thread_read 在内部休眠等待目标进程将上次发出的进程间通信请求的结果返回回来, 将其唤醒. 即休眠等待 SM 进程将注册结果返回后唤醒.

    OK ,现在到唤醒 SM 进程来处理它 todo 队列中类型为 BINDER_WORK_TRANSACTION 的工作项了.

    35. binder_thread_read 唤醒 ServiceManager 进程

    源码路径: kernel 3.18下的 /drivers/staging/android/binder.c

    binder_thread_read 函数主要就是负责处理一个线程或者一个进程的 todo 工作队列中的工作项, 处理完成后, 就会向目标进程发送一个返回协议.

    上一步将一个类型为 BINDER_WORK_TRANSACTION 的工作项添加到了目标进程的 todo 队列. 那么接下来目标进程 SM 就会被唤醒, 继续向下执行 binder_thread_read 函数. 后续代码较多, 分为两段进行分析.

    static int binder_thread_read(struct binder_proc *proc,
                      struct binder_thread *thread,
                      binder_uintptr_t binder_buffer, size_t size,
                      binder_size_t *consumed, int non_block)
    {
            ...
            if (non_block) {
                ...
            } else
    01          ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
        } else {
            ...
        }
        ...
    
        while (1) {
            uint32_t cmd;
            struct binder_transaction_data tr;
            struct binder_work *w;
            struct binder_transaction *t = NULL;
    
    02      if (!list_empty(&thread->todo)) {
                w = list_first_entry(&thread->todo, struct binder_work,entry);
    03      } else if (!list_empty(&proc->todo) && wait_for_proc_work) {
                w = list_first_entry(&proc->todo, struct binder_work,entry);
            } else {
                if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
                    goto retry;
                break;
            }
                   ...
    
    

    首先代码 01 处就是之前 SM 休眠的地方, 现在有工作项进入了, 就接着向下分析.

    在代码 02 处检查线程 thread 自己的 todo 队列中是否有工作项需要处理. 如果没有, 在代码 03处再检查它所属进程 proctodo 队列中是否有工作项需要处理. 只要两个中的任何一个todo 队列中有工作项需要处理, 就会将它取出来保存在 binder_word 结构体 w 中.

    binder_thread_read 代码第二段

          switch (w->type) {
            case BINDER_WORK_TRANSACTION: {
    01          t = container_of(w, struct binder_transaction, work);
            } break;
            
            ...
    02      if (t->buffer->target_node) {
                ..
    03          tr.target.ptr = target_node->ptr;
    04          tr.cookie =  target_node->cookie;
                ...
                cmd = BR_TRANSACTION;
            } else {
                ...
            }
    05      tr.code = t->code;
    06      tr.flags = t->flags;
            ...
    07      tr.data_size = t->buffer->data_size;
    08      tr.offsets_size = t->buffer->offsets_size;
    09      tr.data.ptr.buffer = (binder_uintptr_t)( (uintptr_t)t->buffer->data + proc->user_buffer_offset);
    10      tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *));
            ...
    11      list_del(&t->work.entry);
    12      t->buffer->allow_user_free = 1;
    13      if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
                t->to_parent = thread->transaction_stack;
                t->to_thread = thread;
                thread->transaction_stack = t;
            } else {
                ...
            }
            break;
        }
    

    代码 01 处由于 binder_word 结构体 w 的类型为 BINDER_WORK_TRANSACTION, 即它是一个嵌入在一个 binder_transaction 结构体中的工作项, 因此就可以安全的将它转换为一个 binder_transaction 结构体 t.

    Binder 驱动程序处理 BINDER_WORK_TRANSACTION 类型的工作项的方式是向目标线程 thread 发送一个 BR_TRANSACTION 返回协议. BR_TRANSACTION 返回协议是使用一个 binder_transaction_data 结构体来描述的, 因此 Binder 驱动程序在向目标线程thread 发送 BR_TRANSACTION 返回协议之前, 需要定义一个 binder_transaction_data 结构体 tr, 同时将其保存在 binder_transaction 结构体 t 中.

    因为 binder_transaction 结构体 t 的内核缓冲区 buffer 的成员变量 target_node 指向了引用 SM 的 Binder 实体对象 binder_context_mgr_node, 因此代码 02 处直接命中 if.

    在代码 03 与 04 处将 binder_transaction 结构体 t里面的目标 Binder 本地对象信息 copy 到 binder_transaction_data 结构体 tr 中. 以便目标线程thread 接收到 Binder 驱动程序给他发送的 BR_TRANSACTION 返回协议后, 可以将返回协议交给指定的 Binder 本地对象来处理. 接着设置返回命令协议为 BR_TRANSACTION.

    代码 05 与 06 处代是将 binder_transaction 结构体 t 中的进程间数据 copy 到 binder_transaction_data 结构体 tr 中. (变量 code 与 flag 的值分别为 ADD_SERVICE_TRANSACTION 与 TF_ACCEPT_FDS)

    代码 07 至 10 处 将 binder_transaction 结构体 t 中的数据缓冲区与偏移数组的内容 copy 到 binder_transaction_data 结构体 tr

    Binder 驱动程序为进程分配的内核缓冲区是用来传输进程间通信数据的, 即将进程间通信数据传输到用户地址空间. 为了减少一次数据 copy 操作, Binder 驱动程序分配给进程的内核缓冲区同时映射到了进程的内核地址空间和用户地址空间. 因此代码 09 与 10 处其实并不是真的将 binder_transaction 结构体 t 中的数据缓冲区与偏移数组的内容 copy 到 binder_transaction_data 结构体 tr 中, 而是修改 binder_transaction_data 结构体 tr 中的数据缓冲区和偏移数组的地址值, 使他们指向 t 中的数据缓冲区与偏移数组.

    代码 11 处将 binder_work 结构体 w 从目标线程 thread 或者目标进程的 todo 队列中删除, 因为它所描述的工作项已经得到处理了.

    代码 12 处将 binder_transaction 结构体 t 的成员变量 allow_user_free 设置为 1 .表示 Binder 驱动程序为它分配的内核缓冲区允许目标线程 thread或者目标进程在用户空间中发出 BC_FREE_BUFFER 命令协议来释放.

    代码 13 处判断当前 Binder 驱动程序向目标线程或者进程发送的是一个 BR_TRANSACTION 返回协议, 并且 binder_transaction 结构体 t 的成员变量 flagsTF_ONE_WAY 位等于 0. 那么命中 if, 说明 Binder 驱动程序正在请求目标线程或者进程执行一个同步的进程间通信请求. 接着在 if内 就将 binder_transaction 接头体 t 压入到目标线程或者进程的事务堆栈 transaction_stack 中, 以便 Binder 驱动程序以后可以从目标线程所属进程的 Binder 线程池中选择一个最优的空闲 Binder 线程来处理其他的进程间通信请求.

    这里时候的目标线程 thread 或者进程, 指的是 SM进程.

    至此 SM 进程在 Binder 驱动程序的函数 binder_thread_read 中被唤醒, 并且返回到用户空间之后, 就会调用 SM 进程中的函数 biner_parse 来处理从 Binder 驱动程序接收到的返回协议. 即返回到 Android Service Manager 的启动流程 中第8步中的 16 行代码处.

    36. binder_parse. 返回到 ServiceManager 处理 Binder 驱动程序的返回协议

    源码路径: /frameworks/native/cmds/servicemanager/binder.c

    int binder_parse(struct binder_state *bs, struct binder_io *bio, uintptr_t ptr, size_t size, binder_handler func)
    {
       ...
    
        while (ptr < end) {
    01      uint32_t cmd = *(uint32_t *) ptr;
            ...
            switch(cmd) {
            ...
            case BR_TRANSACTION: {
    02          struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
                ...
                binder_dump_txn(txn);
                if (func) {
                    unsigned rdata[256/4];
    03              struct binder_io msg;
    04              struct binder_io reply;
                    int res;
    
                    bio_init(&reply, rdata, sizeof(rdata), 4);
                    bio_init_from_txn(&msg, txn);
    05              res = func(bs, txn, &msg, &reply);
    06              binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                }
                ptr += sizeof(*txn);
                break;
            }
                ...
            }
        }
        return r;
    }
    

    按照目前流程, 只需要关心它处理 BR_TRANSACTION 返回协议的过程.

    代码 01 处从缓冲区 ptr 读出 BR_TRANSACTION 返回协议代码之后, 在代码 02 处将返回协议的内容读取到一个 binder_transaction_data 结构体 txn 中.

    接着在代码 03 与 04 处定义了两个 binder_io 结构体 msgreply. 其中 msg 用来解析从 Binder 驱动程序读取回来的进程间通信数据, 而 reply 用来将进程间通信结果数据保存到缓冲区 rdata 中, 以便后面可以将它返回给 Binder 驱动程序. 它们分别使用 bio_initbio_init_from_txn 来初始化.

    代码 05处调用函数 func 来处理保存在 binder_io 结构体 msg 中的 BR_TRANSACTION 返回协议, 并将处理结果保存至 binder_io 结构体 reply中.

    最终在代码 06 处调用函数 binder_send_reply 将进程间通信结果, 即 binder_io 结构体 reply 返回给 Binder 驱动程序.

    那么接下来还是分两步来分析, 第一先看 func 是如何处理返回协议的. 第二再看 binder_send_reply 如何将进程间通信结果返回的.

    Android Service Manager 的启动流程 中第8步中调用 binder_parse 时传入的参数 func 有解释, 它指向 SM 中的函数 svcmgr_handler, 它是用来处理 Service 组件和 Client 组件进程间通信请求的.

    现在进入到 svcmgr_handler

    37. svcmgr_handler. 处理 BR_TRANSACTION 返回协议

    源码路径: /frameworks/native/cmds/servicemanager/service_manager.c

    int svcmgr_handler(struct binder_state *bs, struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply)
    {
        ...
        switch(txn->code) {
        ...
        case SVC_MGR_ADD_SERVICE:
    01      s = bio_get_string16(msg, &len);
            ...
    02      handle = bio_get_ref(msg);
            ...
    03      if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, txn->sender_pid))
                return -1;
            break;
        ...
        }
        bio_put_uint32(reply, 0);
        return 0;
    }
    

    由于 AMS 进程请求 SM 执行的操作是注册 Service 组件 AMS, 对应的操作代码为 SVC_MGR_ADD_SERVICE . 因此接下来只需要分析 case SVC_MGR_ADD_SERVICE: 的情况.

    代码 01 处从 binder_io 结构体 msg 的数据缓冲区中取出要注册的 Service 组件的名称.
    代码 02 处调用函数 bio_get_refbinder_io 结构体 msg 的数据缓冲区中获得一个 Binder 引用对象的句柄值, 这个 Binder 引用对象是在 Binder 驱动程序中创建的. 它引用了即将要注册的 Servie 组件.

    获得了用来描述即将要注册的 Service 组件的一个句柄值 handle 之后, 在代码 03 处就调用函数 do_add_service 将这个 Service 组件注册到 SM 中.

    38. do_add_service 注册 AMS 到 SM 中.

    源码路径: /frameworks/native/cmds/servicemanager/service_manager.c

    
    int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, uid_t uid, int allow_isolated, pid_t spid)
    {
        ...
    01  if (!svc_can_register(s, len, spid, uid)) {
            ...
        }
    
    02  si = find_svc(s, len);
    03   if (si) {
          ...
        } else {
    04      si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
            ...
            si->handle = handle;
            si->len = len;
            memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
            si->name[len] = '\0';
            si->death.func = (void*) svcinfo_death;
            si->death.ptr = si;
            si->allow_isolated = allow_isolated;
            si->next = svclist;
    05      svclist = si;
        }
       ...
    }
    

    参数 s 表示要注册的 Service 组件的名称.
    参数 uid 表示请求 SM 注册 Service 组件的进程的用户 ID ,

    代码 01 处调用函数 svc_can_register 来检查是否有权限请求 SM 注册一个名称为 s 的 Service 组件.
    如果没有直接返回错误.

    将 Service 组件注册到 SM 是一种特权, 不是所有的进程都可以将 Service 组件注册到 SM 中. SM 中定义了一个全局的 allwoed, 它定义了那些进程可以注册什么名称的 Service 组件.

    通过了权限检查后, 在代码 02 处调用 find_svc 函数来检查服务名称是否已经被注册了. 目前流程走到这里, AMS 还未被注册. 所以命中 else , 从代码 04 处至代码 05 处之间, 就会创建一个 svcinfo 结构体来描述要注册的 Service 组件. 并且将它添加到全局队列 svclist 中.

    至此一个AMS 进程就成的注册到 SM 中了. 接着返回到 37 步 04 处代码, 调用 bio_put_uint32 函数将注册成功代码 0 写入到 binder_io 结构体 reply 中. 以便后面可以将它返回给请求注册 Service 组件的过程.

    int svcmgr_handler(struct binder_state *bs, struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply)
    {
        ...
        switch(txn->code) {
        ...
        case SVC_MGR_ADD_SERVICE:
    01      s = bio_get_string16(msg, &len);
            ...
    02      handle = bio_get_ref(msg);
            ...
    03      if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, txn->sender_pid))
                return -1;
            break;
        ...
        }
     04  bio_put_uint32(reply, 0);
        return 0;
    }
    

    OK, 继续向上返回, 返回到第 36 步中的代码 06 处. 代码如下

    int binder_parse(struct binder_state *bs, struct binder_io *bio, uintptr_t ptr, size_t size, binder_handler func)
    {
       ...
    
        while (ptr < end) {
    01      uint32_t cmd = *(uint32_t *) ptr;
            ...
    05              res = func(bs, txn, &msg, &reply);
    06              binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                }
                ptr += sizeof(*txn);
                break;
            }
                ...
            }
        }
        return r;
    }
    

    SM 成功的将一个 Service 组件注册到内部的 Service 组件列表 svclist 之后, 就会调用代码 06 处的 binder_send_reply 函数将 Service 组件注册结果返回给 Binder 驱动程序. Binder 驱动程序再将结果返回给请求注册 Service 组件的进程.

    39. binder_send_reply SM 将 AMS 的注册结果返回给 Binder 驱动程序.

    源码路径: /frameworks/native/cmds/servicemanager/binder.c

    void binder_send_reply(struct binder_state *bs, struct binder_io *reply, binder_uintptr_t buffer_to_free, int status)
    {
        ...
    01  data.cmd_free = BC_FREE_BUFFER;
    02  data.buffer = buffer_to_free;
    03  data.cmd_reply = BC_REPLY;
        data.txn.target.ptr = 0;
        data.txn.cookie = 0;
        data.txn.code = 0;
    04  if (status) {
                ...
        } else {
            data.txn.flags = 0;
            data.txn.data_size = reply->data - reply->data0;
            data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
            data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
            data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
    05  }
    06    binder_write(bs, &data, sizeof(data));
    }
    

    参数 reply 指向了一个 binder_io 结构体, 内部包含了进程间通信结果数据.
    参数 buffer_to_free 是一个用户空间地址, 指向了一块用来传输进程间通信数据的内核缓冲区.
    参数 status 用来描述 SM 是否成功的处理了一个进程间通信请求. 即是否成功的注册了一个 Service 组件.

    BC_FREE_BUFFER 后面跟的通信数据是一个内核缓冲区的用户空间地址.
    BC_REPLY 后面跟的通信数据是一个 binder_transaction_data 结构体.

    代码 01 处与 02 处设置匿名结构体 data 中的 BC_FREE_BUFFER 命令协议内容.
    代码 03 处到 05 处都是设置 BC_REPLY 命令协议内容.

    代码 04 处是判断 SM 在处理一个进程间通信请求发生了错误. 即 if 语句为 true. 这种情况下, SM 需要将该错误代码通过 BC_REPLY 命令协议返回给 Binder 驱动程序, 以便 Binder 驱动程序可以继续将它返回给发出该进程通信请求的 Client 进程. 按以上流程执行到这里是为 false 的. 所以分析 else 中内容.

    命中 else 说明 SM 成功的处理了一个进程间通信请求, 这种情况下, 进程间通信结果就保存在 binder_io 结构体 reply 中. 因此 else 中就将 binder_io 结构体 reply 的数据缓冲区和偏移数组设置到匿名结构体 data 中. 以便可以通过 BC_REPLY 命令协议返回给 Binder 驱动程序. Binder 驱动程序再将它们返回给发出该进程间通信请求的 Client 进程.

    最后在代码 06 处 调用函数 binder_write 将匿名结构体 data 中的 BC_FREE_BUFFERBC_REPLY 命令协议发送给 Binder 驱动程序.

    40. binder_write将 BC_FREE_BUFFER 与 BC_REPLY 命令协议发送给 Binder 驱动程序

    源码路径: /frameworks/native/cmds/servicemanager/binder.c

    int binder_write(struct binder_state *bs, void *data, size_t len)
    {
     01 struct binder_write_read bwr;
        int res;
    
        bwr.write_size = len;
        bwr.write_consumed = 0;
    02  bwr.write_buffer = (uintptr_t) data;
        bwr.read_size = 0;
        bwr.read_consumed = 0;
        bwr.read_buffer = 0;
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
         ...
        return res;
    }
    

    函数 binder_write 是通过 IO 控制命令 BINDER_WRITE_READ 来将 BC_FREE_BUFFERBC_REPLY 命令协议发送给 Binder 驱动程序的. 所以在代码 01 处定义了一个 binder_write_read 结构体 bwr.

    在代码 02 处将 binder_write_read 结构体 bwr 的输入缓冲区 write_buffer 设置为由参数 data 所描述的一块用户缓冲区. 参数 data 所描述的一块用户空间缓冲区包含了一个 BC_FREE_BUFFERBC_REPLY 命令协议.

    binder_write_read 结构体 bwr 的输入缓冲区 read_buffer 及其长度都被设置为 0. 因此, 当 SM 通过 IO 控制命令 BINDER_WRITE_READ 进入到 Binder 驱动程序时, Binder 驱动程序调用函数 binder_thread_write 处理完成 binder_write_read 结构体 bwr 的输出缓冲区中的 BC_FREE_BUFFERBC_REPLY 命令协议之后, 就会马上返回到 SM 的用户空间.

    接着分析在 Binder 驱动程序处理 BC_FREE_BUFFERBC_REPLY 命令协议的过程.

    BC_FREE_BUFFER 命令协议是在函数 binder_thread_write 中处理的.

    41. binder_thread_write 处理 BC_FREE_BUFFER 与 BC_REPLY 命令协议

    源码路径: kernel 3.18下的 /drivers/staging/android/binder.c

    static int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed)
    {
        ...
        while (ptr < end && thread->return_error == BR_OK) {
            ...
            switch (cmd) {
            ...
            case BC_FREE_BUFFER: {
                ...
    01          if (get_user(data_ptr, (binder_uintptr_t __user *)ptr))
                    ...
    02          buffer = binder_buffer_lookup(proc, data_ptr);
                ...
    03          binder_transaction_buffer_release(proc, buffer, NULL);
    04          binder_free_buf(proc, buffer);
                break;
            }
            case BC_TRANSACTION:
            case BC_REPLY: {
                ...
    05          binder_transaction(proc, thread, &tr,cmd == BC_REPLY, 0);
                break;
            }
      ...
        return 0;
    }
    

    代码 01 处获得要释放的内核缓冲区的用户空间地址. 保存在变量 data_ptr 中.
    代码 02 处调用函数 binder_buffer_lookup 在进程 proc 中找到与用户空间地址 data_ptr 对应的内核缓冲区 buffer.

    代码 03与 04 处分别是调用函数 binder_transaction_buffer_releasebinder_free_buf 来减少 Binder 实体对象或者 Binder 引用对象的引用计数与释放内核缓冲区 buffer.

    接着是在代码 05 处调用 binder_transaction 处理 BC_REPLY 命令协议.

    42. binder_transaction

    源码路径: kernel 3.18下的 /drivers/staging/android/binder.c
    在上一章的第 30 步, 分析了 binder_transaction 处理 BC_TRANSACTION 命令协议, 其中参数 replyfalse, 现在分析的是它处理 BC_REPLY 协议的过程, 参数 reply 值为 true. 不要混乱了.

    
    static void binder_transaction(struct binder_proc *proc,
                       struct binder_thread *thread,
                       struct binder_transaction_data *tr, int reply,
                       binder_size_t extra_buffers_size)
    {
    
    
        ...
        if (reply) {
    01      in_reply_to = thread->transaction_stack;
            ...
            ...
    02      thread->transaction_stack = in_reply_to->to_parent;
            target_thread = in_reply_to->from;
            ...
            target_proc = target_thread->proc;
        } else {
            ...
        }
        ...
    03  if (reply) {
            ...
    04      binder_pop_transaction(target_thread, in_reply_to);
        } else if (!(t->flags & TF_ONE_WAY)) {
              ...
        } else {
                ...     
        }
        t->work.type = BINDER_WORK_TRANSACTION;
        list_add_tail(&t->work.entry, target_list);
        tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
        list_add_tail(&tcomplete->entry, &thread->todo);
        if (target_wait)
    05      wake_up_interruptible(target_wait);
        return;
    ...
    }
    

    从上面调用可知传进来的 reply 值为 true.所以命中 if.

    在第一个 if 内就来找到之前请求与 SM 进行进程间通信的线程 即 AMS, 找到了这个目标线程 target_thread 之后, Binder 驱动程序就可以向它发出一个 BC_REPLY 返回协议, 以便将进程间通信的结果返回给它

    当 Binder 驱动程序分发一个进程间通信请求给一个线程处理时, 会将一个 binder_transaction 结构体压入到它的事务堆栈中, 因此代码 01 处从就从线程 thread 的事务堆栈中将该 binder_transaction 结构体取出来, 保存在变量 in_reply_to 中.

    binder_transaction 结构体 in_reply_to的成员变量 from 指向了之前请求与线程 thread 进程进程间通信的线程, 因此, 后面就可以通过来获得目标线程 target_thread, 那么此时的 目标线程 target_thread 是谁? 是 AMS, 因为在 SM 中完成了注册, 就需要通过 Binder 驱动程序将结果返回给 AMS. 需要处理的是类型为 BINDER_WORK_TRANSACTION 的工作项.

    binder_transaction 结构体 in_reply_to 中的成员变量 to_parent 指向了用来处理它的线程 thread的下一个需要处理的事务. 因此代码 02 处就将这个事务放在线程 thread 的事务堆栈 transaction_stack 的顶端, 表示线程 thread 接下来要处理它.

    代码 04处调用函数 binder_pop_transaction 从目标线程 target_thead 的事务堆栈中删除 binder_transaction 结构体 in_reply_to, 因为它所描述的一个事务已经处理完成了, 因此目标线程 target_thead 就不需要再保存它了.

    剩下的就是和第 30步差不多了, 封装工作项, 添加到 todo 队列等. 那么此时 AMS 与 SM 要处理的工作项类型如下

    • ActivityManagerServie 要处理的工作项类型为 BINDER_WORK_TRANSACTION.
    • ServiceManager 要处理的工作项类型为 BINDER_WORK_TRANSACTION_COMPLETE.

    那么接下来就又是并发的去处理各自 todo 队列中的工作项. 我们假设先处理的还是 AMS 中的工作项. 在本章第 34步 IPCThreadState.waitForResponse 函数中 AMS 在 binder_thread_read 中休眠等待进程间通信的结果. 那么我们依然还是从 AMS 这里开始. 在代码 05 处唤醒 AMS. (上一章第 30 步唤醒的是 SM)

    未完待续...

    相关文章

      网友评论

        本文标题:Android ActivityManagerService 注

        本文链接:https://www.haomeiwen.com/subject/rdyjeltx.html