Android bindService流程详解
2:37 pm
Tuesday, 14 June 2022 (HKT)
Time in Hong Kong
概述
本文基于Android 10分析总结bindService流程,展示关键流程和关键类。
流程
整体流程分为App侧和SystemServer侧两大块。bindService
与startService
一样,如果service对应的进程还未启动,那么会先启动对应的进程,然后在启动后再查找等待bind的调用。bindService()回调ActivityThread后,会publishService()
发布服务,AMS收到服务发布时会查找等待bind的调用并完成绑定。即服务的启动和绑定是分离的。
App
App提供ServiceConnection
用于监听服务绑定情况,调用ContextImpl
时,会从LoadedApk.getServiceDispatcher()
获取包装了ServiceConnection
和服务绑定相关逻辑的ServiceDispatcher
。ServiceDispatcher
通过Binder调用bindIsolatedService()
发送到AMS进行下一步调用。
其中getServiceDispatcher()
的实现比较简单。在LoadedApk.mServices :Map<Context, Map<ServiceConnection, ServiceDispatcher>>
查找已有的ServiceDispatcher
,没有的话直接创建新的返回并存入LoadedApk.mServices
。
应用层调用bindService()
传入的ServiceConnection
被LoadedApk.mService :Map<Context, Map<ServiceConnection, ServiceDispatcher>>
以及该Map内的ServiceDispatcher
保存了。
向AMS发出Binder调用时,使用的是ServiceDispatcher.InnerConnection
这个对ServiceDispatcher
的包装类。
ServiceDispatcher.InnerConnection
被通过Binder传出,从Binder服务端即AMS侧对它的处理为IServiceConnection
,该接口仅有一个方法connected()
。
SystemServer
整体流程
ActiveServices
负责完成服务启动、Service的onBind
、onRebind
(回调到ActivityThread根据rebind参数触发)、Client的ServiceConnection.onServiceConnected()
、ServiceConnection.onServiceDisconnected()
的回调。其中,服务未启动时,首先启动服务,然后提前返回。在服务启动后由ActivityManagerService检查等待的bind请求,此时再执行bind流程。服务已启动的情况下,如果该client已经调用过bindService绑定该服务了,则回调client的ServiceConnection.onServiceConnected()
,而不再回调Service的onBind()
。如果client是首次绑定该Service,那么通过requestServiceBindingLocked()
完成绑定和回调。
Client此前已经对该Service调用过bind了
这种情况下,不会再回调Service.onBind()
,而是直接通过IServiceConnection.connected()
返回IBinder给Client,回调Client的ServiceConnection.onServiceConnected()
。
这种情况下可能调用Rebind,流程与《Client此前没有bind该Service》接近。
Client此前没有bind该Service
调用requestServiceBindingLocked()
将Client与Service绑定。回调到ActivityThread在App主线程完成Service.onBind()后,通过publishService()
再回调到ActiveService
,找到待绑定的ConnectionRecord
,回调它保存的IServiceConnection.connected()
,将Service的IBinder传递回到client,完成绑定。其中,IServiceConnection.connected()
还有一点流程执行,最终回调到binderSerice使用的ServiceConnection.onServiceConnected()
。
服务所在的进程没有启动,先启动进程
与startService()
流程一致。如果进程没有启动,则会先启动进程。
App侧的回调流程:IServiceConnection.connected()到ServiceConnection.onServiceConnected()
Client发起AMS.bindIsolatedService()
时传递的其实并不是应用层bindService()
使用的ServiceConnection
,而是经过层层包装后的InnerConnection
和ServiceDispatcher
,以及真正和AMS的Binder通信接口IServiceConnection
。当Service.onBind()
完成后,回调到ActiveService
,它调用IServiceConnection.connected()
回调到Client。