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.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader; 20 21 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 22 23 import static org.junit.Assert.assertEquals; 24 import static org.junit.Assert.assertNotNull; 25 import static org.mockito.Mockito.doReturn; 26 import static org.mockito.Mockito.mock; 27 import static org.mockito.Mockito.spy; 28 29 import android.app.ActivityManager; 30 import android.app.usage.UsageStatsManagerInternal; 31 import android.content.ComponentName; 32 import android.content.Context; 33 import android.content.pm.ApplicationInfo; 34 import android.content.pm.PackageManagerInternal; 35 36 import com.android.server.LocalServices; 37 import com.android.server.wm.ActivityTaskManagerService; 38 39 import org.junit.AfterClass; 40 import org.junit.Before; 41 import org.junit.BeforeClass; 42 import org.junit.Test; 43 44 import java.lang.reflect.Field; 45 import java.lang.reflect.Modifier; 46 47 /** 48 * Test class for {@link OomAdjuster}. 49 * 50 * Build/Install/Run: 51 * atest FrameworksServicesTests:OomAdjusterTests 52 */ 53 public class OomAdjusterTests { 54 private static Context sContext; 55 private static ActivityManagerService sService; 56 private static PackageManagerInternal sPackageManagerInternal; 57 58 private ProcessRecord mProcessRecord; 59 60 private static final long ZERO = 0L; 61 private static final long USAGE_STATS_INTERACTION = 10 * 60 * 1000L; 62 private static final long SERVICE_USAGE_INTERACTION = 60 * 1000; 63 64 static class MyOomAdjuster extends OomAdjuster { 65 66 private final PlatformCompatCache mPlatformCompatCache; 67 MyOomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids)68 MyOomAdjuster(ActivityManagerService service, ProcessList processList, 69 ActiveUids activeUids) { 70 super(service, processList, activeUids); 71 mPlatformCompatCache = new MyPlatformCompatCache(new long[]{}); 72 } 73 74 static class MyPlatformCompatCache extends PlatformCompatCache { 75 MyPlatformCompatCache(long[] compatChanges)76 MyPlatformCompatCache(long[] compatChanges) { 77 super(compatChanges); 78 } 79 80 @Override isChangeEnabled(long changeId, ApplicationInfo app, boolean defaultValue)81 boolean isChangeEnabled(long changeId, ApplicationInfo app, boolean defaultValue) { 82 return true; 83 } 84 } 85 86 @Override getPlatformCompatCache()87 protected OomAdjuster.PlatformCompatCache getPlatformCompatCache() { 88 return mPlatformCompatCache; 89 } 90 } 91 92 @BeforeClass setUpOnce()93 public static void setUpOnce() { 94 sContext = getInstrumentation().getTargetContext(); 95 96 sPackageManagerInternal = mock(PackageManagerInternal.class); 97 doReturn(new ComponentName("", "")).when(sPackageManagerInternal) 98 .getSystemUiServiceComponent(); 99 LocalServices.addService(PackageManagerInternal.class, sPackageManagerInternal); 100 101 // We need to run with dexmaker share class loader to make use of 102 // ActivityTaskManagerService from wm package. 103 runWithDexmakerShareClassLoader(() -> { 104 sService = mock(ActivityManagerService.class); 105 sService.mActivityTaskManager = new ActivityTaskManagerService(sContext); 106 sService.mActivityTaskManager.initialize(null, null, sContext.getMainLooper()); 107 sService.mAtmInternal = sService.mActivityTaskManager.getAtmInternal(); 108 109 setFieldValue(ActivityManagerService.class, sService, "mProcLock", 110 new ActivityManagerProcLock()); 111 sService.mConstants = new ActivityManagerConstants(sContext, sService, 112 sContext.getMainThreadHandler()); 113 final AppProfiler profiler = mock(AppProfiler.class); 114 setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object()); 115 setFieldValue(ActivityManagerService.class, sService, "mAppProfiler", profiler); 116 sService.mOomAdjuster = new MyOomAdjuster(sService, sService.mProcessList, null); 117 LocalServices.addService(UsageStatsManagerInternal.class, 118 mock(UsageStatsManagerInternal.class)); 119 sService.mUsageStatsService = LocalServices.getService(UsageStatsManagerInternal.class); 120 }); 121 } 122 setFieldValue(Class clazz, Object obj, String fieldName, T val)123 private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) { 124 try { 125 Field field = clazz.getDeclaredField(fieldName); 126 field.setAccessible(true); 127 Field mfield = Field.class.getDeclaredField("accessFlags"); 128 mfield.setAccessible(true); 129 mfield.setInt(field, mfield.getInt(field) & ~(Modifier.FINAL | Modifier.PRIVATE)); 130 field.set(obj, val); 131 } catch (NoSuchFieldException | IllegalAccessException e) { 132 } 133 } 134 135 @AfterClass tearDownOnce()136 public static void tearDownOnce() { 137 LocalServices.removeServiceForTest(PackageManagerInternal.class); 138 LocalServices.removeServiceForTest(UsageStatsManagerInternal.class); 139 } 140 141 @Before setUpProcess()142 public void setUpProcess() { 143 // Need to run with dexmaker share class loader to mock package private class. 144 runWithDexmakerShareClassLoader(() -> { 145 mProcessRecord = spy(new ProcessRecord(sService, sContext.getApplicationInfo(), 146 "name", 12345)); 147 }); 148 149 // Ensure certain services and constants are defined properly 150 assertNotNull(sService.mUsageStatsService); 151 assertEquals(USAGE_STATS_INTERACTION, 152 sService.mConstants.USAGE_STATS_INTERACTION_INTERVAL_POST_S); 153 assertEquals(SERVICE_USAGE_INTERACTION, 154 sService.mConstants.SERVICE_USAGE_INTERACTION_TIME_POST_S); 155 } 156 157 @Test testMaybeUpdateUsageStats_ProcStatePersistentUI()158 public void testMaybeUpdateUsageStats_ProcStatePersistentUI() { 159 final long elapsedTime = ZERO; 160 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI); 161 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 162 163 assertProcessRecordState(ZERO, true, elapsedTime); 164 } 165 166 @Test testMaybeUpdateUsageStats_ProcStateTop()167 public void testMaybeUpdateUsageStats_ProcStateTop() { 168 final long elapsedTime = ZERO; 169 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_TOP); 170 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 171 172 assertProcessRecordState(ZERO, true, elapsedTime); 173 } 174 175 @Test testMaybeUpdateUsageStats_ProcStateTop_PreviousInteraction()176 public void testMaybeUpdateUsageStats_ProcStateTop_PreviousInteraction() { 177 final long elapsedTime = ZERO; 178 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_TOP); 179 mProcessRecord.mState.setReportedInteraction(true); 180 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 181 182 assertProcessRecordState(ZERO, true, ZERO); 183 } 184 185 @Test testMaybeUpdateUsageStats_ProcStateTop_PastUsageInterval()186 public void testMaybeUpdateUsageStats_ProcStateTop_PastUsageInterval() { 187 final long elapsedTime = 3 * USAGE_STATS_INTERACTION; 188 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_TOP); 189 mProcessRecord.mState.setReportedInteraction(true); 190 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 191 192 assertProcessRecordState(ZERO, true, elapsedTime); 193 } 194 195 @Test testMaybeUpdateUsageStats_ProcStateBoundTop()196 public void testMaybeUpdateUsageStats_ProcStateBoundTop() { 197 final long elapsedTime = ZERO; 198 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_TOP); 199 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 200 201 assertProcessRecordState(ZERO, true, elapsedTime); 202 } 203 204 @Test testMaybeUpdateUsageStats_ProcStateFGS()205 public void testMaybeUpdateUsageStats_ProcStateFGS() { 206 final long elapsedTime = ZERO; 207 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); 208 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 209 210 assertProcessRecordState(elapsedTime, false, ZERO); 211 } 212 213 @Test testMaybeUpdateUsageStats_ProcStateFGS_ShortInteraction()214 public void testMaybeUpdateUsageStats_ProcStateFGS_ShortInteraction() { 215 final long elapsedTime = ZERO; 216 final long fgInteractionTime = 1000L; 217 mProcessRecord.mState.setFgInteractionTime(fgInteractionTime); 218 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); 219 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 220 221 assertProcessRecordState(fgInteractionTime, false, ZERO); 222 } 223 224 @Test testMaybeUpdateUsageStats_ProcStateFGS_LongInteraction()225 public void testMaybeUpdateUsageStats_ProcStateFGS_LongInteraction() { 226 final long elapsedTime = 2 * SERVICE_USAGE_INTERACTION; 227 final long fgInteractionTime = 1000L; 228 mProcessRecord.mState.setFgInteractionTime(fgInteractionTime); 229 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); 230 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 231 232 assertProcessRecordState(fgInteractionTime, true, elapsedTime); 233 } 234 235 @Test testMaybeUpdateUsageStats_ProcStateFGS_PreviousLongInteraction()236 public void testMaybeUpdateUsageStats_ProcStateFGS_PreviousLongInteraction() { 237 final long elapsedTime = 2 * SERVICE_USAGE_INTERACTION; 238 final long fgInteractionTime = 1000L; 239 mProcessRecord.mState.setFgInteractionTime(fgInteractionTime); 240 mProcessRecord.mState.setReportedInteraction(true); 241 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); 242 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 243 244 assertProcessRecordState(fgInteractionTime, true, ZERO); 245 } 246 247 @Test testMaybeUpdateUsageStats_ProcStateFGSLocation()248 public void testMaybeUpdateUsageStats_ProcStateFGSLocation() { 249 final long elapsedTime = ZERO; 250 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); 251 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 252 253 assertProcessRecordState(elapsedTime, false, ZERO); 254 } 255 256 @Test testMaybeUpdateUsageStats_ProcStateBFGS()257 public void testMaybeUpdateUsageStats_ProcStateBFGS() { 258 final long elapsedTime = ZERO; 259 mProcessRecord.mState.setCurProcState( 260 ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE); 261 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 262 263 assertProcessRecordState(ZERO, true, elapsedTime); 264 } 265 266 @Test testMaybeUpdateUsageStats_ProcStateImportantFG()267 public void testMaybeUpdateUsageStats_ProcStateImportantFG() { 268 final long elapsedTime = ZERO; 269 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); 270 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 271 272 assertProcessRecordState(ZERO, true, elapsedTime); 273 } 274 275 @Test testMaybeUpdateUsageStats_ProcStateImportantFG_PreviousInteraction()276 public void testMaybeUpdateUsageStats_ProcStateImportantFG_PreviousInteraction() { 277 final long elapsedTime = ZERO; 278 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); 279 mProcessRecord.mState.setReportedInteraction(true); 280 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 281 282 assertProcessRecordState(ZERO, true, ZERO); 283 } 284 285 @Test testMaybeUpdateUsageStats_ProcStateImportantFG_PastUsageInterval()286 public void testMaybeUpdateUsageStats_ProcStateImportantFG_PastUsageInterval() { 287 final long elapsedTime = 3 * USAGE_STATS_INTERACTION; 288 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); 289 mProcessRecord.mState.setReportedInteraction(true); 290 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 291 292 assertProcessRecordState(ZERO, true, elapsedTime); 293 } 294 295 @Test testMaybeUpdateUsageStats_ProcStateImportantBG()296 public void testMaybeUpdateUsageStats_ProcStateImportantBG() { 297 final long elapsedTime = ZERO; 298 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); 299 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 300 301 assertProcessRecordState(ZERO, false, ZERO); 302 } 303 304 @Test testMaybeUpdateUsageStats_ProcStateService()305 public void testMaybeUpdateUsageStats_ProcStateService() { 306 final long elapsedTime = ZERO; 307 mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_SERVICE); 308 sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); 309 310 assertProcessRecordState(ZERO, false, ZERO); 311 } 312 assertProcessRecordState(long fgInteractionTime, boolean reportedInteraction, long interactionEventTime)313 private void assertProcessRecordState(long fgInteractionTime, boolean reportedInteraction, 314 long interactionEventTime) { 315 assertEquals("Foreground interaction time was not updated correctly.", 316 fgInteractionTime, mProcessRecord.mState.getFgInteractionTime()); 317 assertEquals("Interaction was not updated correctly.", 318 reportedInteraction, mProcessRecord.mState.hasReportedInteraction()); 319 assertEquals("Interaction event time was not updated correctly.", 320 interactionEventTime, mProcessRecord.mState.getInteractionEventTime()); 321 } 322 } 323