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

Commit e5a9b12d authored by Hui Yu's avatar Hui Yu Committed by Android (Google) Code Review
Browse files

Merge "All FGS exemptions should be propagated via service bindings." into sc-dev

parents ef6dd9b1 fbf67aac
Loading
Loading
Loading
Loading
+93 −30
Original line number Diff line number Diff line
@@ -21,38 +21,40 @@ import static android.Manifest.permission.REQUEST_COMPANION_START_FOREGROUND_SER
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
import static android.os.PowerExemptionManager.REASON_ACTIVITY_STARTER;
import static android.os.PowerExemptionManager.REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD;
import static android.os.PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE;
import static android.os.PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerExemptionManager.REASON_BACKGROUND_FGS_PERMISSION;
import static android.os.PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER;
import static android.os.PowerExemptionManager.REASON_DENIED;
import static android.os.PowerExemptionManager.REASON_DEVICE_DEMO_MODE;
import static android.os.PowerExemptionManager.REASON_DEVICE_OWNER;
import static android.os.PowerExemptionManager.REASON_FGS_BINDING;
import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION;
import static android.os.PowerExemptionManager.REASON_OPT_OUT_REQUESTED;
import static android.os.PowerExemptionManager.REASON_OP_ACTIVATE_PLATFORM_VPN;
import static android.os.PowerExemptionManager.REASON_OP_ACTIVATE_VPN;
import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT;
import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI;
import static android.os.PowerExemptionManager.REASON_PROC_STATE_TOP;
import static android.os.PowerExemptionManager.REASON_PROFILE_OWNER;
import static android.os.PowerExemptionManager.REASON_SERVICE_LAUNCH;
import static android.os.PowerExemptionManager.REASON_START_ACTIVITY_FLAG;
import static android.os.PowerExemptionManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
import static android.os.PowerExemptionManager.REASON_SYSTEM_ALLOW_LISTED;
import static android.os.PowerExemptionManager.REASON_SYSTEM_UID;
import static android.os.PowerExemptionManager.REASON_TEMP_ALLOWED_WHILE_IN_USE;
import static android.os.PowerWhitelistManager.REASON_ACTIVITY_STARTER;
import static android.os.PowerWhitelistManager.REASON_ALLOWLISTED_PACKAGE;
import static android.os.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_BACKGROUND_FGS_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_COMPANION_DEVICE_MANAGER;
import static android.os.PowerWhitelistManager.REASON_DENIED;
import static android.os.PowerWhitelistManager.REASON_DEVICE_DEMO_MODE;
import static android.os.PowerWhitelistManager.REASON_DEVICE_OWNER;
import static android.os.PowerWhitelistManager.REASON_FGS_BINDING;
import static android.os.PowerWhitelistManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_PROC_STATE_PERSISTENT;
import static android.os.PowerWhitelistManager.REASON_PROC_STATE_PERSISTENT_UI;
import static android.os.PowerWhitelistManager.REASON_PROC_STATE_TOP;
import static android.os.PowerWhitelistManager.REASON_PROFILE_OWNER;
import static android.os.PowerWhitelistManager.REASON_START_ACTIVITY_FLAG;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_UID;
import static android.os.PowerWhitelistManager.REASON_UID_VISIBLE;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.PowerWhitelistManager.getReasonCodeFromProcState;
import static android.os.PowerWhitelistManager.reasonCodeToString;
import static android.os.PowerExemptionManager.REASON_UID_VISIBLE;
import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.PowerExemptionManager.getReasonCodeFromProcState;
import static android.os.PowerExemptionManager.reasonCodeToString;
import static android.os.Process.INVALID_UID;
import static android.os.Process.NFC_UID;
import static android.os.Process.ROOT_UID;
@@ -118,8 +120,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerWhitelistManager;
import android.os.PowerWhitelistManager.ReasonCode;
import android.os.PowerExemptionManager.ReasonCode;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
@@ -135,6 +136,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
@@ -3614,8 +3616,9 @@ public final class ActiveServices {
                        + " for fg-service launch");
            }
            mAm.tempAllowlistUidLocked(r.appInfo.uid,
                    SERVICE_START_FOREGROUND_TIMEOUT, PowerWhitelistManager.REASON_SERVICE_LAUNCH,
                    "fg-service-launch", TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
                    SERVICE_START_FOREGROUND_TIMEOUT, REASON_SERVICE_LAUNCH,
                    "fg-service-launch",
                    TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
                    r.mRecentCallingUid);
        }

@@ -5740,6 +5743,66 @@ public final class ActiveServices {
        int ret = shouldAllowFgsStartForegroundLocked(allowWhileInUse, callingPid, callingUid,
                callingPackage, r);

        String bindFromPackage = null;
        if (ret == REASON_DENIED) {
            // If the callingUid is not allowed to start FGS, check if the callingUid has any
            // service that is bound by a clientUid, the clientUid can propagate its BG-FGS-start
            // capability down to the callingUid.
            final ArraySet<Integer> checkedClientUids = new ArraySet<>();
            final Pair<Integer, String> isAllowed = mAm.mProcessList.searchEachLruProcessesLOSP(
                    false, pr -> {
                if (pr.uid == callingUid) {
                    final ProcessServiceRecord psr = pr.mServices;
                    final int serviceCount = psr.mServices.size();
                    for (int svc = 0; svc < serviceCount; svc++) {
                        final ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns =
                                psr.mServices.valueAt(svc).getConnections();
                        final int size = conns.size();
                        for (int conni = 0; conni < size; conni++) {
                            final ArrayList<ConnectionRecord> crs = conns.valueAt(conni);
                            for (int con = 0; con < crs.size(); con++) {
                                final ConnectionRecord cr = crs.get(con);
                                final ProcessRecord clientPr = cr.binding.client;
                                // Persistent process does not propagate BG-FGS-start capability
                                // down to service over binding.
                                if (clientPr.mState.getCurProcState()
                                        <= PROCESS_STATE_PERSISTENT_UI) {
                                    continue;
                                }
                                final int clientPid = clientPr.mPid;
                                final int clientUid = clientPr.uid;
                                // An UID can bind to itself, do not check on itself again.
                                // Also skip already checked clientUid.
                                if (clientUid == callingUid
                                        || checkedClientUids.contains(clientUid)) {
                                    continue;
                                }
                                final String clientPackageName = cr.clientPackageName;
                                final @ReasonCode int allowWhileInUse2 =
                                        shouldAllowFgsWhileInUsePermissionLocked(clientPackageName,
                                                clientPid, clientUid, null /* serviceRecord */,
                                                false /* allowBackgroundActivityStarts */);
                                final @ReasonCode int allowStartFgs =
                                        shouldAllowFgsStartForegroundLocked(allowWhileInUse2,
                                                clientPid, clientUid, clientPackageName, null /* targetService */);
                                if (allowStartFgs != REASON_DENIED) {
                                    return new Pair<>(allowStartFgs, clientPackageName);
                                } else {
                                    checkedClientUids.add(clientUid);
                                }

                            }
                        }
                    }
                }
                return null;
            });
            if (isAllowed != null) {
                ret = REASON_FGS_BINDING;
                bindFromPackage = isAllowed.second;
            }
        }

        final int uidState = mAm.getUidStateLocked(callingUid);
        int callerTargetSdkVersion = INVALID_UID;
        try {
@@ -5765,6 +5828,7 @@ public final class ActiveServices {
                        + "; targetSdkVersion:" + r.appInfo.targetSdkVersion
                        + "; callerTargetSdkVersion:" + callerTargetSdkVersion
                        + "; startForegroundCount:" + r.mStartForegroundCount
                        + "; bindFromPackage:" + bindFromPackage
                        + "]";
        if (!debugInfo.equals(r.mInfoAllowStartForeground)) {
            r.mLoggedInfoAllowStartForeground = false;
@@ -5790,9 +5854,7 @@ public final class ActiveServices {
            final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, app -> {
                if (app.uid == callingUid) {
                    final ProcessStateRecord state = app.mState;
                    if (state.getAllowedStartFgs() != REASON_DENIED) {
                        return state.getAllowedStartFgs();
                    } else if (state.isAllowedStartFgsState()) {
                    if (state.isAllowedStartFgsState()) {
                        return getReasonCodeFromProcState(state.getAllowStartFgsState());
                    } else if (state.areBackgroundFgsStartsAllowedByToken()) {
                        return REASON_FGS_BINDING;
@@ -5891,6 +5953,7 @@ public final class ActiveServices {
        }
        if (ret == REASON_DENIED) {
            if (mAm.mConstants.mFgsAllowOptOut
                    && targetService != null
                    && targetService.appInfo.hasRequestForegroundServiceExemption()) {
                ret = REASON_OPT_OUT_REQUESTED;
            }
+1 −11
Original line number Diff line number Diff line
@@ -42,7 +42,6 @@ import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
import static android.os.PowerWhitelistManager.REASON_DENIED;
import static android.os.Process.SCHED_OTHER;
import static android.os.Process.THREAD_GROUP_BACKGROUND;
import static android.os.Process.THREAD_GROUP_DEFAULT;
@@ -1574,8 +1573,7 @@ public class OomAdjuster {
        state.setAdjTarget(null);
        state.setEmpty(false);
        state.setCached(false);
        state.setAllowStartFgsState(PROCESS_STATE_NONEXISTENT);
        state.resetAllowStartFgs();
        state.resetAllowStartFgsState();
        app.mOptRecord.setShouldNotFreeze(false);

        final int appUid = app.info.uid;
@@ -1630,7 +1628,6 @@ public class OomAdjuster {
            state.setCurAdj(state.getMaxAdj());
            state.setCompletedAdjSeq(state.getAdjSeq());
            state.bumpAllowStartFgsState(state.getCurProcState());
            state.setAllowStartFgs();
            // if curAdj is less than prevAppAdj, then this process was promoted
            return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState;
        }
@@ -2028,12 +2025,6 @@ public class OomAdjuster {

                    final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP;

                    // pass client's mAllowStartFgs to the app if client is not persistent process.
                    if (cstate.getAllowedStartFgs() != REASON_DENIED
                            && cstate.getMaxAdj() >= ProcessList.FOREGROUND_APP_ADJ) {
                        state.setAllowStartFgs(cstate.getAllowedStartFgs());
                    }

                    if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) {
                        if (shouldSkipDueToCycle(state, cstate, procState, adj, cycleReEval)) {
                            continue;
@@ -2524,7 +2515,6 @@ public class OomAdjuster {
        state.updateLastInvisibleTime(hasVisibleActivities);
        state.setHasForegroundActivities(foregroundActivities);
        state.setCompletedAdjSeq(mAdjSeq);
        state.setAllowStartFgs();

        // if curAdj or curProcState improved, then this process was promoted
        return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState
+1 −1
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ final class ProcessServiceRecord {
    /**
     * All ServiceRecord running in this process.
     */
    private final ArraySet<ServiceRecord> mServices = new ArraySet<>();
    final ArraySet<ServiceRecord> mServices = new ArraySet<>();

    /**
     * Services that are currently executing code (need to remain foreground).
+1 −139
Original line number Diff line number Diff line
@@ -16,28 +16,9 @@

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_CAPABILITY_NONE;
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.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_BACKGROUND_FGS_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_DENIED;
import static android.os.PowerWhitelistManager.REASON_DEVICE_OWNER;
import static android.os.PowerWhitelistManager.REASON_PROFILE_OWNER;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_UID;
import static android.os.PowerWhitelistManager.ReasonCode;
import static android.os.PowerWhitelistManager.getReasonCodeFromProcState;
import static android.os.PowerWhitelistManager.reasonCodeToString;
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.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
import static com.android.server.am.ProcessRecord.TAG;
@@ -47,7 +28,6 @@ import android.app.ActivityManager;
import android.content.ComponentName;
import android.os.Binder;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Slog;
import android.util.TimeUtils;
@@ -56,7 +36,6 @@ import com.android.internal.annotations.CompositeRWLock;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.FrameworkStatsLog;


import java.io.PrintWriter;

/**
@@ -326,20 +305,6 @@ final class ProcessStateRecord {
    @GuardedBy("mService")
    private final ArraySet<Binder> mBackgroundFgsStartTokens = new ArraySet<>();

    /**
     * Does the process has permission to start FGS from background.
     */
    @GuardedBy("mService")
    private @ReasonCode int mAllowStartFgsByPermission = REASON_DENIED;

    /**
     * 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.
     */
    @GuardedBy("mService")
    private @ReasonCode int mAllowStartFgs = REASON_DENIED;

    /**
     * Whether or not this process has been in forced-app-standby state.
     */
@@ -435,7 +400,6 @@ final class ProcessStateRecord {
        mApp = app;
        mService = app.mService;
        mProcLock = mService.mProcLock;
        setAllowStartFgsByPermission();
    }

    void init(long now) {
@@ -1152,9 +1116,8 @@ final class ProcessStateRecord {
    }

    @GuardedBy("mService")
    void resetAllowStartFgs() {
    void resetAllowStartFgsState() {
        mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
        mAllowStartFgs = mAllowStartFgsByPermission;
    }

    @GuardedBy("mService")
@@ -1164,11 +1127,6 @@ final class ProcessStateRecord {
        }
    }

    @GuardedBy("mService")
    void setAllowStartFgsState(int allowStartFgsState) {
        mAllowStartFgsState = allowStartFgsState;
    }

    @GuardedBy("mService")
    int getAllowStartFgsState() {
        return mAllowStartFgsState;
@@ -1179,98 +1137,6 @@ final class ProcessStateRecord {
        return mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
    }

    @GuardedBy("mService")
    void setAllowStartFgsByPermission() {
        int ret = REASON_DENIED;
        boolean isSystem = false;
        final int uid = UserHandle.getAppId(mApp.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 = REASON_SYSTEM_UID;
        }

        if (ret == REASON_DENIED) {
            if (ActivityManager.checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND,
                    mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
                ret = REASON_BACKGROUND_ACTIVITY_PERMISSION;
            } else if (ActivityManager.checkComponentPermission(
                    START_FOREGROUND_SERVICES_FROM_BACKGROUND,
                    mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
                ret = REASON_BACKGROUND_FGS_PERMISSION;
            } else if (ActivityManager.checkComponentPermission(SYSTEM_ALERT_WINDOW,
                    mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
                ret = REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
            }
        }
        mAllowStartFgs = mAllowStartFgsByPermission = ret;
    }

    // TODO(b/188063200) Clean up this method. Why do we need to duplicate only some of the checks?
    @GuardedBy("mService")
    void setAllowStartFgs() {
        if (mAllowStartFgs != REASON_DENIED) {
            return;
        }
        if (mAllowStartFgs == REASON_DENIED) {
            if (isAllowedStartFgsState()) {
                mAllowStartFgs = getReasonCodeFromProcState(mAllowStartFgsState);
            }
        }

        if (mAllowStartFgs == REASON_DENIED) {
            // Is the calling UID a device owner app?
            if (mService.mInternal != null) {
                if (mService.mInternal.isDeviceOwner(mApp.info.uid)) {
                    mAllowStartFgs = REASON_DEVICE_OWNER;
                }
            }
        }

        if (mAllowStartFgs == REASON_DENIED) {
            // Is the calling UID a profile owner app?
            if (mService.mInternal != null) {
                if (mService.mInternal.isProfileOwner(mApp.info.uid)) {
                    mAllowStartFgs = REASON_PROFILE_OWNER;
                }
            }
        }

        if (mAllowStartFgs == REASON_DENIED) {
            // uid is on DeviceIdleController's user/system allowlist
            // or AMS's FgsStartTempAllowList.
            ActivityManagerService.FgsTempAllowListItem item =
                    mService.isAllowlistedForFgsStartLOSP(mApp.info.uid);
            if (item != null) {
                if (item == ActivityManagerService.FAKE_TEMP_ALLOW_LIST_ITEM) {
                    mAllowStartFgs = REASON_SYSTEM_ALLOW_LISTED;
                } else {
                    mAllowStartFgs = item.mReasonCode;
                }
            }
        }
    }

    @GuardedBy("mService")
    void setAllowStartFgs(@ReasonCode int allowStartFgs) {
        mAllowStartFgs = allowStartFgs;
    }

    @GuardedBy("mService")
    @ReasonCode int getAllowedStartFgs() {
        return mAllowStartFgs;
    }

    @GuardedBy("mService")
    void setForcedAppStandby(boolean standby) {
        mForcedAppStandby = standby;
@@ -1334,10 +1200,6 @@ final class ProcessStateRecord {
        pw.println();
        pw.print(prefix); pw.print("allowStartFgsState=");
        pw.println(mAllowStartFgsState);
        if (mAllowStartFgs != REASON_DENIED) {
            pw.print(prefix); pw.print("allowStartFgs=");
            pw.println(reasonCodeToString(mAllowStartFgs));
        }
        if (mHasShownUi || mApp.mProfile.hasPendingUiClean()) {
            pw.print(prefix); pw.print("hasShownUi="); pw.print(mHasShownUi);
            pw.print(" pendingUiClean="); pw.println(mApp.mProfile.hasPendingUiClean());