Add CTS test for StateTracker annotations
Test using a metric which slices by BleScanStateChanged atom and uses a
fake atom as the what for the metric.
Bug: 153880954
Test: atest
CtsStatsdHostTestCases: android.cts.statsd.metric.CountMetricsTests#testSlicedStateCountMetric
Change-Id: I27f561f83bbb638c065e059f677a76fc40f0e3a9
diff --git a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
index 53682ad..b53d151 100644
--- a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
+++ b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
@@ -62,6 +62,7 @@
import android.os.HandlerThread;
import android.os.Looper;
import android.os.PowerManager;
+import android.os.Process;
import android.os.SystemClock;
import android.os.VibrationEffect;
import android.os.Vibrator;
@@ -85,6 +86,7 @@
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.BiConsumer;
public class AtomTests {
private static final String TAG = AtomTests.class.getSimpleName();
@@ -226,7 +228,68 @@
performBleScan(scanSettings, Arrays.asList(scanFilter.build()), true);
}
- private static void performBleScan(ScanSettings scanSettings, List<ScanFilter> scanFilters, boolean waitForResult) {
+ @Test
+ public void testBleScanInterrupted() throws Exception {
+ performBleAction((bluetoothAdapter, bleScanner) -> {
+ ScanSettings scanSettings = new ScanSettings.Builder()
+ .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
+ ScanCallback scanCallback = new ScanCallback() {
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ Log.v(TAG, "called onScanResult");
+ }
+ @Override
+ public void onScanFailed(int errorCode) {
+ Log.v(TAG, "called onScanFailed");
+ }
+ @Override
+ public void onBatchScanResults(List<ScanResult> results) {
+ Log.v(TAG, "called onBatchScanResults");
+ }
+ };
+
+ int uid = Process.myUid();
+ int whatAtomId = 9_999;
+
+ // Change state to State.ON.
+ bleScanner.startScan(null, scanSettings, scanCallback);
+ sleep(500);
+ writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
+ writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
+ bluetoothAdapter.disable();
+ sleep(500);
+
+ // Trigger State.RESET so that new state is State.OFF.
+ if (!bluetoothAdapter.enable()) {
+ Log.e(TAG, "Could not enable bluetooth to trigger state reset");
+ return;
+ }
+ sleep(2_000); // Wait for Bluetooth to fully turn on.
+ writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
+ writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
+ writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
+ });
+ }
+
+ private static void writeSliceByBleScanStateChangedAtom(int atomId, int firstUid,
+ boolean field2, boolean field3,
+ boolean field4) {
+ final StatsEvent.Builder builder = StatsEvent.newBuilder()
+ .setAtomId(atomId)
+ .writeAttributionChain(new int[] {firstUid}, new String[] {"tag1"})
+ .writeBoolean(field2)
+ .writeBoolean(field3)
+ .writeBoolean(field4)
+ .usePooledBuffer();
+
+ StatsLog.write(builder.build());
+ }
+
+ /**
+ * Set up BluetoothLeScanner and perform the action in the callback.
+ * Restore Bluetooth to original state afterwards.
+ **/
+ private static void performBleAction(BiConsumer<BluetoothAdapter, BluetoothLeScanner> actions) {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
Log.e(TAG, "Device does not support Bluetooth");
@@ -238,7 +301,7 @@
Log.e(TAG, "Bluetooth is not enabled");
return;
}
- sleep(8_000);
+ sleep(2_000); // Wait for Bluetooth to fully turn on.
bluetoothEnabledByTest = true;
}
BluetoothLeScanner bleScanner = bluetoothAdapter.getBluetoothLeScanner();
@@ -247,38 +310,45 @@
return;
}
- CountDownLatch resultsLatch = new CountDownLatch(1);
- ScanCallback scanCallback = new ScanCallback() {
- @Override
- public void onScanResult(int callbackType, ScanResult result) {
- Log.v(TAG, "called onScanResult");
- resultsLatch.countDown();
- }
- @Override
- public void onScanFailed(int errorCode) {
- Log.v(TAG, "called onScanFailed");
- }
- @Override
- public void onBatchScanResults(List<ScanResult> results) {
- Log.v(TAG, "called onBatchScanResults");
- resultsLatch.countDown();
- }
- };
+ actions.accept(bluetoothAdapter, bleScanner);
- bleScanner.startScan(scanFilters, scanSettings, scanCallback);
- if (waitForResult) {
- waitForReceiver(InstrumentationRegistry.getContext(), 59_000, resultsLatch, null);
- } else {
- sleep(2_000);
- }
- bleScanner.stopScan(scanCallback);
-
- // Restore adapter state at end of test
+ // Restore adapter state
if (bluetoothEnabledByTest) {
bluetoothAdapter.disable();
}
}
+
+ private static void performBleScan(ScanSettings scanSettings, List<ScanFilter> scanFilters, boolean waitForResult) {
+ performBleAction((bluetoothAdapter, bleScanner) -> {
+ CountDownLatch resultsLatch = new CountDownLatch(1);
+ ScanCallback scanCallback = new ScanCallback() {
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ Log.v(TAG, "called onScanResult");
+ resultsLatch.countDown();
+ }
+ @Override
+ public void onScanFailed(int errorCode) {
+ Log.v(TAG, "called onScanFailed");
+ }
+ @Override
+ public void onBatchScanResults(List<ScanResult> results) {
+ Log.v(TAG, "called onBatchScanResults");
+ resultsLatch.countDown();
+ }
+ };
+
+ bleScanner.startScan(scanFilters, scanSettings, scanCallback);
+ if (waitForResult) {
+ waitForReceiver(InstrumentationRegistry.getContext(), 59_000, resultsLatch, null);
+ } else {
+ sleep(2_000);
+ }
+ bleScanner.stopScan(scanCallback);
+ });
+ }
+
@Test
public void testCameraState() throws Exception {
Context context = InstrumentationRegistry.getContext();
diff --git a/hostsidetests/statsd/src/android/cts/statsd/metric/CountMetricsTests.java b/hostsidetests/statsd/src/android/cts/statsd/metric/CountMetricsTests.java
index 4eeb74c..aaf94af 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/metric/CountMetricsTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/metric/CountMetricsTests.java
@@ -21,8 +21,12 @@
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;
@@ -296,7 +300,7 @@
assertThat(bucketInfo.getCount()).isEqualTo(1);
assertWithMessage("First report's bucket should be less than 1 day")
.that(bucketInfo.getEndBucketElapsedNanos())
- .isLessThan(bucketInfo.getStartBucketElapsedNanos() +
+ .isLessThan(bucketInfo.getStartBucketElapsedNanos() +
1_000_000_000L * 60L * 60L * 24L);
//Second report should have a count of 2.
@@ -307,4 +311,118 @@
}
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);
+ }
}