Service的启动概述
本章我们来分析Service的启动过程。
Service生命周期
先来看下Service的生命周期:
startService和bindService启动的服务生命周期略有不同。
Service启动方式
我们启动一个Serivce服务的时候,可以通过3种方式来启动:
- startService()方法,启动一个Service。
- bindService()方法,使用bind的方式启动一个Service。
- startForegroundService()方法,启动一个前台服务。
这几种启动方式,定义在Activity的父类型ContextWrapper类中,它们都通过调用mBase来执行具体实现,这里的mBase,就是一个ContextImpl实例对象。
startService启动——Client进程端
ContextImpl的相关实现
service启动的几个方法:
/frameworks/base/core/java/android/app/ContextImpl.java
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
@Override
public ComponentName startForegroundService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, true, mUser);
}
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), getUser());
}
逻辑解析:
- startService和startForegroundService都调用了startServiceCommon方法,只是第二个参数不同(前台服务是true)。
- bindService实现稍有不同,这里调用了bindServiceCommon方法。
我们重点来分析startService的后续流程。
来看startServiceCommon方法:
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service
+ " without permission " + cn.getClassName());
} else if (cn.getPackageName().equals("!!")) {
throw new SecurityException(
"Unable to start service " + service
+ ": " + cn.getClassName());
} else if (cn.getPackageName().equals("?")) {
throw new IllegalStateException(
"Not allowed to start service " + service + ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
逻辑解析:
- 验证Intent相关设置,如果Service是隐式启动,则在Android L之上会抛出错误,在小于该版本输出提示日志但不报错。
- 判断是否将要离开当前进程,并且设置Intent相关属性。
- 调用AMS的startService方法来启动Service,在此之后,代码的执行由Client端切换到了系统服务AMS进程。
startService启动——Server进程端
AMS的startService方法
AMS的startService方法:
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService"); //判断是否是隔离的程序,如果是,则不允许执行,抛出错误
……
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
逻辑解析:
- 执行一些简单的验证工作,例如判断是否是隔离程序,调用者的包名是否为null等。
- 调用mServices.startServiceLocked执行启动过程。这里的mServices是ActiveServices的一个实例,用来管理Serivice的。
ActiveServices的startServiceLocked方法
ActiveServices的startServiceLocked方法:
/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage,
final int userId, boolean allowBackgroundActivityStarts)
throws TransactionTooLargeException {
……
//判断当前调用进程是否属于前台进程组(进程组优先级!= ProcessList.SCHED_GROUP_BACKGROUND)
final boolean callerFg;
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + callingPid
+ ") when starting service " + service);
}
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
//调用retrieveServiceLocked方法来获取一个ServiceLookupResult对象。
ServiceLookupResult res =
retrieveServiceLocked(service, null, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false, false);
……
ServiceRecord r = res.record; //从ServiceLookupResult对象中,取出ServiceRecord对象,以进行后续操作。
……
//处理、校验启动权限等相关的逻辑,并且判断将要启动的服务是否是前台服务等。
……
// At this point we've applied allowed-to-start policy based on whether this was
// an ordinary startService() or a startForegroundService(). Now, only require that
// the app follow through on the startForegroundService() -> startForeground()
// contract if it actually targets O+.
if (r.appInfo.targetSdkVersion < Build.VERSION_CODES.O && fgRequired) {
if (DEBUG_BACKGROUND_CHECK || DEBUG_FOREGROUND_SERVICE) {
Slog.i(TAG, "startForegroundService() but host targets "
+ r.appInfo.targetSdkVersion + " - not requiring startForeground()");
}
fgRequired = false; //fgRequired表示是否需要执行startForeground来启动Service。
}
//对是否需要启动前弹框进行判断
NeededUriGrants neededGrants = mAm.mUgmInternal.checkGrantUriPermissionFromIntent(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);
……
……
if (fgRequired) { //启动前台服务
// We are now effectively running a foreground service.
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setForeground(true, mAm.mProcessStats.getMemFactorLocked(),
r.lastActivity);
}
mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, true);
}
……
if (allowBackgroundActivityStarts) { //如果允许从后台Activity启动
r.whitelistBgActivityStartsOnServiceStart();
}
//执行常规的启动流程
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
逻辑解析:
- 判断当前调用者是否属于前台进程组(进程组优先级!= ProcessList.SCHED_GROUP_BACKGROUND)。
- 调用retrieveServiceLocked方法来获取一个ServiceLookupResult对象。retrieveServiceLocked首先从缓存列表中查找是否已经存在该Service记录,如果不存在,则从包资源里解析获取,最终生成一个含有Service信息的ServiceLookupResult对象。
- 从ServiceLookupResult对象中,取出ServiceRecord对象,以进行后续操作。
- 处理、校验启动权限等相关的逻辑,并且判断将要启动的服务是否是前台服务等。
- fgRequired表示是否需要执行startForeground来启动Service。
- 对是否需要启动前弹框进行判断。
- 如果是前台服务,则执行启动前台服务。
- 调用startServiceInnerLocked执行常规的启动流程。
ActiveServices的startServiceInnerLocked方法
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);//更新ServiceRecord的ServiceState
}
r.callStart = false;
StatsLog.write(StatsLog.SERVICE_STATE_CHANGED, r.appInfo.uid, r.name.getPackageName(),
r.name.getClassName(), StatsLog.SERVICE_STATE_CHANGED__STATE__START);
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();//用于耗电统计,开启运行的状态
}
//service启动的核心方法
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
if (error != null) {
return new ComponentName("!!", error);
}
if (r.startRequested && addToStarting) {
boolean first = smap.mStartingBackground.size() == 0;//是否是当前用户进程的第一个服务
smap.mStartingBackground.add(r);
r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT;
if (DEBUG_DELAYED_SERVICE) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r, here);
} else if (DEBUG_DELAYED_STARTS) {
Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r);
}
if (first) {
smap.rescheduleDelayedStartsLocked();//执行延迟启动
}
} else if (callerFg || r.fgRequired) {
smap.ensureNotStartingBackgroundLocked(r);//清楚map数据
}
return r.name;
}
逻辑解析:
- 调用service的bringUpServiceLocked方法来启动Service。
- 当启动完成的时候设置启动超时时间。
- 启动成功之后将ServiceRecord加入到smap中的mStartingBackground中。
- 如果是第一次启动则处理延迟启动相关逻辑。
ActiveServices的bringUpServiceLocked方法
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
if (r.app != null && r.app.thread != null) {//处理Service已经启动的情况,此时只是发送新的StartItem
sendServiceArgsLocked(r, execInFg, false);
return null;
}
if (!whileRestarting && mRestartingServices.contains(r)) { //如果Service因为crash被系统重启,则return
// If waiting for a restart, then do nothing.
return null;
}
……
//正在启动服务,因此不再处于重新启动状态,把service从重启服务队列中移除。
if (mRestartingServices.remove(r)) {
clearRestartingIfNeededLocked(r);
}
//确保此服务不再被视为延迟,设置r.delayed为false。
if (r.delayed) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r);
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
// 确保拥有该服务的user已经启动,如果未启动,则终止操作,并执行清理工作。
if (!mAm.mUserController.hasStartedUserState(r.userId)) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": user " + r.userId + " is stopped";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
// 服务正在启动,设置package停止状态为false
try {
AppGlobals.getPackageManager().setPackageStoppedState(
r.packageName, false, r.userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ r.packageName + ": " + e);
}
//判断当前服务是否需要在隔离进程中启动。(如果在Manifest中设置了隔离进程的标志位则该值等于标志位的值)
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
ProcessRecord app;
if (!isolated) { //常规进程中启动
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg); //真正启动Service的地方
return null;
}
……
}
} else {
……
}
//处理进程没有启动的情况
if (app == null && !permissionsReviewRequired) {
//启动service所要运行的进程
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingRecord, false, isolated, false)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r);// 进程启动失败
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
……
if (!mPendingServices.contains(r)) {//mPendingServices保存待启动服务,当进程启动后,会重新启动该服务
mPendingServices.add(r);
}
if (r.delayedStop) {//服务还未完成启动,就收到结束请求时,会直接停止该服务
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Applying delayed stop (in bring up): " + r);
stopServiceLocked(r);//停止服务
}
}
return null;
}
逻辑解析:
- 处理Service已经启动的情况,此时只是发送新的StartItem,调用service.onStartCommand()过程。
- 如果Service因为crash被系统重启,则return。
- 正在启动服务,因此不再处于重新启动状态,把service从重启服务队列中移除。
- 确保此服务不再被视为延迟,设置r.delayed为false。
- 确保拥有该服务的user已经启动,如果未启动,则终止操作,并执行清理工作。
- 服务正在启动,设置package停止状态为false。
- 判断当前服务是否需要在隔离进程中启动。(如果在Manifest中设置了隔离进程的标志位则该值等于标志位的值)
- 如果不是在隔离进程中启动,则调用realStartServiceLocked(r, app, execInFg); 真正启动Service。
- 如果进程没有启动,启动service所要运行的进程。
- mPendingServices保存待启动服务,当进程启动后,会重新启动该服务。
ActiveServices的realStartServiceLocked方法
即将在Client中创建并启动Service实例对象,从bindService()启动的Service也会调用这个方法。
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
……
这里主要更新进程和ServiceRecord的一些信息
bumpServiceExecutingLocked(r, execInFg, "create");//将service和进程关联起来(更新ServiceRecord中的信息)
//更新进程对应的优先级
mAm.updateLruProcessLocked(app, false, null);
updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
boolean created = false;
try {
……
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);//强制更改进程的状态为ActivityManager.PROCESS_STATE_SERVICE
//调用Client端ApplicationThread对象的实例方法scheduleCreateService来创建Service。
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
r.postNotification();
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app);
throw e;
} finally {
if (!created) {
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying); //执行清理工作
// Cleanup.
if (newService) {
app.services.remove(r);
r.setProcess(null);
}
// Retry.
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);//尝试重新启动服务
}
}
}
if (r.whitelistManager) {
app.whitelistManager = true;
}
//如果调用过bindService,则会调用requestServiceBindingsLocked()执行onBind方法。
requestServiceBindingsLocked(r, execInFg);
//如果客户端Bind Service成功,按需更新服务端进程优先级
updateServiceClientActivitiesLocked(app, null, true);
if (newService && created) {
app.addBoundClientUidsOfNewService(r);
}
//如果service已经启动,并且符合条件,则方法onStartCommand() 将被调用
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null, 0));
}
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {//如果service是延时启动的则将其从mDelayedStartList中移除
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (r.delayedStop) { //如果service被主动要求停止那么调用
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Applying delayed stop (from start): " + r);
stopServiceLocked(r);
}
}
}
逻辑解析:
- 更新进程和ServiceRecord的一些信息,并将service和进程关联起来(更新ServiceRecord中的信息)。
- 更新进程对应的优先级。
- 强制更改进程的状态为ActivityManager.PROCESS_STATE_SERVICE。
- 调用Client端ApplicationThread对象的实例方法scheduleCreateService来创建Service。
- 如果服务创建失败,则执行清理工作,并且尝试重新启动服务。
- 如果调用过bindService,则会调用requestServiceBindingsLocked()执行onBind方法,成功后,更新进程优先级。
- 如果service已经启动,并且符合条件,则方法onStartCommand() 将被调用。
- 如果service是延时启动的则将其从mDelayedStartList中移除。
- 如果service被主动要求停止那么调用。
startService启动——回到Client端
在ActiveServices的realStartServiceLocked方法中,调用了Client端ApplicationThread对象的实例方法scheduleCreateService来创建Service。
ApplicationThread对象的scheduleCreateService方法:
android.app.ActivityThread.java
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
这里发生给Handler一个CREATE_SERVICE的消息,我们直接来看该消息的处理方法。
private void handleCreateService(CreateServiceData data) {
//对将要进行GC进行处理。
unscheduleGcIdler();
//获得这个进程对应的LoadedApk对象
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
//通过反射调用,创建一个Serice对象
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
} catch (Exception e) {
……
}
try {
……
//创建Service的ContextImpl对象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
//获取进程对应的Application对象。
Application app = packageInfo.makeApplication(false, mInstrumentation);
//调用service对象的attach方法进行初始化设置
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
//调用Service的onCreate方法。
service.onCreate();
mServices.put(data.token, service);//添加服务到mServices中
try {
//通知AMS service启动成功,进行取消超时消息等操作
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
逻辑解析:
- 对将要进行GC进行处理,跳过。
- 获得这个进程对应的LoadedApk对象。
- 通过反射调用,创建一个Serice对象。
- 创建Service的ContextImpl对象。
- 获取进程对应的Application对象。
- 调用service对象的attach方法进行初始化设置。
- 调用Service的onCreate方法。
- 添加服务到mServices中。
- 通知AMS service启动成功,进行取消超时消息等操作。
到了这里,Service已经完成了启动过程。
Service的onStartCommand调用过程
那么Service的onStartCommand又是怎么样的调用流程呢?
它的起点是ActiveServices的sendServiceArgsLocked方法:
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
……
try {
r.app.thread.scheduleServiceArgs(r, slice);
}
……
}
这里调用了ApplicationThread对象的scheduleServiceArgs方法,该方法又给ActivityThread对象的Handler对象发送了H.SERVICE_ARGS消息,最终调用handleServiceArgs方法来处理该消息。
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
data.args.prepareToEnterProcess();
}
int res;
if (!data.taskRemoved) {
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}
……
}
}
这里调用了Servcie对象的onStartCommand方法。
到了这里,Service的启动逻辑相关的重要过程也就分析完了。
总结
通过本文分析,我们对startSerivce的启动流程已经了解了,这里来做一个简单的总结:
- 可以通过3种方式来启动一个Serivce服务:startService()方法,启动一个Service;bindService()方法,使用bind的方式启动一个Service;startForegroundService()方法,启动一个前台服务。
- 上述3种启动方法的是在ContextImpl中实现的。
- startService启动在Client进程端发起,并且进行Intent相关设置,以及一些校验工作。
- 然后进入到Server端(AMS所在进程),AMS使用ActiveServices类来对服务进行管理,系统服务端的主要处理工作都是在ActiveServices中进行的,最终调用到ActiveServices的realStartServiceLocked方法。
- ActiveServices的realStartServiceLocked方法调用了Client端ApplicationThread对象的实例方法scheduleCreateService来创建Service(回到Client端来进行Service的创建,这里的Client是Service的所在进程,不一定是启动时发起请求的Client进程了,这里需要注意)。
- ActiveServices的sendServiceArgsLocked方法最终调用了Service的onStartCommand方法。