Loading services/core/java/com/android/server/am/CachedAppOptimizer.java +65 −17 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ApplicationExitInfo; import android.database.ContentObserver; import android.net.Uri; import android.os.Debug; import android.os.Handler; import android.os.Message; Loading Loading @@ -80,6 +82,8 @@ public final class CachedAppOptimizer { "compact_full_delta_rss_throttle_kb"; @VisibleForTesting static final String KEY_COMPACT_PROC_STATE_THROTTLE = "compact_proc_state_throttle"; @VisibleForTesting static final String KEY_FREEZER_DEBOUNCE_TIMEOUT = "freeze_debounce_timeout"; // Phenotype sends int configurations and we map them to the strings we'll use on device, // preventing a weird string value entering the kernel. Loading Loading @@ -116,6 +120,10 @@ public final class CachedAppOptimizer { // Format of this string should be a comma separated list of integers. @VisibleForTesting static final String DEFAULT_COMPACT_PROC_STATE_THROTTLE = String.valueOf(ActivityManager.PROCESS_STATE_RECEIVER); @VisibleForTesting static final long DEFAULT_FREEZER_DEBOUNCE_TIMEOUT = 600_000L; @VisibleForTesting static final Uri CACHED_APP_FREEZER_ENABLED_URI = Settings.Global.getUriFor( Settings.Global.CACHED_APPS_FREEZER_ENABLED); @VisibleForTesting interface PropertyChangedCallbackForTest { Loading @@ -141,9 +149,6 @@ public final class CachedAppOptimizer { static final int SET_FROZEN_PROCESS_MSG = 3; static final int REPORT_UNFREEZE_MSG = 4; //TODO:change this static definition into a configurable flag. static final long FREEZE_TIMEOUT_MS = 600000; static final int DO_FREEZE = 1; static final int REPORT_UNFREEZE = 2; Loading Loading @@ -198,6 +203,8 @@ public final class CachedAppOptimizer { updateMinOomAdjThrottle(); } else if (KEY_COMPACT_THROTTLE_MAX_OOM_ADJ.equals(name)) { updateMaxOomAdjThrottle(); } else if (KEY_FREEZER_DEBOUNCE_TIMEOUT.equals(name)) { updateFreezerDebounceTimeout(); } } } Loading @@ -207,6 +214,23 @@ public final class CachedAppOptimizer { } }; private final class SettingsContentObserver extends ContentObserver { SettingsContentObserver() { super(mAm.mHandler); } @Override public void onChange(boolean selfChange, Uri uri) { if (CACHED_APP_FREEZER_ENABLED_URI.equals(uri)) { synchronized (mPhenotypeFlagLock) { updateUseFreezer(); } } } } private final SettingsContentObserver mSettingsObserver; private final Object mPhenotypeFlagLock = new Object(); // Configured by phenotype. Updates from the server take effect immediately. Loading Loading @@ -259,6 +283,8 @@ public final class CachedAppOptimizer { @GuardedBy("mProcLock") private boolean mFreezerOverride = false; @VisibleForTesting volatile long mFreezerDebounceTimeout = DEFAULT_FREEZER_DEBOUNCE_TIMEOUT; // Maps process ID to last compaction statistics for processes that we've fully compacted. Used // when evaluating throttles that we only consider for "full" compaction, so we don't store // data for "some" compactions. Uses LinkedHashMap to ensure insertion order is kept and Loading Loading @@ -293,6 +319,7 @@ public final class CachedAppOptimizer { mProcStateThrottle = new HashSet<>(); mProcessDependencies = processDependencies; mTestCallback = callback; mSettingsObserver = new SettingsContentObserver(); } /** Loading @@ -303,6 +330,8 @@ public final class CachedAppOptimizer { // TODO: initialize flags to default and only update them if values are set in DeviceConfig DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, ActivityThread.currentApplication().getMainExecutor(), mOnFlagsChangedListener); mAm.mContext.getContentResolver().registerContentObserver( CACHED_APP_FREEZER_ENABLED_URI, false, mSettingsObserver); synchronized (mPhenotypeFlagLock) { updateUseCompaction(); updateCompactionActions(); Loading @@ -315,6 +344,7 @@ public final class CachedAppOptimizer { updateUseFreezer(); updateMinOomAdjThrottle(); updateMaxOomAdjThrottle(); updateFreezerDebounceTimeout(); } } Loading Loading @@ -367,6 +397,7 @@ public final class CachedAppOptimizer { + " processes."); pw.println(" " + KEY_USE_FREEZER + "=" + mUseFreezer); pw.println(" " + KEY_FREEZER_STATSD_SAMPLE_RATE + "=" + mFreezerStatsdSampleRate); pw.println(" " + KEY_FREEZER_DEBOUNCE_TIMEOUT + "=" + mFreezerDebounceTimeout); if (DEBUG_COMPACTION) { for (Map.Entry<Integer, LastCompactionStats> entry : mLastCompactionStats.entrySet()) { Loading Loading @@ -627,7 +658,10 @@ public final class CachedAppOptimizer { mUseFreezer = isFreezerSupported(); } if (mUseFreezer && mFreezeHandler == null) { final boolean useFreezer = mUseFreezer; // enableFreezer() would need the global ActivityManagerService lock, post it. mAm.mHandler.post(() -> { if (useFreezer) { Slog.d(TAG_AM, "Freezer enabled"); enableFreezer(true); Loading @@ -635,13 +669,17 @@ public final class CachedAppOptimizer { mCachedAppOptimizerThread.start(); } if (mFreezeHandler == null) { mFreezeHandler = new FreezeHandler(); } Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(), Process.THREAD_GROUP_SYSTEM); } else { Slog.d(TAG_AM, "Freezer disabled"); enableFreezer(false); } }); } @GuardedBy("mPhenotypeFlagLock") Loading Loading @@ -794,6 +832,16 @@ public final class CachedAppOptimizer { } } @GuardedBy("mPhenotypeFlagLock") private void updateFreezerDebounceTimeout() { mFreezerDebounceTimeout = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_FREEZER_DEBOUNCE_TIMEOUT, DEFAULT_FREEZER_DEBOUNCE_TIMEOUT); if (mFreezerDebounceTimeout < 0) { mFullDeltaRssThrottleKb = DEFAULT_FREEZER_DEBOUNCE_TIMEOUT; } } private boolean parseProcStateThrottle(String procStateThrottleString) { String[] procStates = TextUtils.split(procStateThrottleString, ","); mProcStateThrottle.clear(); Loading @@ -818,7 +866,7 @@ public final class CachedAppOptimizer { return COMPACT_ACTION_STRING[action]; } // This will ensure app will be out of the freezer for at least FREEZE_TIMEOUT_MS // This will ensure app will be out of the freezer for at least mFreezerDebounceTimeout. @GuardedBy("mAm") void unfreezeTemporarily(ProcessRecord app) { if (mUseFreezer) { Loading @@ -838,7 +886,7 @@ public final class CachedAppOptimizer { mFreezeHandler.sendMessageDelayed( mFreezeHandler.obtainMessage( SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app), FREEZE_TIMEOUT_MS); mFreezerDebounceTimeout); } @GuardedBy({"mAm", "mProcLock"}) Loading services/core/java/com/android/server/am/OomAdjuster.java +4 −0 Original line number Diff line number Diff line Loading @@ -2017,6 +2017,10 @@ public final class OomAdjuster { } String adjType = null; if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) { // Similar to BIND_WAIVE_PRIORITY, keep it unfrozen. if (clientAdj < ProcessList.CACHED_APP_MIN_ADJ) { app.mOptRecord.setShouldNotFreeze(true); } // Not doing bind OOM management, so treat // this guy more like a started service. if (state.hasShownUi() && !state.getCachedIsHomeProcess()) { Loading services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java +5 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.am; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; Loading @@ -28,6 +29,9 @@ final class ProcessCachedOptimizerRecord { private final ActivityManagerGlobalLock mProcLock; @VisibleForTesting static final String IS_FROZEN = "isFrozen"; /** * The last time that this process was compacted. */ Loading Loading @@ -169,5 +173,6 @@ final class ProcessCachedOptimizerRecord { void dump(PrintWriter pw, String prefix, long nowUptime) { pw.print(prefix); pw.print("lastCompactTime="); pw.print(mLastCompactTime); pw.print(" lastCompactAction="); pw.println(mLastCompactAction); pw.print(" " + IS_FROZEN + "="); pw.println(mFrozen); } } services/tests/servicestests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ android_test { "androidx.test.ext.truth", "androidx.test.runner", "androidx.test.rules", "cts-wm-util", "platform-compat-test-rules", "mockito-target-minus-junit4", "platform-test-annotations", Loading services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java +101 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,9 @@ import android.os.Messenger; import android.os.RemoteException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; import android.provider.Settings; import android.server.wm.settings.SettingsSession; import android.support.test.uiautomator.UiDevice; import android.test.suitebuilder.annotation.LargeTest; import android.text.TextUtils; Loading @@ -61,6 +64,8 @@ import java.io.IOException; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Tests for {@link ActivityManager}. Loading Loading @@ -316,6 +321,102 @@ public class ActivityManagerTest { } } @LargeTest @Test public void testAppFreezerWithAllowOomAdj() throws Exception { final long waitFor = 5000; boolean freezerWasEnabled = isFreezerEnabled(); SettingsSession<String> freezerEnabled = null; SettingsSession<String> amConstantsSettings = null; DeviceConfigSession<Long> freezerDebounceTimeout = null; MyServiceConnection autoConnection = null; try { if (!freezerWasEnabled) { freezerEnabled = new SettingsSession<>( Settings.Global.getUriFor(Settings.Global.CACHED_APPS_FREEZER_ENABLED), Settings.Global::getString, Settings.Global::putString); freezerEnabled.set("enabled"); Thread.sleep(waitFor); if (!isFreezerEnabled()) { // Still not enabled? Probably because the device doesn't support it. return; } } freezerDebounceTimeout = new DeviceConfigSession<>( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, CachedAppOptimizer.KEY_FREEZER_DEBOUNCE_TIMEOUT, DeviceConfig::getLong, CachedAppOptimizer.DEFAULT_FREEZER_DEBOUNCE_TIMEOUT); freezerDebounceTimeout.set(waitFor); final String activityManagerConstants = Settings.Global.ACTIVITY_MANAGER_CONSTANTS; amConstantsSettings = new SettingsSession<>( Settings.Global.getUriFor(activityManagerConstants), Settings.Global::getString, Settings.Global::putString); amConstantsSettings.set( ActivityManagerConstants.KEY_MAX_SERVICE_INACTIVITY + "=" + waitFor); final Intent intent = new Intent(); intent.setClassName(TEST_APP, TEST_CLASS); final CountDownLatch latch = new CountDownLatch(1); autoConnection = new MyServiceConnection(latch); mContext.bindService(intent, autoConnection, Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_OOM_MANAGEMENT); try { assertTrue("Timeout to bind to service " + intent.getComponent(), latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail("Unable to bind to service " + intent.getComponent()); } assertFalse(TEST_APP + " shouldn't be frozen now.", isAppFrozen(TEST_APP)); // Trigger oomAdjUpdate/ toggleScreenOn(false); toggleScreenOn(true); // Wait for the freezer kick in if there is any. Thread.sleep(waitFor * 4); // It still shouldn't be frozen, although it's been in cached state. assertFalse(TEST_APP + " shouldn't be frozen now.", isAppFrozen(TEST_APP)); } finally { toggleScreenOn(true); if (amConstantsSettings != null) { amConstantsSettings.close(); } if (freezerEnabled != null) { freezerEnabled.close(); } if (freezerDebounceTimeout != null) { freezerDebounceTimeout.close(); } if (autoConnection != null) { mContext.unbindService(autoConnection); } } } private boolean isFreezerEnabled() throws Exception { final String output = runShellCommand("dumpsys activity settings"); final Matcher matcher = Pattern.compile("\\b" + CachedAppOptimizer.KEY_USE_FREEZER + "\\b=\\b(true|false)\\b").matcher(output); if (matcher.find()) { return Boolean.parseBoolean(matcher.group(1)); } return false; } private boolean isAppFrozen(String packageName) throws Exception { final String output = runShellCommand("dumpsys activity p " + packageName); final Matcher matcher = Pattern.compile("\\b" + ProcessCachedOptimizerRecord.IS_FROZEN + "\\b=\\b(true|false)\\b").matcher(output); if (matcher.find()) { return Boolean.parseBoolean(matcher.group(1)); } return false; } /** * Make sure the screen state. */ Loading Loading
services/core/java/com/android/server/am/CachedAppOptimizer.java +65 −17 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ApplicationExitInfo; import android.database.ContentObserver; import android.net.Uri; import android.os.Debug; import android.os.Handler; import android.os.Message; Loading Loading @@ -80,6 +82,8 @@ public final class CachedAppOptimizer { "compact_full_delta_rss_throttle_kb"; @VisibleForTesting static final String KEY_COMPACT_PROC_STATE_THROTTLE = "compact_proc_state_throttle"; @VisibleForTesting static final String KEY_FREEZER_DEBOUNCE_TIMEOUT = "freeze_debounce_timeout"; // Phenotype sends int configurations and we map them to the strings we'll use on device, // preventing a weird string value entering the kernel. Loading Loading @@ -116,6 +120,10 @@ public final class CachedAppOptimizer { // Format of this string should be a comma separated list of integers. @VisibleForTesting static final String DEFAULT_COMPACT_PROC_STATE_THROTTLE = String.valueOf(ActivityManager.PROCESS_STATE_RECEIVER); @VisibleForTesting static final long DEFAULT_FREEZER_DEBOUNCE_TIMEOUT = 600_000L; @VisibleForTesting static final Uri CACHED_APP_FREEZER_ENABLED_URI = Settings.Global.getUriFor( Settings.Global.CACHED_APPS_FREEZER_ENABLED); @VisibleForTesting interface PropertyChangedCallbackForTest { Loading @@ -141,9 +149,6 @@ public final class CachedAppOptimizer { static final int SET_FROZEN_PROCESS_MSG = 3; static final int REPORT_UNFREEZE_MSG = 4; //TODO:change this static definition into a configurable flag. static final long FREEZE_TIMEOUT_MS = 600000; static final int DO_FREEZE = 1; static final int REPORT_UNFREEZE = 2; Loading Loading @@ -198,6 +203,8 @@ public final class CachedAppOptimizer { updateMinOomAdjThrottle(); } else if (KEY_COMPACT_THROTTLE_MAX_OOM_ADJ.equals(name)) { updateMaxOomAdjThrottle(); } else if (KEY_FREEZER_DEBOUNCE_TIMEOUT.equals(name)) { updateFreezerDebounceTimeout(); } } } Loading @@ -207,6 +214,23 @@ public final class CachedAppOptimizer { } }; private final class SettingsContentObserver extends ContentObserver { SettingsContentObserver() { super(mAm.mHandler); } @Override public void onChange(boolean selfChange, Uri uri) { if (CACHED_APP_FREEZER_ENABLED_URI.equals(uri)) { synchronized (mPhenotypeFlagLock) { updateUseFreezer(); } } } } private final SettingsContentObserver mSettingsObserver; private final Object mPhenotypeFlagLock = new Object(); // Configured by phenotype. Updates from the server take effect immediately. Loading Loading @@ -259,6 +283,8 @@ public final class CachedAppOptimizer { @GuardedBy("mProcLock") private boolean mFreezerOverride = false; @VisibleForTesting volatile long mFreezerDebounceTimeout = DEFAULT_FREEZER_DEBOUNCE_TIMEOUT; // Maps process ID to last compaction statistics for processes that we've fully compacted. Used // when evaluating throttles that we only consider for "full" compaction, so we don't store // data for "some" compactions. Uses LinkedHashMap to ensure insertion order is kept and Loading Loading @@ -293,6 +319,7 @@ public final class CachedAppOptimizer { mProcStateThrottle = new HashSet<>(); mProcessDependencies = processDependencies; mTestCallback = callback; mSettingsObserver = new SettingsContentObserver(); } /** Loading @@ -303,6 +330,8 @@ public final class CachedAppOptimizer { // TODO: initialize flags to default and only update them if values are set in DeviceConfig DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, ActivityThread.currentApplication().getMainExecutor(), mOnFlagsChangedListener); mAm.mContext.getContentResolver().registerContentObserver( CACHED_APP_FREEZER_ENABLED_URI, false, mSettingsObserver); synchronized (mPhenotypeFlagLock) { updateUseCompaction(); updateCompactionActions(); Loading @@ -315,6 +344,7 @@ public final class CachedAppOptimizer { updateUseFreezer(); updateMinOomAdjThrottle(); updateMaxOomAdjThrottle(); updateFreezerDebounceTimeout(); } } Loading Loading @@ -367,6 +397,7 @@ public final class CachedAppOptimizer { + " processes."); pw.println(" " + KEY_USE_FREEZER + "=" + mUseFreezer); pw.println(" " + KEY_FREEZER_STATSD_SAMPLE_RATE + "=" + mFreezerStatsdSampleRate); pw.println(" " + KEY_FREEZER_DEBOUNCE_TIMEOUT + "=" + mFreezerDebounceTimeout); if (DEBUG_COMPACTION) { for (Map.Entry<Integer, LastCompactionStats> entry : mLastCompactionStats.entrySet()) { Loading Loading @@ -627,7 +658,10 @@ public final class CachedAppOptimizer { mUseFreezer = isFreezerSupported(); } if (mUseFreezer && mFreezeHandler == null) { final boolean useFreezer = mUseFreezer; // enableFreezer() would need the global ActivityManagerService lock, post it. mAm.mHandler.post(() -> { if (useFreezer) { Slog.d(TAG_AM, "Freezer enabled"); enableFreezer(true); Loading @@ -635,13 +669,17 @@ public final class CachedAppOptimizer { mCachedAppOptimizerThread.start(); } if (mFreezeHandler == null) { mFreezeHandler = new FreezeHandler(); } Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(), Process.THREAD_GROUP_SYSTEM); } else { Slog.d(TAG_AM, "Freezer disabled"); enableFreezer(false); } }); } @GuardedBy("mPhenotypeFlagLock") Loading Loading @@ -794,6 +832,16 @@ public final class CachedAppOptimizer { } } @GuardedBy("mPhenotypeFlagLock") private void updateFreezerDebounceTimeout() { mFreezerDebounceTimeout = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_FREEZER_DEBOUNCE_TIMEOUT, DEFAULT_FREEZER_DEBOUNCE_TIMEOUT); if (mFreezerDebounceTimeout < 0) { mFullDeltaRssThrottleKb = DEFAULT_FREEZER_DEBOUNCE_TIMEOUT; } } private boolean parseProcStateThrottle(String procStateThrottleString) { String[] procStates = TextUtils.split(procStateThrottleString, ","); mProcStateThrottle.clear(); Loading @@ -818,7 +866,7 @@ public final class CachedAppOptimizer { return COMPACT_ACTION_STRING[action]; } // This will ensure app will be out of the freezer for at least FREEZE_TIMEOUT_MS // This will ensure app will be out of the freezer for at least mFreezerDebounceTimeout. @GuardedBy("mAm") void unfreezeTemporarily(ProcessRecord app) { if (mUseFreezer) { Loading @@ -838,7 +886,7 @@ public final class CachedAppOptimizer { mFreezeHandler.sendMessageDelayed( mFreezeHandler.obtainMessage( SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app), FREEZE_TIMEOUT_MS); mFreezerDebounceTimeout); } @GuardedBy({"mAm", "mProcLock"}) Loading
services/core/java/com/android/server/am/OomAdjuster.java +4 −0 Original line number Diff line number Diff line Loading @@ -2017,6 +2017,10 @@ public final class OomAdjuster { } String adjType = null; if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) { // Similar to BIND_WAIVE_PRIORITY, keep it unfrozen. if (clientAdj < ProcessList.CACHED_APP_MIN_ADJ) { app.mOptRecord.setShouldNotFreeze(true); } // Not doing bind OOM management, so treat // this guy more like a started service. if (state.hasShownUi() && !state.getCachedIsHomeProcess()) { Loading
services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java +5 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.am; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; Loading @@ -28,6 +29,9 @@ final class ProcessCachedOptimizerRecord { private final ActivityManagerGlobalLock mProcLock; @VisibleForTesting static final String IS_FROZEN = "isFrozen"; /** * The last time that this process was compacted. */ Loading Loading @@ -169,5 +173,6 @@ final class ProcessCachedOptimizerRecord { void dump(PrintWriter pw, String prefix, long nowUptime) { pw.print(prefix); pw.print("lastCompactTime="); pw.print(mLastCompactTime); pw.print(" lastCompactAction="); pw.println(mLastCompactAction); pw.print(" " + IS_FROZEN + "="); pw.println(mFrozen); } }
services/tests/servicestests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ android_test { "androidx.test.ext.truth", "androidx.test.runner", "androidx.test.rules", "cts-wm-util", "platform-compat-test-rules", "mockito-target-minus-junit4", "platform-test-annotations", Loading
services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java +101 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,9 @@ import android.os.Messenger; import android.os.RemoteException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; import android.provider.Settings; import android.server.wm.settings.SettingsSession; import android.support.test.uiautomator.UiDevice; import android.test.suitebuilder.annotation.LargeTest; import android.text.TextUtils; Loading @@ -61,6 +64,8 @@ import java.io.IOException; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Tests for {@link ActivityManager}. Loading Loading @@ -316,6 +321,102 @@ public class ActivityManagerTest { } } @LargeTest @Test public void testAppFreezerWithAllowOomAdj() throws Exception { final long waitFor = 5000; boolean freezerWasEnabled = isFreezerEnabled(); SettingsSession<String> freezerEnabled = null; SettingsSession<String> amConstantsSettings = null; DeviceConfigSession<Long> freezerDebounceTimeout = null; MyServiceConnection autoConnection = null; try { if (!freezerWasEnabled) { freezerEnabled = new SettingsSession<>( Settings.Global.getUriFor(Settings.Global.CACHED_APPS_FREEZER_ENABLED), Settings.Global::getString, Settings.Global::putString); freezerEnabled.set("enabled"); Thread.sleep(waitFor); if (!isFreezerEnabled()) { // Still not enabled? Probably because the device doesn't support it. return; } } freezerDebounceTimeout = new DeviceConfigSession<>( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, CachedAppOptimizer.KEY_FREEZER_DEBOUNCE_TIMEOUT, DeviceConfig::getLong, CachedAppOptimizer.DEFAULT_FREEZER_DEBOUNCE_TIMEOUT); freezerDebounceTimeout.set(waitFor); final String activityManagerConstants = Settings.Global.ACTIVITY_MANAGER_CONSTANTS; amConstantsSettings = new SettingsSession<>( Settings.Global.getUriFor(activityManagerConstants), Settings.Global::getString, Settings.Global::putString); amConstantsSettings.set( ActivityManagerConstants.KEY_MAX_SERVICE_INACTIVITY + "=" + waitFor); final Intent intent = new Intent(); intent.setClassName(TEST_APP, TEST_CLASS); final CountDownLatch latch = new CountDownLatch(1); autoConnection = new MyServiceConnection(latch); mContext.bindService(intent, autoConnection, Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_OOM_MANAGEMENT); try { assertTrue("Timeout to bind to service " + intent.getComponent(), latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail("Unable to bind to service " + intent.getComponent()); } assertFalse(TEST_APP + " shouldn't be frozen now.", isAppFrozen(TEST_APP)); // Trigger oomAdjUpdate/ toggleScreenOn(false); toggleScreenOn(true); // Wait for the freezer kick in if there is any. Thread.sleep(waitFor * 4); // It still shouldn't be frozen, although it's been in cached state. assertFalse(TEST_APP + " shouldn't be frozen now.", isAppFrozen(TEST_APP)); } finally { toggleScreenOn(true); if (amConstantsSettings != null) { amConstantsSettings.close(); } if (freezerEnabled != null) { freezerEnabled.close(); } if (freezerDebounceTimeout != null) { freezerDebounceTimeout.close(); } if (autoConnection != null) { mContext.unbindService(autoConnection); } } } private boolean isFreezerEnabled() throws Exception { final String output = runShellCommand("dumpsys activity settings"); final Matcher matcher = Pattern.compile("\\b" + CachedAppOptimizer.KEY_USE_FREEZER + "\\b=\\b(true|false)\\b").matcher(output); if (matcher.find()) { return Boolean.parseBoolean(matcher.group(1)); } return false; } private boolean isAppFrozen(String packageName) throws Exception { final String output = runShellCommand("dumpsys activity p " + packageName); final Matcher matcher = Pattern.compile("\\b" + ProcessCachedOptimizerRecord.IS_FROZEN + "\\b=\\b(true|false)\\b").matcher(output); if (matcher.find()) { return Boolean.parseBoolean(matcher.group(1)); } return false; } /** * Make sure the screen state. */ Loading