Android AIDL理解

  • 业务逻辑语境中,实现Service onBInd的那个app进程是服务端。技术上,A进程调用B进程的方法,B就是服务端;B调用A传递过来的callback方法,A就是服务端。

  • aidl接口参数的in out修饰符看的是技术上的服务端,数据流进就是in,数据流出就是out。实际上有更简单明确的理解,对于aidl接口的调用方,看到in参数就想:我把参数in进去就不用管了,对于out参数就想:我对这个参数我待会还得out出来用,有out参数的方法是同步阻塞的。inout具备双重特性

  • 服务端拿到in参数的副本进行访问和修改,不会影响到客户端的实参。客户端调用方法时传入out参数,是不是实例对象无所谓,声明变量名 user = null,调用xxx(user),由于是out参数没有被binder驱动序列化到服务端,服务端拿不到也不关心user里在客户端那边的实例细节(服务端拿到的参数是binder驱动给的初始值没有意义),服务端创建一个user对象,处理好数据,赋值给user变量名,客户端那边的user变量就引用服务端实际处理的user对象的副本。客户端调用xxx(user),得等服务端xxx方法执行完处理完user数据,out参数aidl方法是一个同步阻塞的方法,不能用oneway修饰

  • aidl接口原生支持参数类型是基本数据类型和String类型,默认都是in。自定义参数类型分为两种一种是bean,得声明android.os.Parcelable接口,支持binder机制序列化/反序列化,一种是回调对象/监听器,也得声明为aidl interface,自定义参数类型最好显示声明in out

  • oneway修饰的方法,是异步的,不能有返回值,只能有in参数,调用处不用等待服务端方法实现处的执行结束。不加oneway默认是同步阻塞的,就像普通的方法调用一样,无论有无返回值,调用处都得等这个远程方法执行完,服务端方法执行完,才走调用处后续代码。

  • aidl接口实现跨进程通信是靠Android的binder机制,跨进程调用时要经过内核的binder驱动。服务端进程在内核binder驱动中映射一块缓存(binder内存映射技术),服务端可以访问。客户端通过binder驱动copy一次数据到缓存区,服务端就可以访问。

  • 如果aidl接口的调用方和实现方在一个进程内,就不用走内核的binder驱动。

  • binder机制是Android系统中跨进程通信的核心,Broadcast、ContentProvider等都是依赖binder机制。aidl接口也是。

  • 服务端定义aidl接口文件,Do.aidl,会被编译为一个java类,里面有接口存根Stub,里面定义abc三个方法,由上到下顺序,在Service onBind中实现Do.stub中的abc方法并返回binder对象。

  • 客户端bindService异步请求绑定服务端service,连接回调走的是ServiceConnection中的方法。在什么线程调用bindService,客户端收到的连接回调就走在什么线程。

  • bindService时如果service端没有起来,会被拉起。建立连接后,系统会维护这个binder连接,如果服务端crash挂掉,系统会拉起服务端,保证连接的健壮性(一个项目的实践经验,有待确认)

  • 客户端通过ServiceConnection的onServiceConnected方法拿到客户端binder对象的引用,通过Do.Stub.asInterface(binder)转化为程序里面可调abc方法的binder代理对象。

  • 服务端和客户端都得有Do.aidl文件,双方都才能访问abc方法。互相复制一份相同的aidl文件,或者一方打包sdk给另一方集成

  • 注意aidl的版本管理:aidl文件要具有"包名.类名"唯一性,Binder驱动会对双方的aidl文件里面定义的方法abc,按照顺序进行编号,编号->映射服务端对方法的实现。客户端调用方法时,传递方法编号,附带数值/可序列化的数据包作为参数,到Binder驱动中,binder驱动进行编号方法名映射,序列化/反序列化处理。

  • 双方的aidl文件是相同的,都是包名.类名、方法定义、顺序都是一样的,举例编号1->a,2->b,3->c。最好双方aidl定义都一样,保持版本同步。如果服务端的aidl定义供很多客户端使用,下次改版时如果只是针对某个app aClient,不想大面积修改发版,增加一个方法d,得追加到最后,aidl文件同步给这个aClient,这个aClient和服务端都有编号1->a,2->b,3->c,4->d,其他客户端使用老版本aidl接口仍然是1->a,2->b,3->c,都可以编号方法映射正确。

  • 如果双发都是1->a,2->b,3->c,现在服务端要改b为e,那么服务端1->a,2->e,3->c,客户端没改aidl定义,那么客户端仍然是1->a,2->b,3->c。那么客户端调用b时,告知binder驱动编号2,而在服务端2映射e方法,参数列表也可以能不一致,最终调用错乱,不符合业务逻辑。

  • aidl方法调用按照编号映射方法,而不是方法名匹配。当同一套aidl接口,涉及多端时,一定注意版本控制。注意同步/追加方法,绝对不能单方修改方法顺序

  • Binder驱动为服务端维护一个线程池,方法的调用是在那个线程时客户端的先择,服务端作为方法的实现端,被客户端调用时,方法执行在服务端binder线程中。

相关推荐
维核科技20 小时前
AI Agent从“玩具“进化成“劳动力“:2026年智能体商业化元年
运维·人工智能·服务器维修·gpu维修
谜之锋20 小时前
Linux 源码编译安装 net-snmp-5.9.1 并配置使用 SNMPv3
linux·运维·服务器·snmpv3
RuiZN20 小时前
Muduo---Channel类
运维·服务器·c++
一直在努力学习的菜鸟20 小时前
阿里云2G2核的服务器可以做什么?
linux·运维
可涵不会debug21 小时前
【LangChain系列】 零基础入门实战:从环境搭建到 LCEL 链式完整 Demo 详解
运维·服务器·langchain·vibe coding
我命由我1234521 小时前
Android 在构建过程中,发现有两个依赖库都包含了相同路径的资源文件
android·java·开发语言·java-ee·kotlin·android-studio·android runtime
tedcloud12321 小时前
Orca 部署指南:开源 AI 推理服务的 Linux 部署实践
linux·运维·服务器·人工智能·开源·自动化·excel
Coffeeee21 小时前
谷歌的一个优化建议,让我重新学了一遍Android里面如何正确处理位图
android·google·kotlin
公众号:fuwuqiBMC21 小时前
(转自“服务器BMC”)服务器BMC芯片——AST2800
运维·服务器
冰暮流星21 小时前
mysql之新建表及对表的查询
android·数据库·mysql