• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.power;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertTrue;
21 import static org.mockito.Mockito.when;
22 
23 import android.app.ActivityManager;
24 import android.app.IActivityManager;
25 import android.os.Process;
26 import android.os.RemoteException;
27 import android.platform.test.annotations.Presubmit;
28 
29 import org.junit.Before;
30 import org.junit.Rule;
31 import org.junit.Test;
32 import org.mockito.Mock;
33 import org.mockito.junit.MockitoJUnit;
34 import org.mockito.junit.MockitoRule;
35 
36 import java.io.File;
37 import java.io.IOException;
38 import java.io.PrintWriter;
39 import java.io.StringWriter;
40 import java.nio.charset.StandardCharsets;
41 import java.nio.file.Files;
42 import java.nio.file.Paths;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.List;
46 import java.util.Locale;
47 import java.util.TimeZone;
48 
49 /**
50  * Run: atest FrameworksServicesTests:ShutdownCheckPointsTest
51  */
52 @Presubmit
53 public class ShutdownCheckPointsTest {
54 
55     @Rule
56     public MockitoRule rule = MockitoJUnit.rule();
57 
58     @Mock
59     private IActivityManager mActivityManager;
60 
61     private TestInjector mTestInjector;
62     private ShutdownCheckPoints mInstance;
63 
64     @Before
setUp()65     public void setUp() {
66         Locale.setDefault(Locale.UK);
67         TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
68         mTestInjector = new TestInjector(mActivityManager);
69         mInstance = new ShutdownCheckPoints(mTestInjector);
70     }
71 
72     @Test
testSystemServerEntry()73     public void testSystemServerEntry() {
74         mTestInjector.setCurrentTime(1000);
75         mInstance.recordCheckPointInternal("reason1");
76 
77         assertTrue(dumpToString().startsWith(
78                 "Shutdown request from SYSTEM for reason reason1 "
79                         + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
80                         + "com.android.server.power.ShutdownCheckPointsTest"
81                         + ".testSystemServerEntry\n at "));
82     }
83 
84     @Test
testSystemServerEntryWithoutReason()85     public void testSystemServerEntryWithoutReason() {
86         mTestInjector.setCurrentTime(1000);
87         mInstance.recordCheckPointInternal(null);
88 
89         assertTrue(dumpToString().startsWith(
90                 "Shutdown request from SYSTEM at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"));
91     }
92 
93     @Test
testSystemServiceBinderEntry()94     public void testSystemServiceBinderEntry() {
95         mTestInjector.setCurrentTime(1000);
96         mInstance.recordCheckPointInternal(Process.myPid(), "reason1");
97 
98         assertTrue(dumpToString().startsWith(
99                 "Shutdown request from SYSTEM for reason reason1 "
100                         + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
101                         + "com.android.server.power.ShutdownCheckPointsTest"
102                         + ".testSystemServiceBinderEntry\n at "));
103     }
104 
105     @Test
testCallerProcessBinderEntry()106     public void testCallerProcessBinderEntry() throws RemoteException {
107         List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfos = new ArrayList<>();
108         runningAppProcessInfos.add(
109                 new ActivityManager.RunningAppProcessInfo("process_name", 1, new String[0]));
110         when(mActivityManager.getRunningAppProcesses()).thenReturn(runningAppProcessInfos);
111 
112         mTestInjector.setCurrentTime(1000);
113         mInstance.recordCheckPointInternal(1, "reason1");
114 
115         assertEquals(
116                 "Shutdown request from BINDER for reason reason1 "
117                         + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
118                         + "com.android.server.power.ShutdownCheckPointsTest"
119                         + ".testCallerProcessBinderEntry\n"
120                         + "From process process_name (pid=1)\n\n",
121                 dumpToString());
122     }
123 
124     @Test
testRemoteExceptionOnBinderEntry()125     public void testRemoteExceptionOnBinderEntry() throws RemoteException {
126         when(mActivityManager.getRunningAppProcesses()).thenThrow(new RemoteException("Error"));
127 
128         mTestInjector.setCurrentTime(1000);
129         mInstance.recordCheckPointInternal(1, "reason1");
130 
131         assertEquals(
132                 "Shutdown request from BINDER for reason reason1 "
133                         + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
134                         + "com.android.server.power.ShutdownCheckPointsTest"
135                         + ".testRemoteExceptionOnBinderEntry\n"
136                         + "From process ? (pid=1)\n\n",
137                 dumpToString());
138     }
139 
140     @Test
testUnknownProcessBinderEntry()141     public void testUnknownProcessBinderEntry() {
142         mTestInjector.setCurrentTime(1000);
143         mInstance.recordCheckPointInternal(1, "reason1");
144 
145         assertEquals(
146                 "Shutdown request from BINDER for reason reason1 "
147                         + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
148                         + "com.android.server.power.ShutdownCheckPointsTest"
149                         + ".testUnknownProcessBinderEntry\n"
150                         + "From process ? (pid=1)\n\n",
151                 dumpToString());
152     }
153 
154     @Test
testBinderEntryWithoutReason()155     public void testBinderEntryWithoutReason() throws RemoteException {
156         mTestInjector.setCurrentTime(1000);
157         mInstance.recordCheckPointInternal(1, null);
158 
159         assertTrue(dumpToString().startsWith(
160                 "Shutdown request from BINDER at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"));
161     }
162 
163     @Test
testSystemServiceIntentEntry()164     public void testSystemServiceIntentEntry() {
165         mTestInjector.setCurrentTime(1000);
166         mInstance.recordCheckPointInternal("some.intent", "android", "reason1");
167 
168         assertTrue(dumpToString().startsWith(
169                 "Shutdown request from SYSTEM for reason reason1 "
170                         + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
171                         + "com.android.server.power.ShutdownCheckPointsTest"
172                         + ".testSystemServiceIntentEntry\n at "));
173     }
174 
175     @Test
testIntentEntry()176     public void testIntentEntry() {
177         mTestInjector.setCurrentTime(1000);
178         mInstance.recordCheckPointInternal("some.intent", "some.app", "reason1");
179 
180         assertEquals(
181                 "Shutdown request from INTENT for reason reason1 "
182                         + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
183                         + "Intent: some.intent\n"
184                         + "Package: some.app\n\n",
185                 dumpToString());
186     }
187 
188     @Test
testIntentEntryWithoutReason()189     public void testIntentEntryWithoutReason() {
190         mTestInjector.setCurrentTime(1000);
191         mInstance.recordCheckPointInternal("some.intent", "some.app", null);
192 
193         assertTrue(dumpToString().startsWith(
194                 "Shutdown request from INTENT at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"));
195     }
196 
197     @Test
testMultipleEntries()198     public void testMultipleEntries() {
199         mTestInjector.setCurrentTime(1000);
200         mInstance.recordCheckPointInternal(1, "reason1");
201         mTestInjector.setCurrentTime(2000);
202         mInstance.recordCheckPointInternal(2, "reason2");
203         mTestInjector.setCurrentTime(3000);
204         mInstance.recordCheckPointInternal("intent", "app", "reason3");
205 
206         assertEquals(
207                 "Shutdown request from BINDER for reason reason1 "
208                         + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
209                         + "com.android.server.power.ShutdownCheckPointsTest.testMultipleEntries\n"
210                         + "From process ? (pid=1)\n\n"
211                         + "Shutdown request from BINDER for reason reason2 "
212                         + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
213                         + "com.android.server.power.ShutdownCheckPointsTest.testMultipleEntries\n"
214                         + "From process ? (pid=2)\n\n"
215                         + "Shutdown request from INTENT for reason reason3 "
216                         + "at 1970-01-01 00:00:03.000 UTC (epoch=3000)\n"
217                         + "Intent: intent\n"
218                         + "Package: app\n\n",
219                 dumpToString());
220     }
221 
222     @Test
testTooManyEntriesDropsOlderOnes()223     public void testTooManyEntriesDropsOlderOnes() {
224         mTestInjector.setCheckPointsLimit(2);
225         ShutdownCheckPoints limitedInstance = new ShutdownCheckPoints(mTestInjector);
226 
227         mTestInjector.setCurrentTime(1000);
228         limitedInstance.recordCheckPointInternal("intent.1", "app.1", "reason1");
229         mTestInjector.setCurrentTime(2000);
230         limitedInstance.recordCheckPointInternal("intent.2", "app.2", "reason2");
231         mTestInjector.setCurrentTime(3000);
232         limitedInstance.recordCheckPointInternal("intent.3", "app.3", "reason3");
233 
234         // Drops first intent.
235         assertEquals(
236                 "Shutdown request from INTENT for reason reason2 "
237                         + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
238                         + "Intent: intent.2\n"
239                         + "Package: app.2\n\n"
240                         + "Shutdown request from INTENT for reason reason3 "
241                         + "at 1970-01-01 00:00:03.000 UTC (epoch=3000)\n"
242                         + "Intent: intent.3\n"
243                         + "Package: app.3\n\n",
244                 dumpToString(limitedInstance));
245     }
246 
247     @Test
testDumpToFile()248     public void testDumpToFile() throws Exception {
249         File tempDir = createTempDir();
250         File baseFile = new File(tempDir, "checkpoints");
251 
252         mTestInjector.setCurrentTime(1000);
253         mInstance.recordCheckPointInternal("first.intent", "first.app", "reason1");
254         dumpToFile(baseFile);
255 
256         mTestInjector.setCurrentTime(2000);
257         mInstance.recordCheckPointInternal("second.intent", "second.app", "reason2");
258         dumpToFile(baseFile);
259 
260         File[] dumpFiles = tempDir.listFiles();
261         Arrays.sort(dumpFiles);
262 
263         assertEquals(2, dumpFiles.length);
264         assertEquals(
265                 "Shutdown request from INTENT for reason reason1 "
266                         + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
267                         + "Intent: first.intent\n"
268                         + "Package: first.app\n\n",
269                 readFileAsString(dumpFiles[0].getAbsolutePath()));
270         assertEquals(
271                 "Shutdown request from INTENT for reason reason1 "
272                         + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
273                         + "Intent: first.intent\n"
274                         + "Package: first.app\n\n"
275                         + "Shutdown request from INTENT for reason reason2 "
276                         + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
277                         + "Intent: second.intent\n"
278                         + "Package: second.app\n\n",
279                 readFileAsString(dumpFiles[1].getAbsolutePath()));
280     }
281 
282     @Test
testTooManyFilesDropsOlderOnes()283     public void testTooManyFilesDropsOlderOnes() throws Exception {
284         mTestInjector.setDumpFilesLimit(1);
285         ShutdownCheckPoints instance = new ShutdownCheckPoints(mTestInjector);
286         File tempDir = createTempDir();
287         File baseFile = new File(tempDir, "checkpoints");
288 
289         mTestInjector.setCurrentTime(1000);
290         instance.recordCheckPointInternal("first.intent", "first.app", "reason1");
291         dumpToFile(instance, baseFile);
292 
293         mTestInjector.setCurrentTime(2000);
294         instance.recordCheckPointInternal("second.intent", "second.app", "reason2");
295         dumpToFile(instance, baseFile);
296 
297         File[] dumpFiles = tempDir.listFiles();
298         assertEquals(1, dumpFiles.length);
299         assertEquals(
300                 "Shutdown request from INTENT for reason reason1 "
301                         + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
302                         + "Intent: first.intent\n"
303                         + "Package: first.app\n\n"
304                         + "Shutdown request from INTENT for reason reason2 "
305                         + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
306                         + "Intent: second.intent\n"
307                         + "Package: second.app\n\n",
308                 readFileAsString(dumpFiles[0].getAbsolutePath()));
309     }
310 
dumpToString()311     private String dumpToString() {
312         return dumpToString(mInstance);
313     }
314 
dumpToString(ShutdownCheckPoints instance)315     private String dumpToString(ShutdownCheckPoints instance) {
316         StringWriter sw = new StringWriter();
317         PrintWriter pw = new PrintWriter(sw);
318         instance.dumpInternal(pw);
319         return sw.toString();
320     }
321 
dumpToFile(File baseFile)322     private void dumpToFile(File baseFile) throws InterruptedException {
323         dumpToFile(mInstance, baseFile);
324     }
325 
dumpToFile(ShutdownCheckPoints instance, File baseFile)326     private void dumpToFile(ShutdownCheckPoints instance, File baseFile)
327             throws InterruptedException {
328         Thread dumpThread = instance.newDumpThreadInternal(baseFile);
329         dumpThread.start();
330         dumpThread.join();
331     }
332 
readFileAsString(String absolutePath)333     private String readFileAsString(String absolutePath) throws IOException {
334         return new String(Files.readAllBytes(Paths.get(absolutePath)), StandardCharsets.UTF_8);
335     }
336 
createTempDir()337     private File createTempDir() throws IOException {
338         File tempDir = File.createTempFile("checkpoints", "out");
339         tempDir.delete();
340         tempDir.mkdir();
341         return tempDir;
342     }
343 
344     /** Fake system dependencies for testing. */
345     private final class TestInjector implements ShutdownCheckPoints.Injector {
346         private long mNow;
347         private int mCheckPointsLimit;
348         private int mDumpFilesLimit;
349         private IActivityManager mActivityManager;
350 
TestInjector(IActivityManager activityManager)351         TestInjector(IActivityManager activityManager) {
352             mNow = 0;
353             mCheckPointsLimit = 100;
354             mDumpFilesLimit = 2;
355             mActivityManager = activityManager;
356         }
357 
358         @Override
currentTimeMillis()359         public long currentTimeMillis() {
360             return mNow;
361         }
362 
363         @Override
maxCheckPoints()364         public int maxCheckPoints() {
365             return mCheckPointsLimit;
366         }
367 
368         @Override
maxDumpFiles()369         public int maxDumpFiles() {
370             return mDumpFilesLimit;
371         }
372 
373         @Override
activityManager()374         public IActivityManager activityManager() {
375             return mActivityManager;
376         }
377 
setCurrentTime(long time)378         void setCurrentTime(long time) {
379             mNow = time;
380         }
381 
setCheckPointsLimit(int limit)382         void setCheckPointsLimit(int limit) {
383             mCheckPointsLimit = limit;
384         }
385 
setDumpFilesLimit(int dumpFilesLimit)386         void setDumpFilesLimit(int dumpFilesLimit) {
387             mDumpFilesLimit = dumpFilesLimit;
388         }
389     }
390 }
391