• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 package android.cts.statsd.validation;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 
20 import android.cts.statsd.atom.ProcStateTestCase;
21 import android.service.procstats.ProcessState;
22 import android.service.procstats.AggregatedProcessState;
23 
24 import com.android.internal.os.StatsdConfigProto.StatsdConfig;
25 import com.android.os.AtomsProto.Atom;
26 import com.android.os.AtomsProto.ProcessStateAggregated;
27 import com.android.os.AtomsProto.ProcessStatsPackageProto;
28 import com.android.os.AtomsProto.ProcessStatsProto;
29 import com.android.os.AtomsProto.ProcessStatsStateProto;
30 import com.android.os.StatsLog.DimensionsValue;
31 import com.android.os.StatsLog.ValueBucketInfo;
32 import com.android.os.StatsLog.ValueMetricData;
33 import com.android.tradefed.device.ITestDevice;
34 import com.android.tradefed.log.LogUtil;
35 
36 import java.util.List;
37 
38 /**
39  * Side-by-side comparison between statsd and procstats.
40  */
41 public class ProcStatsValidationTests extends ProcStateTestCase {
42 
43     private static final String TAG = "Statsd.ProcStatsValidationTests";
44 
45     private static final int EXTRA_WAIT_TIME_MS = 1_000; // as buffer when proc state changing.
46 
testProcessStatePssValue()47     public void testProcessStatePssValue() throws Exception {
48         if(isPssProfilingDisabled())  {
49             LogUtil.CLog.i("testProcessStatePssValue is ignored when PSS profiling is disabled");
50             return;
51         }
52         final String fileName = "PROCSTATSQ_PROCS_STATE_PSS_VALUE.pbtxt";
53         StatsdConfig config = createValidationUtil().getConfig(fileName);
54         LogUtil.CLog.d("Updating the following config:\n" + config.toString());
55         uploadConfig(config);
56         clearProcStats();
57         toggleScreenAndSleep(WAIT_TIME_SHORT);
58 
59         // foreground service
60         executeForegroundService();
61         toggleScreenAndSleep(SLEEP_OF_FOREGROUND_SERVICE + EXTRA_WAIT_TIME_MS);
62         // background
63         executeBackgroundService(ACTION_BACKGROUND_SLEEP);
64         toggleScreenAndSleep(SLEEP_OF_ACTION_BACKGROUND_SLEEP + EXTRA_WAIT_TIME_MS);
65         // top
66         executeForegroundActivity(ACTION_LONG_SLEEP_WHILE_TOP);
67         toggleScreenAndSleep(SLEEP_OF_ACTION_LONG_SLEEP_WHILE_TOP + EXTRA_WAIT_TIME_MS);
68         // Start extremely short-lived activity, so app goes into cache state (#1 - #3 above).
69         executeBackgroundService(ACTION_END_IMMEDIATELY);
70         final int cacheTime = 2_000; // process should be in cached state for up to this long
71         toggleScreenAndSleep(cacheTime);
72         // foreground
73         // overlay should take 2 sec to appear. So this makes it 4 sec in TOP
74         executeForegroundActivity(ACTION_SHOW_APPLICATION_OVERLAY);
75         toggleScreenAndSleep(EXTRA_WAIT_TIME_MS + 5_000);
76 
77         // Sorted list of events in order in which they occurred.
78         List<ValueMetricData> statsdData = getValueMetricDataList();
79 
80         List<ProcessStatsProto> processStatsProtoList = getProcStatsProto();
81 
82         LogUtil.CLog.d("======================");
83 
84         String statsdPkgName = "com.android.server.cts.device.statsd";
85         double valueInStatsd = 0;
86         for (ValueMetricData d : statsdData) {
87             List<DimensionsValue> dimensionsValuesInWhat = d.getDimensionLeafValuesInWhatList();
88             if (dimensionsValuesInWhat.get(0).getValueStr().equals(statsdPkgName)
89                     && dimensionsValuesInWhat.get(1).getValueStr().equals(statsdPkgName)) {
90                 LogUtil.CLog.d(d.toString());
91                 for (ValueBucketInfo bucket : d.getBucketInfoList()) {
92                     valueInStatsd = Math.max(bucket.getValues(0).getValueLong(), valueInStatsd);
93                 }
94             }
95         }
96 
97         double valueInProcStats = 0;
98         for (ProcessStatsProto p : processStatsProtoList) {
99             if (p.getProcess().equals(statsdPkgName)) {
100                 LogUtil.CLog.d(p.toString());
101                 for (ProcessStatsStateProto s : p.getStatesList()) {
102                     valueInProcStats = Math.max(s.getPss().getMax(), valueInProcStats);
103                 }
104             }
105         }
106         assertThat(valueInProcStats).isGreaterThan(0d);
107         assertThat(valueInStatsd).isWithin(1e-10).of(valueInProcStats);
108     }
109 
toggleScreenAndSleep(final long duration)110     private void toggleScreenAndSleep(final long duration) throws Exception {
111         final long half = duration >> 1;
112         Thread.sleep(half);
113         turnScreenOff();
114         Thread.sleep(half);
115         turnScreenOn();
116     }
117 
testProcessStateByPulling()118     public void testProcessStateByPulling() throws Exception {
119         startProcStatsTesting();
120         clearProcStats();
121         Thread.sleep(WAIT_TIME_SHORT);
122 
123         // foreground service
124         executeForegroundService();
125         Thread.sleep(SLEEP_OF_FOREGROUND_SERVICE + EXTRA_WAIT_TIME_MS);
126         // background
127         executeBackgroundService(ACTION_BACKGROUND_SLEEP);
128         Thread.sleep(SLEEP_OF_ACTION_BACKGROUND_SLEEP + EXTRA_WAIT_TIME_MS);
129         // top
130         executeForegroundActivity(ACTION_SLEEP_WHILE_TOP);
131         Thread.sleep(SLEEP_OF_ACTION_SLEEP_WHILE_TOP + EXTRA_WAIT_TIME_MS);
132         // Start extremely short-lived activity, so app goes into cache state (#1 - #3 above).
133         executeBackgroundService(ACTION_END_IMMEDIATELY);
134         final int cacheTime = 2_000; // process should be in cached state for up to this long
135         Thread.sleep(cacheTime);
136         // foreground
137         // overlay should take 2 sec to appear. So this makes it 4 sec in TOP
138         executeForegroundActivity(ACTION_SHOW_APPLICATION_OVERLAY);
139         Thread.sleep(EXTRA_WAIT_TIME_MS + 5_000);
140 
141         Thread.sleep(60_000);
142         uninstallPackage();
143         stopProcStatsTesting();
144         commitProcStatsToDisk();
145         Thread.sleep(WAIT_TIME_SHORT);
146 
147         final String fileName = "PROCSTATSQ_PULL.pbtxt";
148         StatsdConfig config = createValidationUtil().getConfig(fileName);
149         LogUtil.CLog.d("Updating the following config:\n" + config.toString());
150         uploadConfig(config);
151         Thread.sleep(WAIT_TIME_SHORT);
152         setAppBreadcrumbPredicate();
153         Thread.sleep(WAIT_TIME_SHORT + 5_000);
154 
155         List<Atom> statsdData = getGaugeMetricDataList();
156 
157         List<android.service.procstats.ProcessStatsProto> processStatsProtoList
158                 = getAllProcStatsProtoForStatsd();
159 
160         // We pull directly from ProcessStatsService, so not necessary to compare every field.
161         // Make sure that 1. both capture statsd package 2. spot check some values are reasonable
162         LogUtil.CLog.d("======================");
163 
164         String statsdPkgName = "com.android.server.cts.device.statsd";
165         long rssAvgStatsd = 0;
166         for (Atom d : statsdData) {
167             for (ProcessStatsProto proc : d.getProcStats().getProcStatsSection().getProcessStatsList()) {
168                 if (proc.getProcess().equals(statsdPkgName)) {
169                     LogUtil.CLog.d("Got proto from statsd:");
170                     LogUtil.CLog.d(proc.toString());
171                     for (ProcessStatsStateProto state : proc.getStatesList()) {
172                         if (state.getProcessStateAggregated()
173                                 == ProcessStateAggregated.PROCESS_STATE_IMPORTANT_FOREGROUND) {
174                             rssAvgStatsd = state.getRss().getMeanKb();
175                         }
176                     }
177                 }
178             }
179         }
180 
181         long rssAvgProcstats = 0;
182         for (android.service.procstats.ProcessStatsProto process: processStatsProtoList) {
183             if (process.getProcess().equals(statsdPkgName)) {
184                 LogUtil.CLog.d("Got proto from procstats dumpsys:");
185                 LogUtil.CLog.d(process.toString());
186                 for (android.service.procstats.ProcessStatsStateProto state
187                         : process.getStatesList()) {
188                     if (AggregatedProcessState.AGGREGATED_PROCESS_STATE_IMPORTANT_FOREGROUND
189                             == state.getProcessStateAggregated()) {
190                         rssAvgProcstats = state.getRss().getMeanKb();
191                         break;
192                     }
193                 }
194             }
195         }
196 
197         assertThat(rssAvgStatsd).isEqualTo(rssAvgProcstats);
198     }
199 
testProcStatsPkgProcStats()200     public void testProcStatsPkgProcStats() throws Exception {
201         /**
202          * Temporarily disable this test as the proc stats data being pulled into the statsd
203          * doesn't include the pkg part now.
204          *
205         startProcStatsTesting();
206         clearProcStats();
207         Thread.sleep(WAIT_TIME_SHORT);
208 
209         // foreground service
210         executeForegroundService();
211         Thread.sleep(SLEEP_OF_FOREGROUND_SERVICE + EXTRA_WAIT_TIME_MS);
212         // background
213         executeBackgroundService(ACTION_BACKGROUND_SLEEP);
214         Thread.sleep(SLEEP_OF_ACTION_BACKGROUND_SLEEP + EXTRA_WAIT_TIME_MS);
215         // top
216         executeForegroundActivity(ACTION_SLEEP_WHILE_TOP);
217         Thread.sleep(SLEEP_OF_ACTION_SLEEP_WHILE_TOP + EXTRA_WAIT_TIME_MS);
218         // Start extremely short-lived activity, so app goes into cache state (#1 - #3 above).
219         executeBackgroundService(ACTION_END_IMMEDIATELY);
220         final int cacheTime = 2_000; // process should be in cached state for up to this long
221         Thread.sleep(cacheTime);
222         // foreground
223         // overlay should take 2 sec to appear. So this makes it 4 sec in TOP
224         executeForegroundActivity(ACTION_SHOW_APPLICATION_OVERLAY);
225         Thread.sleep(EXTRA_WAIT_TIME_MS + 5_000);
226 
227         Thread.sleep(60_000);
228         uninstallPackage();
229         stopProcStatsTesting();
230         commitProcStatsToDisk();
231         Thread.sleep(WAIT_TIME_SHORT);
232 
233         final String fileName = "PROCSTATSQ_PULL_PKG_PROC.pbtxt";
234         StatsdConfig config = createValidationUtil().getConfig(fileName);
235         LogUtil.CLog.d("Updating the following config:\n" + config.toString());
236         uploadConfig(config);
237         Thread.sleep(WAIT_TIME_SHORT);
238         setAppBreadcrumbPredicate();
239         Thread.sleep(WAIT_TIME_SHORT);
240 
241         List<Atom> statsdData = getGaugeMetricDataList();
242         assertThat(statsdData).isNotEmpty();
243         assertThat(
244                 statsdData.get(0).getProcStatsPkgProc().getProcStatsSection()
245                         .getProcessStatsList()
246         ).isNotEmpty();
247 
248         // We pull directly from ProcessStatsService, so not necessary to compare every field.
249         // Make sure that 1. both capture statsd package 2. spot check some values are reasonable
250         LogUtil.CLog.d("======================");
251 
252         String statsdPkgName = "com.android.server.cts.device.statsd";
253         long rssAvgStatsd = 0;
254         long durationStatsd = 0;
255         for (Atom d : statsdData) {
256             for (ProcessStatsPackageProto pkg : d.getProcStatsPkgProc().getProcStatsSection().getPackageStatsList()) {
257                 if (pkg.getPackage().equals(statsdPkgName)) {
258                     LogUtil.CLog.d("Got proto from statsd:");
259                     LogUtil.CLog.d(pkg.toString());
260                     for (ProcessStatsProto process : pkg.getProcessStatsList()) {
261                         for (ProcessStatsStateProto state : process.getStatesList()) {
262                             if (state.getProcessState()
263                                     == ProcessState.PROCESS_STATE_IMPORTANT_FOREGROUND) {
264                                 durationStatsd = state.getDurationMillis();
265                                 rssAvgStatsd = state.getRss().getAverage();
266                             }
267                         }
268                     }
269                 }
270                 assertThat(pkg.getServiceStatsCount()).isEqualTo(0L);
271                 assertThat(pkg.getAssociationStatsCount()).isEqualTo(0L);
272             }
273         }
274 
275         LogUtil.CLog.d("avg rss from statsd is " + rssAvgStatsd);
276 
277         List<ProcessStatsPackageProto> processStatsPackageProtoList = getAllProcStatsProto();
278 
279         long pssAvgProcstats = 0;
280         long ussAvgProcstats = 0;
281         long rssAvgProcstats = 0;
282         long durationProcstats = 0;
283         int serviceStatsCount = 0;
284         int associationStatsCount = 0;
285         for (ProcessStatsPackageProto pkg : processStatsPackageProtoList) {
286             if (pkg.getPackage().equals(statsdPkgName)) {
287                 LogUtil.CLog.d("Got proto from procstats dumpsys:");
288                 LogUtil.CLog.d(pkg.toString());
289                 for (ProcessStatsProto process : pkg.getProcessStatsList()) {
290                     for (ProcessStatsStateProto state : process.getStatesList()) {
291                         if (state.getProcessState()
292                                 == ProcessState.PROCESS_STATE_IMPORTANT_FOREGROUND) {
293                             durationProcstats = state.getDurationMillis();
294                             pssAvgProcstats = state.getPss().getAverage();
295                             ussAvgProcstats = state.getUss().getAverage();
296                             rssAvgProcstats = state.getRss().getAverage();
297                         }
298                     }
299                 }
300             }
301             serviceStatsCount += pkg.getServiceStatsCount();
302             associationStatsCount += pkg.getAssociationStatsCount();
303         }
304         assertThat(serviceStatsCount).isGreaterThan(0);
305         assertThat(associationStatsCount).isGreaterThan(0);
306 
307         LogUtil.CLog.d("avg pss from procstats is " + pssAvgProcstats);
308         assertThat(rssAvgStatsd).isEqualTo(rssAvgProcstats);
309         */
310     }
311 
isPssProfilingDisabled()312     private boolean isPssProfilingDisabled() throws Exception {
313         ITestDevice device = getDevice();
314         final String disablePssProfilingKey = "disable_app_profiler_pss_profiling";
315         final String stringToCompare = " " + disablePssProfilingKey + "=true";
316 
317         final String dumpsys = device.executeShellCommand("dumpsys activity settings");
318         return (dumpsys.contains(stringToCompare));
319     }
320 }
321