这篇文章涉及的知识点:
- Binder的应用场景及原理
- AIDL的应用场景及原理
- Messenger的应用场景及原理
- Service
官网:
注:只有允许不同应用的客户端用 IPC 方式访问服务,并且想要在服务中处理多线程时,才有必要使用 AIDL。 如果您不需要执行跨越不同应用的并发 IPC,就应该通过实现一个 Binder创建接口;或者,如果您想执行 IPC,但根本不需要处理多线程,则使用 Messenger 类来实现接口。无论如何,在实现 AIDL 之前,请您务必理解绑定服务。
这段话说了跨进程的三种方式以及每种的使用场景
- 跨应用(此时跨应用就是在不同进程内)并且在服务中处理多线程时使用AIDL
- 同一个应用不同进程存在多线程时使用Binder
- 同一个应用不同进程在不需要处理多线程时使用Messenger
Binder原理
简单的可以理解为Server在ServiceManager中进行注册,Client要调用Server的方法,但是ServerManager不会把真的Server返回给Client,而把Server的一个代理对象Proxy返回给Client。再次Client调用Proxy的add方法ServerManager会帮Client调用Server的add方法并把结果返回给Client。
AIDL的原理
官网:
注:在您开始设计 AIDL 接口之前,要注意 AIDL 接口的调用是直接函数调用。 您不应该假设发生调用的线程。 视调用来自本地进程还是远程进程中的线程,实际情况会有所差异。 具体而言:
注:在您开始设计 AIDL 接口之前,要注意 AIDL 接口的调用是直接函数调用。 您不应该假设发生调用的线程。 视调用来自本地进程还是远程进程中的线程,实际情况会有所差异。 具体而言:
- 来自本地进程的调用在发起调用的同一线程内执行。如果该线程是您的主 UI 线程,则该线程继续在 AIDL 接口中执行。 如果该线程是其他线程,则其便是在服务中执行您的代码的线程。 因此,只有在本地线程访问服务时,您才能完全控制哪些线程在服务中执行(但如果真是这种情况,您根本不应该使用 AIDL,而是应该通过实现 Binder 类创建接口)。
- 来自远程进程的调用分派自平台在您的自有进程内部维护的线程池。 您必须为来自未知线程的多次并发传入调用做好准备。 换言之,AIDL 接口的实现必须是完全线程安全实现。
neway
关键字用于修改远程调用的行为。使用该关键字时,远程调用不会阻塞;它只是发送事务数据并立即返回。接口的实现最终接收此调用时,是以正常远程调用形式将其作为来自Binder
线程池的常规调用进行接收。 如果oneway
用于本地调用,则不会有任何影响,调用仍是同步调用。
用此图说明原理很清晰:
来自Android插件话开发指南
解释图片上跨进程的流程:
1.无论是Client还是Server 里面都有类Stub,Proxy。从Client看,对于AIDL使用者,我们这样写程序:
MyAidl.Stub.asInterface(某IBinder对象).sum(1,2)
asInterface()方法的作用是判断参数也就是IBinder和自己是否是在一个进程中,如果在就直接调用和跨进层没有关系。
如果不是则把这个IBinder参数包装成一个Proxy对象,则调用Stub的sum方法就是间接调用Proxy的sum方法。
2.Proxy在自己的sum方法中,会使用Parcelable来准备数据,把函数名称、函数参数都写入_data,让_reply接受函数返回值。最后使用IBinder的transact方法,就可以把数据传给Binder的Server端了。
3.Server接受Client传输过来的方法名,参数后,根据方法名再找到对应的函数并传入参数得出结果返回给客户端。
Server处理过程:接收数据->调用函数->把数据返回写数据的过程。