关于AIDL接口定义中oneway的修饰符源码解析.

关于Binder (AIDL)的 oneway 机制 开篇总结 Binder 是 Android 中的 IPC(进程间通信)的最要一环,它的作用就是: 异步调用(单个binder请求) 应用向 binder 驱动发送数据后不需要挂起线程等待 binder 驱动的回复,而是直接结束。 串行化处理(多个binder请求) 对于一个服务端的 AIDL 接口而言,所有的 oneway 方法不会同时执行,binder 驱动会将他们串行化处理,排队一个一个调用。 像一些系统服务调用应用进程的时候就会使用 oneway,比如 AMS 调用应用进程启动 Activi 阅读详情

以下源码出自于Android 8.1

该部分源码基于我另外一篇文章,Binder通信流程浅析有提到,在binder进行传输数据时有提到这个方法binder_proc_transaction,该方法是把当前client要发送的数据t加入到队列中,并唤起binder线程执行该事务,当时忽略了一个细节oneway修饰符:

static bool binder_proc_transaction(struct binder_transaction *t,
				    struct binder_proc *proc,
				    struct binder_thread *thread)
{
	struct list_head *target_list = NULL;
	struct binder_node *node = t->buffer->target_node;
	struct binder_priority node_prio;
	bool oneway = !!(t->flags & TF_ONE_WAY);
	bool wakeup = true;

	BUG_ON(!node);
	binder_node_lock(node);
	node_prio.prio = node->min_priority;
	node_prio.sched_policy = node->sched_policy;

	if (oneway) {
		BUG_ON(thread);
		if (node->has_async_transaction) {
			target_list = &node->async_todo;
			wakeup = false;
		} else {
			node->has_async_transaction = 1;
		}
	}

	binder_inner_proc_lock(proc);

	if (proc->is_dead || (thread && thread->is_dead)) {
		binder_inner_proc_unlock(proc);
		binder_node_unlock(node);
		return false;
	}

	if (!thread && !target_list)
		thread = binder_select_thread_ilocked(proc);

	if (thread) {
		target_list = &thread->todo;
		binder_transaction_priority(thread->task, t, node_prio,
					    node->inherit_rt);
	} else if (!target_list) {
		target_list = &proc->todo;
	} else {
		BUG_ON(target_list != &node->async_todo);
	}

	binder_enqueue_work_ilocked(&t->work, target_list);

	if (wakeup)
		binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);

	binder_inner_proc_unlock(proc);
	binder_node_unlock(node);

	return true;
}

我们在定义AIDL接口的时候,可以在方法返回值前,加个oneway进行修饰,如下:

interface ITest {
    oneway void test1();//异步
    oneway void test2();//异步
    int test3();// 同步
}

简单的说,oneway表示的异步调用,串行执行,什么意思呢,看代码:
如果接口方法加了oneway修饰,那么通过 bool oneway = !!(t->flags & TF_ONE_WAY);这行代码得到的bool为1.
假设有两个进程分别为B跟C同时调用ITest.test1(),服务端是否能同时响应这两个binder请求?

我们看第一次的执行逻辑:

static bool binder_proc_transaction(struct binder_transaction *t,
				    struct binder_proc *proc,
				    struct binder_thread *thread)
{
	struct list_head *target_list = NULL;
	struct binder_node *node = t->buffer->target_node;
	struct binder_priority node_prio;
	bool oneway = !!(t->flags & TF_ONE_WAY);
	bool wakeup = true;

	BUG_ON(!node);
	binder_node_lock(node);
	node_prio.prio = node->min_priority;
	node_prio.sched_policy = node->sched_policy;
    //第一次进来,oneway为1,表示true
	if (oneway) {
		BUG_ON(thread);
		//node->has_async_transaction默认为0的,表示false
		if (node->has_async_transaction) {
		//不执行这个if
			target_list = &node->async_todo;
			wakeup = false;
		} else {
			node->has_async_transaction = 1;
		}
	}

	binder_inner_proc_lock(proc);

	if (proc->is_dead || (thread && thread->is_dead)) {
		binder_inner_proc_unlock(proc);
		binder_node_unlock(node);
		return false;
	}

    //第一次oneway调用,thread为空,target_list也为空,找到一个空闲的线程,响应这次的调用
	if (!thread && !target_list)
		thread = binder_select_thread_ilocked(proc);

	if (thread) {
	   //第一次调用执行这个if
		target_list = &thread->todo;
		binder_transaction_priority(thread->task, t, node_prio,
					    node->inherit_rt);
	} else if (!target_list) {
		target_list = &proc->todo;
	} else {
		BUG_ON(target_list != &node->async_todo);
	}
    //把任务入队
	binder_enqueue_work_ilocked(&t->work, target_list);
    //第一次wakeup为true,唤醒一条线程执行工作队列中的任务
	if (wakeup)
		binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);

	binder_inner_proc_unlock(proc);
	binder_node_unlock(node);

	return true;
}

第二次的执行逻辑:

static bool binder_proc_transaction(struct binder_transaction *t,
				    struct binder_proc *proc,
				    struct binder_thread *thread)
{
	struct list_head *target_list = NULL;
	struct binder_node *node = t->buffer->target_node;
	struct binder_priority node_prio;
	bool oneway = !!(t->flags & TF_ONE_WAY);
	bool wakeup = true;

	BUG_ON(!node);
	binder_node_lock(node);
	node_prio.prio = node->min_priority;
	node_prio.sched_policy = node->sched_policy;
    //第二次执行ITest.test2(),因为调用的是同一个服务,所以实体node是之前是一样的,也就是说经过第一次调用,node->has_async_transaction已经为1.
	if (oneway) {
		BUG_ON(thread);
		if (node->has_async_transaction) {
		//所以第二次调用执行这个if
			target_list = &node->async_todo;
			wakeup = false;
		} else {
			node->has_async_transaction = 1;
		}
	}

	binder_inner_proc_lock(proc);

	if (proc->is_dead || (thread && thread->is_dead)) {
		binder_inner_proc_unlock(proc);
		binder_node_unlock(node);
		return false;
	}
   //第二次调用oneway方法,不执行这个if,即thread为空,但target_list已经赋值为node->async_todo,但值还是为null.
	if (!thread && !target_list)
	//不执行
		thread = binder_select_thread_ilocked(proc);

	if (thread) {
		target_list = &thread->todo;
		binder_transaction_priority(thread->task, t, node_prio,
					    node->inherit_rt);
	} else if (!target_list) {
		target_list = &proc->todo;
	} else {
	//执行这里
		BUG_ON(target_list != &node->async_todo);
	}
   //第二次调用把任务放到target_list,此时target_list就是node->async_todo,不会立即执行改请求
	binder_enqueue_work_ilocked(&t->work, target_list);
   //wakeup为false
	if (wakeup)
		binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);

	binder_inner_proc_unlock(proc);
	binder_node_unlock(node);

	return true;
}

结论:
1.当不同进程同时调用远程接口的同一个用oneway修饰的方法时,server端是不会同时响应的,必须等 前一个先执行完,排队一个个来.
2.当不同进程同时调用远程接口的不同(oneway修饰)方法时,结论同1一致,因为binder实体node是相同的,还是得排队一个个来.
3.如果node不同,则可以同时响应.
4.oneway修饰,表示调用端不会阻塞,无需等待服务端的返回结果,提高效率,非oneway反之,调用端会休眠,等待服务端的返回结果

AIDL中oneway的三大陷阱:从Binder驱动看串行化处理的边界条件 本文从Binder驱动底层视角,深入剖析了Android AIDL中oneway关键字的三大陷阱。重点揭示了oneway调用在相同接口间的串行化处理机制、不同接口实例的并发边界,以及高频调用下可能触发的缓冲区限制与调用失败风险,为开发者设计健壮的跨进程通信提供了关键见解。 阅读详情

相关推荐

深入理解AIDL的oneway关键字

在Android开发中,跨进程通信(Inter-Process Communication, IPC)是常见的需求。AIDL提供了一种方便、高效的IPC机制,使得不同进程之间的通信变得简单可靠。在AIDL中,oneway关键字用于标记远程方法调用为单向的,这意味着客户端在发送请求后不需要等待服务器的响应。oneway关键字的主要作用是优化客户端的性能。在传统的双向RPC(Remote Procedure Call)通信中,客户端发送请求后需要等待服务器的响应,这可能会导致客户端线程阻塞,影响用户体验。

xiangzhihong8的专栏 570

AIDL学习

AIDL学习与理解

fengzhiqi1993的博客 1539

Android Binder的两三事--基于Android14源码

Android14-Framework-Binder

保持专注,保持热爱 1141

Android-你真的懂AIDL的oneway嘛?

AIDL是Android Interface definition language的缩写,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口。andr...

嵌入式Linux 1万+

C# 进程间 双内存共享 高帧率图像传输

演示了两个进程之间通过 双内存共享 的方式, 来实时处理图像,并以高帧率(40~60FPS)传输的基本示例。 进程间内存共享的优点:高性能、低延迟、资源效率高、简单可靠。 适用场景:实时图像处理、大数据传输、多进程协作、实时监控系统,等等。

qianqiansd 1996

ENVI SARscape安装全攻略:从下载到汉化一步到位(附最新试用申请链接)

本文提供ENVI SARscape从下载安装到汉化的完整指南,特别针对InSAR(合成孔径雷达干涉测量)分析环境搭建。详细介绍了系统要求、分步安装流程、汉化优化方法及硬件加速配置,并分享数据处理验证和常见问题解决方案,帮助用户高效搭建遥感数据分析平台。

rnn9storyteller的博客 1413

Android面试官:看你简历上写熟悉-AIDL,说一说-oneway-吧,阿里巴巴Android面试题答案

Android高级架构师之路很漫长,一起共勉吧!

2401_84149505的博客 1028

Windows11安装Ubuntu 20.04.3 LTS双系统(详细过程)

一、基础环境 听说BIOS模式的传统MBR模式和新式UEFI模式,会对安装双系统产生影响。Windows11应该都是UEFI吧,可以按win+r输入msinfo32回车确认查看BIOS模式,我的电脑是UEFI+双硬盘 Ubuntu安装准备 1、 官网下载Ubuntu 20.04.3 LTS镜像iso文件:https://ubuntu.com/download/desktop 2、 下载官网推荐的U盘启动制作工具rufus: https://rufus.ie/ 3、制作启动u盘 插入U盘, 运行 rufu

学习随笔 9万+

Android面试官:看你简历上写熟悉-AIDL,说一说-oneway-吧

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人。

2401_85730375的博客 824

Python实战:5分钟搞定抖音无水印视频下载(附完整代码)

本文系统介绍了抖音无水印视频下载的多种技术方案,重点解析了抖音视频的获取逻辑与去水印原理。文章提供了从零代码的浏览器插件到可编程的Python脚本的完整实现路径,并附带了详细的代码示例,帮助用户快速构建自己的抖音视频下载工具箱。

weixin_29089057的博客 848

2021年J题:基于STM32F103的周期信号波形识别与参数测量系统设计(立创EDA+SZPT_ZXL)

本文详细复盘了2021年全国大学生电子设计竞赛J题获奖项目,手把手教你如何基于STM32F103微控制器设计并实现周期信号波形识别与参数测量系统。文章深入剖析了硬件电路设计(包括程控放大、工作点抬升与滞回比较器)与核心软件算法(如动态采样、FFT频谱分析与波形识别逻辑),并分享了DMA传输、FFT库使用等实战要点与避坑指南,为嵌入式信号处理与电赛备赛提供了宝贵经验。

weixin_32673065的博客 230

Android面试官:看你简历上写熟悉-AIDL,说一说-oneway-吧(1),面试官问的那些安卓原理你都懂吗

😨 业余时间经常打游戏、追剧、熬夜,目前月薪 15k:看你简历上写熟悉 AIDL,说一说 oneway 吧😨:用 oneway 修饰的 AIDL 接口方法,是单向调用,不需要等待另一个进程的返回结果,所以方法的返回类型也只允许是 void.:怎么理解 “单向调用” ,有了解过它的实现原理吗?😨:由应用进程到服务进程是通过 binder 驱动进行 IPC 通信的,单向的意思应该是应用进程只向 binder 驱动发送一次数据就结束返回,不再等待回复数据;

2401_84149496的博客 1048

【软件系统架构】系列六:MBSE(基于模型的系统工程)

基于模型的系统工程(MBSE)是一种以模型为核心的系统工程方法论,通过结构化、可视化的模型取代传统文档,实现从需求到验证的全生命周期管理。MBSE采用SysML建模语言,包含需求、功能、架构和验证四大要素,支持自动追踪、仿真分析和代码生成。相比文档式工程,MBSE具有变更影响自动分析、跨团队协作和高可视化等优势,广泛应用于航空航天、汽车电子等领域。典型开发流程包括需求建模、行为建模、架构建模等阶段,配合MagicDraw、Cameo等工具链实现。MBSE正与数字孪生、AI技术融合,推动自动化建模和智能验证的

moton2017的博客 2784

CameraService笔记

CameraDevice主要交互逻辑java层调用c++层:提供接口给上层控制操作CameraDevice,主要接口是CameraDeviceBase;调用过程:APP先调用Client,然后通过CameraDeviceBase调用CameraDevice,最后调到HAL;c++层回调java层:回调ResultMetadata和ImageBuffer给上层,主要接口是FrameProcessor和Stream。

u012123938的专栏 1238

Arcgis中的模型构建器(ModelBuilder)技术之批量图层转KML

这段时间全省各地都在开展耕地流出图斑整改恢复工作,期间或多或少都需要村委会协助摸排举证,除了举证软件外,奥维、外业精灵等软件想必大家接触得也很多。这就经常需要我们转kmz文件给业主或者摸排人员,那么有没有什么方法在arcgis下快速批量转kmz文件呢,今天就介绍一下如何在模型构建器(ModelBuilder)构建批量图层转KML的模型。

weixin_44671081的博客 1325

STM32(HAL库)驱动st7789LCD屏幕(7引脚240*240)

屏幕厂家提供的都是标准库,网上找了找没看到好用的HAL库屏幕驱动,因此本文对HAL库驱动TFT屏幕进行详细讲解。

weixin_44597885的博客 6065

Vector 2.2 热修复详解:libxposed API 102 热重载、每用户模块作用域与构建修复

Vector 2.2 是紧随 2.1 发布的热修复版本,其核心是引入 libxposed API 102——从此模块可以在不拖垮宿主进程的情况下被原地替换(热重载)。本文以 [zygisk/changelog.md](https://link.gitcode.com/i/b1947d6bdb939bddd9abf3a66bb67e3c) 为主线,结合仓库源码逐条拆解 2.2 修复的 2.1 遗留问

gitblog_00725的博客 469

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

android aidl 机制和oneway使用

-----------客户端2日志----------------------------------服务端2日志----------------------------------客户端3日志----------------------------------服务端3日志-----------------------------客户端1日志-----------------------------服务端1日志----------------------

kk3087961的博客 1733

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Android Aidl跨进程通讯(三)--进阶使用

学更好的别人,做更好的自己。——《微卡智享》本文长度为2478字,预计阅读6分钟前言Android的AIDL使用和异常报错都已经介绍过了,今天这篇还是在原来的Demo基础上加入几个AIDL的进阶使用方法。】AIDL进阶使用微卡智享in,out,inout的使用关于in,out,inout在AIDL的基础介绍中有提到过AIDL中还有定向的Tag,包括了in、out、inout。其中 in 表示数据只...

Vaccae的博客 1378

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

AIDL oneway 以及in、out、inout参数的理解

oneway oneway可以用来修饰在interface之前,这样会造成interface内所有的方法都隐式地带上oneway; oneway也可以修饰在interface里的各个方法之前。 被oneway修饰了的方法不可以有返回值,也不可以有带out或inout的参数。 带oneway的实现 带oneway的方法,不会生成局部变量_reply。且Proxy中transact中第四个参数必为an...

anlian523的博客 1万+

oneway

在Android开发中,AIDL(Android Interface Definition Language)是一种用于定义客户端和服务端之间通信接口的语言,特别是当它们运行在不同的进程时。AIDL接口允许你进行跨进程的函数调用(IPC, Inter-Process Communication)。在AIDL中,oneway是一个关键的概念,用于指示服务端的实现不需要等待调用者的确认就可以继续执行后续的操作。换句话说,使用oneway。

weixin_48959446的博客 1248

android aidl oneway 使用举例

ide相关视频讲解:搭建私人助理大模型需要什么环境?Android AIDL Oneway 使用举例 在Android开发中,AIDL(Android Interface Definition Language)是一种用于定义进程间通信(IPC)接口的语言。通过AIDL,我们可以在不同的进程之间进行通信。而Oneway是...

weixin_37065356的博客 382

红茶一杯话Binder(传输机制篇_下)

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33923762的博客 348

Binder 线程池溢出问题

第一行是 proc 2890 表示进程的 pid,第二行表示 binder 类型,接下来就是 buffer,用于表示内核中的 binder_buffer,如果这个 buffer 在程序运行过程中越来越多,那么就有内存泄漏的可能存在,不过这种情况很少,应用程序都是通过 libbinder 这个库来使用 binder 驱动的,在一次 ipc 调用结束后,库本生会执行 binder_buffer 的清理操作,这种系统中的公用库一般都非常稳定,出 bug 的几率很小。一个关于binder的debug技巧。

chuyouyinghe的专栏 1241

Android跨进程通信方式总结

1、AIDL定义 IPC:Inter-Process Communication,即跨进程通信 AIDL:Android Interface Definition Language,即Android接口定义语言,进程间通信的桥梁;用于让某个Service与多个App之间进行跨进程通信,从而可以实现多个App共享同一个Service的功能。 2、Android跨进程通信实现方式 Android跨进程通信实现方式采用远程Service。 3、使用场景 多个应用程序共享同一个后台服务(远...

ming15920的博客 1433
上一篇: Binder通信流程浅析
下一篇: JAVA字节码
Only_Studio
博客等级 码龄11年 115粉丝 18原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值