1 /*
2  * Copyright (C) 2017 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 android.dumpsys.cts;
18 
19 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
20 
21 import java.io.BufferedReader;
22 import java.io.StringReader;
23 import java.util.Date;
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26 import java.text.SimpleDateFormat;
27 
28 /**
29  * Test to check the format of the dumps of the processstats test.
30  */
31 public class StoragedDumpsysTest extends BaseDumpsysTest {
32     private static final String DEVICE_SIDE_TEST_APK = "CtsStoragedTestApp.apk";
33     private static final String DEVICE_SIDE_TEST_PACKAGE = "com.android.server.cts.storaged";
34 
35     @Override
tearDown()36     protected void tearDown() throws Exception {
37         super.tearDown();
38         getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE);
39     }
40 
getCgroupFromLog(String log)41     private String getCgroupFromLog(String log) {
42         Pattern pattern = Pattern.compile("cgroup:([^\\s]+)", Pattern.MULTILINE);
43         Matcher matcher = pattern.matcher(log);
44         if (matcher.find()) {
45             return matcher.group(1);
46         }
47         return null;
48     }
49 
getCurrentLogcatDate()50     private String getCurrentLogcatDate() throws Exception {
51         long timestampMs = getDevice().getDeviceDate();
52         return new SimpleDateFormat("MM-dd HH:mm:ss.SSS")
53             .format(new Date(timestampMs));
54     }
55 
56     /**
57      * Tests the output of "dumpsys storaged --force --hours 0.01".
58      *
59      * @throws Exception
60      */
testStoragedOutput()61     public void testStoragedOutput() throws Exception {
62         String result = mDevice.executeShellCommand("stat /proc/uid_io/stats");
63         if(result.contains("No such file or directory")) {
64             return;
65         }
66 
67         if (mDevice.getAppPackageInfo(DEVICE_SIDE_TEST_APK) != null) {
68             getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE);
69         }
70 
71         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
72         mDevice.installPackage(buildHelper.getTestFile(DEVICE_SIDE_TEST_APK), true);
73 
74         mDevice.executeShellCommand("dumpsys storaged --force");
75 
76         String logcatDate = getCurrentLogcatDate();
77 
78         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE,
79                 "com.android.server.cts.storaged.StoragedTest",
80                 "testBackgroundIO");
81         String log = mDevice.executeAdbCommand(
82                 "logcat", "-v", "brief", "-d", "-t", logcatDate,
83                 "SimpleIOService:I", "*:S");
84         String serviceCgroup = getCgroupFromLog(log);
85         if (serviceCgroup != null && serviceCgroup.equals("/top")) {
86             System.out.println("WARNING: Service was not in the correct cgroup; ActivityManager may be unresponsive.");
87         }
88 
89         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE,
90                 "com.android.server.cts.storaged.StoragedTest",
91                 "testForegroundIO");
92 
93         String output = mDevice.executeShellCommand("dumpsys storaged --force --hours 0.01");
94         assertNotNull(output);
95         assertTrue(output.length() > 0);
96 
97         boolean hasTestIO = false;
98         try (BufferedReader reader = new BufferedReader(
99                 new StringReader(output))) {
100 
101             String line;
102             String[] parts;
103             while ((line = reader.readLine()) != null) {
104                 if (line.isEmpty()) {
105                     continue;
106                 }
107 
108                 if (line.contains(",")) {
109                     parts = line.split(",");
110                     assertTrue(parts.length == 2);
111                     if (!parts[0].isEmpty()) {
112                         assertInteger(parts[0]);
113                     }
114                     assertInteger(parts[1]);
115                     continue;
116                 }
117 
118                 parts = line.split(" ");
119                 assertTrue(parts.length == 9);
120                 for (int i = 1; i < parts.length; i++) {
121                     assertInteger(parts[i]);
122                 }
123 
124                 if (parts[0].equals(DEVICE_SIDE_TEST_PACKAGE)) {
125                     /*
126                      * order of parts in StoragedService::dumpUidRecords
127                      *  [0] DEVICE_SIDE_TEST_PACKAGE
128                      *  [1] read foreground charger_off
129                      *  [2] write foreground charger_off
130                      *  [3] read background charger_off
131                      *  [4] write background charger_off
132                      *  [5] read foreground charger_on
133                      *  [6] write foreground charger_on
134                      *  [7] read background charger_on
135                      *  [8] write background charger_on
136                      */
137                     if ((Integer.parseInt(parts[6]) >= 8192 && Integer.parseInt(parts[8]) == 0) ||
138                         (Integer.parseInt(parts[2]) >= 8192 && Integer.parseInt(parts[4]) == 0)) {
139                         System.out.print("WARNING: Background I/O was attributed to the "
140                                 + "foreground. This could indicate a broken or malfunctioning "
141                                 + "ActivityManager or UsageStatsService.\n");
142                     } else if ((Integer.parseInt(parts[2]) >= 4096 && Integer.parseInt(parts[4]) >= 4096) ||
143                                     Integer.parseInt(parts[4]) >= 8192) {
144                         System.out.print("WARNING: charger on I/O was attributed to "
145                                 + "charger off. This could indicate a broken or malfunctioning "
146                                 + "ADB USB connection, or device that refuses to charge at the "
147                                 + "typical 500mA because it is less than 0.05C.\n");
148                     } else {
149                         assertTrue((Integer.parseInt(parts[6]) >= 4096 && Integer.parseInt(parts[8]) >= 4096) ||
150                                     Integer.parseInt(parts[8]) >= 8192);
151                     }
152                     hasTestIO = true;
153                 }
154             }
155 
156             assertTrue(hasTestIO);
157         }
158     }
159 }
160