blob: aaf94af0ef67f64ce3da0af4659eeb5e838e8c8c [file] [log] [blame]
/*
* 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.metric;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import android.cts.statsd.atom.DeviceAtomTestCase;
import com.android.internal.os.StatsdConfigProto;
import com.android.internal.os.StatsdConfigProto.FieldMatcher;
import com.android.internal.os.StatsdConfigProto.Position;
import com.android.os.AtomsProto.Atom;
import com.android.os.AtomsProto.AppBreadcrumbReported;
import com.android.os.AtomsProto.AttributionNode;
import com.android.os.AtomsProto.BleScanStateChanged;
import com.android.os.StatsLog;
import com.android.os.StatsLog.ConfigMetricsReport;
import com.android.os.StatsLog.ConfigMetricsReportList;
import com.android.os.StatsLog.CountBucketInfo;
import com.android.os.StatsLog.CountMetricData;
import com.android.os.StatsLog.StatsLogReport;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil;
import java.util.Arrays;
import java.util.List;
public class CountMetricsTests extends DeviceAtomTestCase {
public void testSimpleEventCountMetric() throws Exception {
if (statsdDisabled()) {
return;
}
int matcherId = 1;
StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder();
builder.addCountMetric(StatsdConfigProto.CountMetric.newBuilder()
.setId(MetricsUtils.COUNT_METRIC_ID)
.setBucket(StatsdConfigProto.TimeUnit.CTS)
.setWhat(matcherId))
.addAtomMatcher(MetricsUtils.simpleAtomMatcher(matcherId));
uploadConfig(builder);
doAppBreadcrumbReportedStart(0);
doAppBreadcrumbReportedStop(0);
Thread.sleep(2000); // Wait for the metrics to propagate to statsd.
StatsLogReport metricReport = getStatsLogReport();
LogUtil.CLog.d("Got the following stats log report: \n" + metricReport.toString());
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.COUNT_METRIC_ID);
assertThat(metricReport.hasCountMetrics()).isTrue();
StatsLogReport.CountMetricDataWrapper countData = metricReport.getCountMetrics();
assertThat(countData.getDataCount()).isGreaterThan(0);
assertThat(countData.getData(0).getBucketInfo(0).getCount()).isEqualTo(2);
}
public void testEventCountWithCondition() throws Exception {
if (statsdDisabled()) {
return;
}
int startMatcherId = 1;
int endMatcherId = 2;
int whatMatcherId = 3;
int conditionId = 4;
StatsdConfigProto.AtomMatcher whatMatcher =
MetricsUtils.unspecifiedAtomMatcher(whatMatcherId);
StatsdConfigProto.AtomMatcher predicateStartMatcher =
MetricsUtils.startAtomMatcher(startMatcherId);
StatsdConfigProto.AtomMatcher predicateEndMatcher =
MetricsUtils.stopAtomMatcher(endMatcherId);
StatsdConfigProto.Predicate p = StatsdConfigProto.Predicate.newBuilder()
.setSimplePredicate(StatsdConfigProto.SimplePredicate.newBuilder()
.setStart(startMatcherId)
.setStop(endMatcherId)
.setCountNesting(false))
.setId(conditionId)
.build();
StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder()
.addCountMetric(StatsdConfigProto.CountMetric.newBuilder()
.setId(MetricsUtils.COUNT_METRIC_ID)
.setBucket(StatsdConfigProto.TimeUnit.CTS)
.setWhat(whatMatcherId)
.setCondition(conditionId))
.addAtomMatcher(whatMatcher)
.addAtomMatcher(predicateStartMatcher)
.addAtomMatcher(predicateEndMatcher)
.addPredicate(p);
uploadConfig(builder);
doAppBreadcrumbReported(0, AppBreadcrumbReported.State.UNSPECIFIED.ordinal());
Thread.sleep(10);
doAppBreadcrumbReportedStart(0);
Thread.sleep(10);
doAppBreadcrumbReported(0, AppBreadcrumbReported.State.UNSPECIFIED.ordinal());
Thread.sleep(10);
doAppBreadcrumbReportedStop(0);
Thread.sleep(10);
doAppBreadcrumbReported(0, AppBreadcrumbReported.State.UNSPECIFIED.ordinal());
Thread.sleep(2000); // Wait for the metrics to propagate to statsd.
StatsLogReport metricReport = getStatsLogReport();
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.COUNT_METRIC_ID);
assertThat(metricReport.hasCountMetrics()).isTrue();
StatsLogReport.CountMetricDataWrapper countData = metricReport.getCountMetrics();
assertThat(countData.getDataCount()).isGreaterThan(0);
assertThat(countData.getData(0).getBucketInfo(0).getCount()).isEqualTo(1);
}
public void testEventCountWithConditionAndActivation() throws Exception {
if (statsdDisabled()) {
return;
}
int startMatcherId = 1;
int startMatcherLabel = 1;
int endMatcherId = 2;
int endMatcherLabel = 2;
int whatMatcherId = 3;
int whatMatcherLabel = 3;
int conditionId = 4;
int activationMatcherId = 5;
int activationMatcherLabel = 5;
int ttlSec = 5;
StatsdConfigProto.AtomMatcher whatMatcher =
MetricsUtils.appBreadcrumbMatcherWithLabel(whatMatcherId, whatMatcherLabel);
StatsdConfigProto.AtomMatcher predicateStartMatcher =
MetricsUtils.startAtomMatcherWithLabel(startMatcherId, startMatcherLabel);
StatsdConfigProto.AtomMatcher predicateEndMatcher =
MetricsUtils.stopAtomMatcherWithLabel(endMatcherId, endMatcherLabel);
StatsdConfigProto.AtomMatcher activationMatcher =
MetricsUtils.appBreadcrumbMatcherWithLabel(activationMatcherId,
activationMatcherLabel);
StatsdConfigProto.Predicate p = StatsdConfigProto.Predicate.newBuilder()
.setSimplePredicate(StatsdConfigProto.SimplePredicate.newBuilder()
.setStart(startMatcherId)
.setStop(endMatcherId)
.setCountNesting(false))
.setId(conditionId)
.build();
StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder()
.addCountMetric(StatsdConfigProto.CountMetric.newBuilder()
.setId(MetricsUtils.COUNT_METRIC_ID)
.setBucket(StatsdConfigProto.TimeUnit.CTS)
.setWhat(whatMatcherId)
.setCondition(conditionId)
)
.addAtomMatcher(whatMatcher)
.addAtomMatcher(predicateStartMatcher)
.addAtomMatcher(predicateEndMatcher)
.addAtomMatcher(activationMatcher)
.addPredicate(p)
.addMetricActivation(StatsdConfigProto.MetricActivation.newBuilder()
.setMetricId(MetricsUtils.COUNT_METRIC_ID)
.setActivationType(StatsdConfigProto.ActivationType.ACTIVATE_IMMEDIATELY)
.addEventActivation(StatsdConfigProto.EventActivation.newBuilder()
.setAtomMatcherId(activationMatcherId)
.setTtlSeconds(ttlSec)));
uploadConfig(builder);
// Activate the metric.
doAppBreadcrumbReported(activationMatcherLabel);
Thread.sleep(10);
// Set the condition to true.
doAppBreadcrumbReportedStart(startMatcherLabel);
Thread.sleep(10);
// Log an event that should be counted. Bucket 1 Count 1.
doAppBreadcrumbReported(whatMatcherLabel);
Thread.sleep(10);
// Log an event that should be counted. Bucket 1 Count 2.
doAppBreadcrumbReported(whatMatcherLabel);
Thread.sleep(10);
// Set the condition to false.
doAppBreadcrumbReportedStop(endMatcherLabel);
Thread.sleep(10);
// Log an event that should not be counted because condition is false.
doAppBreadcrumbReported(whatMatcherLabel);
Thread.sleep(10);
// Let the metric deactivate.
Thread.sleep(ttlSec * 1000);
// Log an event that should not be counted.
doAppBreadcrumbReported(whatMatcherLabel);
Thread.sleep(10);
// Condition to true again.
doAppBreadcrumbReportedStart(startMatcherLabel);
Thread.sleep(10);
// Event should not be counted, metric is still not active.
doAppBreadcrumbReported(whatMatcherLabel);
Thread.sleep(10);
// Activate the metric.
doAppBreadcrumbReported(activationMatcherLabel);
Thread.sleep(10);
// Log an event that should be counted.
doAppBreadcrumbReported(whatMatcherLabel);
Thread.sleep(10);
// Let the metric deactivate.
Thread.sleep(ttlSec * 1000);
// Log an event that should not be counted.
doAppBreadcrumbReported(whatMatcherLabel);
Thread.sleep(10);
// Wait for the metrics to propagate to statsd.
Thread.sleep(2000);
StatsLogReport metricReport = getStatsLogReport();
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.COUNT_METRIC_ID);
LogUtil.CLog.d("Received the following data: " + metricReport.toString());
assertThat(metricReport.hasCountMetrics()).isTrue();
assertThat(metricReport.getIsActive()).isFalse();
StatsLogReport.CountMetricDataWrapper countData = metricReport.getCountMetrics();
assertThat(countData.getDataCount()).isEqualTo(1);
assertThat(countData.getData(0).getBucketInfoCount()).isEqualTo(2);
assertThat(countData.getData(0).getBucketInfo(0).getCount()).isEqualTo(2);
assertThat(countData.getData(0).getBucketInfo(1).getCount()).isEqualTo(1);
}
public void testPartialBucketCountMetric() throws Exception {
if (statsdDisabled()) {
return;
}
int matcherId = 1;
StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder();
builder.addCountMetric(StatsdConfigProto.CountMetric.newBuilder()
.setId(MetricsUtils.COUNT_METRIC_ID)
.setBucket(StatsdConfigProto.TimeUnit.ONE_DAY) // Should ensure partial bucket.
.setWhat(matcherId))
.addAtomMatcher(MetricsUtils.simpleAtomMatcher(matcherId));
uploadConfig(builder);
doAppBreadcrumbReportedStart(0);
builder.getCountMetricBuilder(0).setBucket(StatsdConfigProto.TimeUnit.CTS);
uploadConfig(builder); // The count metric had a partial bucket.
doAppBreadcrumbReportedStart(0);
Thread.sleep(10);
doAppBreadcrumbReportedStart(0);
Thread.sleep(WAIT_TIME_LONG); // Finish the current bucket.
ConfigMetricsReportList reports = getReportList();
LogUtil.CLog.d("Got following report list: " + reports.toString());
assertThat(reports.getReportsCount()).isEqualTo(2);
boolean inOrder = reports.getReports(0).getCurrentReportWallClockNanos() <
reports.getReports(1).getCurrentReportWallClockNanos();
// Only 1 metric, so there should only be 1 StatsLogReport.
for (ConfigMetricsReport report : reports.getReportsList()) {
assertThat(report.getMetricsCount()).isEqualTo(1);
assertThat(report.getMetrics(0).getCountMetrics().getDataCount()).isEqualTo(1);
}
CountMetricData data1 =
reports.getReports(inOrder? 0 : 1).getMetrics(0).getCountMetrics().getData(0);
CountMetricData data2 =
reports.getReports(inOrder? 1 : 0).getMetrics(0).getCountMetrics().getData(0);
// Data1 should have only 1 bucket, and it should be a partial bucket.
// The count should be 1.
assertThat(data1.getBucketInfoCount()).isEqualTo(1);
CountBucketInfo bucketInfo = data1.getBucketInfo(0);
assertThat(bucketInfo.getCount()).isEqualTo(1);
assertWithMessage("First report's bucket should be less than 1 day")
.that(bucketInfo.getEndBucketElapsedNanos())
.isLessThan(bucketInfo.getStartBucketElapsedNanos() +
1_000_000_000L * 60L * 60L * 24L);
//Second report should have a count of 2.
assertThat(data2.getBucketInfoCount()).isAtMost(2);
int totalCount = 0;
for (CountBucketInfo bucket : data2.getBucketInfoList()) {
totalCount += bucket.getCount();
}
assertThat(totalCount).isEqualTo(2);
}
public void testSlicedStateCountMetric() throws Exception {
if (statsdDisabled()) {
return;
}
if (!hasFeature(FEATURE_BLUETOOTH_LE, true)) return;
int whatMatcherId = 3;
int stateId = 4;
// Atom 9999 {
// repeated AttributionNode attribution_node = 1;
// optional bool is_filtered = 2;
// optional bool is_first_match = 3;
// optional bool is_opportunistic = 4;
// }
int whatAtomId = 9_999;
StatsdConfigProto.AtomMatcher whatMatcher =
MetricsUtils.getAtomMatcher(whatAtomId)
.setId(whatMatcherId)
.build();
StatsdConfigProto.State state = StatsdConfigProto.State.newBuilder()
.setId(stateId)
.setAtomId(Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER)
.build();
StatsdConfigProto.MetricStateLink stateLink = StatsdConfigProto.MetricStateLink.newBuilder()
.setStateAtomId(Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER)
.setFieldsInWhat(FieldMatcher.newBuilder()
.setField(whatAtomId)
.addChild(FieldMatcher.newBuilder()
.setField(1)
.setPosition(Position.FIRST)
.addChild(FieldMatcher.newBuilder()
.setField(AttributionNode.UID_FIELD_NUMBER)
)
)
.addChild(FieldMatcher.newBuilder()
.setField(2)
)
.addChild(FieldMatcher.newBuilder()
.setField(3)
)
.addChild(FieldMatcher.newBuilder()
.setField(4)
)
)
.setFieldsInState(FieldMatcher.newBuilder()
.setField(Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER)
.addChild(FieldMatcher.newBuilder()
.setField(BleScanStateChanged.ATTRIBUTION_NODE_FIELD_NUMBER)
.setPosition(Position.FIRST)
.addChild(FieldMatcher.newBuilder()
.setField(AttributionNode.UID_FIELD_NUMBER)
)
)
.addChild(FieldMatcher.newBuilder()
.setField(BleScanStateChanged.IS_FILTERED_FIELD_NUMBER)
)
.addChild(FieldMatcher.newBuilder()
.setField(BleScanStateChanged.IS_FIRST_MATCH_FIELD_NUMBER)
)
.addChild(FieldMatcher.newBuilder()
.setField(BleScanStateChanged.IS_OPPORTUNISTIC_FIELD_NUMBER)
)
)
.build();
StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder()
.addCountMetric(StatsdConfigProto.CountMetric.newBuilder()
.setId(MetricsUtils.COUNT_METRIC_ID)
.setBucket(StatsdConfigProto.TimeUnit.CTS)
.setWhat(whatMatcherId)
.addSliceByState(stateId)
.addStateLink(stateLink)
)
.addAtomMatcher(whatMatcher)
.addState(state);
uploadConfig(builder);
runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testBleScanInterrupted");
StatsLogReport metricReport = getStatsLogReport();
LogUtil.CLog.d("Got the following stats log report: \n" + metricReport.toString());
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.COUNT_METRIC_ID);
assertThat(metricReport.hasCountMetrics()).isTrue();
StatsLogReport.CountMetricDataWrapper dataWrapper = metricReport.getCountMetrics();
assertThat(dataWrapper.getDataCount()).isEqualTo(2);
CountMetricData data = dataWrapper.getData(0);
assertThat(data.getSliceByStateCount()).isEqualTo(1);
assertThat(data.getSliceByState(0).getAtomId())
.isEqualTo(Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER);
assertThat(data.getSliceByState(0).getValue())
.isEqualTo(BleScanStateChanged.State.OFF.ordinal());
long totalCount = data.getBucketInfoList().stream()
.mapToLong(CountBucketInfo::getCount)
.sum();
assertThat(totalCount).isEqualTo(3);
data = dataWrapper.getData(1);
assertThat(data.getSliceByStateCount()).isEqualTo(1);
assertThat(data.getSliceByState(0).getAtomId())
.isEqualTo(Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER);
assertThat(data.getSliceByState(0).getValue())
.isEqualTo(BleScanStateChanged.State.ON.ordinal());
totalCount = data.getBucketInfoList().stream()
.mapToLong(CountBucketInfo::getCount)
.sum();
assertThat(totalCount).isEqualTo(2);
}
}