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