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