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