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