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.mock;
26 import static org.mockito.Mockito.spy;
27 
28 import android.app.ActivityManager;
29 import android.app.usage.UsageStatsManagerInternal;
30 import android.content.Context;
31 
32 import com.android.server.LocalServices;
33 import com.android.server.wm.ActivityTaskManagerService;
34 
35 import org.junit.Before;
36 import org.junit.BeforeClass;
37 import org.junit.Test;
38 
39 /**
40  * Test class for {@link OomAdjuster}.
41  *
42  * Build/Install/Run:
43  *  atest FrameworksServicesTests:OomAdjusterTests
44  */
45 public class OomAdjusterTests {
46     private static Context sContext;
47     private static ActivityManagerService sService;
48 
49     private ProcessRecord mProcessRecord;
50 
51     private static final long ZERO = 0L;
52     private static final long USAGE_STATS_INTERACTION = 2 * 60 * 60 * 1000L;
53     private static final long SERVICE_USAGE_INTERACTION = 30 * 60 * 1000;
54 
55     @BeforeClass
setUpOnce()56     public static void setUpOnce() {
57         sContext = getInstrumentation().getTargetContext();
58 
59         // We need to run with dexmaker share class loader to make use of
60         // ActivityTaskManagerService from wm package.
61         runWithDexmakerShareClassLoader(() -> {
62             sService = mock(ActivityManagerService.class);
63             sService.mActivityTaskManager = new ActivityTaskManagerService(sContext);
64             sService.mActivityTaskManager.initialize(null, null, sContext.getMainLooper());
65             sService.mAtmInternal = sService.mActivityTaskManager.getAtmInternal();
66 
67             sService.mConstants = new ActivityManagerConstants(sContext, sService,
68                     sContext.getMainThreadHandler());
69             sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList, null);
70             LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
71             LocalServices.addService(UsageStatsManagerInternal.class,
72                     mock(UsageStatsManagerInternal.class));
73             sService.mUsageStatsService = LocalServices.getService(UsageStatsManagerInternal.class);
74         });
75     }
76 
77     @Before
setUpProcess()78     public void setUpProcess() {
79         // Need to run with dexmaker share class loader to mock package private class.
80         runWithDexmakerShareClassLoader(() -> {
81             mProcessRecord = spy(new ProcessRecord(sService, sContext.getApplicationInfo(),
82                     "name", 12345));
83         });
84 
85         // Ensure certain services and constants are defined properly
86         assertNotNull(sService.mUsageStatsService);
87         assertEquals(USAGE_STATS_INTERACTION, sService.mConstants.USAGE_STATS_INTERACTION_INTERVAL);
88         assertEquals(SERVICE_USAGE_INTERACTION, sService.mConstants.SERVICE_USAGE_INTERACTION_TIME);
89     }
90 
91     @Test
testMaybeUpdateUsageStats_ProcStatePersistentUI()92     public void testMaybeUpdateUsageStats_ProcStatePersistentUI() {
93         final long elapsedTime = ZERO;
94         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
95         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
96 
97         assertProcessRecordState(ZERO, true, elapsedTime);
98     }
99 
100     @Test
testMaybeUpdateUsageStats_ProcStateTop()101     public void testMaybeUpdateUsageStats_ProcStateTop() {
102         final long elapsedTime = ZERO;
103         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_TOP);
104         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
105 
106         assertProcessRecordState(ZERO, true, elapsedTime);
107     }
108 
109     @Test
testMaybeUpdateUsageStats_ProcStateTop_PreviousInteraction()110     public void testMaybeUpdateUsageStats_ProcStateTop_PreviousInteraction() {
111         final long elapsedTime = ZERO;
112         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_TOP);
113         mProcessRecord.reportedInteraction = true;
114         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
115 
116         assertProcessRecordState(ZERO, true, ZERO);
117     }
118 
119     @Test
testMaybeUpdateUsageStats_ProcStateTop_PastUsageInterval()120     public void testMaybeUpdateUsageStats_ProcStateTop_PastUsageInterval() {
121         final long elapsedTime = 3 * USAGE_STATS_INTERACTION;
122         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_TOP);
123         mProcessRecord.reportedInteraction = true;
124         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
125 
126         assertProcessRecordState(ZERO, true, elapsedTime);
127     }
128 
129     @Test
testMaybeUpdateUsageStats_ProcStateBoundTop()130     public void testMaybeUpdateUsageStats_ProcStateBoundTop() {
131         final long elapsedTime = ZERO;
132         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_TOP);
133         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
134 
135         assertProcessRecordState(ZERO, true, elapsedTime);
136     }
137 
138     @Test
testMaybeUpdateUsageStats_ProcStateFGS()139     public void testMaybeUpdateUsageStats_ProcStateFGS() {
140         final long elapsedTime = ZERO;
141         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
142         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
143 
144         assertProcessRecordState(elapsedTime, false, ZERO);
145     }
146 
147     @Test
testMaybeUpdateUsageStats_ProcStateFGS_ShortInteraction()148     public void testMaybeUpdateUsageStats_ProcStateFGS_ShortInteraction() {
149         final long elapsedTime = ZERO;
150         final long fgInteractionTime = 1000L;
151         mProcessRecord.setFgInteractionTime(fgInteractionTime);
152         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
153         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
154 
155         assertProcessRecordState(fgInteractionTime, false, ZERO);
156     }
157 
158     @Test
testMaybeUpdateUsageStats_ProcStateFGS_LongInteraction()159     public void testMaybeUpdateUsageStats_ProcStateFGS_LongInteraction() {
160         final long elapsedTime = 2 * SERVICE_USAGE_INTERACTION;
161         final long fgInteractionTime = 1000L;
162         mProcessRecord.setFgInteractionTime(fgInteractionTime);
163         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
164         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
165 
166         assertProcessRecordState(fgInteractionTime, true, elapsedTime);
167     }
168 
169     @Test
testMaybeUpdateUsageStats_ProcStateFGS_PreviousLongInteraction()170     public void testMaybeUpdateUsageStats_ProcStateFGS_PreviousLongInteraction() {
171         final long elapsedTime = 2 * SERVICE_USAGE_INTERACTION;
172         final long fgInteractionTime = 1000L;
173         mProcessRecord.setFgInteractionTime(fgInteractionTime);
174         mProcessRecord.reportedInteraction = true;
175         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
176         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
177 
178         assertProcessRecordState(fgInteractionTime, true, ZERO);
179     }
180 
181     @Test
testMaybeUpdateUsageStats_ProcStateFGSLocation()182     public void testMaybeUpdateUsageStats_ProcStateFGSLocation() {
183         final long elapsedTime = ZERO;
184         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
185         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
186 
187         assertProcessRecordState(elapsedTime, false, ZERO);
188     }
189 
190     @Test
testMaybeUpdateUsageStats_ProcStateBFGS()191     public void testMaybeUpdateUsageStats_ProcStateBFGS() {
192         final long elapsedTime = ZERO;
193         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
194         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
195 
196         assertProcessRecordState(ZERO, true, elapsedTime);
197     }
198 
199     @Test
testMaybeUpdateUsageStats_ProcStateImportantFG()200     public void testMaybeUpdateUsageStats_ProcStateImportantFG() {
201         final long elapsedTime = ZERO;
202         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
203         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
204 
205         assertProcessRecordState(ZERO, true, elapsedTime);
206     }
207 
208     @Test
testMaybeUpdateUsageStats_ProcStateImportantFG_PreviousInteraction()209     public void testMaybeUpdateUsageStats_ProcStateImportantFG_PreviousInteraction() {
210         final long elapsedTime = ZERO;
211         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
212         mProcessRecord.reportedInteraction = true;
213         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
214 
215         assertProcessRecordState(ZERO, true, ZERO);
216     }
217 
218     @Test
testMaybeUpdateUsageStats_ProcStateImportantFG_PastUsageInterval()219     public void testMaybeUpdateUsageStats_ProcStateImportantFG_PastUsageInterval() {
220         final long elapsedTime = 3 * USAGE_STATS_INTERACTION;
221         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
222         mProcessRecord.reportedInteraction = true;
223         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
224 
225         assertProcessRecordState(ZERO, true, elapsedTime);
226     }
227 
228     @Test
testMaybeUpdateUsageStats_ProcStateImportantBG()229     public void testMaybeUpdateUsageStats_ProcStateImportantBG() {
230         final long elapsedTime = ZERO;
231         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
232         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
233 
234         assertProcessRecordState(ZERO, false, ZERO);
235     }
236 
237     @Test
testMaybeUpdateUsageStats_ProcStateService()238     public void testMaybeUpdateUsageStats_ProcStateService() {
239         final long elapsedTime = ZERO;
240         mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_SERVICE);
241         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
242 
243         assertProcessRecordState(ZERO, false, ZERO);
244     }
245 
assertProcessRecordState(long fgInteractionTime, boolean reportedInteraction, long interactionEventTime)246     private void assertProcessRecordState(long fgInteractionTime, boolean reportedInteraction,
247             long interactionEventTime) {
248         assertEquals("Foreground interaction time was not updated correctly.",
249                 fgInteractionTime, mProcessRecord.getFgInteractionTime());
250         assertEquals("Interaction was not updated correctly.",
251                 reportedInteraction, mProcessRecord.reportedInteraction);
252         assertEquals("Interaction event time was not updated correctly.",
253                 interactionEventTime, mProcessRecord.getInteractionEventTime());
254     }
255 }
256