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