Ahao's Technical Blog Ahao's Technical Blog
首页
  • 001.基础篇
  • 002.玩转AOSP篇
  • 003.学穿Binder篇
  • 004.基础组件篇
  • 005.系统启动过程分析
  • 006.Hal开发入门与实践
  • 007.显示系统
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

阿豪讲Framework

不积跬步无以至千里
首页
  • 001.基础篇
  • 002.玩转AOSP篇
  • 003.学穿Binder篇
  • 004.基础组件篇
  • 005.系统启动过程分析
  • 006.Hal开发入门与实践
  • 007.显示系统
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 基础篇

  • 玩转AOSP篇

  • 学穿Binder篇

    • 000.Binder 专题导学 —— 如何深入掌握 Binder
    • 001.学习 Binder 的预备知识
    • 002.Binder 基本原理
    • 003.Binder 程序示例之 C 语言篇
    • 004.Binder 服务注册过程情景分析之 C 语言篇
    • 005.Binder 服务获取与使用过程情景分析之C语言篇
    • 006.Android Binder 驱动框架设计与分析
    • 007.Binder 驱动情景分析之 ServiceManager 启动过程
    • 008.Binder 驱动情景分析之服务注册过程
    • 009.Binder 驱动情景分析之服务获取与使用过程
    • 010.Binder 程序示例之 C++ 篇
    • 011.Binder C++ 程序分析之主要类解析
    • 012.Binder 服务注册过程情景分析之 C++ 篇
    • 013.Binder 服务获取与使用过程情景分析之C++篇
    • 014.Binder 程序示例之 aidl-cpp 篇
    • 015.添加 Android Native 系统服务
    • 016.添加 Native 系统服务回调
    • 017.Binder 程序示例之 Java 篇
    • 018.Binder Java 层初始化
    • 019.Binder Java 层服务注册过程分析
    • 020.Binder Java 层服务获取与使用过程分析
    • 021.添加 Java 系统服务
    • 022.Android Java 系统服务框架与第三方 App 使用自定义 Java 系统服务
    • 023.添加 Java 系统服务回调
    • 024.AIDL 数据类型详解之 Java 篇
    • 025.AIDL 数据类型详解之 C++ 篇
    • 026.Java 调用 Native 服务
    • 027.Native 调用 Java Binder 服务
    • 028.AIDL 关键字 in out inout oneway 解析
    • 029.Binder 驱动 Debug 入门指南
    • 030.Binder 匿名服务源码分析
      • Native 系统服务回调源码分析
      • 参考资料
    • 031.Binder 中的 Parcel 数据结构分析(C++)
    • 032.Binder 中的 Parcel 数据结构分析(Java)
    • 033.Binder 多线程情景分析
    • 034.Binder 线程池溢出问题
    • 035.Binder 代理对象泄露问题分析
    • 036.Binder 死亡通知情景分析
    • 037.Binder 异常处理机制
    • 038.Binder 系统源码演进
    • 039.Binder 面试题汇总
    • 补充——LocalService
  • 基础组件篇

  • 系统启动过程分析

  • Hal开发入门与实践

  • 显示系统

  • Framework
  • 学穿Binder篇
阿豪
2023-08-16
目录

030.Binder 匿名服务源码分析

通常,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 类似了。

# 参考资料

  • Android Binder框架实现之何为匿名/实名Binder (opens new window)
029.Binder 驱动 Debug 入门指南
031.Binder 中的 Parcel 数据结构分析(C++)

← 029.Binder 驱动 Debug 入门指南 031.Binder 中的 Parcel 数据结构分析(C++)→

最近更新
01
如何调试 SurfaceFlinger
10-05
02
SurfaceFlinger 概述
10-05
03
HWC 接口分析
10-05
更多文章>
Theme by Vdoing | Copyright © 2020-2025 AHao Framework | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式