• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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