如何修改 startService() 的源代码以识别它是否是从后台调用的?

red*_*man 2 android android-source

从 Android 9 开始,如果从后台调用,它会抛出IllegalStateException。我在开发者控制台中多次看到此异常:startService()

java.lang.IllegalStateException:
  at android.app.ContextImpl.startServiceCommon (ContextImpl.java:1666)
  at android.app.ContextImpl.startService (ContextImpl.java:1611)
Run Code Online (Sandbox Code Playgroud)

在这些情况下,Google 建议改为startForegroundService()在 5 秒内致电 and startForeground()请参阅“后台执行限制”

无论如何,startService()前台调用是完全可以的。现在,我想知道 Android 究竟是如何识别/决定应用程序位于前台而不错误地抛出 IllegalStateException

我开始挖掘Android9/10的源代码,并将其与8/7进行比较,以发现如何startService()修改以识别它是否是从前台/后台调用的。但我确信在我之前的许多开发人员已经这样做了,如果他们能够给出答案,我会很高兴。

jw_*_*jw_ 5

在 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);
        }
Run Code Online (Sandbox Code Playgroud)

然后在客户端:

在 ContextImpl.java 中作为日志:

            else if (cn.getPackageName().equals("?")) {
                throw new IllegalStateException(
                        "Not allowed to start service " + service + ": " + cn.getClassName());
            }
Run Code Online (Sandbox Code Playgroud)