Binder—Binder 对象生命周期

一、注册服务流程

1.1 图片形式

注册服务流程

1.2 文字形式

注册服务,详细步骤如下:

  • 注册服务进程发送 BC_TRANSACTION 协议给 Binder 驱动程序 // 调用的是 binder_thread_write 函数,向 Binder 驱动程序写数据
    调用 binder_transaction(),当前是请求阶段
            // 因为当前跨进程请求目的是为了注册服务,参数肯定不能只有服务名,那再传个什么参数才能代表注册了个服务呢?比如传个指针什么的,可以表示服务的唯一性,事实上,传了一个 type 为 BINDER_TYPE_BINDER 的 Binder 对象,成员 binder 引用了 ptr,这个 ptr 好像就是服务相关的引用(待验证)
            ① 通信对象是 ServiceManager,handle 为 0,当前调用 binder_inc_node 增加对 ServiceManager 这个 Binder 实体的引用计数
            ② 请求数据包含 Binder 对象,开始解析 Binder 数据的流程,根据 Binder 的 type 为 BINDER_TYPE_BINDER
                    调用 binder_get_node 获取属于注册服务进程的 Binder 实体对象(存在就返回,不存在返回 NULL,首次获取时返回 NULL),如果返回 NULL,则调用 binder_new_node 创建属于注册服务进程的 Binder 实体对象(创建 Binder 实体对象过程中,会添加一个类型为 BINDER_WORK_NODE 的事务)
                    调用 binder_get_ref_for_node 去返回一个属于目标进程 ServiceManager 的 binder_ref(不存在就创建,之后就返回已创建的)
                    修改 Binder 对象的 type,由 BINDER_TYPE_BINDER 改成 BINDER_TYPE_HANDLE
                    设置服务句柄 handle 值,赋值为 binder_get_ref_for_node 返回的 binder_ref 对象的 desc 值(可以看成服务注册的顺序)
                    调用 binder_inc_ref,分情况:首次注册服务:会增加 Binder 实体对象的引用计数,非首次注册服务,增加 Binder 引用对象的引用计数(也就是说,只有第一次才真正注册服务,后面的只是增加 Binder 引用对象的引用)
            ③ Binder 驱动程序往目标进程 ServiceManager 进程的 todo 队列塞了一个类型为 BINDER_WORK_TRANSACTION 的事务,唤醒 ServiceManager 进程
    ServiceManager 被唤醒后,收到 Binder 驱动程序发来的事务
  • ServiceManager 处理 Binder 驱动程序中转的注册服务的请求
            ① 取出事务
                    第一次取出的是类型为 BINDER_WORK_NODE 的事务,该类型事务与 Binder 实体对象相关,需要修改 Binder 实体对象对应的 Binder 本地对象的引用计数,通过 put_user 把协议(BR_ACQUIRE、BR_RELEASE、BR_INCREFS、BR_DECREFS)及内容写入 Server 进程用户空间缓冲区,然后 Server 进程收到数据,完成相应请求,如果是请求处理的协议是用来增加 Binder 本地对象的强弱引用的(BR_ACQUIRE、BR_INCREFS),则立马通过协议(BC_ACQUIRE_DONE、BC_INCREFS_DONE)通知 Binder 驱动程序,已增加 Binder 本地对象的强弱引用计数
                    第二次取出的是类型为 BINDER_WORK_TRANSACTION 的事务,将 cmd 改为 BR_TRANSACTION,然后把注册服务的数据通过 put_user、copy_to_user 写到用户空间
                    // 下面的 ②③④⑤⑥⑦ 都在 ServiceManager 进程的用户空间
                    ② 先根据注册服务的数据中的 code 执行相应函数,当前就是注册服务
                    ③ 调用 bio_get_string16 获取要注册的服务名
                    ④ 调用 bio_get_ref 获取服务的引用号 handle(Binder 驱动程序调用 binder_get_ref_for_node 创建引用对象时生成)
                    ⑤ 调用 do_add_service 在应用程序层面注册服务(实际为记录服务名和 handle),如果当前 ServiceManager 进程不存在要注册的服务(首次注册服务),则先创建一个用来描述要注册的服务的 struct svcinfo 结构体对象,然后用注册服务的相关数据给这个结构体对象赋值,再把这个结构体对象添加到链表 svcinfo 中。如果当前 ServiceManager 进程存在要注册的服务(重复注册服务),则更新服务的 handle 值
                    ⑥ 若 do_add_service 注册服务成功,则调用 bio_put_uint32(reply, 0),将用于通知注册服务进程注册服务成功
                    ⑦ 调用 binder_send_reply 通过 BC_REPLY 协议返回 reply(0) 给注册服务进程表示注册服务成功(需要经过 Binder 驱动程序中转)
  • ServiceManager 进程发送 BC_REPLY 协议给 Binder 驱动程序 // 调用的是 binder_thread_write 函数,向 Binder 驱动程序写数据
            调用 binder_transaction(),当前是回复阶段(reply)
            // 当前返回的仅仅是 uint32 类型的 0,即 00 00 00 00,因为携带的数据不含 Binder 对象,则
            ① 返回数据不含 Binder 对象,跳过解析 Binder 的过程
            ② Binder 驱动程序往目标进程注册服务进程的 todo 队列塞了一个类型为 BINDER_WORK_TRANSACTION 的事务,唤醒注册服务进程
    注册服务进程被唤醒后,收到 Binder 驱动程序发来的新事务
  • 注册服务进程处理 Binder 驱动程序中转的回复数据
            ① 取出类型为 BINDER_WORK_TRANSACTION 的事务,将 cmd 改为 BR_REPLY,然后把回复数据通过 put_user 、、copy_to_user 写到用户空间
            // 下面的 ② 都在注册服务进程的用户空间
            ② 此时注册服务进程的用户空间中的 reply 就有值了(reply 中仅包含 00 00 00 00),表示注册服务成功,然后就结束了

1.3 注册服务整个流程,涉及 Binder 对象生命周期的地方,概括如下:

  • 先要获取 ServiceManager 的代理对象(当前进程第一次获取会创建再返回,后续返回已创建的对象),增加 ServiceManager 这个 Binder 实体的引用计数
  • 调用 binder_get_node 获取属于注册服务进程的 Binder 实体对象(存在就返回,不存在返回 NULL),如果返回 NULL,则调用 binder_new_node 创建属于注册服务进程的 Binder 实体对象(创建 Binder 实体对象过程中,会添加一个类型为 BINDER_WORK_NODE 的事务)
    // ServiceManager 处理类型为 BINDER_WORK_NODE 的事务,该类型事务与 Binder 实体对象相关,需要修改 Binder 实体对象对应的 Binder 本地对象的引用计数
  • 调用 binder_get_ref_for_node 获取属于目标进程 ServiceManager 的 binder_ref(不存在就创建,之后就返回已创建的)
  • 调用 binder_inc_ref,分情况:首次注册服务:会增加 Binder 实体对象的引用计数,非首次注册服务,增加 Binder 引用对象的引用计数(也就是说,只有第一次才真正注册服务,后面的只是增加 Binder 引用对象的引用)

二、获取服务流程

2.1 图片形式

获取服务流程

2.2 文字形式

通过服务名获取服务,详细步骤如下:

  • 获取服务进程发送 BC_TRANSACTION 协议给 Binder 驱动程序 // 调用的是 binder_thread_write 函数,向 Binder 驱动程序写数据
    调用 binder_transaction(),当前是请求阶段
            // 因为当前跨进程请求目的是为了获取一个 Binder 代理对象,很明显携带的请求数据不含 Binder 对象(只有服务名),则
            ① 通信对象是 ServiceManager,handle 为 0,当前调用 binder_inc_node 增加对 ServiceManager 这个 Binder 实体的引用计数
            ② 请求数据不含 Binder 对象,跳过解析 Binder 的过程
            ③ Binder 驱动程序往目标进程 ServiceManager 进程的 todo 队列塞了一个事务,唤醒 ServiceManager 进程
    ServiceManager 被唤醒后,收到 Binder 驱动程序发来的新事务
  • ServiceManager 进程处理 Binder 驱动程序中转的获取服务的请求
            ① 取出类型为 BINDER_WORK_TRANSACTION 的事务,将 cmd 改为 BR_TRANSACTION,然后把获取服务的数据通过 put_user、copy_to_user 写到用户空间
            // 下面的 ②③④ 都在 ServiceManager 进程的用户空间
            ② 先根据获取服务的数据执行对应函数,当前就是根据服务名获取服务句柄
            ③ 调用 bio_put_ref 生成一个 Binder 对象,type 类型为 BINDER_TYPE_HANDLE
            ④ 调用 binder_send_reply 通过 BC_REPLY 协议返回服务句柄给获取服务进程(需要经过 Binder 驱动程序中转)
  • ServiceManager 进程发送 BC_REPLY 协议给 Binder 驱动程序 // 调用的是 binder_thread_write 函数,向 Binder 驱动程序写数据
            调用 binder_transaction(),当前是回复阶段(reply)
            // 因为当前跨进程请求目的是返回一个 Binder 代理对象,很明显携带的请求数据含 Binder 对象,则
            ① 回复数据含 Binder 对象,解析返回数据中的 Binder 对象,因为获取服务的进程是客户端进程,不是服务端进程
                    调用 binder_get_ref 根据返回数据中的 Binder 对象服务句柄返回属于获取服务进程的 binder_ref
                    调用 binder_get_ref_for_node 根据 binder_ref->node 去返回一个属于目标进程 ServiceManager 的 binder_ref(不存在就创建,之后就返回已创建的)
                    调用 binder_inc_ref,分情况:首次获取服务:会增加 Binder 实体对象的引用计数,非首次获取服务:增加 Binder 引用对象的引用计数
            ② Binder 驱动程序往目标进程获取服务进程的 todo 队列塞了一个类型为 BINDER_WORK_TRANSACTION 的事务,唤醒获取服务进程
    获取服务进程被唤醒后,收到 Binder 驱动程序发来的新事务
  • 获取服务进程处理 Binder 驱动程序中转的获取服务的请求
            ① 取出事务,把请求数据通过 put_user、copy_to_user 写到用户空间,然后将 cmd 改为 BR_REPLY
            // 下面的 ②③④ 都在获取服务进程的用户空间
            ② 此时获取服务进程的用户空间中的 reply 就有值了(reply 中包含了一个 Binder 代理对象,里面含有服务的句柄值,注意,这里说的代理是说 type 为 BINDER_TYPE_HANDLE 的意思,不是 BpBinder)
    此时,获取服务进程在用户空间通过 getStrongProxyForHandle(Binder 代理对象->服务句柄) 返回一个 BpBinder 对象(第一次创建后返回,之后直接返回已创建的),如果是第一次创建的 BpBinder 对象,此时会发送 BC_INCREFS 协议,增加相应的 Binder 引用对象的弱引用计数

2.3 获取服务整个流程,涉及 Binder 对象生命周期的地方,概括如下:

  • 先要获取 ServiceManager 的代理对象(当前进程第一次获取会创建再返回,后续返回已创建的对象),增加 ServiceManager 这个 Binder 实体的引用计数
  • 生成 type 为 BINDER_TYPE_HANDLE 的 Binder 对象,根据里面的句柄调用 binder_get_ref 找到 binder_ref,再根据 binder_ref->node 调用 binder_get_ref_for_node 去返回一个 binder_ref(不存在就创建,之后就返回已创建的),然后调用 binder_inc_ref 去增加 Binder 实体对象的强引用计数(获取服务进程第一次获取服务,因此这个 binder_ref 是新创建的,这个 Binder 引用对象对 Binder 实体对象的强引用为 0,通过 binder_inc_node 增加实体对象引用,避免实体对象还被引用对象引用时,实体对象被销毁)或增加 Binder 引用对象的引用计数(获取服务进程不是第一次获取服务,使用已创建的 binder_ref,然后增加 Binder 引用对象的引用计数)
  • 将 type 为 BINDER_TYPE_HANDLE 的 Binder 对象返回给获取服务进程,取出里面的服务句柄,返回一个 BpBinder 对象(首次创建 BpBinder:会增加相应的 Binder 引用对象的弱引用计数 + 非首次创建 BpBinder 对象:直接使用该对象)

2.4 获取服务过程,涉及 Binder 对象声明周期,时间路线:

  • BC_REPLY 阶段
    首次获取服务:会增加 Binder 实体对象的强引用计数
    非首次获取服务:增加 Binder 引用对象的引用计数(判断是否是首次获取服务的标准是,能不能根据服务名查到的服务句柄查到的服务引用查到的服务实体,看看获取服务进程的服务引用红黑树上是否存在一个节点对应的 binder_ref 所引用的 binder_node 和前面查到的服务实体相等)
  • BR_REPLY 阶段,首次创建 BpBinder:会增加相应的 Binder 引用对象的弱引用计数 + 非首次创建 BpBinder 对象:直接使用该对象(判断是否需要首次创建 BpBinder 的标准是,能不能根据返回的服务句柄作为关键字从内部的 Binder 代理队列中查找到一个 handle_entry 结构体,若找到则使用 handle_entry 结构体内部的 IBinder 指针指向的 BpBinder 对象,没找到则需要先创建,然后再保存在 handle_entry 中)

三、BpBinder 对象存在直接返回已创建的,从代码角度看体现在哪?

因为上面 “获取服务流程” 最后一段说 “获取服务进程在用户空间通过 getStrongProxyForHandle(Binder 代理对象->服务句柄) 返回一个 BpBinder 对象(第一次创建后返回,之后直接返回已创建的)”,自然想到去查看 getStrongProxyForHandle 函数实现

[frameworks/native/libs/binder/ProcessState.cpp, getStrongProxyForHandle()]

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);

	// 找到了 handle_entry 藏身之处
	// 根据服务句柄 handle 查找对应的资源项 handle_entry,若 lookupHandleLocked() 函数没有对应的资源项,则会创建一个新项 handle_entry 返回(但是成员 binder 为 NULL),这个新项 handle_entry 的内容需要填充
	// 看了很多文章,都说如果找到了服务句柄 handle 对应的资源项 handle_entry,最后直接返回 BpBinder 对象(但当前还未完全理清这一点内容,待完善)
    handle_entry* e = lookupHandleLocked(handle);

	// 上面刚创建完 handle_entry,肯定不为 NULL
    if (e != NULL) {
    	// 成员 binder 为 NULL
        IBinder* b = e->binder;
        // 满足 if 第一个条件:binder 为 NULL
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
        	// 当前的服务句柄值 handle 对应的是 Server 服务,当前 if 不满足
            if (handle == 0) {
                Parcel data;
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }

			// 根据服务句柄 handle 创建 BpBinder 对象
            b = new BpBinder(handle); 
            // 上面不是说 handle_entry 的成员 binder 为 NULL 吗,在此用新创建的 BpBinder 对象赋完值就不为 NULL 了
            // 也说明了,下次再获取相同服务句柄值 handle 时,lookupHandleLocked() 函数返回的 handle_entry 的成员 binder 就不为 NULL 了,也就不需要重复创建 BpBinder 对象了
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            // result 赋值为 BpBinder 对象
            result = b;
        } else {
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }

	// 返回 BpBinder 对象
    return result;
}

[frameworks/native/libs/binder/ProcessState.cpp, lookupHandleLocked()]

// 根据索引查找对应的资源项,没有则创建新的资源项返回,新的资源项之后需要填充
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
    // mHandleToObject:Vector<handle_entry>,本进程中记录所有 BpBinder 的向量表
    const size_t N = mHandleToObject.size();
    if (N <= (size_t)handle) {
        // struct handle_entry {
        //     IBinder* binder;
        //     RefBase::weakref_type* refs;
        // };
        handle_entry e;
        e.binder = NULL; // 成员 binder 设置为 NULL
        e.refs = NULL; // 成员 refs 设置为 NULL
        status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
        if (err < NO_ERROR) return NULL;
    }
    // 返回 handle 对应资源的地址(返回的时成员 binder 还为 NULL)
    return &mHandleToObject.editItemAt(handle);
}

四、一个进程注册多个 Binder 服务,如何区分

提出猜测

当前跨进程请求目的是为了注册服务,参数肯定不能只有服务名,那再传个什么参数才能代表注册了个服务呢?比如传个指针什么的,可以表示服务的唯一性,事实上,传了一个 type 为 BINDER_TYPE_BINDER 的 Binder 对象,成员 binder 引用了 ptr,这个 ptr 应该就是服务相关的引用,下面验证该猜测

验证猜测

当前标题和挖坑待验证说的是一个意思,就是说一个进程可以注册多个 Binder 服务,在使用 Binder 服务时,当提供服务进程收到调用服务请求后,提供服务进程如何确定用哪个 Binder 服务去响应调用服务请求

现在开始验证(需要提前说明的是,当前讨论的前提是 C++ 层面的注册服务),从下面三个角度分析(重点关注注册服务谁代表了注册的服务,至于注册服务的整个流程有空再说)

  • 注册服务进程(注册服务)
  • Binder 驱动程序(中转站)
  • 获取服务进程(使用服务)

4.1 注册服务进程(注册服务)

构造数据,注册服务
[–>bctest.c, svcmgr_publish()]

// 注意最后一个参数 ptr(是一个函数指针,用于响应服务请求),该参数可以用代表注册的服务
int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr)
{
    int status;
    unsigned iodata[512/4];
    struct binder_io msg, reply;

    // 构造数据
    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header
    bio_put_string16_x(&msg, SVC_MGR_NAME);
    // 指定要注册的服务名称
    bio_put_string16_x(&msg, name);
    // 查看 bio_put_obj(),注意这个 ptr,代表了服务
    bio_put_obj(&msg, ptr);

    // 向驱动程序发送数据
    if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
        return -1;

    status = bio_get_uint32(&reply);

    binder_done(bs, &msg, &reply);

    return status;
}

[–>binder.c, bio_put_obj()]

void bio_put_obj(struct binder_io *bio, void *ptr)
{
	// struct flat_binder_object 可以用来描述一个 Binder 对象
	struct flat_binder_object *obj;
	
	obj = bio_alloc_obj(bio);
	if (!obj)
		return;
	
	obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
	// BINDER_TYPE_BINDER 表示当前是一个 Binder 实体对象
	obj->type = BINDER_TYPE_BINDER;
	// 注意传入的 ptr 赋给了 flat_binder_object 的 binder 成员
	obj->binder = (uintptr_t)ptr;
	obj->cookie = 0;
}

构造的数据达到 Binder 驱动程序,准备解析收到的数据

4.2 Binder 驱动程序(中转站)

解析数据,处理数据
[–>kernel/drivers/android/binder.c, binder_transaction()]

static void binder_transaction(struct binder_proc *proc,
			       struct binder_thread *thread,
			       struct binder_transaction_data *tr, int reply)
{
    struct binder_transaction *t;
    struct binder_work *tcomplete;
    size_t *offp, *off_end;
    struct binder_proc *target_proc;
    struct binder_thread *target_thread = NULL;
    struct binder_node *target_node = NULL;
    struct list_head *target_list;
    wait_queue_head_t *target_wait;
    struct binder_transaction *in_reply_to = NULL;
    uint32_t return_error = BR_OK;
    
    ...
    
    // 创建 binder_transaction 结构体
    t = kzalloc(sizeof(*t), GFP_KERNEL);
    if (t == NULL) {
        return_error = BR_FAILED_REPLY;
        goto err_alloc_t_failed;
    }
    binder_stats_created(BINDER_STAT_TRANSACTION);

    // 创建 binder_work 结构体
    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
    if (tcomplete == NULL) {
        return_error = BR_FAILED_REPLY;
        goto err_alloc_tcomplete_failed;
    }
    binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
    
    if (!reply && !(tr->flags & TF_ONE_WAY))
        t->from = thread;
    else
        t->from = NULL;
    
    t->sender_euid = proc->tsk->cred->euid;
    t->to_proc = target_proc;
    t->to_thread = target_thread;
    t->code = tr->code;
    t->flags = tr->flags;
    t->priority = task_nice(current);
    // t->buffer 是从目的进程 target_proc(目的进程是 Service Manager 进程)所映射的空间映射的空间
    t->buffer = binder_alloc_buf(target_proc, tr->data_size, tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
    if (t->buffer == NULL) {
        return_error = BR_FAILED_REPLY;
        goto err_binder_alloc_buf_failed;
    }
    t->buffer->allow_user_free = 0;
    t->buffer->debug_id = t->debug_id;
    t->buffer->transaction = t;
    // 当前目的节点 target_node 为 binder_context_mgr_node(请求阶段有值,回复阶段没有值)
    t->buffer->target_node = target_node;
    if (target_node)
        binder_inc_node(target_node, 1, 0, NULL);

    // offp:数据缓冲区起始地址
    offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));

    // 下面两个 if 从注册服务进程的用户空间拷贝数据到目标进程 target_proc(目的进程是 Service Manager 进程)的内核空间
    	// t->buffer 是从目的进程 target_proc(目的进程是 Service Manager 进程)所映射的空间映射的空间
    	// tr->data.ptr.buffer:binder_transaction_data 数据缓冲区中有一个 type 为 BINDER_TYPE_BINDER 的 Binder 对象
    if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {
        return_error = BR_FAILED_REPLY;
        goto err_copy_data_failed;
    }
    // tr->data.ptr.offsets:binder_transaction_data 偏移数组记录了 Binder 对象在数据缓冲区中的位置
    if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {
        return_error = BR_FAILED_REPLY;
        goto err_copy_data_failed;
    }
    // offsets_size:偏移数组大小 
    off_end = (void *)offp + tr->offsets_size;
    // for 循环遍历数据缓冲区中的 Binder 对象,遍历范围 [offp, off_end]
    for (; offp < off_end; offp++) {
        struct flat_binder_object *fp;
        // 根据数据缓冲区起始位置 + 偏移确定一个 Binder 对象,赋给 fp(flat_binder_object)
        fp = (struct flat_binder_object *)(t->buffer->data + *offp);
        switch (fp->type) {
        case BINDER_TYPE_BINDER: // BINDER 实体,走这个
        case BINDER_TYPE_WEAK_BINDER: {
            struct binder_ref *ref;
            // 在内核态获取一个 binder_node 节点给进程 proc(当前进程是注册服务进程)
            struct binder_node *node = binder_get_node(proc, fp->binder);
            if (node == NULL) {
                // 查看 binder_new_node(),第一次获取为空,则创建 binder_node 节点
                node = binder_new_node(proc, fp->binder, fp->cookie);
                if (node == NULL) {
                    return_error = BR_FAILED_REPLY;
                    goto err_binder_new_node_failed;
                }
                node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
                node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
            }
            // 在内核态构造一个 binder_ref 节点给目的进程 target_proc(目的进程是 Service Manager 进程)
            ref = binder_get_ref_for_node(target_proc, node); // 引用会从 1 开始递增,引用 0 用来表示引用 Service Manager
            if (ref == NULL) {
                return_error = BR_FAILED_REPLY;
                goto err_binder_get_ref_for_node_failed;
            }
            if (fp->type == BINDER_TYPE_BINDER)
                fp->type = BINDER_TYPE_HANDLE; // type 变为 BINDER_TYPE_HANDLE,因为当前为 Service Manager 进程,只能使用 struct binder_ref
            else
                fp->type = BINDER_TYPE_WEAK_HANDLE;
            // handle 从 1 开始增长,代表第几个引用
            fp->handle = ref->desc; // 对于 struct binder_ref,不能使用 binder,需要使用 handle,赋值为 ref->desc
            // 增加 struct binder_ref 的引用计数,同时会返回一些信息给 thread(当前为 Server 中对应的线程),告诉该 thread 有别的线程引用自己
            binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo);
        } break;
        ...
        }
    }
    ...
    // 设置 t(binder_transaction 结构体)任务类型为 BINDER_WORK_TRANSACTION
    t->work.type = BINDER_WORK_TRANSACTION;
    // 将 t(binder_transaction 结构体)添加到目标线程 todo 队列 target_list 中
    list_add_tail(&t->work.entry, target_list);
    // 设置 tcomplete(binder_work 结构体)任务类型为 BINDER_WORK_TRANSACTION_COMPLETE
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    // 将 tcomplete(binder_work 结构体)添加到 ServiceManager 进程主线程的 todo 队列 中
    list_add_tail(&tcomplete->entry, &thread->todo);
    // 目标进程(Service Manager 进程)处于睡眠中,此时唤醒目标进程(Service Manager 进程)
    if (target_wait)
        wake_up_interruptible(target_wait);
    return;

...
}

在上个阶段,我们构造了一个 struct flat_binder_object

  • type = BINDER_TYPE_BINDER // Binder 实体对象
  • binder = (uintptr_t)ptr // ptr 赋给了 flat_binder_object 的 binder 成员

上面的方法中,后面的那个 for 循环,就是用来解析我们构造的 Binder 对象,因为我们指定的 type 是 BINDER_TYPE_BINDER,则会执行 binder_new_node() 函数,用于在内核中为注册服务进程的 Binder 实体对象创建一个 binder_node 节点

// for 循环遍历数据缓冲区中的 Binder 对象
for (; offp < off_end; offp++) {
	struct flat_binder_object *fp;
	// 解析出 struct flat_binder_object
	fp = (struct flat_binder_object *)(t->buffer->data + *offp);
	switch (fp->type) {
        case BINDER_TYPE_BINDER: // BINDER 实体,走这个
        case BINDER_TYPE_WEAK_BINDER: {
        	struct binder_ref *ref;
            // 在内核态获取一个 binder_node 节点给进程 proc(当前进程是注册服务进程)
            struct binder_node *node = binder_get_node(proc, fp->binder);
            if (node == NULL) {
                // 查看 binder_new_node(),第一次获取为空,则创建 binder_node 节点
                // 注意第二个参数 fp->binder,这是 flat_binder_object 的 binder 成员啊
                node = binder_new_node(proc, fp->binder, fp->cookie);
                ...
// 第二个参数 ptr 在上面调用时传入的是 flat_binder_object 的 binder 成员
static struct binder_node *binder_new_node(struct binder_proc *proc,
					   void __user *ptr,
					   void __user *cookie)
{
	struct rb_node **p = &proc->nodes.rb_node;
	struct rb_node *parent = NULL;
	struct binder_node *node;

	while (*p) {
		parent = *p;
		node = rb_entry(parent, struct binder_node, rb_node);

		if (ptr < node->ptr)
			p = &(*p)->rb_left;
		else if (ptr > node->ptr)
			p = &(*p)->rb_right;
		else
			return NULL;
	}

	node = kzalloc(sizeof(*node), GFP_KERNEL);
	if(node == NULL)
		return NULL;
	binder_stats_created(BINDER_STAT_NODE);
	rb_link_node(&node->rb_node, parent, p);
	rb_insert_color(&node->rb_node, &proc->nodes);
	node->debug_id = ++binder_last_id;
	node->proc = proc;
	// 把 ptr 赋给了 binder_node 的 ptr
	node->ptr = ptr;
	node->cookie = cookie;
	node->work.type = BINDER_WORK_NODE;
	INIT_LIST_HEAD(&node->work.entry);
	INIT_LIST_HEAD(&node->async_todo);
	return node;
}

ptr 一开始赋给了 flat_binder_object 的 binder 成员,最终保存在了内核为注册服务进程创建的 binder_node 的 ptr 成员中

4.3 获取服务进程(使用服务)

假设已完成获取服务过程,然后根据获取的服务 handle 去使用服务
[–>kernel/drivers/android/binder.c, binder_transaction()]

static void binder_transaction(struct binder_proc *proc,
			       struct binder_thread *thread,
			       struct binder_transaction_data *tr, int reply)
{
    struct binder_transaction *t;
    struct binder_work *tcomplete;
    size_t *offp, *off_end;
    struct binder_proc *target_proc;
    struct binder_thread *target_thread = NULL;
    struct binder_node *target_node = NULL;
    struct list_head *target_list;
    wait_queue_head_t *target_wait;
    struct binder_transaction *in_reply_to = NULL;
    uint32_t return_error = BR_OK;
    
    if (reply) {
    	...
    } else { // reply 为 false,走这个
    	if (tr->target.handle) { // 上面我们假定获取了服务,拿到了 handle(不为 0),走这个
            struct binder_ref *ref;
            // 根据服务 handle 获取 binder_ref
            ref = binder_get_ref(proc, tr->target.handle);
            if (ref == NULL) {
                return_error = BR_FAILED_REPLY;
                goto err_invalid_target_handle;
            }
            // 获取 binder_node
            target_node = ref->node;
        } else { // 目的进程 ServerManager,值为 0
            target_node = binder_context_mgr_node;
            if (target_node == NULL) {
                return_error = BR_DEAD_REPLY;
                goto err_no_context_mgr_node;
            }
        }
        e->to_node = target_node->debug_id;
        target_proc = target_node->proc; // 提供服务进程
        if (target_proc == NULL) {
            return_error = BR_DEAD_REPLY;
            goto err_dead_binder;
        }
        // 首次请求,获取服务的线程 thread 事务堆栈 transaction_stack 为空
        if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
            struct binder_transaction *tmp;
            tmp = thread->transaction_stack;
            if (tmp->to_thread != thread) {
                return_error = BR_FAILED_REPLY;
                goto err_bad_call_stack;
            }
            while (tmp) {
                if (tmp->from && tmp->from->proc == target_proc)
                    target_thread = tmp->from;
                tmp = tmp->from_parent;
            }
        }
    }
    if (target_thread) {
        target_list = &target_thread->todo;
        target_wait = &target_thread->wait;
    } else { // 目标线程为空,走这个
    	// 获取目标进程 todo 队列
        target_list = &target_proc->todo;
        // 获取目标进程 wait 等待队列
        target_wait = &target_proc->wait;
    }
    
    // 创建 binder_transaction 结构体,用来记录一次单向传输过程
    t = kzalloc(sizeof(*t), GFP_KERNEL);
    if (t == NULL) {
        return_error = BR_FAILED_REPLY;
        goto err_alloc_t_failed;
    }
    binder_stats_created(BINDER_STAT_TRANSACTION);

    // 创建 binder_work 结构体
    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
    if (tcomplete == NULL) {
        return_error = BR_FAILED_REPLY;
        goto err_alloc_tcomplete_failed;
    }
    binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
    
    // 不是回复阶段 && 需要回复,当前是请求阶段,需要回复,
    if (!reply && !(tr->flags & TF_ONE_WAY))
        t->from = thread; // 获取服务的线程
    else
        t->from = NULL;
    
    t->sender_euid = proc->tsk->cred->euid;
    t->to_proc = target_proc; // 提供服务进程
    t->to_thread = target_thread; // 为 NULL
    t->code = tr->code;
    t->flags = tr->flags;
    t->priority = task_nice(current);
    t->buffer = binder_alloc_buf(target_proc, tr->data_size, tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
    if (t->buffer == NULL) {
        return_error = BR_FAILED_REPLY;
        goto err_binder_alloc_buf_failed;
    }
    t->buffer->allow_user_free = 0;
    t->buffer->debug_id = t->debug_id;
    t->buffer->transaction = t;
    // 当前目的节点 target_node 为根据服务 handle 找到的 binder_node(请求阶段有值,回复阶段没有值)
    t->buffer->target_node = target_node;
    if (target_node)
        binder_inc_node(target_node, 1, 0, NULL);

    // offp:数据缓冲区起始位置
    offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));

    // 下面两个 if 从用户空间拷贝数据到内核空间
    // tr->data.ptr.buffer:binder_transaction_data 数据缓冲区中只包含要访问的服务名称
    if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {
        return_error = BR_FAILED_REPLY;
        goto err_copy_data_failed;
    }
    // tr->data.ptr.offsets:binder_transaction_data 偏移数组记录了 Binder 对象在数据缓冲区中的位置(当前数据缓冲区中不含 Binder 对象)
    if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {
        return_error = BR_FAILED_REPLY;
        goto err_copy_data_failed;
    }
    // offsets_size:偏移数组大小 
    off_end = (void *)offp + tr->offsets_size;
    // 当前数据缓冲区中不含 Binder 对象,跳过 for 循环(若有 Binder 对象时,则遍历数据缓冲区中的 Binder 对象,遍历范围 [offp, off_end])
    for (; offp < off_end; offp++) {
    	...
    }
    ...
    // 设置 t(binder_transaction 结构体)任务类型为 BINDER_WORK_TRANSACTION
    t->work.type = BINDER_WORK_TRANSACTION;
    // 将 t(binder_transaction 结构体)添加到目标线程 todo 队列 target_list 中
    list_add_tail(&t->work.entry, target_list);
    // 设置 tcomplete(binder_work 结构体)任务类型为 BINDER_WORK_TRANSACTION_COMPLETE
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    // 将 tcomplete(binder_work 结构体)添加到获取服务的线程的 todo 队列 中
    list_add_tail(&tcomplete->entry, &thread->todo);
    // 提供服务进程处于睡眠中,此时唤醒提供服务进程
    if (target_wait)
        wake_up_interruptible(target_wait);
    return;

...
}

当前根据服务 handle 找到对应的 binder_node,然后 ServiceManager 进程被唤醒,处理任务类型为 BINDER_WORK_TRANSACTION 的事务
[–>kernel/drivers/android/binder.c, 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)
{
    void __user *ptr = buffer + *consumed;
    void __user *end = buffer + size;

    int ret = 0;
    int wait_for_proc_work;

    if (*consumed == 0) {
        // 将 BR_NOOP 写回到用户空间
        if (put_user(BR_NOOP, (uint32_t __user *)ptr))
            return -EFAULT;
        ptr += sizeof(uint32_t);
    }
    
    // while 循环用于处理进程或线程 todo 队列中存在的未处理工作项
    while (1) {
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;
        
        if (!list_empty(&thread->todo))
            w = list_first_entry(&thread->todo, struct binder_work, entry);
        else if (!list_empty(&proc->todo) && wait_for_proc_work) // 当前目标进程 ServiceManager 的 todo 队列不为空
        	// 取出工作项 binder_work
            w = list_first_entry(&proc->todo, struct binder_work, entry);
        else {
            if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added */
                goto retry;
            break;
        }

        if (end - ptr < sizeof(tr) + 4)
            break;
        switch (w->type) {
        case BINDER_WORK_TRANSACTION: { // 处理任务类型为 BINDER_WORK_TRANSACTION 的事务
        	// 根据 binder_work 构造出 binder_transaction
            t = container_of(w, struct binder_transaction, work);
        } break;
        case BINDER_WORK_TRANSACTION_COMPLETE: {
        	...
        } break;
        }
        
        // 收到 BINDER_WORK_TRANSACTION 时,t 不为空
        if (!t)
            continue;
        
        // 请求阶段 target_node 不为空(请求阶段有值,回复阶段没有值),当前为根据服务 handle 找到对应的 binder_node
        if (t->buffer->target_node) { // 当前是请求阶段,走这个
            struct binder_node *target_node = t->buffer->target_node;
            // 注意 target_node->ptr,这就是在注册服务时保存在 binder_node->ptr 中的,现在赋给了 binder_transaction_data.target.ptr
            tr.target.ptr = target_node->ptr;
            tr.cookie =  target_node->cookie;
            t->saved_priority = task_nice(current);
            if (t->priority < target_node->min_priority && !(t->flags & TF_ONE_WAY))
                binder_set_nice(t->priority);
            else if (!(t->flags & TF_ONE_WAY) || t->saved_priority > target_node->min_priority)
                binder_set_nice(target_node->min_priority);
            cmd = BR_TRANSACTION; // BR_TRANSACTION
        } else {
            tr.target.ptr = NULL;
            tr.cookie = NULL;
            cmd = BR_REPLY;
        }
        tr.code = t->code;
        tr.flags = t->flags;
        tr.sender_euid = t->sender_euid;

        if (t->from) {
            struct task_struct *sender = t->from->proc->tsk;
            tr.sender_pid = task_tgid_nr_ns(sender, current->nsproxy->pid_ns);
        } else {
            tr.sender_pid = 0;
        }

        tr.data_size = t->buffer->data_size;
        tr.offsets_size = t->buffer->offsets_size;
        // tr(binder_transaction_data)数据缓冲区中只包含要访问的服务名称
        tr.data.ptr.buffer = (void *)t->buffer->data + proc->user_buffer_offset;
        tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *));

        // 将 cmd = BR_TRANSACTION 写回到用户空间
        if (put_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        ptr += sizeof(uint32_t);
        // 将 tr(binder_transaction_data,数据缓冲区中只包含要访问的服务名称)写回到用户空间
        if (copy_to_user(ptr, &tr, sizeof(tr)))
            return -EFAULT;
        ptr += sizeof(tr);

        binder_stat_br(proc, thread, cmd);

        list_del(&t->work.entry);
        t->buffer->allow_user_free = 1;
        // 当前是 BR_TRANSACTION && 需要回复
        if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
            t->to_parent = thread->transaction_stack; // to_parent 为 NULL
            t->to_thread = thread;
            // 将 t(binder_transaction 结构体)入栈(ServiceManager 进程主线程事务堆栈)
            thread->transaction_stack = t;
        } else {
            t->buffer->transaction = NULL;
            kfree(t);
            binder_stats_deleted(BINDER_STAT_TRANSACTION);
        }
        break;
    }

	...
    // 返回
    return 0;
}

注册服务时保存在 binder_node->ptr 中的那个 ptr,现在赋给了 binder_transaction_data.target.ptr 成员

现在提供服务进程准备处理请求
[–>binder.c]

// binder_loop 读取请求后将解析这些请求,最后调用 binder_handler 完成最终的处理
void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;
    uint32_t readbuf[32];

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;

    readbuf[0] = BC_ENTER_LOOPER;
    binder_write(bs, readbuf, sizeof(uint32_t));

    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;

		// 读取数据
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

        if (res < 0) {
            break;
        }

		// 解析数据(在方法中会通过 func 回调函数,调用对应函数)
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        if (res == 0) {
            break;
        }
        if (res < 0) {
            break;
        }
    }
}

由上面的的代码注释可知,binder_parse() 通过 func 回调函数解析数据,fun 对应函数指针 binder_handler

已知注册服务时保存在 binder_node->ptr 中的那个 ptr,最终赋给了 binder_transaction_data.target.ptr 成员

[–>binder.h]

typedef int (*binder_handler)(struct binder_state *bs,
                              struct binder_transaction_data *txn, // 注意 binder_transaction_data
                              struct binder_io *msg,
                              struct binder_io *reply);

struct binder_transaction_data 用来描述进程间通信过程中传输的数据

struct binder_transaction_data {
	union {
		size_t handle;
		void *ptr;
	} target;
	void *cookie;
	unsigned int code;
	
	unsigned int flags;
	pid_t sender_pid;
	uid_t sender_euid;
	size_t data_size;
	size_t offsets_size;
	
	union {
		struct {
			const void *buffer;
			const void *offsets;
		} ptr;
		uint8_t buf[8];
	} data;
};

验证结论

于是,现在我们可以从 binder_transaction_data.target.ptr 成员中,还原出注册服务时保存在 binder_node->ptr 中的那个 ptr,所以可以说注册服务过程中,参数 ptr(其实是一个函数指针,用于响应服务请求)确实是可以用来代表注册的服务。因此,一开始我们在上面所做的猜测是对的

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值