Service在开发中使用得或许没有activity那么频繁,但它是Android四大组件之一,在Android中也是十分重要的,前面分析了activity的启动流程,这里也来分析一下Service是如何启动的。
Service分为两种工作状态,一种是启动状态,主要用于执行后台计算;另外一种是绑定状态,主要用于其他组件与Service的交互。需要注意的是,Service的两种状态是可以共存的,即Service既可以处于启动状态也可以同时处于绑定状态。通过Context的startService即可启动Service。
Intent intent = new Intent(this, MyService.class);
startService(intent);
通过Context的bindService方法即可以绑定的方式启动一个Service。
Intent intent = new Intent(this, MyService.class);
bindService(intent,mServiceConnection,BIND_AUTO_CREATE);
1、Service的启动过程
startService方法存在于ContextWrapper
中,具体实现如下
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
这里调用了mBase的startService方法,那mBase是什么尼?其实mBase的类型是ContextImpl,在activity的attach方法中会将一个ContextImpl对象传给mBase。那就来ContextImpl中看startService的实现。
public ComponentName startService(Intent service) {
...
return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
...
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
...
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
startService中调用了startServiceCommon这个方法,在startServiceCommon里则通过Binder机制调用AMS中的startService方法。
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException {
...
//分段锁
synchronized(this) {
...
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, userId);
} finally {
...
}
return res;
}
}
startService这个方法很简单,直接调用了ActiveServices
的startServiceLocked方法。
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
...
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
...
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
...
return r.name;
}
startServiceLocked最后会调用startServiceInnerLocked这个方法,这个也比较简单,直接调用了bringUpServiceLocked,这个方法就比较重要了,Service的创建就在这里面实现的。
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
...
//如果该Service已经启动则直接调用Service的onStartCommand方法
if (r.app != null && r.app.thread != null) {
//这个很重要,具体就是调用Service的onStartCommand方法
sendServiceArgsLocked(r, execInFg, false);
return null;
}
...
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
...
if (app != null && app.thread != null) {
try {
...
//创建Service
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
...
} catch (RemoteException e) {
...
}
}
} else {
...
}
//如果需要开启进程,就先开启进程
if (app == null && !permissionsReviewRequired) {
//开启新的进程
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingType, r.name, false, isolated, false)) == null) {
....
//进程创建失败做的清除操作,如解绑Service、停止Service
bringDownServiceLocked(r);
return msg;
}
...
}
...
return null;
}
bringUpServiceLocked中有四个方法非常重要,理解了这四个方法的实现就基本上理解了Service的启动流程。
- sendServiceArgsLocked:会调用Service的onStartCommand方法,当Service已经存在时则直接调用onStartCommand,不再重新创建Service
- realStartServiceLocked:创建一个Service
- startProcessLocked:开启一个新的进程。
- bringDownServiceLocked:主要是做解绑Service、停止Service的操作
先来看sendServiceArgsLocked的实现。
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
//当bindService时,N==0,所以bindService就不会调用onStartCommand
直接采用绑定方式创建服务时这个是没有的,start流程中才有添加过程
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
...
try {
r.app.thread.scheduleServiceArgs(r, slice);
} catch (TransactionTooLargeException e) {
...
} catch (RemoteException e) {
...
} catch (Exception e) {
...
}
...
}
该方法还是比较简单的,直接调用了ApplicationThread的scheduleServiceArgs方法,然后通过系统Handler来调用ActivityThread的handleServiceArgs方法。
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
...
int res;
if (!data.taskRemoved) {