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