Android 13(T) - binder阅读(5)- 使用ServiceManager注册服务2

news/2025/1/3 4:07:27/

上一篇笔记我们看到了binder_transaction,这个方法很长,这一篇我们将把这个方法拆分开来看binder_transaction做了什么,从而学习binder是如何跨进程通信的。

1 binder_transaction

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)

首先我们来看函数的参数,第一个参数proc为调用进程的binder_proc(也就是MediaServer进程所有的binder_proc);第二个参数thread我们这里不讨论,主要用于多任务通信;第三个参数tr为从用户空间拷贝过来的binder_transaction_data

函数一开始声明了一串变量,我们挑出一部分给出注释:

	// 目标进程的binder_proc struct binder_proc *target_proc = NULL;// 目标进程的binder_node struct binder_node *target_node = NULL;// 上下文(servicemanager)struct binder_context *context = proc->context;// 用户空间数据指针const void __user *user_buffer = (const void __user *)(uintptr_t)tr->data.ptr.buffer;

由于我们这边传递的cmd为BC_TRANSACTION,所以这里先不看reply分支的内容:

		// 1. 判断target handle是否为0,如果不为0则进入以下分支if (tr->target.handle) {struct binder_ref *ref;// 2. 查找binder_refref = binder_get_ref_olocked(proc, tr->target.handle,true);if (ref) {target_node = binder_get_node_refs_for_txn(ref->node, &target_proc,&return_error);} } else {// 3. 如果target handle为0,如果不为0则target为servicemanager// servicemanager的binder_node可以从proc->context中获得target_node = context->binder_context_mgr_node;if (target_node)target_node = binder_get_node_refs_for_txn(target_node, &target_proc,&return_error);}

以上代码是根据Handle查找目标进程的binder_node,这里分了两种情况:

  1. handle为0,说明目标进程为ServiceManager,binder_context 存储的binder_node即为ServiceManager进程所属的。
  2. handle不为0,说明是其他进程,这里要引出一个新的结构体变量binder_ref,这个东西在我们每次从servicemanager获取服务代理时,由binder驱动帮助我们创建,binder_ref用于存储服务的进程信息,除此之外binder驱动为该代理创建一个handle也存储在binder_ref中,有了这个handle就可以找到目标进程了,最后把创建的binder_ref存储在调用进程的binder_proc的一个红黑树列表中。
    这里讲的可能比较拗口,用一张图来表示下:
    请添加图片描述

我们还是回到handle为0的情况,调用servicemanager注册服务的流程中。接下来这部分我没有仔细去研究,没太看懂,只能写一些我的猜测在这里,大概就是从用户空间拷贝我们一开始打包的Parcel数据到目标进程的共享内存当中:

	struct binder_transaction *t;t = kzalloc(sizeof(*t), GFP_KERNEL);t->to_proc = target_proc;t->to_thread = target_thread;t->code = tr->code;t->flags = tr->flags;t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,tr->offsets_size, extra_buffers_size,!reply && (t->flags & TF_ONE_WAY), current->tgid);t->buffer->transaction = t;t->buffer->target_node = target_node;t->buffer->clear_on_free = !!(t->flags & TF_CLEAR_BUF);if (binder_alloc_copy_user_to_buffer(&target_proc->alloc,t->buffer,ALIGN(tr->data_size, sizeof(void *)),(const void __user *)(uintptr_t)tr->data.ptr.offsets,tr->offsets_size)) {}

仅仅做完拷贝还没结束,还需要对拷贝的buffer中的一些特殊内容做一些处理,我这里只看是如何处理传递过来的binder对象的:

		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;fp = to_flat_binder_object(hdr);ret = binder_translate_binder(fp, t, thread);} break;case BINDER_TYPE_HANDLE:case BINDER_TYPE_WEAK_HANDLE: {struct flat_binder_object *fp;fp = to_flat_binder_object(hdr);ret = binder_translate_handle(fp, t, thread);} break;

这里主要看binder_translate_binder是如何translate处理的:

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;// 1 从调用进程中查找要传递的binder对象的binder_nodenode = binder_get_node(proc, fp->binder);if (!node) {// 2 如果没有查找到,为调用进程创建一个binder_nodenode = binder_new_node(proc, fp);if (!node)return -ENOMEM;}// 3 查找目标进程是否已经存储有这个binder_ref,如果没有则为其创建一个binder_refret = binder_inc_ref_for_node(target_proc, node,fp->hdr.type == BINDER_TYPE_BINDER,&thread->todo, &rdata);if (ret)goto done;// 将binder实体转换为了引用if (fp->hdr.type == BINDER_TYPE_BINDER)fp->hdr.type = BINDER_TYPE_HANDLE;elsefp->hdr.type = BINDER_TYPE_WEAK_HANDLE;fp->binder = 0;fp->handle = rdata.desc;fp->cookie = 0;
done:binder_put_node(node);return ret;
}

这里主要做了如下几件事情:

  1. 从调用进程中查找要传递的binder对象的binder_nodebinder_proc中同样有一个红黑树链表存储有该进程中的binder_node对象;
  2. 如果没有查找到,为调用进程创建一个binder_node,说明传递的对象是属于调用进程的;
  3. 查找目标进程是否已经有了binder_node对应的binder_ref,如果没有则说明目标进程还没有这个要传递的binder对象的引用,为目标进程创建一个binder_ref引用(handle),存储到flat_binder_object 中写到共享内存当中。

binder驱动会将我们传递的binder实体转化为属于调用进程的binder_node,并且提供一个binder_ref给目标进程,目标进程持有的永远都是代理。
请添加图片描述
到这里,binder数据的传输就结束了。


总结:这一篇笔记写的比较水,最重要的共享内存并没有理解清楚,有想了解的小伙伴可以去看看其他大神的博文。其实我的目标是研究binder对象是如何传输的,到这里也大概也了解了,目的也算达成,后续有机会再去研究共享内存机制。


http://www.ppmy.cn/news/644200.html

相关文章

Android手机病毒分析(二)

上一回我们将手机应用反编译为我们熟悉的Java代码,接下来我们可以进行分析了。 我们将这些应用称之为手机病毒,实际上其并不是病毒,只能算是恶意应用(至少我分析到的app都是这样的)。这些手机应用不具有完整的传播性等…

鸿蒙系统会中毒吗,手机中毒会感染wifi吗

大家好,我是时间财富网智能客服时间君,上述问题将由我为大家进行解答。 理论上是存在有这种可能性的,但是比较低,手机是ios或者andriod系统,wifi没系统也不能写入,wifi只有64m-256m内存,所以说手…

计算机感染木马或病毒,电脑中木马病毒的症状

大家好,我是时间财富网智能客服时间君,上述问题将由我为大家进行解答。 电脑中木马病毒的症状是: 1、文件或文件夹无故消失 当发现电脑中的部分文件或文件夹无缘无故消失,就可以确定电脑已经中了病毒。部分电脑病毒通过将文件或文件夹隐藏,然后伪造已隐藏的文件或文件夹并…

为您揭露手机病毒的真相

目前大家能见到铺天盖地的手机病毒爆发,3G来了要装手机杀毒软件,手机中毒后隐私外泄等等如此骇人的广告和说辞。那手机病毒很多吗?我的手机很慢是中毒了吗?到哪里装手机杀毒软件?哪个手机杀毒软件最好?一个…

移动手机病毒的进化历程

今年,新冠疫情成了与人类对立的最大病毒体,我们的免疫系统与无数昼夜奔波的医护人员即是与之抗衡的安全卫士。 那么,计算机和我们如今最常用的智能手机如何防御病毒,我想写的这个系列就带领大家深谙这一话题。本篇文章先带大家了解…

谈谈最近很火的android手机病毒

““XXX(机主姓名)看这个,ht://********XXshenqi.apk”最近一种手机病毒爆发,机主收到这样的短信,开头是以发送者手机通讯录存储的名字为开头,然后再让对方点开一个网页链接。 其实熟悉android的朋友一看就明白这个病毒原理其实很…

计算机感染木马或病毒后,计算机中木马病毒的症状

大家好,我是Time Fortune.com的明智客户服务。我将为您解答以上问题。 计算机中的木马病毒的症状是: 1、文件或文件夹无故消失 如果发山词霸和QQ管理器,这三种主流的国内安全保护软件都具有自防御防御模块,病毒或木马的第一个攻击…

Android手机病毒分析及研究

最近卡巴斯基报出Backdoor.AndroidOS.Obad.a病毒( http://www.securelist.com/en/blog/8106/The_most_sophisticated_Android_Trojan),该病毒利用Android系统未知安全漏洞。 以下是360病毒分析报告: 最近有媒体爆料,最…