1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.am; 18 19 import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; 20 21 import static com.android.server.am.ActivityManagerService.Injector; 22 23 import static com.google.common.truth.Truth.assertThat; 24 25 import static org.mockito.Mockito.doReturn; 26 import static org.mockito.Mockito.spy; 27 28 import android.content.ComponentName; 29 import android.content.Context; 30 import android.content.pm.ApplicationInfo; 31 import android.content.pm.PackageManagerInternal; 32 import android.os.Handler; 33 import android.os.HandlerThread; 34 import android.os.MessageQueue; 35 import android.os.Process; 36 import android.platform.test.annotations.Presubmit; 37 import android.provider.DeviceConfig; 38 import android.text.TextUtils; 39 40 import androidx.test.platform.app.InstrumentationRegistry; 41 42 import com.android.modules.utils.testing.TestableDeviceConfig; 43 import com.android.server.ExtendedMockitoRule; 44 import com.android.server.LocalServices; 45 import com.android.server.ServiceThread; 46 import com.android.server.appop.AppOpsService; 47 import com.android.server.wm.ActivityTaskManagerService; 48 49 import org.junit.After; 50 import org.junit.Assume; 51 import org.junit.Before; 52 import org.junit.Rule; 53 import org.junit.Test; 54 import org.mockito.Mock; 55 56 import java.io.File; 57 import java.io.IOException; 58 import java.util.HashSet; 59 import java.util.Set; 60 import java.util.concurrent.CountDownLatch; 61 import java.util.concurrent.TimeUnit; 62 63 /** 64 * Tests for {@link CachedAppOptimizer}. 65 * 66 * Build/Install/Run: 67 * atest FrameworksMockingServicesTests:CachedAppOptimizerTest 68 */ 69 @Presubmit 70 public final class CachedAppOptimizerTest { 71 72 private ServiceThread mThread; 73 74 @Mock 75 private AppOpsService mAppOpsService; 76 private CachedAppOptimizer mCachedAppOptimizerUnderTest; 77 private HandlerThread mHandlerThread; 78 private Handler mHandler; 79 private CountDownLatch mCountDown; 80 private ActivityManagerService mAms; 81 private Context mContext; 82 private TestInjector mInjector; 83 private TestProcessDependencies mProcessDependencies; 84 85 @Mock 86 private PackageManagerInternal mPackageManagerInt; 87 88 private final TestableDeviceConfig mDeviceConfig = new TestableDeviceConfig(); 89 90 @Rule 91 public final ApplicationExitInfoTest.ServiceThreadRule 92 mServiceThreadRule = new ApplicationExitInfoTest.ServiceThreadRule(); 93 94 @Rule 95 public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) 96 .dynamiclyConfigureSessionBuilder( 97 sessionBuilder -> mDeviceConfig.setUpMockedClasses(sessionBuilder)) 98 .build(); 99 100 @Before setUp()101 public void setUp() { 102 System.loadLibrary("mockingservicestestjni"); 103 mDeviceConfig.setUpMockBehaviors(); 104 mHandlerThread = new HandlerThread(""); 105 mHandlerThread.start(); 106 mHandler = new Handler(mHandlerThread.getLooper()); 107 mThread = new ServiceThread("TestServiceThread", Process.THREAD_PRIORITY_DEFAULT, 108 true /* allowIo */); 109 mThread.start(); 110 mContext = InstrumentationRegistry.getInstrumentation().getContext(); 111 mInjector = new TestInjector(mContext); 112 mAms = new ActivityManagerService( 113 new TestInjector(mContext), mServiceThreadRule.getThread()); 114 doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent(); 115 mProcessDependencies = new TestProcessDependencies(); 116 mCachedAppOptimizerUnderTest = new CachedAppOptimizer(mAms, 117 new CachedAppOptimizer.PropertyChangedCallbackForTest() { 118 @Override 119 public void onPropertyChanged() { 120 if (mCountDown != null) { 121 mCountDown.countDown(); 122 } 123 } 124 }, mProcessDependencies); 125 LocalServices.removeServiceForTest(PackageManagerInternal.class); 126 LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt); 127 } 128 129 @After tearDown()130 public void tearDown() { 131 mHandlerThread.quit(); 132 mThread.quit(); 133 mCountDown = null; 134 mDeviceConfig.tearDown(); 135 } 136 makeProcessRecord(int pid, int uid, int packageUid, String processName, String packageName)137 private ProcessRecord makeProcessRecord(int pid, int uid, int packageUid, String processName, 138 String packageName) { 139 ApplicationInfo ai = new ApplicationInfo(); 140 ai.packageName = packageName; 141 ProcessRecord app = new ProcessRecord(mAms, ai, processName, uid); 142 app.setPid(pid); 143 app.info.uid = packageUid; 144 // Exact value does not mater, it can be any state for which compaction is allowed. 145 app.mState.setSetProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE); 146 app.mState.setSetAdj(899); 147 app.mState.setCurAdj(940); 148 return app; 149 } 150 151 @Test init_setsDefaults()152 public void init_setsDefaults() { 153 mCachedAppOptimizerUnderTest.init(); 154 synchronized (mCachedAppOptimizerUnderTest.mPhenotypeFlagLock) { 155 assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isEqualTo( 156 CachedAppOptimizer.DEFAULT_USE_COMPACTION); 157 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeSome).isEqualTo( 158 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1); 159 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeFull).isEqualTo( 160 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_2); 161 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullSome).isEqualTo( 162 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_3); 163 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullFull).isEqualTo( 164 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_4); 165 assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo( 166 CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE); 167 assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo( 168 CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE); 169 assertThat(mCachedAppOptimizerUnderTest.mFullAnonRssThrottleKb).isEqualTo( 170 CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB); 171 assertThat(mCachedAppOptimizerUnderTest.mFullDeltaRssThrottleKb).isEqualTo( 172 CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB); 173 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMinOomAdj).isEqualTo( 174 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ); 175 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMaxOomAdj).isEqualTo( 176 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ); 177 } 178 179 180 Set<Integer> expected = new HashSet<>(); 181 for (String s : TextUtils.split( 182 CachedAppOptimizer.DEFAULT_COMPACT_PROC_STATE_THROTTLE, ",")) { 183 expected.add(Integer.parseInt(s)); 184 } 185 assertThat(mCachedAppOptimizerUnderTest.mProcStateThrottle) 186 .containsExactlyElementsIn(expected); 187 188 Assume.assumeTrue(mCachedAppOptimizerUnderTest.isFreezerSupported()); 189 assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo( 190 CachedAppOptimizer.DEFAULT_USE_FREEZER); 191 } 192 193 @SuppressWarnings("GuardedBy") 194 @Test init_withDeviceConfigSetsParameters()195 public void init_withDeviceConfigSetsParameters() { 196 // When the DeviceConfig already has a flag value stored (note this test will need to 197 // change if the default value changes from false). 198 assertThat(CachedAppOptimizer.DEFAULT_USE_COMPACTION).isTrue(); 199 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 200 CachedAppOptimizer.KEY_USE_COMPACTION, "true", false); 201 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 202 CachedAppOptimizer.KEY_COMPACT_THROTTLE_1, 203 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1 + 1), false); 204 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 205 CachedAppOptimizer.KEY_COMPACT_THROTTLE_2, 206 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_2 + 1), false); 207 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 208 CachedAppOptimizer.KEY_COMPACT_THROTTLE_3, 209 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_3 + 1), false); 210 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 211 CachedAppOptimizer.KEY_COMPACT_THROTTLE_4, 212 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_4 + 1), false); 213 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 214 CachedAppOptimizer.KEY_COMPACT_THROTTLE_5, 215 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_5 + 1), false); 216 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 217 CachedAppOptimizer.KEY_COMPACT_THROTTLE_6, 218 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_6 + 1), false); 219 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 220 CachedAppOptimizer.KEY_COMPACT_STATSD_SAMPLE_RATE, 221 Float.toString(CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false); 222 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 223 CachedAppOptimizer.KEY_FREEZER_STATSD_SAMPLE_RATE, 224 Float.toString(CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false); 225 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 226 CachedAppOptimizer.KEY_COMPACT_FULL_RSS_THROTTLE_KB, 227 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1), false); 228 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 229 CachedAppOptimizer.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, 230 Long.toString( 231 CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1), false); 232 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 233 CachedAppOptimizer.KEY_COMPACT_THROTTLE_MIN_OOM_ADJ, 234 Long.toString( 235 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ + 10), false); 236 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 237 CachedAppOptimizer.KEY_COMPACT_THROTTLE_MAX_OOM_ADJ, 238 Long.toString( 239 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ - 10), false); 240 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 241 CachedAppOptimizer.KEY_COMPACT_PROC_STATE_THROTTLE, "1,2,3", false); 242 assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse(); 243 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 244 CachedAppOptimizer.KEY_USE_FREEZER, CachedAppOptimizer.DEFAULT_USE_FREEZER 245 ? "false" : "true", false); 246 247 // Then calling init will read and set that flag. 248 mCachedAppOptimizerUnderTest.init(); 249 assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isTrue(); 250 assertThat(mCachedAppOptimizerUnderTest.mCachedAppOptimizerThread.isAlive()).isTrue(); 251 252 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeSome).isEqualTo( 253 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1 + 1); 254 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeFull).isEqualTo( 255 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_2 + 1); 256 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullSome).isEqualTo( 257 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_3 + 1); 258 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullFull).isEqualTo( 259 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_4 + 1); 260 assertThat(mCachedAppOptimizerUnderTest.mFullDeltaRssThrottleKb).isEqualTo( 261 CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1); 262 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMinOomAdj).isEqualTo( 263 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ + 10); 264 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMaxOomAdj).isEqualTo( 265 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ - 10); 266 assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo( 267 CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f); 268 assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo( 269 CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f); 270 assertThat(mCachedAppOptimizerUnderTest.mFullAnonRssThrottleKb).isEqualTo( 271 CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1); 272 assertThat(mCachedAppOptimizerUnderTest.mProcStateThrottle).containsExactly(1, 2, 3); 273 274 Assume.assumeTrue(CachedAppOptimizer.isFreezerSupported()); 275 if (CachedAppOptimizer.isFreezerSupported()) { 276 if (CachedAppOptimizer.DEFAULT_USE_FREEZER) { 277 assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse(); 278 } else { 279 assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isTrue(); 280 } 281 } 282 } 283 284 @Test useCompaction_listensToDeviceConfigChanges()285 public void useCompaction_listensToDeviceConfigChanges() throws InterruptedException { 286 assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isEqualTo( 287 CachedAppOptimizer.DEFAULT_USE_COMPACTION); 288 // When we call init and change some the flag value... 289 mCachedAppOptimizerUnderTest.init(); 290 mCountDown = new CountDownLatch(1); 291 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 292 CachedAppOptimizer.KEY_USE_COMPACTION, "true", false); 293 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 294 295 // Then that new flag value is updated in the implementation. 296 assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isTrue(); 297 assertThat(mCachedAppOptimizerUnderTest.mCachedAppOptimizerThread.isAlive()).isTrue(); 298 299 // And again, setting the flag the other way. 300 mCountDown = new CountDownLatch(1); 301 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 302 CachedAppOptimizer.KEY_USE_COMPACTION, "false", false); 303 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 304 assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isFalse(); 305 } 306 307 @Test useFreeze_doesNotListenToDeviceConfigChanges()308 public void useFreeze_doesNotListenToDeviceConfigChanges() throws InterruptedException { 309 Assume.assumeTrue(CachedAppOptimizer.isFreezerSupported()); 310 311 assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse(); 312 313 // The freezer DeviceConfig property is read at boot only 314 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 315 CachedAppOptimizer.KEY_USE_FREEZER, "true", false); 316 mCachedAppOptimizerUnderTest.init(); 317 assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isTrue(); 318 mCountDown = new CountDownLatch(1); 319 320 // No notifications should get to the cached app optimizer. 321 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isFalse(); 322 323 // The flag value has to be set correctly. 324 assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isTrue(); 325 // The cached app optimizer thread must be running. 326 assertThat(mCachedAppOptimizerUnderTest.mCachedAppOptimizerThread.isAlive()).isTrue(); 327 328 // Set the flag the other way without rebooting. It shall not change. 329 mCountDown = new CountDownLatch(1); 330 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 331 CachedAppOptimizer.KEY_USE_FREEZER, "false", false); 332 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 333 assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isTrue(); 334 335 // Now, set the flag to false and restart the cached app optimizer 336 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 337 CachedAppOptimizer.KEY_USE_FREEZER, "false", false); 338 mCachedAppOptimizerUnderTest.init(); 339 340 // The flag value has to be set correctly. 341 assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse(); 342 } 343 344 @Test useCompaction_listensToDeviceConfigChangesBadValues()345 public void useCompaction_listensToDeviceConfigChangesBadValues() throws InterruptedException { 346 assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isEqualTo( 347 CachedAppOptimizer.DEFAULT_USE_COMPACTION); 348 mCachedAppOptimizerUnderTest.init(); 349 350 // When we push an invalid flag value... 351 mCountDown = new CountDownLatch(1); 352 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 353 CachedAppOptimizer.KEY_USE_COMPACTION, "foobar", false); 354 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 355 356 // Invalid value is mapped to false 357 assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isEqualTo(false); 358 } 359 360 @Test useFreeze_listensToDeviceConfigChangesBadValues()361 public void useFreeze_listensToDeviceConfigChangesBadValues() throws InterruptedException { 362 Assume.assumeTrue(CachedAppOptimizer.isFreezerSupported()); 363 assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse(); 364 365 // When we push an invalid flag value... 366 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 367 CachedAppOptimizer.KEY_USE_FREEZER, "foobar", false); 368 369 mCachedAppOptimizerUnderTest.init(); 370 371 // DeviceConfig treats invalid value as false 372 assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse(); 373 } 374 375 @Test compactThrottle_listensToDeviceConfigChanges()376 public void compactThrottle_listensToDeviceConfigChanges() throws InterruptedException { 377 mCachedAppOptimizerUnderTest.init(); 378 379 // When we override new reasonable throttle values after init... 380 mCountDown = new CountDownLatch(8); 381 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 382 CachedAppOptimizer.KEY_COMPACT_THROTTLE_1, 383 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1 + 1), false); 384 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 385 CachedAppOptimizer.KEY_COMPACT_THROTTLE_2, 386 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_2 + 1), false); 387 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 388 CachedAppOptimizer.KEY_COMPACT_THROTTLE_3, 389 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_3 + 1), false); 390 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 391 CachedAppOptimizer.KEY_COMPACT_THROTTLE_4, 392 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_4 + 1), false); 393 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 394 CachedAppOptimizer.KEY_COMPACT_THROTTLE_5, 395 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_5 + 1), false); 396 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 397 CachedAppOptimizer.KEY_COMPACT_THROTTLE_6, 398 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_6 + 1), false); 399 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 400 CachedAppOptimizer.KEY_COMPACT_THROTTLE_MIN_OOM_ADJ, 401 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ + 1), false); 402 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 403 CachedAppOptimizer.KEY_COMPACT_THROTTLE_MAX_OOM_ADJ, 404 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ - 1), false); 405 assertThat(mCountDown.await(7, TimeUnit.SECONDS)).isTrue(); 406 407 // Then those flags values are reflected in the compactor. 408 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeSome).isEqualTo( 409 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1 + 1); 410 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeFull).isEqualTo( 411 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_2 + 1); 412 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullSome).isEqualTo( 413 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_3 + 1); 414 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullFull).isEqualTo( 415 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_4 + 1); 416 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMinOomAdj).isEqualTo( 417 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ + 1); 418 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMaxOomAdj).isEqualTo( 419 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ - 1); 420 } 421 422 @Test compactThrottle_listensToDeviceConfigChangesBadValues()423 public void compactThrottle_listensToDeviceConfigChangesBadValues() 424 throws InterruptedException { 425 mCachedAppOptimizerUnderTest.init(); 426 427 // When one of the throttles is overridden with a bad value... 428 mCountDown = new CountDownLatch(1); 429 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 430 CachedAppOptimizer.KEY_COMPACT_THROTTLE_1, "foo", false); 431 // Then all the throttles have the defaults set. 432 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 433 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeSome).isEqualTo( 434 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1); 435 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeFull).isEqualTo( 436 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_2); 437 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullSome).isEqualTo( 438 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_3); 439 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullFull).isEqualTo( 440 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_4); 441 442 // Repeat for each of the throttle keys. 443 mCountDown = new CountDownLatch(1); 444 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 445 CachedAppOptimizer.KEY_COMPACT_THROTTLE_2, "foo", false); 446 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 447 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeSome).isEqualTo( 448 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1); 449 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeFull).isEqualTo( 450 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_2); 451 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullSome).isEqualTo( 452 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_3); 453 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullFull).isEqualTo( 454 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_4); 455 456 mCountDown = new CountDownLatch(1); 457 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 458 CachedAppOptimizer.KEY_COMPACT_THROTTLE_3, "foo", false); 459 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 460 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeSome).isEqualTo( 461 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1); 462 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeFull).isEqualTo( 463 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_2); 464 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullSome).isEqualTo( 465 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_3); 466 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullFull).isEqualTo( 467 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_4); 468 469 mCountDown = new CountDownLatch(1); 470 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 471 CachedAppOptimizer.KEY_COMPACT_THROTTLE_4, "foo", false); 472 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 473 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeSome).isEqualTo( 474 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1); 475 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeFull).isEqualTo( 476 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_2); 477 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullSome).isEqualTo( 478 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_3); 479 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullFull).isEqualTo( 480 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_4); 481 482 mCountDown = new CountDownLatch(1); 483 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 484 CachedAppOptimizer.KEY_COMPACT_THROTTLE_5, "foo", false); 485 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 486 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeSome).isEqualTo( 487 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1); 488 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeFull).isEqualTo( 489 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_2); 490 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullSome).isEqualTo( 491 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_3); 492 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullFull).isEqualTo( 493 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_4); 494 495 mCountDown = new CountDownLatch(1); 496 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 497 CachedAppOptimizer.KEY_COMPACT_THROTTLE_6, "foo", false); 498 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 499 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeSome).isEqualTo( 500 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1); 501 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeFull).isEqualTo( 502 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_2); 503 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullSome).isEqualTo( 504 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_3); 505 assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullFull).isEqualTo( 506 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_4); 507 } 508 509 @Test statsdSampleRate_listensToDeviceConfigChanges()510 public void statsdSampleRate_listensToDeviceConfigChanges() throws InterruptedException { 511 mCachedAppOptimizerUnderTest.init(); 512 513 // When we override mCompactStatsdSampleRate with a reasonable value ... 514 mCountDown = new CountDownLatch(1); 515 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 516 CachedAppOptimizer.KEY_COMPACT_STATSD_SAMPLE_RATE, 517 Float.toString(CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false); 518 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 519 520 // Then that override is reflected in the compactor. 521 assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo( 522 CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f); 523 524 // When we override mFreezerStatsdSampleRate with a reasonable value ... 525 mCountDown = new CountDownLatch(1); 526 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 527 CachedAppOptimizer.KEY_FREEZER_STATSD_SAMPLE_RATE, 528 Float.toString(CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false); 529 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 530 531 // Then that override is reflected in the compactor. 532 assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo( 533 CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f); 534 } 535 536 @Test statsdSampleRate_listensToDeviceConfigChangesBadValues()537 public void statsdSampleRate_listensToDeviceConfigChangesBadValues() 538 throws InterruptedException { 539 mCachedAppOptimizerUnderTest.init(); 540 541 // When we override mCompactStatsdSampleRate with an unreasonable value ... 542 mCountDown = new CountDownLatch(1); 543 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 544 CachedAppOptimizer.KEY_COMPACT_STATSD_SAMPLE_RATE, "foo", false); 545 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 546 547 // Then that override is reflected in the compactor. 548 assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo( 549 CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE); 550 551 // When we override mFreezerStatsdSampleRate with an unreasonable value ... 552 mCountDown = new CountDownLatch(1); 553 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 554 CachedAppOptimizer.KEY_FREEZER_STATSD_SAMPLE_RATE, "foo", false); 555 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 556 557 // Then that override is reflected in the freezer. 558 assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo( 559 CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE); 560 } 561 562 @Test statsdSampleRate_listensToDeviceConfigChangesOutOfRangeValues()563 public void statsdSampleRate_listensToDeviceConfigChangesOutOfRangeValues() 564 throws InterruptedException { 565 mCachedAppOptimizerUnderTest.init(); 566 567 // When we override mCompactStatsdSampleRate with an value outside of [0..1]... 568 mCountDown = new CountDownLatch(1); 569 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 570 CachedAppOptimizer.KEY_COMPACT_STATSD_SAMPLE_RATE, 571 Float.toString(-1.0f), false); 572 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 573 574 // Then the values is capped in the range. 575 assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo(0.0f); 576 577 mCountDown = new CountDownLatch(1); 578 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 579 CachedAppOptimizer.KEY_COMPACT_STATSD_SAMPLE_RATE, 580 Float.toString(1.01f), false); 581 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 582 583 // Then the values is capped in the range. 584 assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo(1.0f); 585 586 // When we override mFreezerStatsdSampleRate with an value outside of [0..1]... 587 mCountDown = new CountDownLatch(1); 588 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 589 CachedAppOptimizer.KEY_FREEZER_STATSD_SAMPLE_RATE, 590 Float.toString(-1.0f), false); 591 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 592 593 // Then the values is capped in the range. 594 assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo(0.0f); 595 596 mCountDown = new CountDownLatch(1); 597 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 598 CachedAppOptimizer.KEY_FREEZER_STATSD_SAMPLE_RATE, 599 Float.toString(1.01f), false); 600 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 601 602 // Then the values is capped in the range. 603 assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo(1.0f); 604 } 605 606 @Test fullCompactionRssThrottleKb_listensToDeviceConfigChanges()607 public void fullCompactionRssThrottleKb_listensToDeviceConfigChanges() 608 throws InterruptedException { 609 mCachedAppOptimizerUnderTest.init(); 610 611 // When we override mStatsdSampleRate with a reasonable value ... 612 mCountDown = new CountDownLatch(1); 613 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 614 CachedAppOptimizer.KEY_COMPACT_FULL_RSS_THROTTLE_KB, 615 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1), false); 616 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 617 618 // Then that override is reflected in the compactor. 619 assertThat(mCachedAppOptimizerUnderTest.mFullAnonRssThrottleKb).isEqualTo( 620 CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1); 621 } 622 623 @Test fullCompactionRssThrottleKb_listensToDeviceConfigChangesBadValues()624 public void fullCompactionRssThrottleKb_listensToDeviceConfigChangesBadValues() 625 throws InterruptedException { 626 mCachedAppOptimizerUnderTest.init(); 627 628 // When we override mStatsdSampleRate with an unreasonable value ... 629 mCountDown = new CountDownLatch(1); 630 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 631 CachedAppOptimizer.KEY_COMPACT_FULL_RSS_THROTTLE_KB, "foo", false); 632 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 633 634 // Then that override is reflected in the compactor. 635 assertThat(mCachedAppOptimizerUnderTest.mFullAnonRssThrottleKb).isEqualTo( 636 CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB); 637 638 mCountDown = new CountDownLatch(1); 639 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 640 CachedAppOptimizer.KEY_COMPACT_FULL_RSS_THROTTLE_KB, "-100", false); 641 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 642 643 // Then that override is reflected in the compactor. 644 assertThat(mCachedAppOptimizerUnderTest.mFullAnonRssThrottleKb).isEqualTo( 645 CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB); 646 } 647 648 @Test fullCompactionDeltaRssThrottleKb_listensToDeviceConfigChanges()649 public void fullCompactionDeltaRssThrottleKb_listensToDeviceConfigChanges() 650 throws InterruptedException { 651 mCachedAppOptimizerUnderTest.init(); 652 653 // When we override mStatsdSampleRate with a reasonable value ... 654 mCountDown = new CountDownLatch(1); 655 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 656 CachedAppOptimizer.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, 657 Long.toString( 658 CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1), false); 659 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 660 661 // Then that override is reflected in the compactor. 662 assertThat(mCachedAppOptimizerUnderTest.mFullDeltaRssThrottleKb).isEqualTo( 663 CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1); 664 } 665 666 @Test fullCompactionDeltaRssThrottleKb_listensToDeviceConfigChangesBadValues()667 public void fullCompactionDeltaRssThrottleKb_listensToDeviceConfigChangesBadValues() 668 throws InterruptedException { 669 mCachedAppOptimizerUnderTest.init(); 670 671 // When we override mStatsdSampleRate with an unreasonable value ... 672 mCountDown = new CountDownLatch(1); 673 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 674 CachedAppOptimizer.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, "foo", false); 675 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 676 677 // Then that override is reflected in the compactor. 678 assertThat(mCachedAppOptimizerUnderTest.mFullDeltaRssThrottleKb).isEqualTo( 679 CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB); 680 681 mCountDown = new CountDownLatch(1); 682 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 683 CachedAppOptimizer.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, "-100", false); 684 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 685 686 // Then that override is reflected in the compactor. 687 assertThat(mCachedAppOptimizerUnderTest.mFullDeltaRssThrottleKb).isEqualTo( 688 CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB); 689 } 690 691 @Test procStateThrottle_listensToDeviceConfigChanges()692 public void procStateThrottle_listensToDeviceConfigChanges() 693 throws InterruptedException { 694 mCachedAppOptimizerUnderTest.init(); 695 mCountDown = new CountDownLatch(1); 696 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 697 CachedAppOptimizer.KEY_COMPACT_PROC_STATE_THROTTLE, "1,2,3", false); 698 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 699 assertThat(mCachedAppOptimizerUnderTest.mProcStateThrottle).containsExactly(1, 2, 3); 700 701 mCountDown = new CountDownLatch(1); 702 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 703 CachedAppOptimizer.KEY_COMPACT_PROC_STATE_THROTTLE, "", false); 704 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 705 assertThat(mCachedAppOptimizerUnderTest.mProcStateThrottle).isEmpty(); 706 } 707 708 @Test procStateThrottle_listensToDeviceConfigChangesBadValues()709 public void procStateThrottle_listensToDeviceConfigChangesBadValues() 710 throws InterruptedException { 711 mCachedAppOptimizerUnderTest.init(); 712 713 Set<Integer> expected = new HashSet<>(); 714 for (String s : TextUtils.split( 715 CachedAppOptimizer.DEFAULT_COMPACT_PROC_STATE_THROTTLE, ",")) { 716 expected.add(Integer.parseInt(s)); 717 } 718 719 // Not numbers 720 mCountDown = new CountDownLatch(1); 721 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 722 CachedAppOptimizer.KEY_COMPACT_PROC_STATE_THROTTLE, "foo", false); 723 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 724 assertThat(mCachedAppOptimizerUnderTest.mProcStateThrottle) 725 .containsExactlyElementsIn(expected); 726 mCountDown = new CountDownLatch(1); 727 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 728 CachedAppOptimizer.KEY_COMPACT_PROC_STATE_THROTTLE, "1,foo", false); 729 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 730 assertThat(mCachedAppOptimizerUnderTest.mProcStateThrottle) 731 .containsExactlyElementsIn(expected); 732 733 // Empty splits 734 mCountDown = new CountDownLatch(1); 735 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 736 CachedAppOptimizer.KEY_COMPACT_PROC_STATE_THROTTLE, ",", false); 737 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 738 assertThat(mCachedAppOptimizerUnderTest.mProcStateThrottle) 739 .containsExactlyElementsIn(expected); 740 mCountDown = new CountDownLatch(1); 741 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 742 CachedAppOptimizer.KEY_COMPACT_PROC_STATE_THROTTLE, ",,3", false); 743 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 744 assertThat(mCachedAppOptimizerUnderTest.mProcStateThrottle) 745 .containsExactlyElementsIn(expected); 746 mCountDown = new CountDownLatch(1); 747 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 748 CachedAppOptimizer.KEY_COMPACT_PROC_STATE_THROTTLE, "1,,3", false); 749 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 750 assertThat(mCachedAppOptimizerUnderTest.mProcStateThrottle) 751 .containsExactlyElementsIn(expected); 752 } 753 754 @SuppressWarnings("GuardedBy") 755 @Test processWithDeltaRSSTooSmall_notFullCompacted()756 public void processWithDeltaRSSTooSmall_notFullCompacted() throws Exception { 757 // Initialize CachedAppOptimizer and set flags to (1) enable compaction, (2) set RSS 758 // throttle to 12000. 759 mCachedAppOptimizerUnderTest.init(); 760 setFlag(CachedAppOptimizer.KEY_USE_COMPACTION, "true", true); 761 setFlag(CachedAppOptimizer.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, "12000", false); 762 initActivityManagerService(); 763 764 // Simulate RSS anon memory larger than throttle. 765 long[] rssBefore1 = 766 new long[]{/*totalRSS*/ 10000, /*fileRSS*/ 10000, /*anonRSS*/ 12000, /*swap*/ 767 10000}; 768 long[] rssAfter1 = 769 new long[]{/*totalRSS*/ 9000, /*fileRSS*/ 9000, /*anonRSS*/ 11000, /*swap*/9000}; 770 // Delta between rssAfter1 and rssBefore2 is below threshold (500). 771 long[] rssBefore2 = 772 new long[]{/*totalRSS*/ 9500, /*fileRSS*/ 9500, /*anonRSS*/ 11500, /*swap*/9500}; 773 long[] rssAfter2 = 774 new long[]{/*totalRSS*/ 8000, /*fileRSS*/ 8000, /*anonRSS*/ 9000, /*swap*/8000}; 775 // Delta between rssAfter1 and rssBefore3 is above threshold (13000). 776 long[] rssBefore3 = 777 new long[]{/*totalRSS*/ 10000, /*fileRSS*/ 18000, /*anonRSS*/ 13000, /*swap*/ 7000}; 778 long[] rssAfter3 = 779 new long[]{/*totalRSS*/ 10000, /*fileRSS*/ 11000, /*anonRSS*/ 10000, /*swap*/ 6000}; 780 long[] valuesAfter = {}; 781 // Process that passes properties. 782 int pid = 1; 783 ProcessRecord processRecord = makeProcessRecord(pid, 2, 3, "p1", "app1"); 784 785 // GIVEN we simulate RSS memory before above thresholds and it is the first time 'p1' is 786 // compacted. 787 mProcessDependencies.setRss(rssBefore1); 788 mProcessDependencies.setRssAfterCompaction(rssAfter1); // 789 // WHEN we try to run compaction 790 mCachedAppOptimizerUnderTest.compactApp(processRecord, 791 CachedAppOptimizer.CompactProfile.FULL, CachedAppOptimizer.CompactSource.APP, 792 false); 793 waitForHandler(); 794 // THEN process IS compacted. 795 assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull(); 796 valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats.get( 797 pid).getRssAfterCompaction(); 798 assertThat(valuesAfter).isEqualTo(rssAfter1); 799 800 // WHEN delta is below threshold (500). 801 mProcessDependencies.setRss(rssBefore2); 802 mProcessDependencies.setRssAfterCompaction(rssAfter2); 803 // This is to avoid throttle of compacting too soon. 804 processRecord.mOptRecord.setLastCompactTime( 805 processRecord.mOptRecord.getLastCompactTime() - 10_000); 806 // WHEN we try to run compaction. 807 mCachedAppOptimizerUnderTest.compactApp(processRecord, 808 CachedAppOptimizer.CompactProfile.FULL, CachedAppOptimizer.CompactSource.APP, 809 false); 810 waitForHandler(); 811 // THEN process IS NOT compacted - values after compaction for process 1 should remain the 812 // same as from the last compaction. 813 assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull(); 814 valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats.get( 815 pid).getRssAfterCompaction(); 816 assertThat(valuesAfter).isEqualTo(rssAfter1); 817 818 // WHEN delta is above threshold (13000). 819 mProcessDependencies.setRss(rssBefore3); 820 mProcessDependencies.setRssAfterCompaction(rssAfter3); 821 // This is to avoid throttle of compacting too soon. 822 processRecord.mOptRecord.setLastCompactTime( 823 processRecord.mOptRecord.getLastCompactTime() - 10_000); 824 // WHEN we try to run compaction 825 mCachedAppOptimizerUnderTest.compactApp(processRecord, 826 CachedAppOptimizer.CompactProfile.FULL, CachedAppOptimizer.CompactSource.APP, 827 false); 828 waitForHandler(); 829 // THEN process IS compacted - values after compaction for process 1 should be updated. 830 assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull(); 831 valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats.get( 832 pid).getRssAfterCompaction(); 833 assertThat(valuesAfter).isEqualTo(rssAfter3); 834 } 835 836 @SuppressWarnings("GuardedBy") 837 @Test processWithAnonRSSTooSmall_notFullCompacted()838 public void processWithAnonRSSTooSmall_notFullCompacted() throws Exception { 839 // Initialize CachedAppOptimizer and set flags to (1) enable compaction, (2) set RSS 840 // throttle to 8000. 841 mCachedAppOptimizerUnderTest.init(); 842 setFlag(CachedAppOptimizer.KEY_USE_COMPACTION, "true", true); 843 setFlag(CachedAppOptimizer.KEY_COMPACT_FULL_RSS_THROTTLE_KB, "8000", false); 844 initActivityManagerService(); 845 846 // Simulate RSS anon memory larger than throttle. 847 long[] rssBelowThreshold = 848 new long[]{/*Total RSS*/ 10000, /*File RSS*/ 10000, /*Anon RSS*/ 7000, /*Swap*/ 849 10000}; 850 long[] rssBelowThresholdAfter = 851 new long[]{/*Total RSS*/ 9000, /*File RSS*/ 7000, /*Anon RSS*/ 4000, /*Swap*/ 852 8000}; 853 long[] rssAboveThreshold = 854 new long[]{/*Total RSS*/ 10000, /*File RSS*/ 10000, /*Anon RSS*/ 9000, /*Swap*/ 855 10000}; 856 long[] rssAboveThresholdAfter = 857 new long[]{/*Total RSS*/ 8000, /*File RSS*/ 9000, /*Anon RSS*/ 6000, /*Swap*/5000}; 858 // Process that passes properties. 859 int pid = 1; 860 ProcessRecord processRecord = 861 makeProcessRecord(pid, 2, 3, "p1", 862 "app1"); 863 864 // GIVEN we simulate RSS memory before below threshold. 865 mProcessDependencies.setRss(rssBelowThreshold); 866 mProcessDependencies.setRssAfterCompaction(rssBelowThresholdAfter); 867 // WHEN we try to run compaction 868 mCachedAppOptimizerUnderTest.compactApp(processRecord, 869 CachedAppOptimizer.CompactProfile.FULL, CachedAppOptimizer.CompactSource.APP, 870 false); 871 waitForHandler(); 872 // THEN process IS NOT compacted. 873 assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNull(); 874 875 // GIVEN we simulate RSS memory before above threshold. 876 mProcessDependencies.setRss(rssAboveThreshold); 877 mProcessDependencies.setRssAfterCompaction(rssAboveThresholdAfter); 878 // WHEN we try to run compaction 879 mCachedAppOptimizerUnderTest.compactApp(processRecord, 880 CachedAppOptimizer.CompactProfile.FULL, CachedAppOptimizer.CompactSource.APP, 881 false); 882 waitForHandler(); 883 // THEN process IS compacted. 884 assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull(); 885 long[] valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats.get( 886 pid).getRssAfterCompaction(); 887 assertThat(valuesAfter).isEqualTo(rssAboveThresholdAfter); 888 } 889 890 @SuppressWarnings("GuardedBy") 891 @Test processWithOomAdjTooSmall_notFullCompacted()892 public void processWithOomAdjTooSmall_notFullCompacted() throws Exception { 893 // Initialize CachedAppOptimizer and set flags to (1) enable compaction, (2) set Min and 894 // Max OOM_Adj throttles. 895 mCachedAppOptimizerUnderTest.init(); 896 setFlag(CachedAppOptimizer.KEY_USE_COMPACTION, "true", true); 897 setFlag(CachedAppOptimizer.KEY_COMPACT_THROTTLE_MIN_OOM_ADJ, Long.toString(920), true); 898 setFlag(CachedAppOptimizer.KEY_COMPACT_THROTTLE_MAX_OOM_ADJ, Long.toString(950), true); 899 initActivityManagerService(); 900 901 // Simulate RSS memory for which compaction should occur. 902 long[] rssBefore = 903 new long[]{/*Total RSS*/ 15000, /*File RSS*/ 15000, /*Anon RSS*/ 15000, 904 /*Swap*/ 10000}; 905 long[] rssAfter = 906 new long[]{/*Total RSS*/ 8000, /*File RSS*/ 9000, /*Anon RSS*/ 6000, /*Swap*/ 907 5000}; 908 // Process that passes properties. 909 int pid = 1; 910 ProcessRecord processRecord = 911 makeProcessRecord(pid, 2, 3, "p1", "app1"); 912 mProcessDependencies.setRss(rssBefore); 913 mProcessDependencies.setRssAfterCompaction(rssAfter); 914 915 // When moving within cached state 916 mCachedAppOptimizerUnderTest.onProcessFrozen(processRecord); 917 waitForHandler(); 918 // THEN process IS compacted. 919 assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull(); 920 long[] valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats 921 .get(pid) 922 .getRssAfterCompaction(); 923 assertThat(valuesAfter).isEqualTo(rssAfter); 924 } 925 926 @SuppressWarnings("GuardedBy") 927 @Test process_forceCompacted()928 public void process_forceCompacted() throws Exception { 929 mCachedAppOptimizerUnderTest.init(); 930 setFlag(CachedAppOptimizer.KEY_USE_COMPACTION, "true", true); 931 setFlag(CachedAppOptimizer.KEY_COMPACT_THROTTLE_MIN_OOM_ADJ, Long.toString(920), true); 932 setFlag(CachedAppOptimizer.KEY_COMPACT_THROTTLE_MAX_OOM_ADJ, Long.toString(950), true); 933 initActivityManagerService(); 934 935 long[] rssBefore = new long[] {/*Total RSS*/ 15000, /*File RSS*/ 15000, /*Anon RSS*/ 15000, 936 /*Swap*/ 10000}; 937 long[] rssAfter = new long[] { 938 /*Total RSS*/ 8000, /*File RSS*/ 9000, /*Anon RSS*/ 6000, /*Swap*/ 5000}; 939 // Process that passes properties. 940 int pid = 1; 941 ProcessRecord processRecord = makeProcessRecord(pid, 2, 3, "p1", "app1"); 942 mProcessDependencies.setRss(rssBefore); 943 mProcessDependencies.setRssAfterCompaction(rssAfter); 944 945 // Use an OOM Adjust value that usually avoids compaction 946 processRecord.mState.setSetAdj(100); 947 processRecord.mState.setCurAdj(100); 948 949 // Compact process full 950 mCachedAppOptimizerUnderTest.compactApp(processRecord, 951 CachedAppOptimizer.CompactProfile.FULL, CachedAppOptimizer.CompactSource.APP, 952 false); 953 waitForHandler(); 954 // the process is not compacted 955 assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNull(); 956 957 // Compact process some 958 mCachedAppOptimizerUnderTest.compactApp(processRecord, 959 CachedAppOptimizer.CompactProfile.SOME, CachedAppOptimizer.CompactSource.APP, 960 false); 961 waitForHandler(); 962 // the process is not compacted 963 assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNull(); 964 965 processRecord.mState.setSetAdj(100); 966 processRecord.mState.setCurAdj(100); 967 968 // We force a full compaction 969 mCachedAppOptimizerUnderTest.compactApp(processRecord, 970 CachedAppOptimizer.CompactProfile.FULL, CachedAppOptimizer.CompactSource.APP, 971 true); 972 waitForHandler(); 973 // then process is compacted. 974 assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull(); 975 976 mCachedAppOptimizerUnderTest.mLastCompactionStats.clear(); 977 978 if (CachedAppOptimizer.ENABLE_FILE_COMPACT) { 979 // We force a some compaction 980 mCachedAppOptimizerUnderTest.compactApp(processRecord, 981 CachedAppOptimizer.CompactProfile.SOME, CachedAppOptimizer.CompactSource.APP, 982 true); 983 waitForHandler(); 984 // then process is compacted. 985 CachedAppOptimizer.CompactProfile executedCompactProfile = 986 processRecord.mOptRecord.getLastCompactProfile(); 987 assertThat(executedCompactProfile).isEqualTo(CachedAppOptimizer.CompactProfile.SOME); 988 } 989 } 990 setFlag(String key, String value, boolean defaultValue)991 private void setFlag(String key, String value, boolean defaultValue) throws Exception { 992 mCountDown = new CountDownLatch(1); 993 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, key, value, defaultValue); 994 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); 995 } 996 waitForHandler()997 private void waitForHandler() { 998 Idle idle = new Idle(); 999 mCachedAppOptimizerUnderTest.mCompactionHandler.getLooper().getQueue().addIdleHandler(idle); 1000 mCachedAppOptimizerUnderTest.mCompactionHandler.post(() -> { }); 1001 idle.waitForIdle(); 1002 } 1003 initActivityManagerService()1004 private void initActivityManagerService() { 1005 mAms = new ActivityManagerService(mInjector, mServiceThreadRule.getThread()); 1006 mAms.mActivityTaskManager = new ActivityTaskManagerService(mContext); 1007 mAms.mActivityTaskManager.initialize(null, null, mContext.getMainLooper()); 1008 mAms.mAtmInternal = spy(mAms.mActivityTaskManager.getAtmInternal()); 1009 mAms.mPackageManagerInt = mPackageManagerInt; 1010 } 1011 1012 private static final class Idle implements MessageQueue.IdleHandler { 1013 private boolean mIdle; 1014 1015 @Override queueIdle()1016 public boolean queueIdle() { 1017 synchronized (this) { 1018 mIdle = true; 1019 notifyAll(); 1020 } 1021 return false; 1022 } 1023 waitForIdle()1024 public synchronized void waitForIdle() { 1025 while (!mIdle) { 1026 try { 1027 // Wait with a timeout of 10s. 1028 wait(10000); 1029 } catch (InterruptedException e) { 1030 } 1031 } 1032 } 1033 } 1034 1035 private class TestInjector extends Injector { 1036 TestInjector(Context context)1037 TestInjector(Context context) { 1038 super(context); 1039 } 1040 1041 @Override getAppOpsService(File recentAccessesFile, File storageFile, Handler handler)1042 public AppOpsService getAppOpsService(File recentAccessesFile, File storageFile, 1043 Handler handler) { 1044 return mAppOpsService; 1045 } 1046 1047 @Override getUiHandler(ActivityManagerService service)1048 public Handler getUiHandler(ActivityManagerService service) { 1049 return mHandler; 1050 } 1051 } 1052 1053 // Test implementation for ProcessDependencies. 1054 private static final class TestProcessDependencies 1055 implements CachedAppOptimizer.ProcessDependencies { 1056 private long[] mRss; 1057 private long[] mRssAfterCompaction; 1058 1059 @Override getRss(int pid)1060 public long[] getRss(int pid) { 1061 return mRss; 1062 } 1063 1064 @Override performCompaction(CachedAppOptimizer.CompactProfile profile, int pid)1065 public void performCompaction(CachedAppOptimizer.CompactProfile profile, int pid) 1066 throws IOException { 1067 mRss = mRssAfterCompaction; 1068 } 1069 setRss(long[] newValues)1070 public void setRss(long[] newValues) { 1071 mRss = newValues; 1072 } 1073 setRssAfterCompaction(long[] newValues)1074 public void setRssAfterCompaction(long[] newValues) { 1075 mRssAfterCompaction = newValues; 1076 } 1077 } 1078 } 1079