Binder 匿名服务源码分析

8/16/2023

通常,Android 中的 binder 服务需要事先注册到 ServiceManager,其他客户端程序才是使用这个 binder 服务。那些不需要事先注册就能被访问的 binder 服务我们称之为 binder 匿名服务。

添加 Native 系统服务回调 (opens new window)添加 Java 系统服务回调 (opens new window) 中我们介绍的回调都属于匿名服务。在源码中,Android 应用进程创建的过程中会调用 ActivityThread 中的 attach 方法将 ApplicationThread Binder 服务代理端(Java 回调) attach 到 AMS 中,这个也属于 binder 匿名服务。

# Native 系统服务回调源码分析

分析之前我们需要明白,匿名 Binder 是建立在实名 Binder 的基础之上的,也就是说先有实名 Binder 服务再有匿名 Binder 服务。需要先建立实名 binder 连接,才能构建匿名 binder 服务。

接下来我们来分析添加 Native 系统服务回调 (opens new window) Demo 中提供的匿名服务(也就是回调)。

我们首先来看看是匿名服务是如何注册的:

// device/jelly/rice14/AIDLCppCallbackDemo/IHello.cpp

//代码又 aidl 自动生成
::android::binder::Status BpHello::registerCallback(const ::android::sp<::com::yuandaima::ICallback>& cb) {
  ::android::Parcel _aidl_data;
  ::android::Parcel _aidl_reply;
  ::android::status_t _aidl_ret_status = ::android::OK;
  ::android::binder::Status _aidl_status;
  _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }

  //向 Parcel 写入 ICallback
  _aidl_ret_status = _aidl_data.writeStrongBinder(::com::yuandaima::ICallback::asBinder(cb));
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }

  //发起远程调用
  _aidl_ret_status = remote()->transact(::android::IBinder::FIRST_CALL_TRANSACTION + 2 /* registerCallback */, _aidl_data, &_aidl_reply);
  
  //......
  return _aidl_status;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

上面代码主要工作是:

  • 将准备好的数据写入 Parcel 结构体
  • 发起远程调用

在写入 ICallback 到 Parcel 的过程中,使用了 asBinder 函数,asBinder 是一个类静态函数,定义在 ICallback 的父类 IInterface 中:

// frameworks/native/libs/binder/IInterface.cpp
sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface)
{
    if (iface == nullptr) return nullptr;
    return iface->onAsBinder();
}
1
2
3
4
5
6

asBinder 会继续调用 onAsBinder,这里 iface 的具体类型是 BnCallback,onAsBinder 实现在 BnCallback 的父类 BnInterface 中:

// frameworks/native/libs/binder/include/binder/IInterface.h
template<typename INTERFACE>
IBinder* BnInterface<INTERFACE>::onAsBinder()
{
    return this;
}
1
2
3
4
5
6

实际就是返回自己。

接着我们看 writeStrongBinder 的具体实现:

status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
    return flatten_binder(ProcessState::self(), val, this);
}

//进一步调用到 flatten_binder
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
    const sp<IBinder>& binder, Parcel* out)
{
    flat_binder_object obj;

    if (IPCThreadState::self()->backgroundSchedulingDisabled()) {
        /* minimum priority for all nodes is nice 0 */
        obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
    } else {
        /* minimum priority for all nodes is MAX_NICE(19) */
        obj.flags = 0x13 | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    }

    if (binder != nullptr) {
        // localBinder 返回 BnCallback 对应的 BBinder 对象
        // BnCallback 是 BBinder 的子类,实际就是返回自己
        BBinder *local = binder->localBinder();
        if (!local) { 
            BpBinder *proxy = binder->remoteBinder();
            if (proxy == nullptr) {
                ALOGE("null proxy");
            }
            const int32_t handle = proxy ? proxy->handle() : 0;
            obj.hdr.type = BINDER_TYPE_HANDLE;
            obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
            obj.handle = handle;
            obj.cookie = 0;
        } else { // 走这个分支
            if (local->isRequestingSid()) {
                obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
            }
            obj.hdr.type = BINDER_TYPE_BINDER; //记住这个常量,进入内核要使用
            obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
            obj.cookie = reinterpret_cast<uintptr_t>(local); //记录 BnCallback 指针
        }
    } else {
        obj.hdr.type = BINDER_TYPE_BINDER;
        obj.binder = 0;
        obj.cookie = 0;
    }

    return finish_flatten_binder(binder, obj, out);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

这里将 Parcel 转换为内核可以识别的 flat_binder_object 格式,其中比较重要的几个数据:

obj.hdr.type = BINDER_TYPE_BINDER; //记住这个常量,进入内核要使用
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local); //记录 BnCallback 指针
1
2
3

准备好数据后,就会调用:

remote()->transact
1

发起远程调用。该方法经过层层传递以后最终会调用到 IPCThreadState::executeCommand 中进而调用 talkwithdriver 函数,最后调用 ioctl 进入内核空间中,调用流程如下:

remote()->transact
	->IPCThreadState::executeCommand
		->talkwithdriver
			->binder_ioctl
  				->binder_thread_write
    				->binder_transaction
1
2
3
4
5
6

这些流程我们在驱动分析中已经分析过了,接着我们就来直接看看在内核的 binder_transaction 函数中是怎么处理应用层发过来的数据(flat_binder_object)的:

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)
{
    //......


    for (buffer_offset = off_start_offset; buffer_offset < off_end_offset;
	     buffer_offset += sizeof(binder_size_t)) {

    //解析出应用层传入的数据
		struct binder_object_header *hdr;
		size_t object_size;
		struct binder_object object;
		binder_size_t object_offset;

		binder_alloc_copy_from_buffer(&target_proc->alloc,
					      &object_offset,
					      t->buffer,
					      buffer_offset,
					      sizeof(object_offset));
		object_size = binder_get_object(target_proc, t->buffer,
						object_offset, &object);
		if (object_size == 0 || object_offset < off_min) {
			binder_user_error("%d:%d got transaction with invalid offset (%lld, min %lld max %lld) or object.\n",
					  proc->pid, thread->pid,
					  (u64)object_offset,
					  (u64)off_min,
					  (u64)t->buffer->data_size);
			return_error = BR_FAILED_REPLY;
			return_error_param = -EINVAL;
			return_error_line = __LINE__;
			goto err_bad_offset;
		}

		hdr = &object.hdr;
		off_min = object_offset + object_size;
		switch (hdr->type) {
		case BINDER_TYPE_BINDER:
		case BINDER_TYPE_WEAK_BINDER: {
			struct flat_binder_object *fp;
      //拿到应用层传入的 flat_binder_object
			fp = to_flat_binder_object(hdr);
      //调用 binder_translate_binde 处理解析出的数据
			ret = binder_translate_binder(fp, t, thread);
			if (ret < 0) {
				return_error = BR_FAILED_REPLY;
				return_error_param = ret;
				return_error_line = __LINE__;
				goto err_translate_failed;
			}
			// fp 拷贝到 binder_buffer 中,服务端会收到这个数据
			binder_alloc_copy_to_buffer(&target_proc->alloc,
						    t->buffer, object_offset,
						    fp, sizeof(*fp));
		} break;

    //......
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

这里会解析出应用层传入的 flat_binder_object 数据,并更具数据内容修改驱动中的一些数据结构。

接着我们看下 binder_translate_binder 是怎么处理我们的数据的:

static int binder_translate_binder(struct flat_binder_object *fp,
				   struct binder_transaction *t,
				   struct binder_thread *thread)
{
	struct binder_node *node;
	struct binder_proc *proc = thread->proc;
	struct binder_proc *target_proc = t->to_proc;
	struct binder_ref_data rdata;
	int ret = 0;

  //这里会创建 BnCallback 对应的 binder_node 节点,并插入当前进程的 binder_proc 结构体的 nodes 红黑树中
	node = binder_get_node(proc, fp->binder);
	if (!node) {
		node = binder_new_node(proc, fp);
		if (!node)
			return -ENOMEM;
	}
	if (fp->cookie != node->cookie) {
		binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n",
				  proc->pid, thread->pid, (u64)fp->binder,
				  node->debug_id, (u64)fp->cookie,
				  (u64)node->cookie);
		ret = -EINVAL;
		goto done;
	}
	if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
		ret = -EPERM;
		goto done;
	}

  //这里会创建一个新的 binder_ref 对象,并插入目标进程 binder_proc 的 refs_by_node 红黑树中
	ret = binder_inc_ref_for_node(target_proc, node,
			fp->hdr.type == BINDER_TYPE_BINDER,
			&thread->todo, &rdata);
	if (ret)
		goto done;

	if (fp->hdr.type == BINDER_TYPE_BINDER)
		fp->hdr.type = BINDER_TYPE_HANDLE;
	else
		fp->hdr.type = BINDER_TYPE_WEAK_HANDLE;
	fp->binder = 0;
	//把计算出的 handle 值写入 fp 中
	fp->handle = rdata.desc;
	fp->cookie = 0;

	trace_binder_transaction_node_to_ref(t, node, &rdata);
	binder_debug(BINDER_DEBUG_TRANSACTION,
		     "        node %d u%016llx -> ref %d desc %d\n",
		     node->debug_id, (u64)node->ptr,
		     rdata.debug_id, rdata.desc);
done:
	binder_put_node(node);
	return ret;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

通过代码可以看到当匿名 Binder 注册数据传入到 Binder 驱动以后,将会在匿名 Binder 在驱动中的宿主进程中创建一个 binder_node 节点,并且在目标进程中创建一个 binder_ref 的引用,最终完成了在 Binde r驱动中关于该匿名 Binder 的相关存储,而我们的目的端进程此时持有了 binder_ref 引用进而可以构建 BpBinder,有了 BpBinder 那么就可以操作匿名 Binder 对象了,这个过程就和实名 Binder 类似了。

# 参考资料

# 关于

我叫阿豪,2015 年本科毕业于国防科学技术大学指挥信息系统专业,毕业后从事信息化装备的研发工作,主要研究方向是 Android Framework 与 Linux Kernel。

如果你对 Android Framework 感兴趣或者正在学习 Android Framework,可以关注我的微信公众号和抖音,我会持续分享我的学习经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。