Loading core/java/android/app/ActivityManagerInternal.java +8 −0 Original line number Diff line number Diff line Loading @@ -955,4 +955,12 @@ public abstract class ActivityManagerInternal { * @hide */ public abstract void stopForegroundServiceDelegate(@NonNull ServiceConnection connection); /** * Called by PowerManager. Return whether a given procstate is allowed to hold * wake locks in deep doze. Because it's called with the power manager lock held, we can't * hold AM locks in it. * @hide */ public abstract boolean canHoldWakeLocksInDeepDoze(int uid, int procstate); } services/core/java/com/android/server/am/ActivityManagerService.java +19 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS; import static android.app.ActivityManager.INSTR_FLAG_NO_RESTART; import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY; import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL; import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.app.ActivityManager.PROCESS_STATE_TOP; Loading Loading @@ -3341,6 +3342,7 @@ public class ActivityManagerService extends IActivityManager.Stub } mBatteryStatsService.noteProcessDied(app.info.uid, pid); mOomAdjuster.updateShortFgsOwner(app.info.uid, pid, false); if (!app.isKilled()) { if (!fromBinderDied) { Loading Loading @@ -18305,6 +18307,23 @@ public class ActivityManagerService extends IActivityManager.Stub public void unregisterStrictModeCallback(int callingPid) { mStrictModeCallbacks.remove(callingPid); } @Override public boolean canHoldWakeLocksInDeepDoze(int uid, int procstate) { // This method is called with the PowerManager lock held. Do not hold AM here. // If the procstate is high enough, it's always allowed. if (procstate <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { return true; } // IF it's too low, it's not allowed. if (procstate > PROCESS_STATE_IMPORTANT_FOREGROUND) { return false; } // If it's PROCESS_STATE_IMPORTANT_FOREGROUND, then we allow it only wheen the UID // has a SHORT_FGS. return mOomAdjuster.hasUidShortForegroundService(uid); } } long inputDispatchingTimedOut(int pid, final boolean aboveSystem, TimeoutRecord timeoutRecord) { services/core/java/com/android/server/am/OomAdjuster.java +59 −3 Original line number Diff line number Diff line Loading @@ -126,6 +126,7 @@ import android.os.Trace; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import android.util.SparseSetArray; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.CompositeRWLock; Loading Loading @@ -364,6 +365,19 @@ public class OomAdjuster { @GuardedBy("mService") private boolean mPendingFullOomAdjUpdate = false; /** * PIDs that has a SHORT_SERVICE. We need to access it with the PowerManager lock held, * so we use a fine-grained lock here. */ @GuardedBy("mPidsWithShortFgs") private final ArraySet<Integer> mPidsWithShortFgs = new ArraySet<>(); /** * UIDs -> PIDs map, used with mPidsWithShortFgs. */ @GuardedBy("mPidsWithShortFgs") private final SparseSetArray<Integer> mUidsToPidsWithShortFgs = new SparseSetArray<>(); /** Overrideable by a test */ @VisibleForTesting protected boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId, Loading Loading @@ -1849,6 +1863,11 @@ public class OomAdjuster { int capabilityFromFGS = 0; // capability from foreground service. final boolean hasForegroundServices = psr.hasForegroundServices(); final boolean hasNonShortForegroundServices = psr.hasNonShortForegroundServices(); final boolean hasShortForegroundServices = hasForegroundServices && !psr.areAllShortForegroundServicesProcstateTimedOut(now); // Adjust for FGS or "has-overlay-ui". if (adj > PERCEPTIBLE_APP_ADJ || procState > PROCESS_STATE_FOREGROUND_SERVICE) { Loading @@ -1856,7 +1875,7 @@ public class OomAdjuster { int newAdj = 0; int newProcState = 0; if (psr.hasForegroundServices() && psr.hasNonShortForegroundServices()) { if (hasForegroundServices && hasNonShortForegroundServices) { // For regular (non-short) FGS. adjType = "fg-service"; newAdj = PERCEPTIBLE_APP_ADJ; Loading @@ -1867,11 +1886,11 @@ public class OomAdjuster { newAdj = PERCEPTIBLE_APP_ADJ; newProcState = PROCESS_STATE_IMPORTANT_FOREGROUND; } else if (psr.hasForegroundServices()) { } else if (hasForegroundServices) { // If we get here, hasNonShortForegroundServices() must be false. // TODO(short-service): Proactively run OomAjudster when the grace period finish. if (psr.areAllShortForegroundServicesProcstateTimedOut(now)) { if (!hasShortForegroundServices) { // All the short-FGSes within this process are timed out. Don't promote to FGS. // TODO(short-service): Should we set some unique oom-adj to make it detectable, // in a long trace? Loading Loading @@ -1907,6 +1926,7 @@ public class OomAdjuster { } } } updateShortFgsOwner(psr.mApp.uid, psr.mApp.mPid, hasShortForegroundServices); // If the app was recently in the foreground and moved to a foreground service status, // allow it to get a higher rank in memory for some time, compared to other foreground Loading Loading @@ -3337,4 +3357,40 @@ public class OomAdjuster { mCachedAppOptimizer.unfreezeAppLSP(app, oomAdjReason); } } /** * Update {@link #mPidsWithShortFgs} and {@link #mUidsToPidsWithShortFgs} to keep track * of which UID/PID has a short FGS. * * TODO(short-FGS): Remove it and all the relevant code once SHORT_FGS use the FGS procstate. */ void updateShortFgsOwner(int uid, int pid, boolean add) { synchronized (mPidsWithShortFgs) { if (add) { mUidsToPidsWithShortFgs.add(uid, pid); mPidsWithShortFgs.add(pid); } else { mUidsToPidsWithShortFgs.remove(uid, pid); mPidsWithShortFgs.remove(pid); } } } /** * Whether a UID has a (non-timed-out) short FGS or not. * It's indirectly called by PowerManager, so we can't hold the AM lock in it. */ boolean hasUidShortForegroundService(int uid) { synchronized (mPidsWithShortFgs) { final ArraySet<Integer> pids = mUidsToPidsWithShortFgs.get(uid); if (pids == null || pids.size() == 0) { return false; } for (int i = pids.size() - 1; i >= 0; i--) { final int pid = pids.valueAt(i); return mPidsWithShortFgs.contains(pid); } } return false; } } services/core/java/com/android/server/power/PowerManagerService.java +5 −3 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; import android.app.SynchronousUserSwitchObserver; import android.content.BroadcastReceiver; Loading Loading @@ -311,6 +312,7 @@ public final class PowerManagerService extends SystemService private SettingsObserver mSettingsObserver; private DreamManagerInternal mDreamManager; private LogicalLight mAttentionLight; private ActivityManagerInternal mAmInternal; private final InattentiveSleepWarningController mInattentiveSleepWarningOverlayController; private final AmbientDisplaySuppressionController mAmbientDisplaySuppressionController; Loading Loading @@ -1237,6 +1239,7 @@ public final class PowerManagerService extends SystemService mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class); mPolicy = getLocalService(WindowManagerPolicy.class); mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class); mAmInternal = getLocalService(ActivityManagerInternal.class); mAttentionDetector.systemReady(mContext); SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper()); Loading Loading @@ -4077,9 +4080,8 @@ public final class PowerManagerService extends SystemService final UidState state = wakeLock.mUidState; if (Arrays.binarySearch(mDeviceIdleWhitelist, appid) < 0 && Arrays.binarySearch(mDeviceIdleTempWhitelist, appid) < 0 && state.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT && state.mProcState > ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { (mAmInternal != null && !mAmInternal.canHoldWakeLocksInDeepDoze( state.mUid, state.mProcState))) { disabled = true; } } Loading services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java +56 −0 Original line number Diff line number Diff line Loading @@ -305,4 +305,60 @@ public class OomAdjusterTests { assertEquals("Interaction event time was not updated correctly.", interactionEventTime, mProcessRecord.mState.getInteractionEventTime()); } private void updateShortFgsOwner(int uid, int pid, boolean add) { sService.mOomAdjuster.updateShortFgsOwner(uid, pid, add); } private void assertHasUidShortForegroundService(int uid, boolean expected) { assertEquals(expected, sService.mOomAdjuster.hasUidShortForegroundService(uid)); } @Test public void testHasUidShortForegroundService() { assertHasUidShortForegroundService(1, false); assertHasUidShortForegroundService(2, false); assertHasUidShortForegroundService(3, false); assertHasUidShortForegroundService(100, false); assertHasUidShortForegroundService(101, false); updateShortFgsOwner(1, 100, true); assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(100, false); assertHasUidShortForegroundService(2, false); updateShortFgsOwner(1, 101, true); assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(101, false); assertHasUidShortForegroundService(2, false); updateShortFgsOwner(2, 200, true); assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(2, true); assertHasUidShortForegroundService(200, false); updateShortFgsOwner(1, 101, false); assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(2, true); updateShortFgsOwner(1, 99, false); // unused PID assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(2, true); updateShortFgsOwner(1, 100, false); assertHasUidShortForegroundService(1, false); assertHasUidShortForegroundService(2, true); updateShortFgsOwner(1, 100, true); assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(2, true); updateShortFgsOwner(2, 200, false); assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(2, false); updateShortFgsOwner(2, 201, true); assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(2, true); } } Loading
core/java/android/app/ActivityManagerInternal.java +8 −0 Original line number Diff line number Diff line Loading @@ -955,4 +955,12 @@ public abstract class ActivityManagerInternal { * @hide */ public abstract void stopForegroundServiceDelegate(@NonNull ServiceConnection connection); /** * Called by PowerManager. Return whether a given procstate is allowed to hold * wake locks in deep doze. Because it's called with the power manager lock held, we can't * hold AM locks in it. * @hide */ public abstract boolean canHoldWakeLocksInDeepDoze(int uid, int procstate); }
services/core/java/com/android/server/am/ActivityManagerService.java +19 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS; import static android.app.ActivityManager.INSTR_FLAG_NO_RESTART; import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY; import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL; import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.app.ActivityManager.PROCESS_STATE_TOP; Loading Loading @@ -3341,6 +3342,7 @@ public class ActivityManagerService extends IActivityManager.Stub } mBatteryStatsService.noteProcessDied(app.info.uid, pid); mOomAdjuster.updateShortFgsOwner(app.info.uid, pid, false); if (!app.isKilled()) { if (!fromBinderDied) { Loading Loading @@ -18305,6 +18307,23 @@ public class ActivityManagerService extends IActivityManager.Stub public void unregisterStrictModeCallback(int callingPid) { mStrictModeCallbacks.remove(callingPid); } @Override public boolean canHoldWakeLocksInDeepDoze(int uid, int procstate) { // This method is called with the PowerManager lock held. Do not hold AM here. // If the procstate is high enough, it's always allowed. if (procstate <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { return true; } // IF it's too low, it's not allowed. if (procstate > PROCESS_STATE_IMPORTANT_FOREGROUND) { return false; } // If it's PROCESS_STATE_IMPORTANT_FOREGROUND, then we allow it only wheen the UID // has a SHORT_FGS. return mOomAdjuster.hasUidShortForegroundService(uid); } } long inputDispatchingTimedOut(int pid, final boolean aboveSystem, TimeoutRecord timeoutRecord) {
services/core/java/com/android/server/am/OomAdjuster.java +59 −3 Original line number Diff line number Diff line Loading @@ -126,6 +126,7 @@ import android.os.Trace; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import android.util.SparseSetArray; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.CompositeRWLock; Loading Loading @@ -364,6 +365,19 @@ public class OomAdjuster { @GuardedBy("mService") private boolean mPendingFullOomAdjUpdate = false; /** * PIDs that has a SHORT_SERVICE. We need to access it with the PowerManager lock held, * so we use a fine-grained lock here. */ @GuardedBy("mPidsWithShortFgs") private final ArraySet<Integer> mPidsWithShortFgs = new ArraySet<>(); /** * UIDs -> PIDs map, used with mPidsWithShortFgs. */ @GuardedBy("mPidsWithShortFgs") private final SparseSetArray<Integer> mUidsToPidsWithShortFgs = new SparseSetArray<>(); /** Overrideable by a test */ @VisibleForTesting protected boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId, Loading Loading @@ -1849,6 +1863,11 @@ public class OomAdjuster { int capabilityFromFGS = 0; // capability from foreground service. final boolean hasForegroundServices = psr.hasForegroundServices(); final boolean hasNonShortForegroundServices = psr.hasNonShortForegroundServices(); final boolean hasShortForegroundServices = hasForegroundServices && !psr.areAllShortForegroundServicesProcstateTimedOut(now); // Adjust for FGS or "has-overlay-ui". if (adj > PERCEPTIBLE_APP_ADJ || procState > PROCESS_STATE_FOREGROUND_SERVICE) { Loading @@ -1856,7 +1875,7 @@ public class OomAdjuster { int newAdj = 0; int newProcState = 0; if (psr.hasForegroundServices() && psr.hasNonShortForegroundServices()) { if (hasForegroundServices && hasNonShortForegroundServices) { // For regular (non-short) FGS. adjType = "fg-service"; newAdj = PERCEPTIBLE_APP_ADJ; Loading @@ -1867,11 +1886,11 @@ public class OomAdjuster { newAdj = PERCEPTIBLE_APP_ADJ; newProcState = PROCESS_STATE_IMPORTANT_FOREGROUND; } else if (psr.hasForegroundServices()) { } else if (hasForegroundServices) { // If we get here, hasNonShortForegroundServices() must be false. // TODO(short-service): Proactively run OomAjudster when the grace period finish. if (psr.areAllShortForegroundServicesProcstateTimedOut(now)) { if (!hasShortForegroundServices) { // All the short-FGSes within this process are timed out. Don't promote to FGS. // TODO(short-service): Should we set some unique oom-adj to make it detectable, // in a long trace? Loading Loading @@ -1907,6 +1926,7 @@ public class OomAdjuster { } } } updateShortFgsOwner(psr.mApp.uid, psr.mApp.mPid, hasShortForegroundServices); // If the app was recently in the foreground and moved to a foreground service status, // allow it to get a higher rank in memory for some time, compared to other foreground Loading Loading @@ -3337,4 +3357,40 @@ public class OomAdjuster { mCachedAppOptimizer.unfreezeAppLSP(app, oomAdjReason); } } /** * Update {@link #mPidsWithShortFgs} and {@link #mUidsToPidsWithShortFgs} to keep track * of which UID/PID has a short FGS. * * TODO(short-FGS): Remove it and all the relevant code once SHORT_FGS use the FGS procstate. */ void updateShortFgsOwner(int uid, int pid, boolean add) { synchronized (mPidsWithShortFgs) { if (add) { mUidsToPidsWithShortFgs.add(uid, pid); mPidsWithShortFgs.add(pid); } else { mUidsToPidsWithShortFgs.remove(uid, pid); mPidsWithShortFgs.remove(pid); } } } /** * Whether a UID has a (non-timed-out) short FGS or not. * It's indirectly called by PowerManager, so we can't hold the AM lock in it. */ boolean hasUidShortForegroundService(int uid) { synchronized (mPidsWithShortFgs) { final ArraySet<Integer> pids = mUidsToPidsWithShortFgs.get(uid); if (pids == null || pids.size() == 0) { return false; } for (int i = pids.size() - 1; i >= 0; i--) { final int pid = pids.valueAt(i); return mPidsWithShortFgs.contains(pid); } } return false; } }
services/core/java/com/android/server/power/PowerManagerService.java +5 −3 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; import android.app.SynchronousUserSwitchObserver; import android.content.BroadcastReceiver; Loading Loading @@ -311,6 +312,7 @@ public final class PowerManagerService extends SystemService private SettingsObserver mSettingsObserver; private DreamManagerInternal mDreamManager; private LogicalLight mAttentionLight; private ActivityManagerInternal mAmInternal; private final InattentiveSleepWarningController mInattentiveSleepWarningOverlayController; private final AmbientDisplaySuppressionController mAmbientDisplaySuppressionController; Loading Loading @@ -1237,6 +1239,7 @@ public final class PowerManagerService extends SystemService mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class); mPolicy = getLocalService(WindowManagerPolicy.class); mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class); mAmInternal = getLocalService(ActivityManagerInternal.class); mAttentionDetector.systemReady(mContext); SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper()); Loading Loading @@ -4077,9 +4080,8 @@ public final class PowerManagerService extends SystemService final UidState state = wakeLock.mUidState; if (Arrays.binarySearch(mDeviceIdleWhitelist, appid) < 0 && Arrays.binarySearch(mDeviceIdleTempWhitelist, appid) < 0 && state.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT && state.mProcState > ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { (mAmInternal != null && !mAmInternal.canHoldWakeLocksInDeepDoze( state.mUid, state.mProcState))) { disabled = true; } } Loading
services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java +56 −0 Original line number Diff line number Diff line Loading @@ -305,4 +305,60 @@ public class OomAdjusterTests { assertEquals("Interaction event time was not updated correctly.", interactionEventTime, mProcessRecord.mState.getInteractionEventTime()); } private void updateShortFgsOwner(int uid, int pid, boolean add) { sService.mOomAdjuster.updateShortFgsOwner(uid, pid, add); } private void assertHasUidShortForegroundService(int uid, boolean expected) { assertEquals(expected, sService.mOomAdjuster.hasUidShortForegroundService(uid)); } @Test public void testHasUidShortForegroundService() { assertHasUidShortForegroundService(1, false); assertHasUidShortForegroundService(2, false); assertHasUidShortForegroundService(3, false); assertHasUidShortForegroundService(100, false); assertHasUidShortForegroundService(101, false); updateShortFgsOwner(1, 100, true); assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(100, false); assertHasUidShortForegroundService(2, false); updateShortFgsOwner(1, 101, true); assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(101, false); assertHasUidShortForegroundService(2, false); updateShortFgsOwner(2, 200, true); assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(2, true); assertHasUidShortForegroundService(200, false); updateShortFgsOwner(1, 101, false); assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(2, true); updateShortFgsOwner(1, 99, false); // unused PID assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(2, true); updateShortFgsOwner(1, 100, false); assertHasUidShortForegroundService(1, false); assertHasUidShortForegroundService(2, true); updateShortFgsOwner(1, 100, true); assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(2, true); updateShortFgsOwner(2, 200, false); assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(2, false); updateShortFgsOwner(2, 201, true); assertHasUidShortForegroundService(1, true); assertHasUidShortForegroundService(2, true); } }