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

Commit 631f90a7 authored by Hui Yu's avatar Hui Yu
Browse files

The ability to start FGS can be passed down by service binding.

1. Add field mAllowStartFgs in ProcessRecord to indicate this app can
start FGS.
2. mAllowStartFgs is true if the process has
  * any of these permissions: START_ACTIVITIES_FROM_BACKGROUND,
START_FOREGROUND_SERVICES_FROM_BACKGROUND, SYSTEM_ALERT_WINDOW
  * the process's uid is ROOT_UID, SYSTEM_UID, NFC_UID, SHELL_UID.
  * the process's proc state is higher or equals to
PROCESS_STATE_BOUND_FOREGROUND_SERVICE.
  * the process's uid is DeviceOwner, or allowlisted by
DeviceIdleController.
3. The mAllowStartFgs ability can be passed to another process by
service binding. Except if the binder is PROCESS_STATE_PERSISTENT, this
ability does not pass down.

Bug: 171305836
Test: atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java#testFgsBindingFlagNone

Change-Id: I20d977ce7ae65316cdec2cd0ef9cf9bafec2adbd
parent 3d8a47bd
Loading
Loading
Loading
Loading
+14 −7
Original line number Diff line number Diff line
@@ -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,13 +5245,17 @@ 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) {
                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;
                    }
                }
            }
        }

        if (ret == FGS_FEATURE_DENIED) {
            for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
@@ -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 "";
        }
+9 −3
Original line number Diff line number Diff line
@@ -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 ;
+90 −0
Original line number Diff line number Diff line
@@ -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<Binder> 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 */