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

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

Merge "Kill bg restricted app when it's been cached & idle for a while"

parents ca098fee aed1e2ec
Loading
Loading
Loading
Loading
+14 −8
Original line number Diff line number Diff line
@@ -25,19 +25,25 @@ public interface AppStateTracker {
    String TAG = "AppStateTracker";

    /**
     * Register a {@link ServiceStateListener} to listen for forced-app-standby changes that should
     * affect services.
     * Register a {@link BackgroundRestrictedAppListener} to listen for background restricted mode
     * changes that should affect services etc.
     */
    void addServiceStateListener(@NonNull ServiceStateListener listener);
    void addBackgroundRestrictedAppListener(@NonNull BackgroundRestrictedAppListener listener);

    /**
     * A listener to listen to forced-app-standby changes that should affect services.
     * @return {code true} if the given UID/package has been in background restricted mode,
     * it does NOT include the case where the "force app background restricted" is enabled.
     */
    interface ServiceStateListener {
    boolean isAppBackgroundRestricted(int uid, @NonNull String packageName);

    /**
     * A listener to listen to background restricted mode changes that should affect services etc.
     */
    interface BackgroundRestrictedAppListener {
        /**
         * Called when an app goes into forced app standby and its foreground
         * services need to be removed from that state.
         * Called when an app goes in/out of background restricted mode.
         */
        void stopForegroundServicesForUidPackage(int uid, String packageName);
        void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
                boolean restricted);
    }
}
+62 −10
Original line number Diff line number Diff line
@@ -60,8 +60,10 @@ import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;

import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * Class to keep track of the information related to "force app standby", which includes:
@@ -160,16 +162,34 @@ public class AppStateTrackerImpl implements AppStateTracker {
    @GuardedBy("mLock")
    boolean mForcedAppStandbyEnabled;

    /**
     * A lock-free set of (uid, packageName) pairs in background restricted mode.
     *
     * <p>
     * It's bascially shadowing the {@link #mRunAnyRestrictedPackages} together with
     * the {@link #mForcedAppStandbyEnabled} - mutations on them would result in copy-on-write.
     * </p>
     */
    volatile Set<Pair<Integer, String>> mBackgroundRestrictedUidPackages = Collections.emptySet();

    @Override
    public void addServiceStateListener(@NonNull ServiceStateListener listener) {
    public void addBackgroundRestrictedAppListener(
            @NonNull BackgroundRestrictedAppListener listener) {
        addListener(new Listener() {
            @Override
            public void stopForegroundServicesForUidPackage(int uid, String packageName) {
                listener.stopForegroundServicesForUidPackage(uid, packageName);
            public void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
                    boolean restricted) {
                listener.updateBackgroundRestrictedForUidPackage(uid, packageName, restricted);
            }
        });
    }

    @Override
    public boolean isAppBackgroundRestricted(int uid, @NonNull String packageName) {
        final Set<Pair<Integer, String>> bgRestrictedUidPkgs = mBackgroundRestrictedUidPackages;
        return bgRestrictedUidPkgs.contains(Pair.create(uid, packageName));
    }

    interface Stats {
        int UID_FG_STATE_CHANGED = 0;
        int UID_ACTIVE_STATE_CHANGED = 1;
@@ -233,6 +253,7 @@ public class AppStateTrackerImpl implements AppStateTracker {
                        return;
                    }
                    mForcedAppStandbyEnabled = enabled;
                    updateBackgroundRestrictedUidPackagesLocked();
                    if (DEBUG) {
                        Slog.d(TAG, "Forced app standby feature flag changed: "
                                + mForcedAppStandbyEnabled);
@@ -277,7 +298,11 @@ public class AppStateTrackerImpl implements AppStateTracker {
            if (!sender.isRunAnyInBackgroundAppOpsAllowed(uid, packageName)) {
                Slog.v(TAG, "Package " + packageName + "/" + uid
                        + " toggled into fg service restriction");
                stopForegroundServicesForUidPackage(uid, packageName);
                updateBackgroundRestrictedForUidPackage(uid, packageName, true);
            } else {
                Slog.v(TAG, "Package " + packageName + "/" + uid
                        + " toggled out of fg service restriction");
                updateBackgroundRestrictedForUidPackage(uid, packageName, false);
            }
        }

@@ -366,10 +391,10 @@ public class AppStateTrackerImpl implements AppStateTracker {
        }

        /**
         * Called when an app goes into forced app standby and its foreground
         * services need to be removed from that state.
         * Called when an app goes in/out of background restricted mode.
         */
        public void stopForegroundServicesForUidPackage(int uid, String packageName) {
        public void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
                boolean restricted) {
        }

        /**
@@ -438,10 +463,13 @@ public class AppStateTrackerImpl implements AppStateTracker {
                        final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
                        // No need to notify for state change as all the alarms and jobs should be
                        // removed too.
                        synchronized (mLock) {
                            mExemptedBucketPackages.remove(userId, pkgName);
                            mRunAnyRestrictedPackages.remove(Pair.create(uid, pkgName));
                            updateBackgroundRestrictedUidPackagesLocked();
                            mActiveUids.delete(uid);
                        }
                    }
                    break;
            }
        }
@@ -580,6 +608,28 @@ public class AppStateTrackerImpl implements AppStateTracker {
                }
            }
        }
        updateBackgroundRestrictedUidPackagesLocked();
    }

    /**
     * Update the {@link #mBackgroundRestrictedUidPackages} upon mutations on
     * {@link #mRunAnyRestrictedPackages} or {@link #mForcedAppStandbyEnabled}.
     */
    @GuardedBy("mLock")
    private void updateBackgroundRestrictedUidPackagesLocked() {
        if (!mForcedAppStandbyEnabled) {
            mBackgroundRestrictedUidPackages = Collections.emptySet();
            return;
        }
        if (mForceAllAppsStandby) {
            mBackgroundRestrictedUidPackages = null;
            return;
        }
        Set<Pair<Integer, String>> fasUidPkgs = new ArraySet<>();
        for (int i = 0, size = mRunAnyRestrictedPackages.size(); i < size; i++) {
            fasUidPkgs.add(mRunAnyRestrictedPackages.valueAt(i));
        }
        mBackgroundRestrictedUidPackages = Collections.unmodifiableSet(fasUidPkgs);
    }

    private void updateForceAllAppStandbyState() {
@@ -645,6 +695,7 @@ public class AppStateTrackerImpl implements AppStateTracker {
        } else {
            mRunAnyRestrictedPackages.removeAt(index);
        }
        updateBackgroundRestrictedUidPackagesLocked();
        return true;
    }

@@ -966,6 +1017,7 @@ public class AppStateTrackerImpl implements AppStateTracker {
                    mRunAnyRestrictedPackages.removeAt(i);
                }
            }
            updateBackgroundRestrictedUidPackagesLocked();
            cleanUpArrayForUser(mActiveUids, removedUserId);
            mExemptedBucketPackages.remove(removedUserId);
        }
+25 −8
Original line number Diff line number Diff line
@@ -329,16 +329,25 @@ public final class ActiveServices {
    };

    /**
     * Watch for apps being put into forced app standby, so we can step their fg
     * Reference to the AppStateTracker service. No lock is needed as we'll assign with the same
     * instance to it always.
     */
    AppStateTracker mAppStateTracker;

    /**
     * Watch for apps being put into background restricted, so we can step their fg
     * services down.
     */
    class ForcedStandbyListener implements AppStateTracker.ServiceStateListener {
    class BackgroundRestrictedListener implements AppStateTracker.BackgroundRestrictedAppListener {
        @Override
        public void stopForegroundServicesForUidPackage(final int uid, final String packageName) {
        public void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
                boolean restricted) {
            synchronized (mAm) {
                if (!isForegroundServiceAllowedInBackgroundRestricted(uid, packageName)) {
                    stopAllForegroundServicesLocked(uid, packageName);
                }
                mAm.mProcessList.updateBackgroundRestrictedForUidPackageLocked(
                        uid, packageName, restricted);
            }
        }
    }
@@ -523,12 +532,18 @@ public final class ActiveServices {
    }

    void systemServicesReady() {
        AppStateTracker ast = LocalServices.getService(AppStateTracker.class);
        ast.addServiceStateListener(new ForcedStandbyListener());
        getAppStateTracker().addBackgroundRestrictedAppListener(new BackgroundRestrictedListener());
        mAppWidgetManagerInternal = LocalServices.getService(AppWidgetManagerInternal.class);
        setAllowListWhileInUsePermissionInFgs();
    }

    private AppStateTracker getAppStateTracker() {
        if (mAppStateTracker == null) {
            mAppStateTracker = LocalServices.getService(AppStateTracker.class);
        }
        return mAppStateTracker;
    }

    private void setAllowListWhileInUsePermissionInFgs() {
        final String attentionServicePackageName =
                mAm.mContext.getPackageManager().getAttentionServicePackageName();
@@ -607,9 +622,11 @@ public final class ActiveServices {
    }

    private boolean appRestrictedAnyInBackground(final int uid, final String packageName) {
        final int mode = mAm.getAppOpsManager().checkOpNoThrow(
                AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName);
        return (mode != AppOpsManager.MODE_ALLOWED);
        final AppStateTracker appStateTracker = getAppStateTracker();
        if (appStateTracker != null) {
            return appStateTracker.isAppBackgroundRestricted(uid, packageName);
        }
        return false;
    }

    void updateAppRestrictedAnyInBackgroundLocked(final int uid, final String packageName) {
+51 −2
Original line number Diff line number Diff line
@@ -56,7 +56,8 @@ final class ActivityManagerConstants extends ContentObserver {
    private static final String TAG = "ActivityManagerConstants";

    // Key names stored in the settings value.
    private static final String KEY_BACKGROUND_SETTLE_TIME = "background_settle_time";
    static final String KEY_BACKGROUND_SETTLE_TIME = "background_settle_time";

    private static final String KEY_FGSERVICE_MIN_SHOWN_TIME
            = "fgservice_min_shown_time";
    private static final String KEY_FGSERVICE_MIN_REPORT_TIME
@@ -119,9 +120,11 @@ final class ActivityManagerConstants extends ContentObserver {
            "extra_delay_svc_restart_mem_pressure";
    static final String KEY_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE =
            "enable_extra_delay_svc_restart_mem_pressure";
    static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE = "kill_bg_restricted_cached_idle";
    static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME =
            "kill_bg_restricted_cached_idle_settle_time";

    private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
    private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
    private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
    private static final long DEFAULT_FGSERVICE_MIN_REPORT_TIME = 3*1000;
    private static final long DEFAULT_FGSERVICE_SCREEN_ON_BEFORE_TIME = 1*1000;
@@ -164,6 +167,11 @@ final class ActivityManagerConstants extends ContentObserver {
    private static final float DEFAULT_FGS_ATOM_SAMPLE_RATE = 1; // 100 %
    private static final float DEFAULT_FGS_START_ALLOWED_LOG_SAMPLE_RATE = 0.25f; // 25%
    private static final float DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE = 1; // 100%

    static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60 * 1000;
    static final long DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS = 60 * 1000;
    static final boolean DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE = true;

    /**
     * Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
     */
@@ -540,6 +548,19 @@ final class ActivityManagerConstants extends ContentObserver {
     */
    volatile float mFgsStartDeniedLogSampleRate = DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE;

    /**
     * Whether or not to kill apps in background restricted mode and it's cached, its UID state is
     * idle.
     */
    volatile boolean mKillBgRestrictedAndCachedIdle = DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE;

    /**
     * The amount of time we allow an app in background restricted mode to settle after it goes
     * into the cached &amp; UID idle, before we decide to kill it.
     */
    volatile long mKillBgRestrictedAndCachedIdleSettleTimeMs =
            DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS;

    /**
     * Whether to allow "opt-out" from the foreground service restrictions.
     * (https://developer.android.com/about/versions/12/foreground-services)
@@ -776,6 +797,12 @@ final class ActivityManagerConstants extends ContentObserver {
                            case KEY_FGS_START_DENIED_LOG_SAMPLE_RATE:
                                updateFgsStartDeniedLogSamplePercent();
                                break;
                            case KEY_KILL_BG_RESTRICTED_CACHED_IDLE:
                                updateKillBgRestrictedCachedIdle();
                                break;
                            case KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME:
                                updateKillBgRestrictedCachedIdleSettleTime();
                                break;
                            case KEY_FGS_ALLOW_OPT_OUT:
                                updateFgsAllowOptOut();
                                break;
@@ -1142,6 +1169,28 @@ final class ActivityManagerConstants extends ContentObserver {
                DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE);
    }

    private void updateKillBgRestrictedCachedIdle() {
        mKillBgRestrictedAndCachedIdle = DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                KEY_KILL_BG_RESTRICTED_CACHED_IDLE,
                DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE);
    }

    private void updateKillBgRestrictedCachedIdleSettleTime() {
        final long currentSettleTime = mKillBgRestrictedAndCachedIdleSettleTimeMs;
        mKillBgRestrictedAndCachedIdleSettleTimeMs = DeviceConfig.getLong(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME,
                DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS);
        if (mKillBgRestrictedAndCachedIdleSettleTimeMs != currentSettleTime) {
            mService.mHandler.removeMessages(
                    ActivityManagerService.IDLE_UIDS_MSG);
            mService.mHandler.sendEmptyMessageDelayed(
                    ActivityManagerService.IDLE_UIDS_MSG,
                    mKillBgRestrictedAndCachedIdleSettleTimeMs);
        }
    }

    private void updateFgsAllowOptOut() {
        mFgsAllowOptOut = DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+13 −12
Original line number Diff line number Diff line
@@ -1832,18 +1832,6 @@ 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
@@ -9495,6 +9483,15 @@ public class ActivityManagerService extends IActivityManager.Stub
                TimeUtils.dumpTimeWithDelta(pw, expirationInCurrentTime, currentTimeNow);
                pw.println();
            });
            if (!mProcessList.mAppsInBackgroundRestricted.isEmpty()) {
                pw.println("  Processes that are in background restricted:");
                for (int i = 0, size = mProcessList.mAppsInBackgroundRestricted.size();
                        i < size; i++) {
                    pw.println(String.format("%s #%2d: %s", "    ", i,
                            mProcessList.mAppsInBackgroundRestricted.valueAt(i).toString()));
                }
            }
        }
        if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
                || mOrigWaitForDebugger) {
@@ -14441,6 +14438,10 @@ public class ActivityManagerService extends IActivityManager.Stub
        final int capability = uidRec != null ? uidRec.getSetCapability() : 0;
        final boolean ephemeral = uidRec != null ? uidRec.isEphemeral() : isEphemeralLocked(uid);
        if (uidRec != null && uidRec.isIdle() && (change & UidRecord.CHANGE_IDLE) != 0) {
            mProcessList.killAppIfBgRestrictedAndCachedIdleLocked(uidRec);
        }
        if (uidRec != null && !uidRec.isIdle() && (change & UidRecord.CHANGE_GONE) != 0) {
            // If this uid is going away, and we haven't yet reported it is gone,
            // then do so now.
Loading