diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 4872efdce88ba..7d6e54243d89c 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -19,7 +19,6 @@ package com.android.server.am; import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND; import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; -import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST; import static android.os.Process.NFC_UID; @@ -168,6 +167,7 @@ public final class ActiveServices { public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION = 16; public static final int FGS_FEATURE_ALLOWED_BY_FGS_BINDING = 17; public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE = 18; + public static final int FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD = 19; @IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = { FGS_FEATURE_DENIED, @@ -187,7 +187,8 @@ public final class ActiveServices { FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST, FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION, FGS_FEATURE_ALLOWED_BY_FGS_BINDING, - FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE + FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE, + FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD }) @Retention(RetentionPolicy.SOURCE) public @interface FgsFeatureRetCode {} @@ -5244,10 +5245,14 @@ public final class ActiveServices { if (ret == FGS_FEATURE_DENIED) { for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) { final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i); - if (pr.uid == callingUid - && pr.mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { - ret = FGS_FEATURE_ALLOWED_BY_PROC_STATE; - break; + if (pr.uid == callingUid) { + if (pr.mAllowStartFgs) { + ret = FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD; + break; + } else if (pr.isAllowedStartFgsState()) { + ret = FGS_FEATURE_ALLOWED_BY_PROC_STATE; + break; + } } } } @@ -5286,7 +5291,7 @@ public final class ActiveServices { } if (ret == FGS_FEATURE_DENIED) { - if (mAm.isWhitelistedForFgsStartLocked(r.appInfo.uid)) { + if (mAm.isWhitelistedForFgsStartLocked(callingUid)) { // uid is on DeviceIdleController's user/system allowlist // or AMS's FgsStartTempAllowList. ret = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST; @@ -5354,6 +5359,8 @@ public final class ActiveServices { return "ALLOWED_BY_FGS_BINDING"; case FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE: return "ALLOWED_BY_DEVICE_DEMO_MODE"; + case FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD: + return "ALLOWED_BY_PROCESS_RECORD"; default: return ""; } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 771f273781fa2..5b3e6514c6a65 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1329,7 +1329,7 @@ public final class OomAdjuster { app.setCached(false); app.shouldNotFreeze = false; - app.mAllowStartFgsState = PROCESS_STATE_NONEXISTENT; + app.resetAllowStartFgs(); final int appUid = app.info.uid; final int logUid = mService.mCurOomAdjUid; @@ -1351,7 +1351,6 @@ public final class OomAdjuster { app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT); app.curCapability = PROCESS_CAPABILITY_ALL; app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT); - app.bumpAllowStartFgsState(PROCESS_STATE_PERSISTENT); // System processes can do UI, and when they do we want to have // them trim their memory after the user leaves the UI. To // facilitate this, here we need to determine whether or not it @@ -1382,6 +1381,8 @@ public final class OomAdjuster { app.setCurRawProcState(app.getCurProcState()); app.curAdj = app.maxAdj; app.completedAdjSeq = app.adjSeq; + app.bumpAllowStartFgsState(app.getCurProcState()); + app.setAllowStartFgs(); // if curAdj is less than prevAppAdj, then this process was promoted return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState; } @@ -1773,6 +1774,11 @@ public final class OomAdjuster { int clientAdj = client.getCurRawAdj(); int clientProcState = client.getCurRawProcState(); + // pass client's mAllowStartFgs to the app if client is not persistent process. + if (client.mAllowStartFgs && client.maxAdj >= ProcessList.FOREGROUND_APP_ADJ) { + app.mAllowStartFgs = true; + } + if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) { if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) { continue; @@ -2236,7 +2242,7 @@ public final class OomAdjuster { app.setCurRawProcState(procState); app.setHasForegroundActivities(foregroundActivities); app.completedAdjSeq = mAdjSeq; - + app.setAllowStartFgs(); // if curAdj or curProcState improved, then this process was promoted return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState || app.curCapability != prevCapability ; diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index cf4adc65a7fc3..255badd3239f7 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -16,7 +16,16 @@ package com.android.server.am; +import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; +import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND; +import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; +import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.os.Process.NFC_UID; +import static android.os.Process.ROOT_UID; +import static android.os.Process.SHELL_UID; +import static android.os.Process.SYSTEM_UID; import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR; @@ -361,6 +370,17 @@ class ProcessRecord implements WindowProcessListener { private final ArraySet mBackgroundFgsStartTokens = new ArraySet<>(); + // The list of permissions that can start FGS from background. + private static String[] ALLOW_BG_START_FGS_PERMISSIONS = + {START_ACTIVITIES_FROM_BACKGROUND, START_FOREGROUND_SERVICES_FROM_BACKGROUND, + SYSTEM_ALERT_WINDOW}; + // Does the process has permission to start FGS from background. + boolean mAllowStartFgsByPermission; + // Can this process start FGS from background? + // If this process has the ability to start FGS from background, this ability can be passed to + // another process through service binding. + boolean mAllowStartFgs; + void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo, long startTime) { this.startUid = startUid; @@ -476,6 +496,9 @@ class ProcessRecord implements WindowProcessListener { pw.println(); pw.print(prefix); pw.print("allowStartFgsState="); pw.println(mAllowStartFgsState); + if (mAllowStartFgs) { + pw.print(prefix); pw.print("allowStartFgs="); pw.println(mAllowStartFgs); + } if (hasShownUi || mPendingUiClean || hasAboveClient || treatLikeActivity) { pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi); pw.print(" pendingUiClean="); pw.print(mPendingUiClean); @@ -672,6 +695,7 @@ class ProcessRecord implements WindowProcessListener { mWindowProcessController = new WindowProcessController( mService.mActivityTaskManager, info, processName, uid, userId, this, this); pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode)); + setAllowStartFgsByPermission(); } public void setPid(int _pid) { @@ -1983,12 +2007,78 @@ class ProcessRecord implements WindowProcessListener { return mDialogController; } + void resetAllowStartFgs() { + mAllowStartFgsState = PROCESS_STATE_NONEXISTENT; + mAllowStartFgs = mAllowStartFgsByPermission; + } + void bumpAllowStartFgsState(int newProcState) { if (newProcState < mAllowStartFgsState) { mAllowStartFgsState = newProcState; } } + void setAllowStartFgsByPermission() { + boolean ret = false; + if (!ret) { + boolean isSystem = false; + final int uid = UserHandle.getAppId(info.uid); + switch (uid) { + case ROOT_UID: + case SYSTEM_UID: + case NFC_UID: + case SHELL_UID: + isSystem = true; + break; + default: + isSystem = false; + break; + } + + if (isSystem) { + ret = true; + } + } + + if (!ret) { + for (int i = 0; i < ALLOW_BG_START_FGS_PERMISSIONS.length; ++i) { + if (ActivityManager.checkComponentPermission(ALLOW_BG_START_FGS_PERMISSIONS[i], + info.uid, -1, true) + == PERMISSION_GRANTED) { + ret = true; + break; + } + } + } + mAllowStartFgs = mAllowStartFgsByPermission = ret; + } + + boolean isAllowedStartFgsState() { + return mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE; + } + + void setAllowStartFgs() { + if (mAllowStartFgs) { + return; + } + if (!mAllowStartFgs) { + mAllowStartFgs = isAllowedStartFgsState(); + } + + if (!mAllowStartFgs) { + // Is the calling UID a device owner app? + if (mService.mInternal != null) { + mAllowStartFgs = mService.mInternal.isDeviceOwner(info.uid); + } + } + + if (!mAllowStartFgs) { + // uid is on DeviceIdleController's user/system allowlist + // or AMS's FgsStartTempAllowList. + mAllowStartFgs = mService.isWhitelistedForFgsStartLocked(info.uid); + } + } + /** A controller to generate error dialogs in {@link ProcessRecord} */ class ErrorDialogController { /** dialogs being displayed due to crash */