| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package android.cts.statsd.validation; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import android.cts.statsd.atom.ProcStateTestCase; |
| import android.service.procstats.ProcessState; |
| import android.service.procstats.AggregatedProcessState; |
| |
| import com.android.internal.os.StatsdConfigProto.StatsdConfig; |
| import com.android.os.AtomsProto.Atom; |
| import com.android.os.AtomsProto.ProcessStateAggregated; |
| import com.android.os.AtomsProto.ProcessStatsPackageProto; |
| import com.android.os.AtomsProto.ProcessStatsProto; |
| import com.android.os.AtomsProto.ProcessStatsStateProto; |
| import com.android.os.StatsLog.DimensionsValue; |
| import com.android.os.StatsLog.ValueBucketInfo; |
| import com.android.os.StatsLog.ValueMetricData; |
| import com.android.tradefed.device.ITestDevice; |
| import com.android.tradefed.log.LogUtil; |
| |
| import java.util.List; |
| |
| /** |
| * Side-by-side comparison between statsd and procstats. |
| */ |
| public class ProcStatsValidationTests extends ProcStateTestCase { |
| |
| private static final String TAG = "Statsd.ProcStatsValidationTests"; |
| |
| private static final int EXTRA_WAIT_TIME_MS = 1_000; // as buffer when proc state changing. |
| |
| private void toggleScreenAndSleep(final long duration) throws Exception { |
| final long half = duration >> 1; |
| Thread.sleep(half); |
| turnScreenOff(); |
| Thread.sleep(half); |
| turnScreenOn(); |
| } |
| |
| public void testProcessStateByPulling() throws Exception { |
| startProcStatsTesting(); |
| clearProcStats(); |
| Thread.sleep(WAIT_TIME_SHORT); |
| |
| // foreground service |
| executeForegroundService(); |
| Thread.sleep(SLEEP_OF_FOREGROUND_SERVICE + EXTRA_WAIT_TIME_MS); |
| // background |
| executeBackgroundService(ACTION_BACKGROUND_SLEEP); |
| Thread.sleep(SLEEP_OF_ACTION_BACKGROUND_SLEEP + EXTRA_WAIT_TIME_MS); |
| // top |
| executeForegroundActivity(ACTION_SLEEP_WHILE_TOP); |
| Thread.sleep(SLEEP_OF_ACTION_SLEEP_WHILE_TOP + EXTRA_WAIT_TIME_MS); |
| // Start extremely short-lived activity, so app goes into cache state (#1 - #3 above). |
| executeBackgroundService(ACTION_END_IMMEDIATELY); |
| final int cacheTime = 2_000; // process should be in cached state for up to this long |
| Thread.sleep(cacheTime); |
| // foreground |
| // overlay should take 2 sec to appear. So this makes it 4 sec in TOP |
| executeForegroundActivity(ACTION_SHOW_APPLICATION_OVERLAY); |
| Thread.sleep(EXTRA_WAIT_TIME_MS + 5_000); |
| |
| Thread.sleep(60_000); |
| uninstallPackage(); |
| stopProcStatsTesting(); |
| commitProcStatsToDisk(); |
| Thread.sleep(WAIT_TIME_SHORT); |
| |
| final String fileName = "PROCSTATSQ_PULL.pbtxt"; |
| StatsdConfig config = createValidationUtil().getConfig(fileName); |
| LogUtil.CLog.d("Updating the following config:\n" + config.toString()); |
| uploadConfig(config); |
| Thread.sleep(WAIT_TIME_SHORT); |
| setAppBreadcrumbPredicate(); |
| Thread.sleep(WAIT_TIME_SHORT + 5_000); |
| |
| List<Atom> statsdData = getGaugeMetricDataList(); |
| |
| List<android.service.procstats.ProcessStatsProto> processStatsProtoList |
| = getAllProcStatsProtoForStatsd(); |
| |
| // We pull directly from ProcessStatsService, so not necessary to compare every field. |
| // Make sure that 1. both capture statsd package 2. spot check some values are reasonable |
| LogUtil.CLog.d("======================"); |
| |
| String statsdPkgName = "com.android.server.cts.device.statsd"; |
| long rssAvgStatsd = 0; |
| for (Atom d : statsdData) { |
| for (ProcessStatsProto proc : d.getProcStats().getProcStatsSection().getProcessStatsList()) { |
| if (proc.getProcess().equals(statsdPkgName)) { |
| LogUtil.CLog.d("Got proto from statsd:"); |
| LogUtil.CLog.d(proc.toString()); |
| for (ProcessStatsStateProto state : proc.getStatesList()) { |
| if (state.getProcessStateAggregated() |
| == ProcessStateAggregated.PROCESS_STATE_IMPORTANT_FOREGROUND) { |
| rssAvgStatsd = state.getRss().getMeanKb(); |
| } |
| } |
| } |
| } |
| } |
| |
| long rssAvgProcstats = 0; |
| for (android.service.procstats.ProcessStatsProto process: processStatsProtoList) { |
| if (process.getProcess().equals(statsdPkgName)) { |
| LogUtil.CLog.d("Got proto from procstats dumpsys:"); |
| LogUtil.CLog.d(process.toString()); |
| for (android.service.procstats.ProcessStatsStateProto state |
| : process.getStatesList()) { |
| if (AggregatedProcessState.AGGREGATED_PROCESS_STATE_IMPORTANT_FOREGROUND |
| == state.getProcessStateAggregated()) { |
| rssAvgProcstats = state.getRss().getMeanKb(); |
| break; |
| } |
| } |
| } |
| } |
| |
| assertThat(rssAvgStatsd).isEqualTo(rssAvgProcstats); |
| } |
| |
| public void testProcStatsPkgProcStats() throws Exception { |
| /** |
| * Temporarily disable this test as the proc stats data being pulled into the statsd |
| * doesn't include the pkg part now. |
| * |
| startProcStatsTesting(); |
| clearProcStats(); |
| Thread.sleep(WAIT_TIME_SHORT); |
| |
| // foreground service |
| executeForegroundService(); |
| Thread.sleep(SLEEP_OF_FOREGROUND_SERVICE + EXTRA_WAIT_TIME_MS); |
| // background |
| executeBackgroundService(ACTION_BACKGROUND_SLEEP); |
| Thread.sleep(SLEEP_OF_ACTION_BACKGROUND_SLEEP + EXTRA_WAIT_TIME_MS); |
| // top |
| executeForegroundActivity(ACTION_SLEEP_WHILE_TOP); |
| Thread.sleep(SLEEP_OF_ACTION_SLEEP_WHILE_TOP + EXTRA_WAIT_TIME_MS); |
| // Start extremely short-lived activity, so app goes into cache state (#1 - #3 above). |
| executeBackgroundService(ACTION_END_IMMEDIATELY); |
| final int cacheTime = 2_000; // process should be in cached state for up to this long |
| Thread.sleep(cacheTime); |
| // foreground |
| // overlay should take 2 sec to appear. So this makes it 4 sec in TOP |
| executeForegroundActivity(ACTION_SHOW_APPLICATION_OVERLAY); |
| Thread.sleep(EXTRA_WAIT_TIME_MS + 5_000); |
| |
| Thread.sleep(60_000); |
| uninstallPackage(); |
| stopProcStatsTesting(); |
| commitProcStatsToDisk(); |
| Thread.sleep(WAIT_TIME_SHORT); |
| |
| final String fileName = "PROCSTATSQ_PULL_PKG_PROC.pbtxt"; |
| StatsdConfig config = createValidationUtil().getConfig(fileName); |
| LogUtil.CLog.d("Updating the following config:\n" + config.toString()); |
| uploadConfig(config); |
| Thread.sleep(WAIT_TIME_SHORT); |
| setAppBreadcrumbPredicate(); |
| Thread.sleep(WAIT_TIME_SHORT); |
| |
| List<Atom> statsdData = getGaugeMetricDataList(); |
| assertThat(statsdData).isNotEmpty(); |
| assertThat( |
| statsdData.get(0).getProcStatsPkgProc().getProcStatsSection() |
| .getProcessStatsList() |
| ).isNotEmpty(); |
| |
| // We pull directly from ProcessStatsService, so not necessary to compare every field. |
| // Make sure that 1. both capture statsd package 2. spot check some values are reasonable |
| LogUtil.CLog.d("======================"); |
| |
| String statsdPkgName = "com.android.server.cts.device.statsd"; |
| long rssAvgStatsd = 0; |
| long durationStatsd = 0; |
| for (Atom d : statsdData) { |
| for (ProcessStatsPackageProto pkg : d.getProcStatsPkgProc().getProcStatsSection().getPackageStatsList()) { |
| if (pkg.getPackage().equals(statsdPkgName)) { |
| LogUtil.CLog.d("Got proto from statsd:"); |
| LogUtil.CLog.d(pkg.toString()); |
| for (ProcessStatsProto process : pkg.getProcessStatsList()) { |
| for (ProcessStatsStateProto state : process.getStatesList()) { |
| if (state.getProcessState() |
| == ProcessState.PROCESS_STATE_IMPORTANT_FOREGROUND) { |
| durationStatsd = state.getDurationMillis(); |
| rssAvgStatsd = state.getRss().getAverage(); |
| } |
| } |
| } |
| } |
| assertThat(pkg.getServiceStatsCount()).isEqualTo(0L); |
| assertThat(pkg.getAssociationStatsCount()).isEqualTo(0L); |
| } |
| } |
| |
| LogUtil.CLog.d("avg rss from statsd is " + rssAvgStatsd); |
| |
| List<ProcessStatsPackageProto> processStatsPackageProtoList = getAllProcStatsProto(); |
| |
| long pssAvgProcstats = 0; |
| long ussAvgProcstats = 0; |
| long rssAvgProcstats = 0; |
| long durationProcstats = 0; |
| int serviceStatsCount = 0; |
| int associationStatsCount = 0; |
| for (ProcessStatsPackageProto pkg : processStatsPackageProtoList) { |
| if (pkg.getPackage().equals(statsdPkgName)) { |
| LogUtil.CLog.d("Got proto from procstats dumpsys:"); |
| LogUtil.CLog.d(pkg.toString()); |
| for (ProcessStatsProto process : pkg.getProcessStatsList()) { |
| for (ProcessStatsStateProto state : process.getStatesList()) { |
| if (state.getProcessState() |
| == ProcessState.PROCESS_STATE_IMPORTANT_FOREGROUND) { |
| durationProcstats = state.getDurationMillis(); |
| pssAvgProcstats = state.getPss().getAverage(); |
| ussAvgProcstats = state.getUss().getAverage(); |
| rssAvgProcstats = state.getRss().getAverage(); |
| } |
| } |
| } |
| } |
| serviceStatsCount += pkg.getServiceStatsCount(); |
| associationStatsCount += pkg.getAssociationStatsCount(); |
| } |
| assertThat(serviceStatsCount).isGreaterThan(0); |
| assertThat(associationStatsCount).isGreaterThan(0); |
| |
| LogUtil.CLog.d("avg pss from procstats is " + pssAvgProcstats); |
| assertThat(rssAvgStatsd).isEqualTo(rssAvgProcstats); |
| */ |
| } |
| |
| private boolean isPssProfilingDisabled() throws Exception { |
| ITestDevice device = getDevice(); |
| final String disablePssProfilingKey = "disable_app_profiler_pss_profiling"; |
| final String stringToCompare = " " + disablePssProfilingKey + "=true"; |
| |
| final String dumpsys = device.executeShellCommand("dumpsys activity settings"); |
| return (dumpsys.contains(stringToCompare)); |
| } |
| } |