Since about Android 9 it throws an IllegalStateException if startService() was called from the background. I see this exception many times in my developer console:
java.lang.IllegalStateException:
at android.app.ContextImpl.startServiceCommon (ContextImpl.java:1666)
at android.app.ContextImpl.startService (ContextImpl.java:1611)
In these cases, Google recommends to call startForegroundService() and within 5 seconds startForeground(), instead. See "Background execution limits".
Anyway, calling startService() from foreground is perfectly ok. Now, I wonder how exactly Android recognizes/decides that an app is in the foreground to not wrongly throwing an IllegalStateException?
I was starting to dig the source code of Android9/10 and comparing it with 8/7 to discover how startService() was modified to recognize if it was called from foreground/background. But I'm convinced that many developers before me did this already, and I would be happy if they'd give an answer.
In AOSP10 (10.0.0_r25):
Server side:
in startServiceLocked from frameworks\base\services\core\java\com\android\server\am\ActiveServices.java:
// Before going further -- if this app is not allowed to start services in the
// background, then at this point we aren't going to let it period.
final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
Slog.w(TAG, "Background start not allowed: service "
+ service + " to " + r.shortInstanceName
+ " from pid=" + callingPid + " uid=" + callingUid
+ " pkg=" + callingPackage + " startFg?=" + fgRequired);
......
// This app knows it is in the new model where this operation is not
// allowed, so tell it what has happened.
UidRecord uidRec = mAm.mProcessList.getUidRecordLocked(r.appInfo.uid);
return new ComponentName("?", "app is in background uid " + uidRec);
}
Then in client side:
in ContextImpl.java as your log:
else if (cn.getPackageName().equals("?")) {
throw new IllegalStateException(
"Not allowed to start service " + service + ": " + cn.getClassName());
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With