Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 859ba069 authored by Hui Yu's avatar Hui Yu
Browse files

Allow FGS start for proc state BOUND_FOREGROUND_SERVICE and above.

FGS start is allowed for proc state BOUND_FOREGROUND_SERVICE and above.
Allowed states are:
PERSISTENT,
TOP,
BOUND_TOP (when bound by TOP process),
FOREGROUND_SERVICE (when process has FGS),
and BOUND_FOREGROUND_SERVICE (when bound by PERSISTENT process).
The process must arrived at these states by aforementioned bound path.
It should not be transitive.

Add a field mAllowStartFgsState in ProcessRecord, this field is set in
OomAdjuster.java.

Bug: 171305836.
Test: atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java
Change-Id: I3f11b4e13ce2f66c04ca775219f918450710d0b6
parent 79477111
Loading
Loading
Loading
Loading
+86 −45
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.am;

import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
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;
@@ -145,7 +146,7 @@ public final class ActiveServices {
    private static final boolean SHOW_DUNGEON_NOTIFICATION = false;

    public static final int FGS_FEATURE_DENIED = 0;
    public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 1;
    public static final int FGS_FEATURE_ALLOWED_BY_UID_STATE = 1;
    public static final int FGS_FEATURE_ALLOWED_BY_UID_VISIBLE = 2;
    public static final int FGS_FEATURE_ALLOWED_BY_FLAG = 3;
    public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_UID = 4;
@@ -154,10 +155,12 @@ public final class ActiveServices {
    public static final int FGS_FEATURE_ALLOWED_BY_PERMISSION = 7;
    public static final int FGS_FEATURE_ALLOWED_BY_WHITELIST = 8;
    public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER = 9;
    public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 10;
    public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST = 11;

    @IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = {
            FGS_FEATURE_DENIED,
            FGS_FEATURE_ALLOWED_BY_PROC_STATE,
            FGS_FEATURE_ALLOWED_BY_UID_STATE,
            FGS_FEATURE_ALLOWED_BY_UID_VISIBLE,
            FGS_FEATURE_ALLOWED_BY_FLAG,
            FGS_FEATURE_ALLOWED_BY_SYSTEM_UID,
@@ -165,7 +168,9 @@ public final class ActiveServices {
            FGS_FEATURE_ALLOWED_BY_TOKEN,
            FGS_FEATURE_ALLOWED_BY_PERMISSION,
            FGS_FEATURE_ALLOWED_BY_WHITELIST,
            FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER
            FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER,
            FGS_FEATURE_ALLOWED_BY_PROC_STATE,
            FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface FgsFeatureRetCode {}
@@ -576,12 +581,6 @@ public final class ActiveServices {
                if (r.mAllowStartForeground == FGS_FEATURE_DENIED
                        && (mAm.mConstants.mFlagFgsStartRestrictionEnabled
                        || isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
                    if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
                            && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
                        // uid is on DeviceIdleController's allowlist.
                        Slog.d(TAG, "startForegroundService() mAllowStartForeground false "
                                + "but allowlist true: service " + r.shortInstanceName);
                    } else {
                    Slog.w(TAG, "startForegroundService() not allowed due to "
                            + "mAllowStartForeground false: service "
                            + r.shortInstanceName);
@@ -590,7 +589,6 @@ public final class ActiveServices {
                }
            }
        }
        }

        // If this is a direct-to-foreground start, make sure it is allowed as per the app op.
        boolean forceSilentAbort = false;
@@ -1488,13 +1486,6 @@ public final class ActiveServices {
                        if (r.mAllowStartForeground == FGS_FEATURE_DENIED
                                && (mAm.mConstants.mFlagFgsStartRestrictionEnabled
                                || isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
                            if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
                                    && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
                                // uid is on DeviceIdleController's allowlist.
                                Slog.d(TAG, "Service.startForeground() "
                                        + "mAllowStartForeground false but allowlist true: service "
                                        + r.shortInstanceName);
                            } else {
                            Slog.w(TAG, "Service.startForeground() not allowed due to "
                                            + "mAllowStartForeground false: service "
                                            + r.shortInstanceName);
@@ -1504,7 +1495,6 @@ public final class ActiveServices {
                        }
                    }
                }
                }

                // Apps under strict background restrictions simply don't get to have foreground
                // services, so now that we've enforced the startForegroundService() contract
@@ -4944,38 +4934,39 @@ public final class ActiveServices {
            r.mAllowWhileInUsePermissionInFgs = true;
        }

        if (!r.mAllowWhileInUsePermissionInFgs || (r.mAllowStartForeground == FGS_FEATURE_DENIED)) {
            final @FgsFeatureRetCode int temp = shouldAllowFgsFeatureLocked(callingPackage,
                    callingPid, callingUid, intent, r, allowBackgroundActivityStarts);
        if (!r.mAllowWhileInUsePermissionInFgs
                || (r.mAllowStartForeground == FGS_FEATURE_DENIED)) {
            final @FgsFeatureRetCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
                    callingPackage, callingPid, callingUid, r, allowBackgroundActivityStarts);
            if (!r.mAllowWhileInUsePermissionInFgs) {
                r.mAllowWhileInUsePermissionInFgs = (temp != FGS_FEATURE_DENIED);
                r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != FGS_FEATURE_DENIED);
            }
            if (r.mAllowStartForeground == FGS_FEATURE_DENIED) {
                r.mAllowStartForeground = temp;
                r.mAllowStartForeground = shouldAllowFgsStartForegroundLocked(allowWhileInUse,
                        callingPackage, callingPid, callingUid, intent, r,
                        allowBackgroundActivityStarts);
            }
        }
    }

    /**
     * Should allow FGS feature or not.
     * Should allow while-in-use permissions in FGS or not.
     * A typical BG started FGS is not allowed to have while-in-use permissions.
     * @param callingPackage caller app's package name.
     * @param callingUid caller app's uid.
     * @param intent intent to start/bind service.
     * @param r the service to start.
     * @return {@link FgsFeatureRetCode}
     */
    private @FgsFeatureRetCode int shouldAllowFgsFeatureLocked(String callingPackage,
            int callingPid, int callingUid, Intent intent, ServiceRecord r,
    private @FgsFeatureRetCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage,
            int callingPid, int callingUid, ServiceRecord r,
            boolean allowBackgroundActivityStarts) {
        int ret = FGS_FEATURE_DENIED;

        final StringBuilder sb = new StringBuilder(64);
        final int uidState = mAm.getUidState(callingUid);
        if (ret == FGS_FEATURE_DENIED) {
            // Is the calling UID at PROCESS_STATE_TOP or above?
            if (uidState <= ActivityManager.PROCESS_STATE_TOP) {
                sb.append("uidState=").append(uidState);
                ret = FGS_FEATURE_ALLOWED_BY_PROC_STATE;
                ret = FGS_FEATURE_ALLOWED_BY_UID_STATE;
            }
        }

@@ -5010,7 +5001,6 @@ public final class ActiveServices {
            }

            if (isCallerSystem) {
                sb.append("callingUid=").append(callingAppId);
                ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_UID;
            }
        }
@@ -5049,6 +5039,53 @@ public final class ActiveServices {
                ret = FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER;
            }
        }
        return ret;
    }

    /**
     * Should allow the FGS to start (AKA startForeground()) or not.
     * The check in this method is in addition to check in
     * {@link #shouldAllowFgsWhileInUsePermissionLocked}
     * @param allowWhileInUse the return code from {@link #shouldAllowFgsWhileInUsePermissionLocked}
     * @param callingPackage caller app's package name.
     * @param callingUid caller app's uid.
     * @param intent intent to start/bind service.
     * @param r the service to start.
     * @return {@link FgsFeatureRetCode}
     */
    private @FgsFeatureRetCode int shouldAllowFgsStartForegroundLocked(
            @FgsFeatureRetCode int allowWhileInUse, String callingPackage, int callingPid,
            int callingUid, Intent intent, ServiceRecord r, boolean allowBackgroundActivityStarts) {
        int ret = allowWhileInUse;

        final StringBuilder sb = new StringBuilder(64);
        final int uidState = mAm.getUidState(callingUid);
        if (ret == FGS_FEATURE_DENIED) {
            // Is the calling UID at PROCESS_STATE_TOP or above?
            if (uidState <= ActivityManager.PROCESS_STATE_TOP) {
                sb.append("uidState=").append(uidState);
                ret = FGS_FEATURE_ALLOWED_BY_UID_STATE;
            }
        }

        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 (ret == FGS_FEATURE_DENIED) {
            if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
                    && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
                // uid is on DeviceIdleController's allowlist.
                ret = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST;
            }
        }

        final String debugInfo =
                "[callingPackage: " + callingPackage
@@ -5071,8 +5108,8 @@ public final class ActiveServices {
        switch (code) {
            case FGS_FEATURE_DENIED:
                return "DENIED";
            case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
                return "ALLOWED_BY_PROC_STATE";
            case FGS_FEATURE_ALLOWED_BY_UID_STATE:
                return "ALLOWED_BY_UID_STATE";
            case FGS_FEATURE_ALLOWED_BY_UID_VISIBLE:
                return "ALLOWED_BY_UID_VISIBLE";
            case FGS_FEATURE_ALLOWED_BY_FLAG:
@@ -5089,13 +5126,17 @@ public final class ActiveServices {
                return "ALLOWED_BY_WHITELIST";
            case FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER:
                return "ALLOWED_BY_DEVICE_OWNER";
            case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
                return "ALLOWED_BY_PROC_STATE";
            case FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST:
                return "ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST";
            default:
                return "";
        }
    }

    private static boolean isFgsBgStart(@FgsFeatureRetCode int code) {
        return code != FGS_FEATURE_ALLOWED_BY_PROC_STATE
        return code != FGS_FEATURE_ALLOWED_BY_UID_STATE
                && code != FGS_FEATURE_ALLOWED_BY_UID_VISIBLE;
    }

+9 −1
Original line number Diff line number Diff line
@@ -1329,6 +1329,8 @@ public final class OomAdjuster {
        app.setCached(false);
        app.shouldNotFreeze = false;

        app.mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;

        final int appUid = app.info.uid;
        final int logUid = mService.mCurOomAdjUid;

@@ -1349,6 +1351,7 @@ 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
@@ -1403,6 +1406,7 @@ public final class OomAdjuster {
            app.adjType = "top-activity";
            foregroundActivities = true;
            procState = PROCESS_STATE_CUR_TOP;
            app.bumpAllowStartFgsState(PROCESS_STATE_TOP);
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app);
            }
@@ -1500,6 +1504,7 @@ public final class OomAdjuster {
                // The user is aware of this app, so make it visible.
                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                procState = PROCESS_STATE_FOREGROUND_SERVICE;
                app.bumpAllowStartFgsState(PROCESS_STATE_FOREGROUND_SERVICE);
                app.adjType = "fg-service";
                app.setCached(false);
                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
@@ -1887,7 +1892,9 @@ public final class OomAdjuster {
                                // into the top state, since they are not on top.  Instead
                                // give them the best bound state after that.
                                if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) {
                                    clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;                                                                                                                       ;
                                    clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
                                    app.bumpAllowStartFgsState(
                                            PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
                                } else if (mService.mWakefulness
                                        == PowerManagerInternal.WAKEFULNESS_AWAKE
                                        && (cr.flags & Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
@@ -1901,6 +1908,7 @@ public final class OomAdjuster {
                                // Go at most to BOUND_TOP, unless requested to elevate
                                // to client's state.
                                clientProcState = PROCESS_STATE_BOUND_TOP;
                                app.bumpAllowStartFgsState(PROCESS_STATE_BOUND_TOP);
                                boolean enabled = false;
                                try {
                                    enabled = mPlatformCompatCache.isChangeEnabled(
+12 −0
Original line number Diff line number Diff line
@@ -353,6 +353,10 @@ class ProcessRecord implements WindowProcessListener {

    long mKillTime; // The timestamp in uptime when this process was killed.

    // If the proc state is PROCESS_STATE_BOUND_FOREGROUND_SERVICE or above, it can start FGS.
    // It must obtain the proc state from a persistent/top process or FGS, not transitive.
    int mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;

    void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
            long startTime) {
        this.startUid = startUid;
@@ -466,6 +470,8 @@ class ProcessRecord implements WindowProcessListener {
                pw.print(" setCapability=");
                ActivityManager.printCapabilitiesFull(pw, setCapability);
                pw.println();
        pw.print(prefix); pw.print("allowStartFgsState=");
                pw.println(mAllowStartFgsState);
        if (hasShownUi || mPendingUiClean || hasAboveClient || treatLikeActivity) {
            pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
                    pw.print(" pendingUiClean="); pw.print(mPendingUiClean);
@@ -1943,6 +1949,12 @@ class ProcessRecord implements WindowProcessListener {
        return mDialogController;
    }

    void bumpAllowStartFgsState(int newProcState) {
        if (newProcState < mAllowStartFgsState) {
            mAllowStartFgsState = newProcState;
        }
    }

    /** A controller to generate error dialogs in {@link ProcessRecord} */
    class ErrorDialogController {
        /** dialogs being displayed due to crash */