因为关于Android9,如果startService()是从背景调用的,它就会抛出一个。在我的开发人员控制台中,我多次看到这个异常:
java.lang.IllegalStateException:
at android.app.ContextImpl.startServiceCommon (ContextImpl.java:1666)
at android.app.ContextImpl.startService (ContextImpl.java:1611)在这种情况下,谷歌建议调用startForegroundService(),并在5秒内调用startForeground()。见“后台执行限制”。
无论如何,从startService()前台调用是完全可以的。现在,我想知道Android是如何识别/决定应用程序在前台而不是错误地抛出一个IllegalStateException。
我开始挖掘Android9 9/10的源代码,并将其与8/7进行比较,以了解如何修改startService()以识别是否从前台/后台调用它。但我确信,在我之前,许多开发人员已经这样做了,如果他们能给出答案,我会很高兴的。
发布于 2021-03-05 15:29:29
跟着这个链接到Android的源代码,我们找到了getAppStartModeLocked()
int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
int callingPid, boolean alwaysRestrict, boolean disabledOnly) {
UidRecord uidRec = mActiveUids.get(uid);
if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg="
+ packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle="
+ (uidRec != null ? uidRec.idle : false));
if (uidRec == null || alwaysRestrict || uidRec.idle) {
boolean ephemeral;
if (uidRec == null) {
ephemeral = getPackageManagerInternalLocked().isPackageEphemeral(
UserHandle.getUserId(uid), packageName);
} else {
ephemeral = uidRec.ephemeral;
}
if (ephemeral) {
// We are hard-core about ephemeral apps not running in the background.
return ActivityManager.APP_START_MODE_DISABLED;
} else {
if (disabledOnly) {
// The caller is only interested in whether app starts are completely
// disabled for the given package (that is, it is an instant app). So
// we don't need to go further, which is all just seeing if we should
// apply a "delayed" mode for a regular app.
return ActivityManager.APP_START_MODE_NORMAL;
}
final int startMode = (alwaysRestrict)
? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
: appServicesRestrictedInBackgroundLocked(uid, packageName,
packageTargetSdk);
if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid
+ " pkg=" + packageName + " startMode=" + startMode
+ " onwhitelist=" + isOnDeviceIdleWhitelistLocked(uid));
if (startMode == ActivityManager.APP_START_MODE_DELAYED) {
// This is an old app that has been forced into a "compatible as possible"
// mode of background check. To increase compatibility, we will allow other
// foreground apps to cause its services to start.
if (callingPid >= 0) {
ProcessRecord proc;
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(callingPid);
}
if (proc != null &&
!ActivityManager.isProcStateBackground(proc.curProcState)) {
// Whoever is instigating this is in the foreground, so we will allow it
// to go through.
return ActivityManager.APP_START_MODE_NORMAL;
}
}
}
return startMode;
}
}
return ActivityManager.APP_START_MODE_NORMAL;
}方法appRestrictedInBackgroundLocked() (也是从appServicesRestrictedInBackgroundLocked()调用作为后备)决定startMode。
// Unified app-op and target sdk check
int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
// Apps that target O+ are always subject to background check
if (packageTargetSdk >= Build.VERSION_CODES.O) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");
}
return ActivityManager.APP_START_MODE_DELAYED_RIGID;
}
// ...and legacy apps get an AppOp check
int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
uid, packageName);
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop);
}
switch (appop) {
case AppOpsManager.MODE_ALLOWED:
return ActivityManager.APP_START_MODE_NORMAL;
case AppOpsManager.MODE_IGNORED:
return ActivityManager.APP_START_MODE_DELAYED;
default:
return ActivityManager.APP_START_MODE_DELAYED_RIGID;
}
}但是关于前景或背景的最终决定是在ActivityManager.isProcStateBackground(uidRec.setProcState)中完成的。
/** @hide Should this process state be considered a background state? */
public static final boolean isProcStateBackground(int procState) {
return procState >= PROCESS_STATE_TRANSIENT_BACKGROUND;
}因此,这里的第一种方法的这一部分获取前景或背景的当前状态:
ProcessRecord proc;
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(callingPid);
}发布于 2021-02-24 13:36:44
在AOSP10 (10.0.0_r25)中:
服务器端:
在frameworks\base\services\core\java\com\android\server\am\ActiveServices.java:的startServiceLocked中
// 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);
}然后在客户端:
在ContextImpl.java中作为您的日志:
else if (cn.getPackageName().equals("?")) {
throw new IllegalStateException(
"Not allowed to start service " + service + ": " + cn.getClassName());
}发布于 2021-03-04 05:24:29
当应用程序在下面的情况下,它将被允许从背景开始。
https://stackoverflow.com/questions/66314488
复制相似问题