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

Commit 123163ba authored by Jing Ji's avatar Jing Ji Committed by Android (Google) Code Review
Browse files

Merge "Allow certain background restricted apps to run FGS"

parents e4acfba3 c79dfc83
Loading
Loading
Loading
Loading
+54 −6
Original line number Diff line number Diff line
@@ -335,10 +335,12 @@ public final class ActiveServices {
        @Override
        public void stopForegroundServicesForUidPackage(final int uid, final String packageName) {
            synchronized (mAm) {
                if (!isForegroundServiceAllowedInBackgroundRestricted(uid, packageName)) {
                    stopAllForegroundServicesLocked(uid, packageName);
                }
            }
        }
    }

    void stopAllForegroundServicesLocked(final int uid, final String packageName) {
        final ServiceMap smap = getServiceMapLocked(UserHandle.getUserId(uid));
@@ -609,6 +611,17 @@ public final class ActiveServices {
        return (mode != AppOpsManager.MODE_ALLOWED);
    }

    void updateAppRestrictedAnyInBackgroundLocked(final int uid, final String packageName) {
        final boolean restricted = appRestrictedAnyInBackground(uid, packageName);
        final UidRecord uidRec = mAm.mProcessList.getUidRecordLOSP(uid);
        if (uidRec != null) {
            final ProcessRecord app = uidRec.getProcessInPackage(packageName);
            if (app != null) {
                app.mState.setBackgroundRestricted(restricted);
            }
        }
    }

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage,
            @Nullable String callingFeatureId, final int userId)
@@ -1448,7 +1461,8 @@ public final class ActiveServices {
                    if (!aa.mAppOnTop) {
                        // Transitioning a fg-service host app out of top: if it's bg restricted,
                        // it loses the fg service state now.
                        if (!appRestrictedAnyInBackground(aa.mUid, aa.mPackageName)) {
                        if (isForegroundServiceAllowedInBackgroundRestricted(
                                aa.mUid, aa.mPackageName)) {
                            if (active == null) {
                                active = new ArrayList<>();
                            }
@@ -1666,8 +1680,38 @@ public final class ActiveServices {
        }
    }

    private boolean appIsTopLocked(int uid) {
        return mAm.getUidStateLocked(uid) <= PROCESS_STATE_TOP;
    /**
     * Check if the given app is allowed to have FGS running even if it's background restricted.
     *
     * <p>
     * Currently it needs to be in Top/Bound Top/FGS state. An uid could be in the FGS state if:
     * a) Bound by another process in the FGS state;
     * b) There is an active FGS running (ServiceRecord.isForeground is true);
     * c) The startForegroundService() has been called but the startForeground() hasn't - in this
     *    case, it must have passed the background FGS start check so we're safe here.
     * </p>
     */
    private boolean isForegroundServiceAllowedInBackgroundRestricted(ProcessRecord app) {
        final ProcessStateRecord state = app.mState;
        if (!state.isBackgroundRestricted()
                || state.getSetProcState() <= ActivityManager.PROCESS_STATE_BOUND_TOP) {
            return true;
        }
        if (state.getSetProcState() == ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
                && state.isSetBoundByNonBgRestrictedApp()) {
            return true;
        }
        return false;
    }

    /**
     * Check if the given uid/pkg is allowed to have FGS running even if it's background restricted.
     */
    private boolean isForegroundServiceAllowedInBackgroundRestricted(int uid, String packageName) {
        final UidRecord uidRec = mAm.mProcessList.getUidRecordLOSP(uid);
        ProcessRecord app = null;
        return uidRec != null && ((app = uidRec.getProcessInPackage(packageName)) != null)
                && isForegroundServiceAllowedInBackgroundRestricted(app);
    }

    /**
@@ -1761,8 +1805,7 @@ public final class ActiveServices {
                // Apps that are TOP or effectively similar may call startForeground() on
                // their services even if they are restricted from doing that while in bg.
                if (!ignoreForeground
                        && !appIsTopLocked(r.appInfo.uid)
                        && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
                        && !isForegroundServiceAllowedInBackgroundRestricted(r.app)) {
                    Slog.w(TAG,
                            "Service.startForeground() not allowed due to bg restriction: service "
                                    + r.shortInstanceName);
@@ -4640,6 +4683,11 @@ public final class ActiveServices {
    boolean attachApplicationLocked(ProcessRecord proc, String processName)
            throws RemoteException {
        boolean didSomething = false;

        // Update the app background restriction of the caller
        proc.mState.setBackgroundRestricted(appRestrictedAnyInBackground(
                proc.uid, proc.info.packageName));

        // Collect any services that are waiting for this process to come up.
        if (mPendingServices.size() > 0) {
            ServiceRecord sr = null;
+12 −0
Original line number Diff line number Diff line
@@ -1830,6 +1830,18 @@ public class ActivityManagerService extends IActivityManager.Stub
                    }
                });
        mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, null,
                new IAppOpsCallback.Stub() {
                    @Override public void opChanged(int op, int uid, String packageName) {
                        if (op == AppOpsManager.OP_RUN_ANY_IN_BACKGROUND && packageName != null) {
                            synchronized (ActivityManagerService.this) {
                                mServices.updateAppRestrictedAnyInBackgroundLocked(
                                        uid, packageName);
                            }
                        }
                    }
                });
        final int[] cameraOp = {AppOpsManager.OP_CAMERA};
        mAppOpsService.startWatchingActive(cameraOp, new IAppOpsActiveCallback.Stub() {
            @Override
+29 −0
Original line number Diff line number Diff line
@@ -511,6 +511,7 @@ public class OomAdjuster {
        }

        app.mState.resetCachedInfo();
        app.mState.setCurBoundByNonBgRestrictedApp(false);
        UidRecord uidRec = app.getUidRecord();
        if (uidRec != null) {
            if (DEBUG_UID_OBSERVERS) {
@@ -644,6 +645,7 @@ public class OomAdjuster {
        state.setContainsCycle(false);
        state.setProcStateChanged(false);
        state.resetCachedInfo();
        state.setCurBoundByNonBgRestrictedApp(false);
        // Check if this process is in the pending list too, remove from pending list if so.
        mPendingProcessSet.remove(app);
        boolean success = performUpdateOomAdjLSP(app, cachedAdj, topApp,
@@ -934,6 +936,7 @@ public class OomAdjuster {
                state.setCurRawAdj(ProcessList.UNKNOWN_ADJ);
                state.setSetCapability(PROCESS_CAPABILITY_NONE);
                state.resetCachedInfo();
                state.setCurBoundByNonBgRestrictedApp(false);
            }
        }
        mProcessesInCycle.clear();
@@ -1900,6 +1903,7 @@ public class OomAdjuster {
        }

        int capabilityFromFGS = 0; // capability from foreground service.
        boolean boundByNonBgRestricted = state.isCurBoundByNonBgRestrictedApp();
        boolean scheduleLikeTopApp = false;
        for (int is = psr.numberOfRunningServices() - 1;
                is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
@@ -2014,6 +2018,11 @@ public class OomAdjuster {

                    final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP;

                    boundByNonBgRestricted |= cstate.isCurBoundByNonBgRestrictedApp()
                            || clientProcState <= PROCESS_STATE_BOUND_TOP
                            || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
                                    && !cstate.isBackgroundRestricted());

                    if (client.mOptRecord.shouldNotFreeze()) {
                        // Propagate the shouldNotFreeze flag down the bindings.
                        app.mOptRecord.setShouldNotFreeze(true);
@@ -2336,6 +2345,12 @@ public class OomAdjuster {
                    // Propagate the shouldNotFreeze flag down the bindings.
                    app.mOptRecord.setShouldNotFreeze(true);
                }

                boundByNonBgRestricted |= cstate.isCurBoundByNonBgRestrictedApp()
                        || clientProcState <= PROCESS_STATE_BOUND_TOP
                        || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
                                && !cstate.isBackgroundRestricted());

                String adjType = null;
                if (adj > clientAdj) {
                    if (state.hasShownUi() && !state.getCachedIsHomeProcess()
@@ -2513,6 +2528,7 @@ public class OomAdjuster {
        state.updateLastInvisibleTime(hasVisibleActivities);
        state.setHasForegroundActivities(foregroundActivities);
        state.setCompletedAdjSeq(mAdjSeq);
        state.setCurBoundByNonBgRestrictedApp(boundByNonBgRestricted);

        // if curAdj or curProcState improved, then this process was promoted
        return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState
@@ -2855,6 +2871,19 @@ public class OomAdjuster {
            state.setSetCapability(state.getCurCapability());
        }

        final boolean curBoundByNonBgRestrictedApp = state.isCurBoundByNonBgRestrictedApp();
        if (curBoundByNonBgRestrictedApp != state.isSetBoundByNonBgRestrictedApp()) {
            state.setSetBoundByNonBgRestrictedApp(curBoundByNonBgRestrictedApp);
            if (!curBoundByNonBgRestrictedApp && state.isBackgroundRestricted()) {
                mService.mHandler.post(() -> {
                    synchronized (mService) {
                        mService.mServices.stopAllForegroundServicesLocked(
                                app.uid, app.info.packageName);
                    }
                });
            }
        }

        if (changes != 0) {
            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                    "Changes in " + app + ": " + changes);
+55 −1
Original line number Diff line number Diff line
@@ -301,6 +301,23 @@ final class ProcessStateRecord {
    @GuardedBy("mService")
    private int mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;

    /**
     * Whether or not the app is background restricted (OP_RUN_ANY_IN_BACKGROUND is NOT allowed).
     */
    @GuardedBy("mService")
    private boolean mBackgroundRestricted = false;

    /**
     * Whether or not this process is being bound by a non-background restricted app.
     */
    @GuardedBy("mService")
    private boolean mCurBoundByNonBgRestrictedApp = false;

    /**
     * Last set state of {@link #mCurBoundByNonBgRestrictedApp}.
     */
    private boolean mSetBoundByNonBgRestrictedApp = false;

    /**
     * Debugging: primary thing impacting oom_adj.
     */
@@ -1112,6 +1129,36 @@ final class ProcessStateRecord {
        return mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
    }

    @GuardedBy("mService")
    boolean isBackgroundRestricted() {
        return mBackgroundRestricted;
    }

    @GuardedBy("mService")
    void setBackgroundRestricted(boolean restricted) {
        mBackgroundRestricted = restricted;
    }

    @GuardedBy("mService")
    boolean isCurBoundByNonBgRestrictedApp() {
        return mCurBoundByNonBgRestrictedApp;
    }

    @GuardedBy("mService")
    void setCurBoundByNonBgRestrictedApp(boolean bound) {
        mCurBoundByNonBgRestrictedApp = bound;
    }

    @GuardedBy("mService")
    boolean isSetBoundByNonBgRestrictedApp() {
        return mSetBoundByNonBgRestrictedApp;
    }

    @GuardedBy("mService")
    void setSetBoundByNonBgRestrictedApp(boolean bound) {
        mSetBoundByNonBgRestrictedApp = bound;
    }

    @GuardedBy("mService")
    void updateLastInvisibleTime(boolean hasVisibleActivities) {
        if (hasVisibleActivities) {
@@ -1164,7 +1211,14 @@ final class ProcessStateRecord {
        ActivityManager.printCapabilitiesFull(pw, mSetCapability);
        pw.println();
        pw.print(prefix); pw.print("allowStartFgsState=");
        pw.println(mAllowStartFgsState);
        pw.print(mAllowStartFgsState);
        if (mBackgroundRestricted) {
            pw.print(" backgroundRestricted=");
            pw.print(mBackgroundRestricted);
            pw.print(" boundByNonBgRestrictedApp=");
            pw.print(mSetBoundByNonBgRestrictedApp);
        }
        pw.println();
        if (mHasShownUi || mApp.mProfile.hasPendingUiClean()) {
            pw.print(prefix); pw.print("hasShownUi="); pw.print(mHasShownUi);
            pw.print(" pendingUiClean="); pw.println(mApp.mProfile.hasPendingUiClean());
+12 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.app.ActivityManager;
import android.content.pm.PackageManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -282,6 +283,17 @@ public final class UidRecord {
        }
    }

    @GuardedBy(anyOf = {"mService", "mProcLock"})
    ProcessRecord getProcessInPackage(String packageName) {
        for (int i = mProcRecords.size() - 1; i >= 0; i--) {
            final ProcessRecord app = mProcRecords.valueAt(i);
            if (app != null && TextUtils.equals(app.info.packageName, packageName)) {
                return app;
            }
        }
        return null;
    }

    @GuardedBy({"mService", "mProcLock"})
    void addProcess(ProcessRecord app) {
        mProcRecords.add(app);