源码地址
既然startForegroundService是在Android8.0之后出现的问题, 就以Android8.0源码进行分析, startForegroundService为何有兼容性问题, 以及该如何解决, 采用流水式阅读代码进行分析.
1. startForegroundService
class ContextImpl::
@Override
public ComponentName startForegroundService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, true, mUser);
}
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
startForegroundService()调用到startServiceCommon时, 第二个参数为true, startService时第二个参数传入false.
2. startServiceCommon
class ContextImpl::
private ComponentName startServiceCommon(Intent service, boolean requireForeground, UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
// ActivityManagerService = ActivityManager.getService();
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
//...
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
ActivityManager.getService()返回AMS对象
3. AMS.startService
class ActivityManagerService::
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage, int userId) {
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;
}
}
抓住主线:
requireForeground
4. startServiceLocked
class ActiveServices::
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId) {
final boolean callerFg;
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
ServiceRecord r = res.record;
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
/**
* startForegroundService(): fgRequired = true;
* startService(): fgRequired = false;
*/
r.fgRequired = fgRequired;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants, callingUid));
final ServiceMap smap = getServiceMapLocked(r.userId);
boolean addToStarting = false;
// startForegroundService()的情况下fgRequired = true, 跳过if, addToStarting = false;
if (!callerFg && !fgRequired && r.app == null
&& mAm.mUserController.hasStartedUserState(r.userId)) {
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
//...
addToStarting = true;
} else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
// ...
addToStarting = true;
}
}
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
1、先考虑startForegroundService()的情况下, fgRequired = true, 跳过if语句.
5. startServiceInnerLocked
class ActiveServices::
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);
}
r.callStart = false;
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
}
// 1.启动service
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
if (error != null) {
return new ComponentName("!!", error);
}
// 2.startForegroundService: addToStarting = false;
// 3.startService: addToStarting = true.
if (r.startRequested && addToStarting) {
boolean first = smap.mStartingBackground.size() == 0;
smap.mStartingBackground.add(r);
r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT;
if (first) {
smap.rescheduleDelayedStartsLocked();
}
} else if (callerFg || r.fgRequired) {
// 4.startForegroundService: fgRequired = true;
// 5.startService: fgRequired = false.
smap.ensureNotStartingBackgroundLocked(r);
}
return r.name;
}
6. bringUpServiceLocked
class ActiveServices::
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired) {
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
if (!whileRestarting && mRestartingServices.contains(r)) {
// If waiting for a restart, then do nothing.
return null;
}
if (mRestartingServices.remove(r)) {
clearRestartingIfNeededLocked(r);
}
// Make sure this service is no longer considered delayed, we are starting it now.
if (r.delayed) {
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
// Make sure that the user who owns this service is started. If not,
// we don't want to allow it to run.
if (!mAm.mUserController.hasStartedUserState(r.userId)) {
2093 bringDownServiceLocked(r);
2094 return msg;
2095 }
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
2108 final String procName = r.processName;
2109 String hostingType = "service";
ProcessRecord app;
2111
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
// 启动Service
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
} else {
app = r.isolatedProc;
if (WebViewZygote.isMultiprocessEnabled()
&& r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
hostingType = "webview_service";
}
}
// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
if (app == null && !permissionsReviewRequired) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingType, r.name, false, isolated, false)) == null) {
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
if (r.delayedStop) {
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
stopServiceLocked(r);
}
}
return null;
}
7. realStartServiceLocked
class ActiveServices::
private final void realStartServiceLocked(ServiceRecord r,
2190 ProcessRecord app, boolean execInFg) throws RemoteException {
2197 r.app = app;
2198 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
2199
2200 final boolean newService = app.services.add(r);
2201 bumpServiceExecutingLocked(r, execInFg, "create");
2202 mAm.updateLruProcessLocked(app, false, null);
2203 updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
2204 mAm.updateOomAdjLocked();
2205
2206 boolean created = false;
try {
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
// 1.启动目标Service
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} finally {
}
// 2.发送延迟消息
sendServiceArgsLocked(r, execInFg, true);
}
8. scheduleCreateService
class ActivityThread::
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);
}
9. CREATE_SERVICE
private class H extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case CREATE_SERVICE:
handleCreateService((CreateServiceData)msg.obj);
break;
}
}
}
10. handleCreateService
private void handleCreateService(CreateServiceData data) {
LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
}
try {
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
// 启动Service
service.onCreate();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
11. serviceDoneExecuting
class AMS::
public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
synchronized(this) {
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
}
12. sendServiceArgsLocked发送延迟消息
class ActiveServices::
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
ArrayList<ServiceStartArgs> args = new ArrayList<>();
while (r.pendingStarts.size() > 0) {
// 1.startForegroundService: fgRequired = true;
// 2.startService: fgRequired = false;
if (r.fgRequired && !r.fgWaiting) {
// 3.isForeground当前Service是否为前台, true: 是, false: 否
if (!r.isForeground) {
// 4.如果当前Service不是前台, 则发送延迟消息
scheduleServiceForegroundTransitionTimeoutLocked(r);
} else {
// 5.如果当前Service为前台, 不作处理, 同时将fgRequired置为true, 也就是不需要
r.fgRequired = false;
}
}
}
}
13. scheduleServiceForegroundTransitionTimeoutLocked
class ActiveServices::
void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) {
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG);
msg.obj = r;
r.fgWaiting = true;
// 5秒延迟
mAm.mHandler.sendMessageDelayed(msg, SERVICE_START_FOREGROUND_TIMEOUT);
}
14. SERVICE_FOREGROUND_TIMEOUT_MSG接收延迟消息
class AMS::
case SERVICE_FOREGROUND_TIMEOUT_MSG: {
mServices.serviceForegroundTimeout((ServiceRecord)msg.obj);
} break;
15. serviceForegroundTimeout
class ActiveServices::
void serviceForegroundTimeout(ServiceRecord r) {
ProcessRecord app;
synchronized (mAm) {
if (!r.fgRequired || r.destroying) {
return;
}
app = r.app;
r.fgWaiting = false;
stopServiceLocked(r);
}
if (app != null) {
// 抛出异常
mAm.mAppErrors.appNotResponding(app, null, null, false,
"Context.startForegroundService() did not then call Service.startForeground()");
}
}
通过startForegroundService启动Service之后, 会发送一条延迟5秒的消息, 轮询器收到该消息之后, 抛出异常
如何解决?
在onCreate中执行startForeground方法
16. startForeground
class Service::
public final void startForeground(int id, Notification notification) {
try {
mActivityManager.setServiceForeground(
new ComponentName(this, mClassName), mToken, id,
notification, 0);
} catch (RemoteException ex) {
}
}
16. setServiceForeground
class AMS::
@Override
public void setServiceForeground(ComponentName className, IBinder token,
18218 int id, Notification notification, int flags) {
18219 synchronized(this) {
18220 mServices.setServiceForegroundLocked(className, token, id, notification, flags);
18221 }
18222 }
17. setServiceForegroundLocked
class ActiveServices::
public void setServiceForegroundLocked(ComponentName className, IBinder token,
730 int id, Notification notification, int flags) {
731 final int userId = UserHandle.getCallingUserId();
732 final long origId = Binder.clearCallingIdentity();
try {
// 1.寻找目标Service
ServiceRecord r = findServiceLocked(className, token, userId);
if (r != null) {
// 2.找到目标Service之后, 取消延迟消息的发送
setServiceForegroundInnerLocked(r, id, notification, flags);
}
738 } finally {
739 Binder.restoreCallingIdentity(origId);
740 }
741 }
找到目标Servicezhihou, 取消延迟消息的发送.
18. setServiceForegroundInnerLocked
class ActiveServices::
private void setServiceForegroundInnerLocked(ServiceRecord r, int id, Notification notification, int flags) {
if (id != 0) {
if (notification == null) {
throw new IllegalArgumentException("null notification");
}
// Instant apps need permission to create foreground services.
if (r.appInfo.isInstantApp()) {
final int mode = mAm.mAppOpsService.checkOperation(
1028 AppOpsManager.OP_INSTANT_APP_START_FOREGROUND,
1029 r.appInfo.uid,
1030 r.appInfo.packageName);
1031 switch (mode) {
1032 case AppOpsManager.MODE_ALLOWED:
1033 break;
1034 case AppOpsManager.MODE_IGNORED:
1035 Slog.w(TAG, "Instant app " + r.appInfo.packageName
1036 + " does not have permission to create foreground services"
1037 + ", ignoring.");
1038 return;
1039 case AppOpsManager.MODE_ERRORED:
1040 throw new SecurityException("Instant app " + r.appInfo.packageName
1041 + " does not have permission to create foreground services");
1042 default:
1043 try {
1044 if (AppGlobals.getPackageManager().checkPermission(
1045 android.Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
1046 r.appInfo.packageName,
1047 r.appInfo.uid) != PackageManager.PERMISSION_GRANTED) {
1048 throw new SecurityException("Instant app " + r.appInfo.packageName
1049 + " does not have permission to create foreground"
1050 + "services");
1051 }
1052 } catch (RemoteException e) {
1053 throw new SecurityException("Failed to check instant app permission." ,
1054 e);
1055 }
1056 }
1057 }
1058 if (r.fgRequired) {
1062 r.fgRequired = false;
1063 r.fgWaiting = false;
// 取消延迟消息的发送
1064 mAm.mHandler.removeMessages(
1065 ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
1066 }
1067 if (r.foregroundId != id) {
1068 cancelForegroundNotificationLocked(r);
1069 r.foregroundId = id;
1070 }
1071 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
1072 r.foregroundNoti = notification;
1073 if (!r.isForeground) {
1074 final ServiceMap smap = getServiceMapLocked(r.userId);
1075 if (smap != null) {
1076 ActiveForegroundApp active = smap.mActiveForegroundApps.get(r.packageName);
1077 if (active == null) {
1078 active = new ActiveForegroundApp();
1079 active.mPackageName = r.packageName;
1080 active.mUid = r.appInfo.uid;
1081 active.mShownWhileScreenOn = mScreenOn;
1082 if (r.app != null) {
1083 active.mAppOnTop = active.mShownWhileTop =
1084 r.app.uidRecord.curProcState
1085 <= ActivityManager.PROCESS_STATE_TOP;
1086 }
1087 active.mStartTime = active.mStartVisibleTime
1088 = SystemClock.elapsedRealtime();
1089 smap.mActiveForegroundApps.put(r.packageName, active);
1090 requestUpdateActiveForegroundAppsLocked(smap, 0);
1091 }
1092 active.mNumActive++;
1093 }
1094 r.isForeground = true;
1095 }
1096 r.postNotification();
1097 if (r.app != null) {
1098 updateServiceForegroundLocked(r.app, true);
1099 }
1100 getServiceMapLocked(r.userId).ensureNotStartingBackgroundLocked(r);
1101 mAm.notifyPackageUse(r.serviceInfo.packageName,
1102 PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE);
1103 } else {
1104 if (r.isForeground) {
1105 final ServiceMap smap = getServiceMapLocked(r.userId);
1106 if (smap != null) {
1107 decActiveForegroundAppLocked(smap, r);
1108 }
1109 r.isForeground = false;
1110 if (r.app != null) {
1111 mAm.updateLruProcessLocked(r.app, false, null);
1112 updateServiceForegroundLocked(r.app, true);
1113 }
1114 }
1115 if ((flags & Service.STOP_FOREGROUND_REMOVE) != 0) {
1116 cancelForegroundNotificationLocked(r);
1117 r.foregroundId = 0;
1118 r.foregroundNoti = null;
1119 } else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
1120 r.stripForegroundServiceFlagFromNotification();
1121 if ((flags & Service.STOP_FOREGROUND_DETACH) != 0) {
1122 r.foregroundId = 0;
1123 r.foregroundNoti = null;
1124 }
1125 }
1126 }
1127 }