AMS - Service - startService流程
[文章基于android P]
先上时序图:
1 ContextImpl
frameworks/base/core/java/android/app/ContextImpl.java
1.1 startService()
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
我们在Activity中调用startService其实是调用ContextImpl的startService方法,因为ContextImpl和Activity都是Context的子类。接下来直接调用当前类的startServiceCommon方法。
1.2 startServiceCommon()
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
//调用AMS的startService方法
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();
}
}
这个方法主要是binder调用AMS的startService方法,然后根据返回结果,这里有三个throw exception,这也是我们平时开发APP Service时候经常遇到的报错。这里会根据返回packageName是“!”、“!!”、“?”来抛出不同的异常,那什么情况下才会抛这些异常呢?我们继续往下看。
2 ActivityManagerService
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
2.1 startService()
@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;
}
}
这个方法主要获取当前启动要service的pid和uid,然后调用ActiveServices的startServiceLocked去做一些启动service的准备工作。
3 ActiveServices
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
3.1 startServiceLocked()
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
final boolean callerFg;
if (caller != null) {
//【3.1.1】 getRecordForAppLocked获取client端caller进程record,就是调用startService的app进程,如果对端进程已经被kill则直接抛出异常。
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;
}
//【3.1.2】 retrieveServiceLocked
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false, false);
if (res == null) {
return null;
}
//"!"这里return packageName=! ①
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
ServiceRecord r = res.record;
if (!mAm.mUserController.exists(r.userId)) {
Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
return null;
}
final boolean bgLaunch = !mAm.isUidActiveLocked(r.appInfo.uid);
boolean forcedStandby = false;
if (bgLaunch && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
forcedStandby = true;
}
boolean forceSilentAbort = false;
//fgRequired,startService时候这个值为false,如果是startForegroundService时候为true
if (fgRequired) {
final int mode = mAm.mAppOpsService.checkOperation(
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
switch (mode) {
case AppOpsManager.MODE_ALLOWED:
case AppOpsManager.MODE_DEFAULT:
// All okay.
break;
case AppOpsManager.MODE_IGNORED:
Slog.w(TAG, "startForegroundService not allowed due to app op: service "
+ service + " to " + r.name.flattenToShortString()
+ " from pid=" + callingPid + " uid=" + callingUid
+ " pkg=" &#