迷茫,是青春最真实的状态;但奋斗,才是青春的主基调;努力是打败焦虑的绝好方法!
引言
Service的两种工作状态:
- 启动状态——用于执行后台计算
- 绑定状态——用于其他组件和Service的交互
注意:这两种状态可以共存,即Service可以处于启动状态并且同时处于绑定状态。
- 通过Context的startService方法启动Service
Intent intentService = new Intent(this,MyService.class);
startService(intentService);
- 通过Context的bindService方法绑定Service
Intent intentService = new Intent(this,MyService.class);
bindService(intentService,mServiceConnection,BIND_AUTO_CREATE);
启动过程
Service的启动方法调用过程
- ContextWrapper.startService
- ContextImpl.startService
- startServiceCommon
- ActivityManagerNative.getDefault().startService
- AMS.startService
- ActiveServices.startServiceLocked
- startServiceInnerLocked
- bringUpServiceLocked
- realStartServiceLocked
- app.thread.scheduleCreateService
- ActivityThread.handleCreateService
ContextWrapper.startService -> ContextImpl.startService
从ContextWrapper的实现可以看出,大部分操作都是通过mBase(类型ContextImpl)来实现的。这是一种典型的桥接模式。
ContextImpl.startService -> startServiceCommon
public ComponentName startService(Intent service){
warnIfCallingFromSystemProcess();
return startServiceCommon(service,mUser);
}
startServiceCommon -> ActivityManagerNative.getDefault().startService
private ComponentName startServiceCommon(Intent service,UserHandle user){
try{
...
ComponentName cn = ActivityManagerNative.getDefault().startService(...);
...
return cn;
}catch(RemoteException e){
return null;
}
}
ActivityManagerNative.getDefault().startService -> AMS.startService
在Android四大组件之Activity中提过,AMS继承ActivityManagerNative,是它的子类,设计模式中的里氏代换原则说明可以用子类代替父类。
详细见这4到5:Android四大组件之Activity
注:通过AMS来启动服务的行为是一个远程过程调用。
AMS.startService -> ActiveServices.startServiceLocked
public ComponentName startService(...){
...
synchronized(this){
...
ComponentName res = mServices.startServiceLocked(...);
...
return res;
}
}
AMS通过mServices这个对象完成后续的Service启动过程,mServices对象类型是ActiveServices。
ActiveServices.startServiceLocked -> startServiceInnerLocked
ActiveServices是一个辅助AMS进行Service管理的类,包括Service的启动、绑定和停止等。ActiveServices的startServiceLocked 方法的尾部会调用startServiceInnerLocked方法。
startServiceInnerLocked -> bringUpServiceLocked
ComponentName startServiceInnerLocked(ServiceMap smap,Intent service,
ServiceRecord r,boolean callerFg,boolean addToStarting){
...
String error = bringUpServiceLocked(r,service.getFlags(),callerFg,false);
...
return r.name;
}
ServiceRecord描述的是一个Service记录,ServiceRecord一直贯穿着整个Service的启动过程。startServiceInnerLocked 并没有完成具体的启动工作,而是把后续的工作交给了bringUpServiceLocked方法来处理。
bringUpServiceLocked -> realStartServiceLocked
在bringUpServiceLocked中调用了realStartServiceLocked方法。
realStartServiceLocked -> app.thread.scheduleCreateService
app.thread.scheduleCreateService -> ActivityThread.handleCreateService
上述过程已经调用到ApplicationThread的scheduleCreateService方法了。
这个过程和ACtivity的启动是类似的。
- 发送一个启动Service的消息给Handler处理
CreateServiceData s = new CreateServiceData (); sendMessage(H.CREATE_SERVICE,s);
- H会接收这个CREATE_SERVICE消息并通过ActivityThread的handleCreateService方法来完成Service的最终启动。
handleCreateService主要完成了如下几件事:
- 通过类加载器创建Service的实例。
- 创建Application对象并调用其onCreate,当然Application的创建过程只会有一次。
- 创建ContextImpl对象并通过Service的attch方法建立二者之间的关系,这个过程和Activity实际上是类似的,毕竟Service和Activity都是一个Context。
- 调用Service的onCreate方法并将Service对象存储到ActivityThread中的一个列表中。列表定义如下:
final ArrayMap<IBinder,Service> mServices = new ArrayMap<IBinder,Service>()
- Service的onCreate方法被执行了,就意味着Service已经启动了。
绑定过程
Service的绑定方法调用过程
- ContextWrapper.bindService
- ContextImpl.bindService
- ContextImpl.bindServiceCommon
- AMS.bindService
- bindServiceLocked
- bringUpServiceLocked
- realStartServiceLocked
- ApplicationThread.scheduleBindService
- ActivityThread.handleBindService
ContextWrapper.bindService -> ContextImpl.bindService
Service的绑定和Service的启动类似,都要从ContextWrapper开始,ContextWrapper的实现是ContextImpl。
ContextImpl.bindService -> ContextImpl.bindServiceCommon
bindService 最终调用自己的bindServiceCommon方法。
ContextImpl.bindServiceCommon -> AMS.bindService
看图可见,bindServiceCommon调用了ActivityManagerNative.getDefault().bindService。前面已经说过,AMS extends ActivityManagerNative,所以就是调用了AMS的bindService方法。
bindServiceCommon方法完成的事情
- 将客户端的ServiceConnection对象转换为ServiceDispatcher.InnerConnection对象。由LoadedApk的getServiceDispatcher方法完成。
不能直接使用ServiceConnection对象,是因为服务的绑定可能是跨进程的,所以需要借助Binder才可以让远程服务端回调自己的方法,而ServiceDispatcher的内部类InnerConnection刚好充当了Binder这个角色。
ServiceDispatcher的作用:连接ServiceConnection和InnerConnection。
总之,就是将ServiceConnection转换为InnerConnection,使其可以跨进程;然后通过ServiceDispatcher将它们连接起来。
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context,Handler handler,int flags){
synchronized(mServices){
//连接ServiceConnection和InnerConnection的工具类
LoadedApk.ServiceDispatcher sd = null;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map =
mServices.get(context);
if(map != null){
//查找是否存在相同的ServiceConnection
sd = map.get(c);
}
//不存在
if(sd == null){
//新建一个工具类
sd = new ServiceDispatcher(c,context,handler,flags);
if(map == null){
//新建一个关系
map = new ArrayMap<ServiceConnection,LoadedApk
.ServiceDispatcher>();
//存储到mServices中
mServices.put(context,map);
}
//在关系表中加入这个ServiceConnection和ServiceDispatcher的映射关系
map.put(c,sd);
}else{
//存在
sd.validate(context,handler);
}
//返回其保存的ServiceDispatcher
//里面保存了ServiceConnection对象和InnerConnection对象
return sd.getIServiceConnection();
}
}
当Service和客户端建立连接后,系统会通过InnerConnection来调用ServiceConnection中的onServiceConnected方法,这个过程可能是跨进程的。
当ServiceDispatcher创建好了以后,getServiceDispatcher会返回其保存的InnerConnection对象。
- 通过AMS来完成具体绑定过程
AMS.bindService -> bindServiceLocked
public int bindService(...){
...
synchronized(this){
return mServices.bindServiceLocked(...);
}
}
bindServiceLocked -> bringUpServiceLocked
bindServiceLocked中调用bringUpServiceLocked方法
bringUpServiceLocked -> realStartServiceLocked
bringUpServiceLocked中调用realStartServiceLocked方法
realStartServiceLocked -> ApplicationThread.scheduleBindService
realStartServiceLocked的执行逻辑和Service启动中的类似,都是通过ApplicationThread来完成Service的实例的创建并执行onCreate方法。
不同的是:Service的绑定中的ApplicationThread的scheduleBindService方法在ActiveServices的requestServiceBindingLocked中;而启动的ApplicationThread的scheduleCreateService方法就在realStartServiceLocked中。
ApplicationThread.scheduleBindService -> ActivityThread.handleBindService
这个阶段已经说了很多了,scheduleBindService方法中发送一个绑定Service的信号给Handler,Handler处理消息,然后调用handleBindService方法,进行Service的提取和绑定。
handleBindService源码
handleBindService所做的事
- 根据Service的token取出Service对象。
- 调用Service的onBind方法,返回一个Binder供客户端使用。
- onBind方法调用以后,Service就算绑定了。
- 通知客户端Service已连接,所以必须调用ServiceConnection中的onServiceConnected,这个过程由AMS的publishService方法来完成。
当多次绑定同一个Service时,onBind只会调用一次,除非Servie被终止了。
告知客户端Service已连接的方法调用过程:
- AMS.publishService
- ActiveServices.publishServiceLocked
- InnerConnection.connected
- ServiceDispatcher.connected
- H.post(new RunConnection(name,service,0))
- ServiceDispatcher.doConnected
由于ServiceDispatcher内部保存了客户端的ServiceConnection对象,所以可以很方便的调用ServiceConnection的onServiceConnected方法。然后客户端收到消息,了解服务已连接。