Merge "Add @RequiresApi annotation to repeated fields write APIs in StatsEvent" into main
diff --git a/apex/tests/libstatspull/Android.bp b/apex/tests/libstatspull/Android.bp
index c3473e3..d3079e0 100644
--- a/apex/tests/libstatspull/Android.bp
+++ b/apex/tests/libstatspull/Android.bp
@@ -45,7 +45,7 @@
compile_multilib: "both",
}
-cc_library_shared {
+cc_test_library {
name: "libstatspull_testhelper",
srcs: ["jni/stats_pull_helper.cpp"],
cflags: [
@@ -54,12 +54,12 @@
"-Wthread-safety",
],
shared_libs: [
- "libbinder_ndk",
- "statsd-aidl-ndk",
+ "libstatspull",
+ "libstatssocket",
],
+ header_libs: ["libnativehelper_header_only"],
static_libs: [
"libbase",
- "libstatspull_private",
- "libstatssocket_private",
],
+ test_for: ["com.android.os.statsd"],
}
diff --git a/framework/Android.bp b/framework/Android.bp
index fe1a546..7ffa7b5 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -30,6 +30,9 @@
srcs: [
":statslog-statsd-java-gen",
],
+ libs: [
+ "androidx.annotation_annotation",
+ ],
visibility: [
"//cts/hostsidetests/statsd/apps:__subpackages__",
"//vendor:__subpackages__",
diff --git a/lib/libstatspull/Android.bp b/lib/libstatspull/Android.bp
index d10e7e3..28c0a70 100644
--- a/lib/libstatspull/Android.bp
+++ b/lib/libstatspull/Android.bp
@@ -77,20 +77,6 @@
export_include_dirs: ["include"],
}
-// ONLY USE IN TESTS.
-cc_library_static {
- name: "libstatspull_private",
- defaults: [
- "libstatspull_defaults",
- ],
- cflags: [
- "-DLIB_STATS_PULL_TESTS_FLAG",
- ],
- visibility: [
- "//packages/modules/StatsD/apex/tests/libstatspull",
- ],
-}
-
// Note: These unit tests only test PullAtomMetadata and subscriptions
// For full E2E tests of pullers, use LibStatsPullTests
cc_test {
@@ -152,4 +138,5 @@
],
require_root: true,
min_sdk_version: "30",
+ test_for: ["com.android.os.statsd"],
}
diff --git a/lib/libstatspull/stats_pull_atom_callback.cpp b/lib/libstatspull/stats_pull_atom_callback.cpp
index b3194c7..b880f0a 100644
--- a/lib/libstatspull/stats_pull_atom_callback.cpp
+++ b/lib/libstatspull/stats_pull_atom_callback.cpp
@@ -121,8 +121,6 @@
// Convert stats_events into StatsEventParcels.
std::vector<StatsEventParcel> parcels;
- // Resolves fuzz build failure in b/161575591.
-#if defined(__ANDROID_APEX__) || defined(LIB_STATS_PULL_TESTS_FLAG)
for (int i = 0; i < statsEventList.data.size(); i++) {
size_t size;
uint8_t* buffer = AStatsEvent_getBuffer(statsEventList.data[i], &size);
@@ -133,7 +131,6 @@
p.buffer.assign(buffer, buffer + size);
parcels.push_back(std::move(p));
}
-#endif
Status status = resultReceiver->pullFinished(atomTag, success, parcels);
if (!status.isOk()) {
diff --git a/lib/libstatssocket/Android.bp b/lib/libstatssocket/Android.bp
index 36aa4db..fce6a75 100644
--- a/lib/libstatssocket/Android.bp
+++ b/lib/libstatssocket/Android.bp
@@ -74,18 +74,6 @@
min_sdk_version: "30",
}
-//TODO (b/149842105): Figure out if there is a better solution for this.
-cc_test_library {
- name: "libstatssocket_private",
- defaults: [
- "libstatssocket_defaults",
- ],
- visibility: [
- "//packages/modules/StatsD/apex/tests/libstatspull",
- "//packages/modules/StatsD/statsd",
- ],
-}
-
cc_library_headers {
name: "libstatssocket_headers",
export_include_dirs: ["include"],
@@ -114,10 +102,10 @@
static_libs: [
"libbase",
"libgmock",
- "libstatssocket_private",
],
shared_libs: [
"libutils",
+ "libstatssocket",
],
test_suites: [
"device-tests",
@@ -137,6 +125,7 @@
},
require_root: true,
min_sdk_version: "30",
+ test_for: ["com.android.os.statsd"],
}
genrule {
@@ -163,3 +152,29 @@
"stats_statsdsocketlog.cpp",
],
}
+
+cc_fuzz {
+ name: "statsevent_fuzzer",
+ defaults: [
+ "libstatssocket_defaults",
+ ],
+ srcs: [
+ "fuzzers/stats_event_fuzzer.cpp",
+ ],
+ local_include_dirs: [
+ "include",
+ ],
+ host_supported: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wno-unused-parameter",
+ ],
+ fuzz_config: {
+ cc: [
+ "singhtejinder@google.com",
+ "sharaienko@google.com",
+ ],
+ },
+}
diff --git a/lib/libstatssocket/fuzzers/stats_event_fuzzer.cpp b/lib/libstatssocket/fuzzers/stats_event_fuzzer.cpp
new file mode 100644
index 0000000..975ecf7
--- /dev/null
+++ b/lib/libstatssocket/fuzzers/stats_event_fuzzer.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include "include/stats_event.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+
+ // This only tests the libstatssocket APIs.
+ // Since fuzzing is not supported across processes, it does not fuzz statsd.
+ // See statsd_fuzzer.
+
+ AStatsEvent* event = AStatsEvent_obtain();
+
+ AStatsEvent_setAtomId(event, fdp.ConsumeIntegral<int32_t>());
+ // atom-level annotation
+ AStatsEvent_addBoolAnnotation(event, fdp.ConsumeIntegral<int32_t>(), fdp.ConsumeBool());
+
+ while (fdp.remaining_bytes() > 0) {
+ AStatsEvent_writeInt32(event, fdp.ConsumeIntegral<int32_t>());
+ AStatsEvent_addBoolAnnotation(event, fdp.ConsumeIntegral<int32_t>(), fdp.ConsumeBool());
+ AStatsEvent_addInt32Annotation(event, fdp.ConsumeIntegral<int32_t>(),
+ fdp.ConsumeIntegral<int32_t>());
+ AStatsEvent_writeBool(event, fdp.ConsumeBool());
+ AStatsEvent_addBoolAnnotation(event, fdp.ConsumeIntegral<int32_t>(), fdp.ConsumeBool());
+ AStatsEvent_addInt32Annotation(event, fdp.ConsumeIntegral<int32_t>(),
+ fdp.ConsumeIntegral<int32_t>());
+ AStatsEvent_writeFloat(event, fdp.ConsumeFloatingPoint<float>());
+ AStatsEvent_addBoolAnnotation(event, fdp.ConsumeIntegral<int32_t>(), fdp.ConsumeBool());
+ AStatsEvent_addInt32Annotation(event, fdp.ConsumeIntegral<int32_t>(),
+ fdp.ConsumeIntegral<int32_t>());
+ AStatsEvent_writeInt64(event, fdp.ConsumeIntegral<int64_t>());
+ AStatsEvent_addBoolAnnotation(event, fdp.ConsumeIntegral<int32_t>(), fdp.ConsumeBool());
+ AStatsEvent_addInt32Annotation(event, fdp.ConsumeIntegral<int32_t>(),
+ fdp.ConsumeIntegral<int32_t>());
+ AStatsEvent_writeString(event, fdp.ConsumeRandomLengthString().c_str());
+ AStatsEvent_addBoolAnnotation(event, fdp.ConsumeIntegral<int32_t>(), fdp.ConsumeBool());
+ AStatsEvent_addInt32Annotation(event, fdp.ConsumeIntegral<int32_t>(),
+ fdp.ConsumeIntegral<int32_t>());
+ }
+
+ AStatsEvent_write(event);
+ AStatsEvent_release(event);
+ return 0;
+}
diff --git a/lib/libstatssocket/tests/stats_buffer_writer_queue_test.cpp b/lib/libstatssocket/tests/stats_buffer_writer_queue_test.cpp
index 44224c5..008009b 100644
--- a/lib/libstatssocket/tests/stats_buffer_writer_queue_test.cpp
+++ b/lib/libstatssocket/tests/stats_buffer_writer_queue_test.cpp
@@ -24,10 +24,14 @@
#include "utils.h"
using testing::_;
+using testing::AnyNumber;
+using testing::DoAll;
using testing::Return;
using testing::StrictMock;
-constexpr static int WAIT_MS = 200;
+namespace {
+
+constexpr static int WAIT_MS = 100;
static AStatsEvent* generateTestEvent() {
AStatsEvent* event = AStatsEvent_obtain();
@@ -40,12 +44,13 @@
class BasicBufferWriterQueueMock : public BufferWriterQueue {
public:
BasicBufferWriterQueueMock() = default;
- MOCK_METHOD(bool, handleCommand, (const BasicBufferWriterQueueMock::Cmd& cmd),
- (const override));
+ MOCK_METHOD(bool, handleCommand, (const BufferWriterQueue::Cmd& cmd), (const override));
};
typedef StrictMock<BasicBufferWriterQueueMock> BufferWriterQueueMock;
+} // namespace
+
TEST(StatsBufferWriterQueueTest, TestWriteSuccess) {
AStatsEvent* event = generateTestEvent();
@@ -64,6 +69,9 @@
EXPECT_TRUE(addedToQueue);
// to yeld to the queue worker thread
std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_MS));
+
+ queue.drainQueue();
+ EXPECT_EQ(queue.getQueueSize(), 0);
}
TEST(StatsBufferWriterQueueTest, TestWriteOverflow) {
@@ -89,6 +97,9 @@
EXPECT_FALSE(addedToQueue);
EXPECT_EQ(queue.getQueueSize(), BufferWriterQueueMock::kQueueMaxSizeLimit);
+
+ queue.drainQueue();
+ EXPECT_EQ(queue.getQueueSize(), 0);
}
TEST(StatsBufferWriterQueueTest, TestSleepOnOverflow) {
@@ -104,12 +115,16 @@
std::vector<int64_t> attemptsTs;
BufferWriterQueueMock queue;
- EXPECT_CALL(queue, handleCommand(_))
- .WillRepeatedly([&attemptsTs](const BufferWriterQueueMock::Cmd&) {
- // store timestamp for command handler invocations
- attemptsTs.push_back(get_elapsed_realtime_ns());
- return false;
- });
+ ON_CALL(queue, handleCommand(_))
+ .WillByDefault(DoAll(
+ [&attemptsTs](const BufferWriterQueue::Cmd&) {
+ // store timestamp for command handler invocations
+ attemptsTs.push_back(get_elapsed_realtime_ns());
+ return false;
+ },
+ Return(false)));
+
+ EXPECT_CALL(queue, handleCommand(_)).Times(AnyNumber());
// simulate failed write to stats socket to fill the queue
for (int i = 0; i < BufferWriterQueueMock::kQueueMaxSizeLimit; i++) {
@@ -117,10 +132,13 @@
EXPECT_TRUE(addedToQueue);
}
AStatsEvent_release(event);
-
// to yeld to the queue worker thread
std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_MS));
+ // to eliminate extra commands handling on the worker thread
+ queue.drainQueue();
+ EXPECT_EQ(queue.getQueueSize(), 0);
+
EXPECT_GE(attemptsTs.size(), 2);
for (int i = 0; i < attemptsTs.size() - 1; i++) {
EXPECT_GE(attemptsTs[i + 1] - attemptsTs[i],
diff --git a/perfetto/README.md b/perfetto/README.md
new file mode 100644
index 0000000..765b743
--- /dev/null
+++ b/perfetto/README.md
@@ -0,0 +1,16 @@
+To push config to be used at device boot automatically
+
+```
+adb push perfetto/atrace.pbtxt /data/misc/perfetto-configs/boottrace.pbtxt
+adb shell setprop persist.debug.perfetto.boottrace 1
+```
+
+The output trace will be written at /data/misc/perfetto-traces/boottrace.perfetto-trace.
+The file will be removed before a new trace is started.
+
+```
+adb pull /data/misc/perfetto-traces/boottrace.perfetto-trace
+```
+
+# Links
+- https://perfetto.dev/docs/case-studies/android-boot-tracing
diff --git a/perfetto/atrace.pbtxt b/perfetto/atrace.pbtxt
new file mode 100644
index 0000000..e5c512c
--- /dev/null
+++ b/perfetto/atrace.pbtxt
@@ -0,0 +1,30 @@
+buffers: {
+ size_kb: 522240
+ fill_policy: DISCARD
+}
+buffers: {
+ size_kb: 8192
+ fill_policy: RING_BUFFER
+}
+data_sources: {
+ config {
+ name: "linux.process_stats"
+ target_buffer: 1
+ process_stats_config {
+ scan_all_processes_on_start: true
+ }
+ }
+}
+data_sources: {
+ config {
+ name: "linux.ftrace"
+ ftrace_config {
+ atrace_categories: "binder_driver"
+ atrace_categories: "binder_lock"
+ atrace_categories: "sm"
+ atrace_categories: "ss"
+ atrace_apps: "*"
+ }
+ }
+}
+duration_ms: 180000
diff --git a/service/java/com/android/server/stats/StatsCompanionService.java b/service/java/com/android/server/stats/StatsCompanionService.java
index 16e66fe..6e920c5 100644
--- a/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/service/java/com/android/server/stats/StatsCompanionService.java
@@ -755,7 +755,8 @@
// Setup receiver for device reboots or shutdowns.
filter = new IntentFilter(Intent.ACTION_REBOOT);
filter.addAction(Intent.ACTION_SHUTDOWN);
- mContext.registerReceiverForAllUsers(shutdownEventReceiver, filter, null, null);
+ mContext.registerReceiverForAllUsers(shutdownEventReceiver, filter, null,
+ /* scheduler= */ mHandler);
// Register listener for statsd_java properties updates.
DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_STATSD_JAVA,
diff --git a/service/java/com/android/server/stats/StatsManagerService.java b/service/java/com/android/server/stats/StatsManagerService.java
index 61a1c75..a25c91f 100644
--- a/service/java/com/android/server/stats/StatsManagerService.java
+++ b/service/java/com/android/server/stats/StatsManagerService.java
@@ -849,7 +849,6 @@
}
}
}
-
private static final int CHUNK_SIZE = 1024 * 64; // 64 kB
/**
diff --git a/statsd/Android.bp b/statsd/Android.bp
index 193fa06..2199a5c 100644
--- a/statsd/Android.bp
+++ b/statsd/Android.bp
@@ -75,6 +75,7 @@
"src/external/StatsPuller.cpp",
"src/external/StatsPullerManager.cpp",
"src/external/TrainInfoPuller.cpp",
+ "src/external/Uprobestats.cpp",
"src/FieldValue.cpp",
"src/flags/FlagProvider.cpp",
"src/guardrail/StatsdStats.cpp",
@@ -149,6 +150,7 @@
"libbinder_ndk",
"libincident",
"liblog",
+ "libstatssocket",
],
header_libs: [
"libgtest_prod_headers",
@@ -262,10 +264,6 @@
},
stl: "libc++_static",
- shared_libs: [
- "libstatssocket",
- ],
-
apex_available: [
"com.android.os.statsd",
"test_com.android.os.statsd",
@@ -297,7 +295,6 @@
static_libs: [
"libgmock",
"libstatslog_statsdtest",
- "libstatssocket_private",
],
proto: {
type: "lite",
@@ -458,6 +455,7 @@
],
min_sdk_version: "30",
+ test_for: ["com.android.os.statsd"],
}
//#############################
@@ -493,6 +491,8 @@
"libgtest",
"libstats_test_utils",
],
+
+ test_for: ["com.android.os.statsd"],
}
// ==== java proto device library (for test only) ==============================
@@ -589,6 +589,7 @@
defaults: [
"statsd_defaults",
"service_fuzzer_defaults",
+ "fuzzer_disable_leaks",
],
srcs: [
"fuzzers/statsd_service_fuzzer.cpp",
@@ -604,6 +605,36 @@
"-Wno-unused-parameter",
],
fuzz_config: {
+ triage_assignee: "waghpawan@google.com",
+ cc: [
+ "singhtejinder@google.com",
+ "sharaienko@google.com",
+ ],
+ },
+ proto: {
+ type: "lite",
+ static: true,
+ },
+}
+
+cc_fuzz {
+ name: "statsd_fuzzer",
+ defaults: [
+ "statsd_defaults",
+ ],
+ srcs: [
+ "fuzzers/statsd_socket_data_fuzzer.cpp",
+ ],
+ shared_libs: [
+ "libstatssocket",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wno-unused-parameter",
+ ],
+ fuzz_config: {
cc: [
"singhtejinder@google.com",
"sharaienko@google.com",
diff --git a/statsd/fuzzers/statsd_socket_data_fuzzer.cpp b/statsd/fuzzers/statsd_socket_data_fuzzer.cpp
new file mode 100644
index 0000000..bfdfd8b
--- /dev/null
+++ b/statsd/fuzzers/statsd_socket_data_fuzzer.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include "socket/StatsSocketListener.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+void fuzzSocket(const uint8_t* data, size_t size) {
+ LogEventQueue queue(50000);
+ LogEventFilter filter;
+ filter.setFilteringEnabled(false);
+
+ StatsSocketListener::processSocketMessage((const char*)data, size, 0, 0, queue, filter);
+
+ StatsSocketListener::processStatsEventBuffer(data, size, 0, 0, queue, filter);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ using namespace android::os::statsd;
+
+ fuzzSocket(data, size);
+
+ return 0;
+}
diff --git a/statsd/src/FieldValue.cpp b/statsd/src/FieldValue.cpp
index aa129a4..92ed96d 100644
--- a/statsd/src/FieldValue.cpp
+++ b/statsd/src/FieldValue.cpp
@@ -60,6 +60,17 @@
return false;
}
+std::vector<Matcher> dedupFieldMatchers(const std::vector<Matcher>& fieldMatchers) {
+ std::vector<Matcher> dedupedFieldMatchers;
+ for (size_t i = 0; i < fieldMatchers.size(); i++) {
+ if (std::find(dedupedFieldMatchers.begin(), dedupedFieldMatchers.end(), fieldMatchers[i]) ==
+ dedupedFieldMatchers.end()) {
+ dedupedFieldMatchers.push_back(fieldMatchers[i]);
+ }
+ }
+ return dedupedFieldMatchers;
+}
+
void translateFieldMatcher(int tag, const FieldMatcher& matcher, int depth, int* pos, int* mask,
std::vector<Matcher>* output) {
if (depth > kMaxLogDepth) {
@@ -559,6 +570,14 @@
return totalSize;
}
+size_t getFieldValuesSizeV2(const std::vector<FieldValue>& fieldValues) {
+ size_t totalSize = 0;
+ for (const FieldValue& fieldValue : fieldValues) {
+ totalSize += fieldValue.getSizeV2();
+ }
+ return totalSize;
+}
+
bool shouldKeepSample(const FieldValue& sampleFieldValue, int shardOffset, int shardCount) {
int hashValue = 0;
switch (sampleFieldValue.mValue.type) {
diff --git a/statsd/src/FieldValue.h b/statsd/src/FieldValue.h
index 9b81007..22fa89b 100644
--- a/statsd/src/FieldValue.h
+++ b/statsd/src/FieldValue.h
@@ -371,7 +371,6 @@
class Annotations {
public:
Annotations() {
- setNested(true); // Nested = true by default
}
// This enum stores where particular annotations can be found in the
@@ -449,6 +448,10 @@
return mField.getSize() + mValue.getSize();
}
+ size_t getSizeV2() const {
+ return mValue.getSize();
+ }
+
Field mField;
Value mValue;
Annotations mAnnotations;
@@ -464,6 +467,8 @@
/* returns uid if the field is uid field, or -1 if the field is not a uid field */
int getUidIfExists(const FieldValue& value);
+std::vector<Matcher> dedupFieldMatchers(const std::vector<Matcher>& fieldMatchers);
+
void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* output);
bool isAttributionUidField(const Field& field, const Value& value);
@@ -481,6 +486,9 @@
// the size is computed at runtime using the actual contents stored in the FieldValue.
size_t getSize(const std::vector<FieldValue>& fieldValues);
+// Same as getSize but does not compute the size of Field.
+size_t getFieldValuesSizeV2(const std::vector<FieldValue>& fieldValues);
+
bool shouldKeepSample(const FieldValue& sampleFieldValue, int shardOffset, int shardCount);
} // namespace statsd
diff --git a/statsd/src/HashableDimensionKey.cpp b/statsd/src/HashableDimensionKey.cpp
index 837d9e9..03a4229 100644
--- a/statsd/src/HashableDimensionKey.cpp
+++ b/statsd/src/HashableDimensionKey.cpp
@@ -398,6 +398,21 @@
return mStateValuesKey < that.getStateValuesKey();
}
+size_t MetricDimensionKey::getSize(const bool usesNestedDimensions) const {
+ size_t dimensionKeySize = 0;
+ // Dimension/State values
+ if (usesNestedDimensions) {
+ // Assume nested dimension adds an additional atomTag + # of dimension fields
+ dimensionKeySize += sizeof(int32_t);
+ dimensionKeySize += sizeof(int32_t) * getDimensionKeyInWhat().getValues().size();
+ }
+ dimensionKeySize += getFieldValuesSizeV2(getDimensionKeyInWhat().getValues());
+ // Each state value has a atomId and group/value
+ dimensionKeySize += sizeof(int32_t) * getStateValuesKey().getValues().size();
+ dimensionKeySize += getFieldValuesSizeV2(getStateValuesKey().getValues());
+ return dimensionKeySize;
+}
+
bool AtomDimensionKey::operator==(const AtomDimensionKey& that) const {
return mAtomTag == that.getAtomTag() && mAtomFieldValues == that.getAtomFieldValues();
};
diff --git a/statsd/src/HashableDimensionKey.h b/statsd/src/HashableDimensionKey.h
index 5753d98..4792e8d 100644
--- a/statsd/src/HashableDimensionKey.h
+++ b/statsd/src/HashableDimensionKey.h
@@ -135,6 +135,8 @@
bool operator<(const MetricDimensionKey& that) const;
+ size_t getSize(const bool usesNestedDimensions) const;
+
private:
HashableDimensionKey mDimensionKeyInWhat;
HashableDimensionKey mStateValuesKey;
diff --git a/statsd/src/StatsLogProcessor.cpp b/statsd/src/StatsLogProcessor.cpp
index 333b167..95882d5 100644
--- a/statsd/src/StatsLogProcessor.cpp
+++ b/statsd/src/StatsLogProcessor.cpp
@@ -36,6 +36,7 @@
#include "stats_util.h"
#include "statslog_statsd.h"
#include "storage/StorageManager.h"
+#include "utils/api_tracing.h"
using namespace android;
using android::base::StringPrintf;
@@ -73,6 +74,7 @@
const int FIELD_ID_DUMP_REPORT_REASON = 8;
const int FIELD_ID_STRINGS = 9;
const int FIELD_ID_DATA_CORRUPTED_REASON = 11;
+const int FIELD_ID_ESTIMATED_DATA_BYTES = 12;
// for ActiveConfigList
const int FIELD_ID_ACTIVE_CONFIG_LIST_CONFIG = 1;
@@ -388,6 +390,7 @@
}
void StatsLogProcessor::OnLogEvent(LogEvent* event) {
+ ATRACE_CALL();
OnLogEvent(event, getElapsedRealtimeNs());
}
@@ -769,6 +772,8 @@
std::set<string> str_set;
+ int64_t totalSize = it->second->byteSize();
+
ProtoOutputStream tempProto;
// First, fill in ConfigMetricsReport using current data on memory, which
// starts from filling in StatsLogReport's.
@@ -803,7 +808,12 @@
}
// Data corrupted reason
- writeDataCorruptedReasons(tempProto);
+ writeDataCorruptedReasons(tempProto, FIELD_ID_DATA_CORRUPTED_REASON,
+ StatsdStats::getInstance().hasEventQueueOverflow(),
+ StatsdStats::getInstance().hasSocketLoss());
+
+ // Estimated memory bytes
+ tempProto.write(FIELD_TYPE_INT64 | FIELD_ID_ESTIMATED_DATA_BYTES, totalSize);
flushProtoToBuffer(tempProto, buffer);
@@ -1104,8 +1114,11 @@
MetricsManager& metricsManager) {
int64_t elapsedRealtimeNs = getElapsedRealtimeNs();
auto lastCheckTime = mLastByteSizeTimes.find(key);
+ int64_t minCheckPeriodNs = metricsManager.useV2SoftMemoryCalculation()
+ ? StatsdStats::kMinByteSizeV2CheckPeriodNs
+ : StatsdStats::kMinByteSizeCheckPeriodNs;
if (lastCheckTime != mLastByteSizeTimes.end()) {
- if (elapsedRealtimeNs - lastCheckTime->second < StatsdStats::kMinByteSizeCheckPeriodNs) {
+ if (elapsedRealtimeNs - lastCheckTime->second < minCheckPeriodNs) {
return;
}
}
@@ -1449,6 +1462,7 @@
}
void StatsLogProcessor::onStatsdInitCompleted(const int64_t elapsedTimeNs) {
+ ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMetricsMutex);
VLOG("Received boot completed signal");
for (const auto& it : mMetricsManagers) {
@@ -1505,17 +1519,6 @@
mLogEventFilter->setAtomIds(std::move(allAtomIds), this);
}
-void StatsLogProcessor::writeDataCorruptedReasons(ProtoOutputStream& proto) {
- if (StatsdStats::getInstance().hasEventQueueOverflow()) {
- proto.write(FIELD_TYPE_INT32 | FIELD_COUNT_REPEATED | FIELD_ID_DATA_CORRUPTED_REASON,
- DATA_CORRUPTED_EVENT_QUEUE_OVERFLOW);
- }
- if (StatsdStats::getInstance().hasSocketLoss()) {
- proto.write(FIELD_TYPE_INT32 | FIELD_COUNT_REPEATED | FIELD_ID_DATA_CORRUPTED_REASON,
- DATA_CORRUPTED_SOCKET_LOSS);
- }
-}
-
bool StatsLogProcessor::validateAppBreadcrumbEvent(const LogEvent& event) const {
if (event.GetTagId() == util::APP_BREADCRUMB_REPORTED) {
// Check that app breadcrumb reported fields are valid.
diff --git a/statsd/src/StatsLogProcessor.h b/statsd/src/StatsLogProcessor.h
index c1c7dd6..c5faaf2 100644
--- a/statsd/src/StatsLogProcessor.h
+++ b/statsd/src/StatsLogProcessor.h
@@ -327,8 +327,6 @@
/* Tells LogEventFilter about atom ids to parse */
void updateLogEventFilterLocked() const;
- void writeDataCorruptedReasons(ProtoOutputStream& proto);
-
bool validateAppBreadcrumbEvent(const LogEvent& event) const;
// Function used to send a broadcast so that receiver for the config key can call getData
@@ -485,6 +483,8 @@
FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithDimensions);
FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions);
FRIEND_TEST(ValueMetricE2eTest, TestInitWithValueFieldPositionALL);
+ FRIEND_TEST(ValueMetricE2eTest, TestInitWithMultipleAggTypes);
+ FRIEND_TEST(ValueMetricE2eTest, TestInitWithDefaultAggType);
FRIEND_TEST(KllMetricE2eTest, TestInitWithKllFieldPositionALL);
diff --git a/statsd/src/StatsService.cpp b/statsd/src/StatsService.cpp
index 86c2de8..9cbd7b1 100644
--- a/statsd/src/StatsService.cpp
+++ b/statsd/src/StatsService.cpp
@@ -43,6 +43,7 @@
#include "storage/StorageManager.h"
#include "subscriber/SubscriberReporter.h"
#include "utils/DbUtils.h"
+#include "utils/api_tracing.h"
using namespace android;
@@ -230,10 +231,14 @@
if (mEventQueue != nullptr) {
mLogsReaderThread = std::make_unique<std::thread>([this] { readLogs(); });
+ if (mLogsReaderThread) {
+ pthread_setname_np(mLogsReaderThread->native_handle(), "statsd.reader");
+ }
}
}
StatsService::~StatsService() {
+ ATRACE_CALL();
if (mEventQueue != nullptr) {
stopReadingLogs();
mLogsReaderThread->join();
@@ -984,6 +989,7 @@
}
Status StatsService::informAllUidData(const ScopedFileDescriptor& fd) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
// Parse fd into proto.
@@ -1001,6 +1007,7 @@
Status StatsService::informOnePackage(const string& app, int32_t uid, int64_t version,
const string& versionString, const string& installer,
const vector<uint8_t>& certificateHash) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::informOnePackage was called");
@@ -1011,6 +1018,7 @@
}
Status StatsService::informOnePackageRemoved(const string& app, int32_t uid) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::informOnePackageRemoved was called");
@@ -1026,6 +1034,7 @@
}
Status StatsService::informAlarmForSubscriberTriggeringFired() {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called");
@@ -1042,6 +1051,7 @@
}
Status StatsService::informPollAlarmFired() {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::informPollAlarmFired was called");
@@ -1051,6 +1061,7 @@
}
Status StatsService::systemRunning() {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
// When system_server is up and running, schedule the dropbox task to run.
@@ -1060,6 +1071,7 @@
}
Status StatsService::informDeviceShutdown() {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::informDeviceShutdown");
int64_t elapsedRealtimeNs = getElapsedRealtimeNs();
@@ -1081,6 +1093,7 @@
}
Status StatsService::statsCompanionReady() {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::statsCompanionReady was called");
@@ -1099,6 +1112,7 @@
}
Status StatsService::bootCompleted() {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::bootCompleted was called");
@@ -1122,6 +1136,7 @@
}
void StatsService::Startup() {
+ ATRACE_CALL();
mConfigManager->Startup();
int64_t wallClockNs = getWallClockNs();
int64_t elapsedRealtimeNs = getElapsedRealtimeNs();
@@ -1131,6 +1146,7 @@
}
void StatsService::Terminate() {
+ ATRACE_CALL();
ALOGI("StatsService::Terminating");
if (mProcessor != nullptr) {
int64_t elapsedRealtimeNs = getElapsedRealtimeNs();
@@ -1151,6 +1167,7 @@
}
Status StatsService::getData(int64_t key, const int32_t callingUid, vector<uint8_t>* output) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
getDataChecked(key, callingUid, output);
return Status::ok();
@@ -1158,6 +1175,7 @@
Status StatsService::getDataFd(int64_t key, const int32_t callingUid,
const ScopedFileDescriptor& fd) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
vector<uint8_t> reportData;
getDataChecked(key, callingUid, &reportData);
@@ -1194,6 +1212,7 @@
}
Status StatsService::getMetadata(vector<uint8_t>* output) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
StatsdStats::getInstance().dumpStats(output, false); // Don't reset the counters.
@@ -1202,6 +1221,7 @@
Status StatsService::addConfiguration(int64_t key, const vector <uint8_t>& config,
const int32_t callingUid) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
if (addConfigurationChecked(callingUid, key, config)) {
@@ -1225,6 +1245,7 @@
Status StatsService::removeDataFetchOperation(int64_t key,
const int32_t callingUid) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
ConfigKey configKey(callingUid, key);
mConfigManager->RemoveConfigReceiver(configKey);
@@ -1234,6 +1255,7 @@
Status StatsService::setDataFetchOperation(int64_t key,
const shared_ptr<IPendingIntentRef>& pir,
const int32_t callingUid) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
ConfigKey configKey(callingUid, key);
@@ -1249,6 +1271,7 @@
Status StatsService::setActiveConfigsChangedOperation(const shared_ptr<IPendingIntentRef>& pir,
const int32_t callingUid,
vector<int64_t>* output) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
mConfigManager->SetActiveConfigsChangedReceiver(callingUid, pir);
@@ -1261,6 +1284,7 @@
}
Status StatsService::removeActiveConfigsChangedOperation(const int32_t callingUid) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
mConfigManager->RemoveActiveConfigsChangedReceiver(callingUid);
@@ -1268,6 +1292,7 @@
}
Status StatsService::removeConfiguration(int64_t key, const int32_t callingUid) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
ConfigKey configKey(callingUid, key);
@@ -1279,6 +1304,7 @@
int64_t subscriberId,
const shared_ptr<IPendingIntentRef>& pir,
const int32_t callingUid) {
+ ATRACE_CALL();
VLOG("StatsService::setBroadcastSubscriber called.");
ENFORCE_UID(AID_SYSTEM);
@@ -1296,6 +1322,7 @@
Status StatsService::unsetBroadcastSubscriber(int64_t configId,
int64_t subscriberId,
const int32_t callingUid) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::unsetBroadcastSubscriber called.");
@@ -1306,6 +1333,7 @@
}
Status StatsService::allPullersFromBootRegistered() {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::allPullersFromBootRegistered was called");
@@ -1317,6 +1345,7 @@
int64_t timeoutMillis,
const std::vector<int32_t>& additiveFields,
const shared_ptr<IPullAtomCallback>& pullerCallback) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::registerPullAtomCallback called.");
mPullerManager->RegisterPullAtomCallback(uid, atomTag, MillisToNano(coolDownMillis),
@@ -1329,6 +1358,7 @@
int32_t atomTag, int64_t coolDownMillis, int64_t timeoutMillis,
const std::vector<int32_t>& additiveFields,
const shared_ptr<IPullAtomCallback>& pullerCallback) {
+ ATRACE_CALL();
if (!checkPermission(kPermissionRegisterPullAtom)) {
return exception(
EX_SECURITY,
@@ -1344,6 +1374,7 @@
}
Status StatsService::unregisterPullAtomCallback(int32_t uid, int32_t atomTag) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::unregisterPullAtomCallback called.");
mPullerManager->UnregisterPullAtomCallback(uid, atomTag);
@@ -1351,6 +1382,7 @@
}
Status StatsService::unregisterNativePullAtomCallback(int32_t atomTag) {
+ ATRACE_CALL();
if (!checkPermission(kPermissionRegisterPullAtom)) {
return exception(
EX_SECURITY,
@@ -1364,6 +1396,7 @@
}
Status StatsService::getRegisteredExperimentIds(std::vector<int64_t>* experimentIdsOut) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
// TODO: add verifier permission
@@ -1393,6 +1426,7 @@
}
void StatsService::statsCompanionServiceDied(void* cookie) {
+ ATRACE_CALL();
auto thiz = static_cast<StatsService*>(cookie);
thiz->statsCompanionServiceDiedImpl();
}
@@ -1431,6 +1465,7 @@
const shared_ptr<IPendingIntentRef>& pir,
const int32_t callingUid,
vector<int64_t>* output) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
if (!isAtLeastU()) {
ALOGW("setRestrictedMetricsChangedOperation invoked on U- device");
@@ -1448,6 +1483,7 @@
Status StatsService::removeRestrictedMetricsChangedOperation(const int64_t configId,
const string& configPackage,
const int32_t callingUid) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
if (!isAtLeastU()) {
ALOGW("removeRestrictedMetricsChangedOperation invoked on U- device");
@@ -1462,6 +1498,7 @@
const shared_ptr<IStatsQueryCallback>& callback,
const int64_t configKey, const string& configPackage,
const int32_t callingUid) {
+ ATRACE_CALL();
ENFORCE_UID(AID_SYSTEM);
if (callback == nullptr) {
ALOGW("querySql called with null callback.");
@@ -1477,6 +1514,7 @@
Status StatsService::addSubscription(const vector<uint8_t>& subscriptionConfig,
const shared_ptr<IStatsSubscriptionCallback>& callback) {
+ ATRACE_CALL();
ENFORCE_SID(kTracedProbesSid);
initShellSubscriber();
@@ -1486,6 +1524,7 @@
}
Status StatsService::removeSubscription(const shared_ptr<IStatsSubscriptionCallback>& callback) {
+ ATRACE_CALL();
ENFORCE_SID(kTracedProbesSid);
if (mShellSubscriber != nullptr) {
@@ -1495,6 +1534,7 @@
}
Status StatsService::flushSubscription(const shared_ptr<IStatsSubscriptionCallback>& callback) {
+ ATRACE_CALL();
ENFORCE_SID(kTracedProbesSid);
if (mShellSubscriber != nullptr) {
diff --git a/statsd/src/StatsService.h b/statsd/src/StatsService.h
index 3c34492..0a167dd 100644
--- a/statsd/src/StatsService.h
+++ b/statsd/src/StatsService.h
@@ -415,7 +415,7 @@
*/
void onStatsdInitCompleted();
- /**
+ /*
* This method is used to stop log reader thread.
*/
void stopReadingLogs();
diff --git a/statsd/src/anomaly/AnomalyTracker.h b/statsd/src/anomaly/AnomalyTracker.h
index 4a4f7ff..d57a4b8 100644
--- a/statsd/src/anomaly/AnomalyTracker.h
+++ b/statsd/src/anomaly/AnomalyTracker.h
@@ -34,7 +34,6 @@
using std::optional;
using std::shared_ptr;
-using std::unordered_map;
// Does NOT allow negative values.
class AnomalyTracker : public virtual RefBase {
@@ -184,7 +183,7 @@
// declared for that dimension) ends, in seconds. From this moment and onwards, anomalies
// can be declared again.
// Entries may be, but are not guaranteed to be, removed after the period is finished.
- unordered_map<MetricDimensionKey, uint32_t> mRefractoryPeriodEndsSec;
+ std::unordered_map<MetricDimensionKey, uint32_t> mRefractoryPeriodEndsSec;
// Advances mMostRecentBucketNum to bucketNum, deleting any data that is now too old.
// Specifically, since it is now too old, removes the data for
diff --git a/statsd/src/anomaly/DurationAnomalyTracker.cpp b/statsd/src/anomaly/DurationAnomalyTracker.cpp
index f3bfc05..82e5bc8 100644
--- a/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ b/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -93,7 +93,7 @@
// seldomly called. The alternative would be having InternalAlarms store information about the
// DurationAnomalyTracker and key, but that's a lot of data overhead to speed up something that
// is rarely ever called.
- unordered_map<MetricDimensionKey, sp<const InternalAlarm>> matchedAlarms;
+ std::unordered_map<MetricDimensionKey, sp<const InternalAlarm>> matchedAlarms;
for (const auto& kv : mAlarms) {
if (firedAlarms.count(kv.second) > 0) {
matchedAlarms.insert({kv.first, kv.second});
diff --git a/statsd/src/anomaly/DurationAnomalyTracker.h b/statsd/src/anomaly/DurationAnomalyTracker.h
index ce06df0..73e741e 100644
--- a/statsd/src/anomaly/DurationAnomalyTracker.h
+++ b/statsd/src/anomaly/DurationAnomalyTracker.h
@@ -23,8 +23,6 @@
namespace os {
namespace statsd {
-using std::unordered_map;
-
class DurationAnomalyTracker : public virtual AnomalyTracker {
public:
DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey,
diff --git a/statsd/src/anomaly/subscriber_util.cpp b/statsd/src/anomaly/subscriber_util.cpp
index beeadcf..19d0ea5 100644
--- a/statsd/src/anomaly/subscriber_util.cpp
+++ b/statsd/src/anomaly/subscriber_util.cpp
@@ -20,6 +20,7 @@
#include "subscriber_util.h"
#include "external/Perfetto.h"
+#include "external/Uprobestats.h"
#include "subscriber/IncidentdReporter.h"
#include "subscriber/SubscriberReporter.h"
@@ -58,6 +59,11 @@
ALOGW("Failed to generate perfetto traces.");
}
break;
+ case Subscription::SubscriberInformationCase::kUprobestatsDetails:
+ if (!StartUprobeStats(subscription.uprobestats_details())) {
+ ALOGW("Failed to start uprobestats.");
+ }
+ break;
case Subscription::SubscriberInformationCase::kBroadcastSubscriberDetails:
SubscriberReporter::getInstance().alertBroadcastSubscriber(configKey, subscription,
dimensionKey);
diff --git a/statsd/src/config/ConfigManager.h b/statsd/src/config/ConfigManager.h
index e881949..5a213b7 100644
--- a/statsd/src/config/ConfigManager.h
+++ b/statsd/src/config/ConfigManager.h
@@ -19,7 +19,9 @@
#include <aidl/android/os/IPendingIntentRef.h>
#include <stdio.h>
+#include <map>
#include <mutex>
+#include <set>
#include <string>
#include "config/ConfigKey.h"
diff --git a/statsd/src/config/ConfigMetadataProvider.h b/statsd/src/config/ConfigMetadataProvider.h
new file mode 100644
index 0000000..451503a
--- /dev/null
+++ b/statsd/src/config/ConfigMetadataProvider.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+#pragma once
+
+#include <utils/RefBase.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class ConfigMetadataProvider : virtual public RefBase {
+public:
+ virtual ~ConfigMetadataProvider() {
+ }
+
+ virtual bool useV2SoftMemoryCalculation() = 0;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/statsd/src/external/StatsPuller.cpp b/statsd/src/external/StatsPuller.cpp
index 0051b0c..e0fce5e 100644
--- a/statsd/src/external/StatsPuller.cpp
+++ b/statsd/src/external/StatsPuller.cpp
@@ -18,10 +18,12 @@
#include "Log.h"
#include "StatsPuller.h"
+
#include "StatsPullerManager.h"
#include "guardrail/StatsdStats.h"
#include "puller_util.h"
#include "stats_log_util.h"
+#include "utils/api_tracing.h"
namespace android {
namespace os {
@@ -44,6 +46,7 @@
PullErrorCode StatsPuller::Pull(const int64_t eventTimeNs,
std::vector<std::shared_ptr<LogEvent>>* data) {
+ ATRACE_CALL();
lock_guard<std::mutex> lock(mLock);
const int64_t elapsedTimeNs = getElapsedRealtimeNs();
const int64_t systemUptimeMillis = getSystemUptimeMillis();
diff --git a/statsd/src/external/StatsPullerManager.cpp b/statsd/src/external/StatsPullerManager.cpp
index 4fb63a6..bba32b9 100644
--- a/statsd/src/external/StatsPullerManager.cpp
+++ b/statsd/src/external/StatsPullerManager.cpp
@@ -54,12 +54,14 @@
bool StatsPullerManager::Pull(int tagId, const ConfigKey& configKey, const int64_t eventTimeNs,
vector<shared_ptr<LogEvent>>* data) {
+ ATRACE_CALL();
std::lock_guard<std::mutex> _l(mLock);
return PullLocked(tagId, configKey, eventTimeNs, data);
}
bool StatsPullerManager::Pull(int tagId, const vector<int32_t>& uids, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data) {
+ ATRACE_CALL();
std::lock_guard<std::mutex> _l(mLock);
return PullLocked(tagId, uids, eventTimeNs, data);
}
@@ -217,6 +219,7 @@
}
void StatsPullerManager::OnAlarmFired(int64_t elapsedTimeNs) {
+ ATRACE_CALL();
std::lock_guard<std::mutex> _l(mLock);
int64_t wallClockNs = getWallClockNs();
@@ -231,8 +234,8 @@
// receiver to the list that will pull on this alarm.
// If pullNecessary is false, check if next pull time needs to be updated.
sp<PullDataReceiver> receiverPtr = receiverInfo.receiver.promote();
- const bool pullNecessary = receiverPtr != nullptr && receiverPtr->isPullNeeded();
- if (receiverInfo.nextPullTimeNs <= elapsedTimeNs && pullNecessary) {
+ if (receiverInfo.nextPullTimeNs <= elapsedTimeNs && receiverPtr != nullptr &&
+ receiverPtr->isPullNeeded()) {
receivers.push_back(&receiverInfo);
} else {
if (receiverInfo.nextPullTimeNs <= elapsedTimeNs) {
@@ -294,6 +297,7 @@
}
int StatsPullerManager::ForceClearPullerCache() {
+ ATRACE_CALL();
std::lock_guard<std::mutex> _l(mLock);
int totalCleared = 0;
for (const auto& pulledAtom : kAllPullAtomInfo) {
@@ -303,6 +307,7 @@
}
int StatsPullerManager::ClearPullerCacheIfNecessary(int64_t timestampNs) {
+ ATRACE_CALL();
std::lock_guard<std::mutex> _l(mLock);
int totalCleared = 0;
for (const auto& pulledAtom : kAllPullAtomInfo) {
@@ -315,6 +320,7 @@
const int64_t coolDownNs, const int64_t timeoutNs,
const vector<int32_t>& additiveFields,
const shared_ptr<IPullAtomCallback>& callback) {
+ ATRACE_CALL();
std::lock_guard<std::mutex> _l(mLock);
VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag);
@@ -339,6 +345,7 @@
}
void StatsPullerManager::UnregisterPullAtomCallback(const int uid, const int32_t atomTag) {
+ ATRACE_CALL();
std::lock_guard<std::mutex> _l(mLock);
PullerKey key = {.uid = uid, .atomTag = atomTag};
if (kAllPullAtomInfo.find(key) != kAllPullAtomInfo.end()) {
diff --git a/statsd/src/external/Uprobestats.cpp b/statsd/src/external/Uprobestats.cpp
new file mode 100644
index 0000000..ad6613c
--- /dev/null
+++ b/statsd/src/external/Uprobestats.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#define STATSD_DEBUG false // STOPSHIP if true
+#include "Log.h"
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <private/android_filesystem_config.h>
+
+#include <string>
+
+#include "src/statsd_config.pb.h" // Alert
+
+namespace android {
+namespace os {
+namespace statsd {
+
+bool StartUprobeStats(const UprobestatsDetails& config) {
+ // TODO: Add an implementation.
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/statsd/src/external/Uprobestats.h b/statsd/src/external/Uprobestats.h
new file mode 100644
index 0000000..e045e8f
--- /dev/null
+++ b/statsd/src/external/Uprobestats.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// Starts the uprobestats process.
+bool StartUprobeStats(const UprobestatsDetails& config);
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/statsd/src/guardrail/StatsdStats.cpp b/statsd/src/guardrail/StatsdStats.cpp
index 191ea3f..16354b7 100644
--- a/statsd/src/guardrail/StatsdStats.cpp
+++ b/statsd/src/guardrail/StatsdStats.cpp
@@ -63,6 +63,7 @@
const int FIELD_ID_SUBSCRIPTION_STATS = 23;
const int FIELD_ID_SOCKET_LOSS_STATS = 24;
const int FIELD_ID_QUEUE_STATS = 25;
+const int FIELD_ID_SOCKET_READ_STATS = 26;
const int FIELD_ID_RESTRICTED_METRIC_QUERY_STATS_CALLING_UID = 1;
const int FIELD_ID_RESTRICTED_METRIC_QUERY_STATS_CONFIG_ID = 2;
@@ -136,6 +137,7 @@
const int FIELD_ID_DB_DELETION_TOO_OLD = 35;
const int FIELD_ID_DB_DELETION_CONFIG_REMOVED = 36;
const int FIELD_ID_DB_DELETION_CONFIG_UPDATED = 37;
+const int FIELD_ID_CONFIG_METADATA_PROVIDER_PROMOTION_FAILED = 38;
const int FIELD_ID_INVALID_CONFIG_REASON_ENUM = 1;
const int FIELD_ID_INVALID_CONFIG_REASON_METRIC_ID = 2;
@@ -200,13 +202,17 @@
const int FIELD_ID_PER_SUBSCRIPTION_STATS_END_TIME = 5;
const int FIELD_ID_PER_SUBSCRIPTION_STATS_FLUSH_COUNT = 6;
+// Socket read stats
+const int FIELD_ID_SOCKET_READ_STATS_BATCHED_READ_SIZE = 1;
+
const std::map<int, std::pair<size_t, size_t>> StatsdStats::kAtomDimensionKeySizeLimitMap = {
{util::BINDER_CALLS, {6000, 10000}},
{util::LOOPER_STATS, {1500, 2500}},
{util::CPU_TIME_PER_UID_FREQ, {6000, 10000}},
};
-StatsdStats::StatsdStats() : mStatsdStatsId(rand()) {
+StatsdStats::StatsdStats()
+ : mStatsdStatsId(rand()), mSocketBatchReadHistogram(kNumBinsInSocketBatchReadHistogram) {
mPushedAtomStats.resize(kMaxPushedAtomId + 1);
mStartTimeSec = getWallClockSec();
}
@@ -292,6 +298,28 @@
mLogLossStats.emplace_back(wallClockTimeSec, count, lastError, lastTag, uid, pid);
}
+void StatsdStats::noteBatchSocketRead(int32_t size) {
+ // Calculate the bin.
+ int bin = 0;
+ if (size < 0) {
+ ALOGE("Unexpected negative size read from socket. This should never happen");
+ bin = 0;
+ } else if (size < 5) {
+ bin = size; // bin = [0,4].
+ } else if (size < 10) {
+ bin = 4 + (size / 5); // bin = 5.
+ } else if (size < 100) {
+ bin = 5 + (size / 10); // bin = [6,14].
+ } else if (size < 1000) {
+ bin = 14 + (size / 100); // bin = [15-23].
+ } else if (size < 2000) {
+ bin = 19 + (size / 200); // bin = [24-28].
+ } else { // 2000+
+ bin = 29;
+ }
+ lock_guard<std::mutex> lock(mLock);
+ mSocketBatchReadHistogram[bin] += 1;
+}
void StatsdStats::noteBroadcastSent(const ConfigKey& key) {
noteBroadcastSent(key, getWallClockSec());
}
@@ -525,6 +553,16 @@
it->second->db_deletion_config_updated++;
}
+void StatsdStats::noteConfigMetadataProviderPromotionFailed(const ConfigKey& key) {
+ lock_guard<std::mutex> lock(mLock);
+ auto it = mConfigStats.find(key);
+ if (it == mConfigStats.end()) {
+ ALOGE("Config key %s not found!", key.ToString().c_str());
+ return;
+ }
+ it->second->config_metadata_provider_promote_failure++;
+}
+
void StatsdStats::noteUidMapDropped(int deltas) {
lock_guard<std::mutex> lock(mLock);
mUidMapStats.dropped_changes += mUidMapStats.dropped_changes + deltas;
@@ -1068,6 +1106,7 @@
config.second->db_deletion_too_old = 0;
config.second->db_deletion_config_removed = 0;
config.second->db_deletion_config_updated = 0;
+ config.second->config_metadata_provider_promote_failure = 0;
}
for (auto& pullStats : mPulledAtomStats) {
pullStats.second.totalPull = 0;
@@ -1100,6 +1139,7 @@
mPushedAtomDropsStats.clear();
mRestrictedMetricQueryStats.clear();
mSubscriptionPullThreadWakeupCount = 0;
+ std::fill(mSocketBatchReadHistogram.begin(), mSocketBatchReadHistogram.end(), 0);
for (auto it = mSubscriptionStats.begin(); it != mSubscriptionStats.end();) {
if (it->second.end_time_sec > 0) {
@@ -1184,6 +1224,10 @@
configStats->db_deletion_too_old, configStats->db_deletion_config_removed,
configStats->db_deletion_config_updated);
}
+ if (configStats->config_metadata_provider_promote_failure > 0) {
+ dprintf(out, "ConfigMetadataProviderPromotionFailure=%d",
+ configStats->config_metadata_provider_promote_failure);
+ }
dprintf(out, "\n");
if (!configStats->is_valid) {
dprintf(out, "\tinvalid config reason: %s\n",
@@ -1206,7 +1250,8 @@
auto dropBytesPtr = configStats->data_drop_bytes.begin();
for (int i = 0; i < (int)configStats->data_drop_time_sec.size();
i++, dropTimePtr++, dropBytesPtr++) {
- dprintf(out, "\tdata drop time: %d with size %lld", *dropTimePtr,
+ dprintf(out, "\tdata drop time: %s(%lld) with %lld bytes\n",
+ buildTimeString(*dropTimePtr).c_str(), (long long)*dropTimePtr,
(long long)*dropBytesPtr);
}
@@ -1412,6 +1457,28 @@
(long long)restart);
}
+ dprintf(out, "********Socket batch read size stats***********\n");
+ for (int i = 0; i < kNumBinsInSocketBatchReadHistogram; i++) {
+ if (mSocketBatchReadHistogram[i] == 0) {
+ continue;
+ }
+ string range;
+ if (i < 5) {
+ range = "[" + to_string(i) + "]";
+ } else if (i == 5) {
+ range = "[5-9]";
+ } else if (i < 15) {
+ range = "[" + to_string(i - 5) + "0-" + to_string(i - 5) + "9]";
+ } else if (i < 24) {
+ range = "[" + to_string(i - 14) + "00-" + to_string(i - 14) + "99]";
+ } else if (i < 29) {
+ range = "[" + to_string((i - 19) * 2) + "00-" + to_string((i - 19) * 2 + 1) + "99]";
+ } else {
+ range = "[2000+]";
+ }
+ dprintf(out, "%s: %lld\n", range.c_str(), (long long)mSocketBatchReadHistogram[i]);
+ }
+
for (const auto& loss : mLogLossStats) {
dprintf(out,
"Log loss: %lld (wall clock sec) - %d (count), %d (last error), %d (last tag), %d "
@@ -1491,6 +1558,7 @@
dprintf(out, "Statsd Stats Id %d\n", mStatsdStatsId);
dprintf(out, "********Shard Offset Provider stats***********\n");
dprintf(out, "Shard Offset: %u\n", ShardOffsetProvider::getInstance().getShardOffset());
+ dprintf(out, "\n");
}
void addConfigStatsToProto(const ConfigStats& configStats, ProtoOutputStream* proto) {
@@ -1682,6 +1750,8 @@
configStats.db_deletion_config_removed, proto);
writeNonZeroStatToStream(FIELD_TYPE_INT32 | FIELD_ID_DB_DELETION_CONFIG_UPDATED,
configStats.db_deletion_config_updated, proto);
+ writeNonZeroStatToStream(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_METADATA_PROVIDER_PROMOTION_FAILED,
+ configStats.config_metadata_provider_promote_failure, proto);
for (int64_t latency : configStats.total_flush_latency_ns) {
proto->write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_STATS_RESTRICTED_CONFIG_FLUSH_LATENCY |
FIELD_COUNT_REPEATED,
@@ -1930,6 +2000,16 @@
proto.end(socketLossStatsToken);
+ // Socket batch read stats.
+ const uint64_t socketReadStatsToken =
+ proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_SOCKET_READ_STATS);
+ for (const auto& it : mSocketBatchReadHistogram) {
+ proto.write(FIELD_TYPE_INT64 | FIELD_ID_SOCKET_READ_STATS_BATCHED_READ_SIZE |
+ FIELD_COUNT_REPEATED,
+ it);
+ }
+ proto.end(socketReadStatsToken);
+
output->clear();
proto.serializeToVector(output);
diff --git a/statsd/src/guardrail/StatsdStats.h b/statsd/src/guardrail/StatsdStats.h
index e3ab443..03266ee 100644
--- a/statsd/src/guardrail/StatsdStats.h
+++ b/statsd/src/guardrail/StatsdStats.h
@@ -91,6 +91,8 @@
int32_t db_deletion_too_old = 0;
int32_t db_deletion_config_removed = 0;
int32_t db_deletion_config_updated = 0;
+ // Stores the number of ConfigMetadataProvider promotion failures
+ int32_t config_metadata_provider_promote_failure = 0;
// Stores reasons for why config is valid or not
std::optional<InvalidConfigReason> reason;
@@ -180,8 +182,8 @@
const static int kMaxConfigCountPerUid = 20;
const static int kMaxAlertCountPerConfig = 200;
const static int kMaxConditionCountPerConfig = 500;
- const static int kMaxMetricCountPerConfig = 2000;
- const static int kMaxMatcherCountPerConfig = 2500;
+ const static int kMaxMetricCountPerConfig = 3000;
+ const static int kMaxMatcherCountPerConfig = 3500;
// The max number of old config stats we keep.
const static int kMaxIceBoxSize = 20;
@@ -234,7 +236,11 @@
static const int64_t kMinBroadcastPeriodNs = 60 * NS_PER_SEC;
/* Min period between two checks of byte size per config key in nanoseconds. */
- static const int64_t kMinByteSizeCheckPeriodNs = 60 * NS_PER_SEC;
+ static const int64_t kMinByteSizeCheckPeriodNs = 1 * 60 * NS_PER_SEC;
+
+ // Min period between two checks of byte size per config key in nanoseconds for V2 memory
+ // calculations.
+ static const int64_t kMinByteSizeV2CheckPeriodNs = 5 * 60 * NS_PER_SEC;
/* Min period between two checks of restricted metrics TTLs. */
static const int64_t kMinTtlCheckPeriodNs = 60 * 60 * NS_PER_SEC;
@@ -277,7 +283,7 @@
// Maximum atom id value that we consider a platform pushed atom.
// This should be updated once highest pushed atom id in atoms.proto approaches this value.
- static const int kMaxPushedAtomId = 900;
+ static const int kMaxPushedAtomId = 1500;
// Atom id that is the start of the pulled atoms.
static const int kPullAtomStartTag = 10000;
@@ -301,6 +307,8 @@
static const int32_t kMaxLoggedBucketDropEvents = 10;
+ static const int32_t kNumBinsInSocketBatchReadHistogram = 30;
+
/**
* Report a new config has been received and report the static stats about the config.
*
@@ -386,6 +394,11 @@
void noteDbDeletionConfigUpdated(const ConfigKey& key);
/**
+ * Reports that the promotion for ConfigMetadataProvider failed.
+ */
+ void noteConfigMetadataProviderPromotionFailed(const ConfigKey& key);
+
+ /**
* Report the size of output tuple of a condition.
*
* Note: only report when the condition has an output dimension, and the tuple
@@ -706,6 +719,8 @@
*/
void noteSubscriptionPullThreadWakeup();
+ void noteBatchSocketRead(int32_t readSize);
+
/**
* Reset the historical stats. Including all stats in icebox, and the tracked stats about
* metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue
@@ -936,6 +951,8 @@
std::list<int32_t> mSystemServerRestartSec;
+ std::vector<int64_t> mSocketBatchReadHistogram;
+
struct RestrictedMetricQueryStats {
RestrictedMetricQueryStats(int32_t callingUid, int64_t configId,
const string& configPackage, std::optional<int32_t> configUid,
@@ -1030,6 +1047,7 @@
FRIEND_TEST(StatsdStatsTest, TestAtomLoggedAndDroppedStats);
FRIEND_TEST(StatsdStatsTest, TestAtomMetricsStats);
FRIEND_TEST(StatsdStatsTest, TestAtomSkippedStats);
+ FRIEND_TEST(StatsdStatsTest, TestConfigMetadataProviderPromotionFailed);
FRIEND_TEST(StatsdStatsTest, TestConfigRemove);
FRIEND_TEST(StatsdStatsTest, TestHasHitDimensionGuardrail);
FRIEND_TEST(StatsdStatsTest, TestInvalidConfigAdd);
@@ -1054,6 +1072,7 @@
FRIEND_TEST(StatsdStatsTest, TestSystemServerCrash);
FRIEND_TEST(StatsdStatsTest, TestTimestampThreshold);
FRIEND_TEST(StatsdStatsTest, TestValidConfigAdd);
+ FRIEND_TEST(StatsdStatsTest, TestSocketBatchReadStats);
};
InvalidConfigReason createInvalidConfigReasonWithMatcher(const InvalidConfigReasonEnum reason,
diff --git a/statsd/src/guardrail/stats_log_enums.proto b/statsd/src/guardrail/stats_log_enums.proto
index d47bc80..c468d52 100644
--- a/statsd/src/guardrail/stats_log_enums.proto
+++ b/statsd/src/guardrail/stats_log_enums.proto
@@ -148,6 +148,11 @@
INVALID_CONFIG_REASON_MATCHER_INVALID_VALUE_MATCHER_WITH_STRING_REPLACE = 90;
INVALID_CONFIG_REASON_MATCHER_COMBINATION_WITH_STRING_REPLACE = 91;
INVALID_CONFIG_REASON_MATCHER_STRING_REPLACE_WITH_NO_VALUE_MATCHER_WITH_POSITION_ANY = 92;
+ INVALID_CONFIG_REASON_METRIC_INCORRECT_PULL_PROBABILITY = 93;
+ INVALID_CONFIG_REASON_GAUGE_METRIC_PUSHED_WITH_PULL_PROBABILITY = 94;
+ INVALID_CONFIG_REASON_GAUGE_METRIC_RANDOM_ONE_SAMPLE_WITH_PULL_PROBABILITY = 95;
+ INVALID_CONFIG_REASON_VALUE_METRIC_DEFINES_SINGLE_AND_MULTIPLE_AGG_TYPES = 96;
+ INVALID_CONFIG_REASON_VALUE_METRIC_AGG_TYPES_DNE_VALUE_FIELDS_SIZE = 97;
};
enum InvalidQueryReason {
diff --git a/statsd/src/logd/LogEvent.cpp b/statsd/src/logd/LogEvent.cpp
index d325186..94fe5cf 100644
--- a/statsd/src/logd/LogEvent.cpp
+++ b/statsd/src/logd/LogEvent.cpp
@@ -395,8 +395,10 @@
int value = readNextValue<int32_t>();
// should be one of predefined category in StatsLog.java
switch (value) {
- // Only diagnostic is currently supported for use.
case ASTATSLOG_RESTRICTION_CATEGORY_DIAGNOSTIC:
+ case ASTATSLOG_RESTRICTION_CATEGORY_SYSTEM_INTELLIGENCE:
+ case ASTATSLOG_RESTRICTION_CATEGORY_AUTHENTICATION:
+ case ASTATSLOG_RESTRICTION_CATEGORY_FRAUD_AND_ABUSE:
break;
default:
mValid = false;
diff --git a/statsd/src/metrics/CountMetricProducer.cpp b/statsd/src/metrics/CountMetricProducer.cpp
index e7a331b..32be42e 100644
--- a/statsd/src/metrics/CountMetricProducer.cpp
+++ b/statsd/src/metrics/CountMetricProducer.cpp
@@ -54,6 +54,7 @@
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
const int FIELD_ID_IS_ACTIVE = 14;
const int FIELD_ID_DIMENSION_GUARDRAIL_HIT = 17;
+const int FIELD_ID_ESTIMATED_MEMORY_BYTES = 18;
// for CountMetricDataWrapper
const int FIELD_ID_DATA = 1;
@@ -73,13 +74,14 @@
const ConfigKey& key, const CountMetric& metric, const int conditionIndex,
const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
const uint64_t protoHash, const int64_t timeBaseNs, const int64_t startTimeNs,
+ const wp<ConfigMetadataProvider> configMetadataProvider,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
: MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard,
protoHash, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
- stateGroupMap, getAppUpgradeBucketSplit(metric)),
+ stateGroupMap, getAppUpgradeBucketSplit(metric), configMetadataProvider),
mDimensionGuardrailHit(false),
mDimensionHardLimit(
StatsdStats::clampDimensionKeySizeLimit(metric.max_dimensions_per_bucket())) {
@@ -214,6 +216,7 @@
void CountMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
mPastBuckets.clear();
+ mTotalDataSize = 0;
}
void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
@@ -239,6 +242,8 @@
mDimensionGuardrailHit);
}
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ESTIMATED_MEMORY_BYTES,
+ (long long)byteSizeLocked());
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
@@ -314,6 +319,7 @@
if (erase_data) {
mPastBuckets.clear();
mDimensionGuardrailHit = false;
+ mTotalDataSize = 0;
}
}
@@ -321,6 +327,7 @@
flushIfNeededLocked(dropTimeNs);
StatsdStats::getInstance().noteBucketDropped(mMetricId);
mPastBuckets.clear();
+ mTotalDataSize = 0;
}
void CountMetricProducer::onConditionChangedLocked(const bool conditionMet,
@@ -455,7 +462,10 @@
if (countPassesThreshold(counter.second)) {
info.mCount = counter.second;
auto& bucketList = mPastBuckets[counter.first];
+ const bool isFirstBucket = bucketList.empty();
bucketList.push_back(info);
+ mTotalDataSize += computeBucketSizeLocked(eventTimeNs < fullBucketEndTimeNs,
+ counter.first, isFirstBucket);
VLOG("metric %lld, dump key value: %s -> %lld", (long long)mMetricId,
counter.first.toString().c_str(), (long long)counter.second);
}
@@ -501,6 +511,11 @@
// greater than actual data size as it contains each dimension of
// CountMetricData is duplicated.
size_t CountMetricProducer::byteSizeLocked() const {
+ sp<ConfigMetadataProvider> configMetadataProvider = getConfigMetadataProvider();
+ if (configMetadataProvider != nullptr && configMetadataProvider->useV2SoftMemoryCalculation()) {
+ return computeOverheadSizeLocked(!mPastBuckets.empty(), mDimensionGuardrailHit) +
+ mTotalDataSize;
+ }
size_t totalSize = 0;
for (const auto& pair : mPastBuckets) {
totalSize += pair.second.size() * kBucketSize;
@@ -508,6 +523,24 @@
return totalSize;
}
+// Estimate for the size of a CountBucket.
+size_t CountMetricProducer::computeBucketSizeLocked(const bool isFullBucket,
+ const MetricDimensionKey& dimKey,
+ const bool isFirstBucket) const {
+ size_t bucketSize =
+ MetricProducer::computeBucketSizeLocked(isFullBucket, dimKey, isFirstBucket);
+
+ // Count Value
+ bucketSize += sizeof(int32_t);
+
+ // ConditionTrueNanos
+ if (mConditionTrackerIndex >= 0 && mSlicedStateAtoms.empty() && !mConditionSliced) {
+ bucketSize += sizeof(int64_t);
+ }
+
+ return bucketSize;
+}
+
void CountMetricProducer::onActiveStateChangedLocked(const int64_t eventTimeNs,
const bool isActive) {
MetricProducer::onActiveStateChangedLocked(eventTimeNs, isActive);
diff --git a/statsd/src/metrics/CountMetricProducer.h b/statsd/src/metrics/CountMetricProducer.h
index 7fa463f..d34181c 100644
--- a/statsd/src/metrics/CountMetricProducer.h
+++ b/statsd/src/metrics/CountMetricProducer.h
@@ -47,6 +47,7 @@
const ConfigKey& key, const CountMetric& countMetric, int conditionIndex,
const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
const uint64_t protoHash, int64_t timeBaseNs, int64_t startTimeNs,
+ const wp<ConfigMetadataProvider> configMetadataProvider,
const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
eventDeactivationMap = {},
@@ -100,6 +101,9 @@
void onActiveStateChangedLocked(const int64_t eventTimeNs, const bool isActive) override;
+ size_t computeBucketSizeLocked(const bool isFullBucket, const MetricDimensionKey& dimKey,
+ const bool isFirstBucket) const override;
+
optional<InvalidConfigReason> onConfigUpdatedLocked(
const StatsdConfig& config, int configIndex, int metricIndex,
const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
diff --git a/statsd/src/metrics/DurationMetricProducer.cpp b/statsd/src/metrics/DurationMetricProducer.cpp
index 9973a9e..b07f2e3 100644
--- a/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/statsd/src/metrics/DurationMetricProducer.cpp
@@ -53,6 +53,7 @@
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
const int FIELD_ID_IS_ACTIVE = 14;
const int FIELD_ID_DIMENSION_GUARDRAIL_HIT = 17;
+const int FIELD_ID_ESTIMATED_MEMORY_BYTES = 18;
// for DurationMetricDataWrapper
const int FIELD_ID_DATA = 1;
// for DurationMetricData
@@ -73,13 +74,14 @@
const int startIndex, const int stopIndex, const int stopAllIndex, const bool nesting,
const sp<ConditionWizard>& wizard, const uint64_t protoHash,
const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs,
+ const wp<ConfigMetadataProvider> configMetadataProvider,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
: MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard,
protoHash, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
- stateGroupMap, getAppUpgradeBucketSplit(metric)),
+ stateGroupMap, getAppUpgradeBucketSplit(metric), configMetadataProvider),
mAggregationType(metric.aggregation_type()),
mStartIndex(startIndex),
mStopIndex(stopIndex),
@@ -318,6 +320,7 @@
const HashableDimensionKey& primaryKey,
const FieldValue& oldState,
const FieldValue& newState) {
+ std::lock_guard<std::mutex> lock(mMutex);
// Check if this metric has a StateMap. If so, map the new state value to
// the correct state group id.
FieldValue newStateCopy = newState;
@@ -522,6 +525,9 @@
return;
}
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ESTIMATED_MEMORY_BYTES,
+ (long long)byteSizeLocked());
+
if (StatsdStats::getInstance().hasHitDimensionGuardrail(mMetricId)) {
protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_DIMENSION_GUARDRAIL_HIT, true);
}
@@ -841,8 +847,42 @@
eventTimeNs, values);
}
+// Estimate for the size of a DurationBucket.
+size_t DurationMetricProducer::computeBucketSizeLocked(const bool isFullBucket,
+ const MetricDimensionKey& dimKey,
+ const bool isFirstBucket) const {
+ size_t bucketSize =
+ MetricProducer::computeBucketSizeLocked(isFullBucket, dimKey, isFirstBucket);
+
+ // Duration Value
+ bucketSize += sizeof(int64_t);
+
+ // ConditionTrueNanos
+ if (mConditionTrackerIndex >= 0 && mSlicedStateAtoms.empty() && !mConditionSliced) {
+ bucketSize += sizeof(int64_t);
+ }
+
+ return bucketSize;
+}
+
size_t DurationMetricProducer::byteSizeLocked() const {
size_t totalSize = 0;
+ sp<ConfigMetadataProvider> configMetadataProvider = getConfigMetadataProvider();
+ if (configMetadataProvider != nullptr && configMetadataProvider->useV2SoftMemoryCalculation()) {
+ bool hasHitDimensionGuardrail =
+ StatsdStats::getInstance().hasHitDimensionGuardrail(mMetricId);
+ totalSize += computeOverheadSizeLocked(!mPastBuckets.empty(), hasHitDimensionGuardrail);
+ for (const auto& pair : mPastBuckets) {
+ bool isFirstBucket = true;
+ for (const auto& bucket : pair.second) {
+ bool isFullBucket = bucket.mBucketEndNs - bucket.mBucketStartNs >= mBucketSizeNs;
+ totalSize +=
+ computeBucketSizeLocked(isFullBucket, /*dimKey=*/pair.first, isFirstBucket);
+ isFirstBucket = false;
+ }
+ }
+ return totalSize;
+ }
for (const auto& pair : mPastBuckets) {
totalSize += pair.second.size() * kBucketSize;
}
diff --git a/statsd/src/metrics/DurationMetricProducer.h b/statsd/src/metrics/DurationMetricProducer.h
index 2f3d859..c5403ff 100644
--- a/statsd/src/metrics/DurationMetricProducer.h
+++ b/statsd/src/metrics/DurationMetricProducer.h
@@ -44,6 +44,7 @@
const int startIndex, int stopIndex, int stopAllIndex, const bool nesting,
const sp<ConditionWizard>& wizard, const uint64_t protoHash,
const FieldMatcher& internalDimensions, int64_t timeBaseNs, const int64_t startTimeNs,
+ const wp<ConfigMetadataProvider> configMetadataProvider,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap = {},
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap = {},
const vector<int>& slicedStateAtoms = {},
@@ -138,6 +139,9 @@
void addAnomalyTrackerLocked(sp<AnomalyTracker>& anomalyTracker,
const UpdateStatus& updateStatus, int64_t updateTimeNs);
+ size_t computeBucketSizeLocked(const bool isFullBucket, const MetricDimensionKey& dimKey,
+ const bool isFirstBucket) const override;
+
const DurationMetric_AggregationType mAggregationType;
// Index of the SimpleAtomMatcher which defines the start.
diff --git a/statsd/src/metrics/EventMetricProducer.cpp b/statsd/src/metrics/EventMetricProducer.cpp
index aabd2b3..540e3d0 100644
--- a/statsd/src/metrics/EventMetricProducer.cpp
+++ b/statsd/src/metrics/EventMetricProducer.cpp
@@ -48,6 +48,9 @@
const int FIELD_ID_ID = 1;
const int FIELD_ID_EVENT_METRICS = 4;
const int FIELD_ID_IS_ACTIVE = 14;
+const int FIELD_ID_ESTIMATED_MEMORY_BYTES = 18;
+const int FIELD_ID_DATA_CORRUPTED_REASON = 19;
+
// for EventMetricDataWrapper
const int FIELD_ID_DATA = 1;
// for EventMetricData
@@ -60,13 +63,14 @@
const ConfigKey& key, const EventMetric& metric, const int conditionIndex,
const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
const uint64_t protoHash, const int64_t startTimeNs,
+ const wp<ConfigMetadataProvider> configMetadataProvider,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
: MetricProducer(metric.id(), key, startTimeNs, conditionIndex, initialConditionCache, wizard,
protoHash, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
- stateGroupMap, /*splitBucketForAppUpgrade=*/nullopt),
+ stateGroupMap, /*splitBucketForAppUpgrade=*/nullopt, configMetadataProvider),
mSamplingPercentage(metric.sampling_percentage()) {
if (metric.links().size() > 0) {
for (const auto& link : metric.links()) {
@@ -79,7 +83,6 @@
mConditionSliced = true;
}
- mTotalSize = 0;
VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)mMetricId,
(long long)mBucketSizeNs, (long long)mTimeBaseNs);
}
@@ -135,7 +138,9 @@
void EventMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
mAggregatedAtoms.clear();
- mTotalSize = 0;
+ mDataCorruptedDueToSocketLoss = false;
+ mDataCorruptedDueToQueueOverflow = false;
+ mTotalDataSize = 0;
StatsdStats::getInstance().noteBucketDropped(mMetricId);
}
@@ -162,7 +167,9 @@
void EventMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
mAggregatedAtoms.clear();
- mTotalSize = 0;
+ mDataCorruptedDueToSocketLoss = false;
+ mDataCorruptedDueToQueueOverflow = false;
+ mTotalDataSize = 0;
}
void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
@@ -173,6 +180,13 @@
ProtoOutputStream* protoOutput) {
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_IS_ACTIVE, isActiveLocked());
+ // Data corrupted reason
+ writeDataCorruptedReasons(*protoOutput, FIELD_ID_DATA_CORRUPTED_REASON,
+ mDataCorruptedDueToQueueOverflow, mDataCorruptedDueToSocketLoss);
+ if (!mAggregatedAtoms.empty()) {
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ESTIMATED_MEMORY_BYTES,
+ (long long)byteSizeLocked());
+ }
uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS);
for (const auto& [atomDimensionKey, elapsedTimestampsNs] : mAggregatedAtoms) {
uint64_t wrapperToken =
@@ -192,10 +206,13 @@
protoOutput->end(aggregatedToken);
protoOutput->end(wrapperToken);
}
+
protoOutput->end(protoToken);
if (erase_data) {
mAggregatedAtoms.clear();
- mTotalSize = 0;
+ mDataCorruptedDueToSocketLoss = false;
+ mDataCorruptedDueToQueueOverflow = false;
+ mTotalDataSize = 0;
}
}
@@ -222,14 +239,24 @@
std::vector<int64_t>& aggregatedTimestampsNs = mAggregatedAtoms[key];
if (aggregatedTimestampsNs.empty()) {
- mTotalSize += getSize(key.getAtomFieldValues().getValues());
+ sp<ConfigMetadataProvider> provider = getConfigMetadataProvider();
+ if (provider != nullptr && provider->useV2SoftMemoryCalculation()) {
+ mTotalDataSize += getFieldValuesSizeV2(key.getAtomFieldValues().getValues());
+ } else {
+ mTotalDataSize += getSize(key.getAtomFieldValues().getValues());
+ }
}
aggregatedTimestampsNs.push_back(elapsedTimeNs);
- mTotalSize += sizeof(int64_t); // Add the size of the event timestamp
+ mTotalDataSize += sizeof(int64_t); // Add the size of the event timestamp
}
size_t EventMetricProducer::byteSizeLocked() const {
- return mTotalSize;
+ sp<ConfigMetadataProvider> provider = getConfigMetadataProvider();
+ if (provider != nullptr && provider->useV2SoftMemoryCalculation()) {
+ return mTotalDataSize +
+ computeOverheadSizeLocked(/*hasPastBuckets=*/false, /*dimensionGuardrailHit=*/false);
+ }
+ return mTotalDataSize;
}
} // namespace statsd
diff --git a/statsd/src/metrics/EventMetricProducer.h b/statsd/src/metrics/EventMetricProducer.h
index 6e02659..d64552b 100644
--- a/statsd/src/metrics/EventMetricProducer.h
+++ b/statsd/src/metrics/EventMetricProducer.h
@@ -38,6 +38,7 @@
const ConfigKey& key, const EventMetric& eventMetric, int conditionIndex,
const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
const uint64_t protoHash, int64_t startTimeNs,
+ const wp<ConfigMetadataProvider> configMetadataProvider,
const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
eventDeactivationMap = {},
@@ -50,9 +51,6 @@
return METRIC_TYPE_EVENT;
}
-protected:
- size_t mTotalSize;
-
private:
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
diff --git a/statsd/src/metrics/GaugeMetricProducer.cpp b/statsd/src/metrics/GaugeMetricProducer.cpp
index 10a02d6..979b344 100644
--- a/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -50,6 +50,7 @@
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
const int FIELD_ID_IS_ACTIVE = 14;
const int FIELD_ID_DIMENSION_GUARDRAIL_HIT = 17;
+const int FIELD_ID_ESTIMATED_MEMORY_BYTES = 18;
// for GaugeMetricDataWrapper
const int FIELD_ID_DATA = 1;
const int FIELD_ID_SKIPPED = 2;
@@ -80,12 +81,14 @@
const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int triggerAtomId,
const int atomId, const int64_t timeBaseNs, const int64_t startTimeNs,
const sp<StatsPullerManager>& pullerManager,
+ const wp<ConfigMetadataProvider> configMetadataProvider,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
const size_t dimensionSoftLimit, const size_t dimensionHardLimit)
: MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard,
protoHash, eventActivationMap, eventDeactivationMap, /*slicedStateAtoms=*/{},
- /*stateGroupMap=*/{}, getAppUpgradeBucketSplit(metric)),
+ /*stateGroupMap=*/{}, getAppUpgradeBucketSplit(metric),
+ configMetadataProvider),
mWhatMatcherIndex(whatMatcherIndex),
mEventMatcherWizard(matcherWizard),
mPullerManager(pullerManager),
@@ -101,7 +104,8 @@
mDimensionHardLimit(dimensionHardLimit),
mGaugeAtomsPerDimensionLimit(metric.max_num_gauge_atoms_per_bucket()),
mDimensionGuardrailHit(false),
- mSamplingPercentage(metric.sampling_percentage()) {
+ mSamplingPercentage(metric.sampling_percentage()),
+ mPullProbability(metric.pull_probability()) {
mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
int64_t bucketSizeMills = 0;
@@ -240,6 +244,7 @@
flushIfNeededLocked(dumpTimeNs);
mPastBuckets.clear();
mSkippedBuckets.clear();
+ mTotalDataSize = 0;
}
void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
@@ -262,6 +267,9 @@
return;
}
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ESTIMATED_MEMORY_BYTES,
+ (long long)byteSizeLocked());
+
if (mDimensionGuardrailHit) {
protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_DIMENSION_GUARDRAIL_HIT,
mDimensionGuardrailHit);
@@ -367,6 +375,7 @@
mPastBuckets.clear();
mSkippedBuckets.clear();
mDimensionGuardrailHit = false;
+ mTotalDataSize = 0;
}
}
@@ -394,7 +403,7 @@
default:
break;
}
- if (!triggerPuller) {
+ if (!triggerPuller || !shouldKeepRandomSample(mPullProbability)) {
return;
}
vector<std::shared_ptr<LogEvent>> allData;
@@ -620,6 +629,7 @@
flushIfNeededLocked(dropTimeNs);
StatsdStats::getInstance().noteBucketDropped(mMetricId);
mPastBuckets.clear();
+ mTotalDataSize = 0;
}
// When a new matched event comes in, we check if event falls into the current
@@ -667,7 +677,11 @@
elapsedTimestampsNs.push_back(atom.mElapsedTimestampNs);
}
auto& bucketList = mPastBuckets[slice.first];
+ const bool isFirstBucket = bucketList.empty();
bucketList.push_back(info);
+ mTotalDataSize += computeGaugeBucketSizeLocked(eventTimeNs >= fullBucketEndTimeNs,
+ /*dimKey=*/slice.first, isFirstBucket,
+ info.mAggregatedAtoms);
VLOG("Gauge gauge metric %lld, dump key value: %s", (long long)mMetricId,
slice.first.toString().c_str());
}
@@ -679,6 +693,7 @@
buildDropEvent(eventTimeNs, BucketDropReason::BUCKET_TOO_SMALL));
}
mSkippedBuckets.emplace_back(mCurrentSkippedBucket);
+ mTotalDataSize += computeSkippedBucketSizeLocked(mCurrentSkippedBucket);
}
// If we have anomaly trackers, we need to update the partial bucket values.
@@ -702,7 +717,29 @@
mHasHitGuardrail = false;
}
+// Estimate for the size of a GaugeBucket.
+size_t GaugeMetricProducer::computeGaugeBucketSizeLocked(
+ const bool isFullBucket, const MetricDimensionKey& dimKey, const bool isFirstBucket,
+ const std::unordered_map<AtomDimensionKey, std::vector<int64_t>>& aggregatedAtoms) const {
+ size_t bucketSize =
+ MetricProducer::computeBucketSizeLocked(isFullBucket, dimKey, isFirstBucket);
+
+ // Gauge Atoms and timestamps
+ for (const auto& pair : aggregatedAtoms) {
+ bucketSize += getFieldValuesSizeV2(pair.first.getAtomFieldValues().getValues());
+ bucketSize += sizeof(int64_t) * pair.second.size();
+ }
+
+ return bucketSize;
+}
+
size_t GaugeMetricProducer::byteSizeLocked() const {
+ sp<ConfigMetadataProvider> configMetadataProvider = getConfigMetadataProvider();
+ if (configMetadataProvider != nullptr && configMetadataProvider->useV2SoftMemoryCalculation()) {
+ return computeOverheadSizeLocked(!mPastBuckets.empty() || !mSkippedBuckets.empty(),
+ mDimensionGuardrailHit) +
+ mTotalDataSize;
+ }
size_t totalSize = 0;
for (const auto& pair : mPastBuckets) {
for (const auto& bucket : pair.second) {
diff --git a/statsd/src/metrics/GaugeMetricProducer.h b/statsd/src/metrics/GaugeMetricProducer.h
index 7c737a4..daff08c 100644
--- a/statsd/src/metrics/GaugeMetricProducer.h
+++ b/statsd/src/metrics/GaugeMetricProducer.h
@@ -66,6 +66,7 @@
const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard,
const int pullTagId, int triggerAtomId, int atomId, const int64_t timeBaseNs,
int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager,
+ const wp<ConfigMetadataProvider> configMetadataProvider,
const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
eventDeactivationMap = {},
@@ -81,7 +82,8 @@
// Determine if metric needs to pull
bool isPullNeeded() const override {
std::lock_guard<std::mutex> lock(mMutex);
- return mIsActive && (mCondition == ConditionState::kTrue);
+ return mIsActive && (mCondition == ConditionState::kTrue) &&
+ shouldKeepRandomSample(mPullProbability);
};
// GaugeMetric needs to immediately trigger another pull when we create the partial bucket.
@@ -94,8 +96,8 @@
// GaugeMetric needs to immediately trigger another pull when we create the partial bucket.
void onStatsdInitCompleted(int64_t eventTimeNs) override {
+ ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
-
flushLocked(eventTimeNs);
if (mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE && mIsActive) {
pullAndMatchEventsLocked(eventTimeNs);
@@ -147,6 +149,11 @@
// Only call if mCondition == ConditionState::kTrue && metric is active.
void pullAndMatchEventsLocked(const int64_t timestampNs);
+ size_t computeGaugeBucketSizeLocked(
+ const bool isFullBucket, const MetricDimensionKey& dimKey, const bool isFirstBucket,
+ const std::unordered_map<AtomDimensionKey, std::vector<int64_t>>& aggregatedAtoms)
+ const;
+
optional<InvalidConfigReason> onConfigUpdatedLocked(
const StatsdConfig& config, int configIndex, int metricIndex,
const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
@@ -227,6 +234,8 @@
const int mSamplingPercentage;
+ const int mPullProbability;
+
FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition);
FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition);
FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition);
diff --git a/statsd/src/metrics/KllMetricProducer.cpp b/statsd/src/metrics/KllMetricProducer.cpp
index 8e50567..cc59e3c 100644
--- a/statsd/src/metrics/KllMetricProducer.cpp
+++ b/statsd/src/metrics/KllMetricProducer.cpp
@@ -58,9 +58,11 @@
const ConditionOptions& conditionOptions,
const StateOptions& stateOptions,
const ActivationOptions& activationOptions,
- const GuardrailOptions& guardrailOptions)
+ const GuardrailOptions& guardrailOptions,
+ const wp<ConfigMetadataProvider> configMetadataProvider)
: ValueMetricProducer(metric.id(), key, protoHash, pullOptions, bucketOptions, whatOptions,
- conditionOptions, stateOptions, activationOptions, guardrailOptions) {
+ conditionOptions, stateOptions, activationOptions, guardrailOptions,
+ configMetadataProvider) {
}
KllMetricProducer::DumpProtoFields KllMetricProducer::getDumpProtoFields() const {
@@ -151,7 +153,26 @@
return bucket;
}
+// Estimate for the size of NumericValues.
+size_t KllMetricProducer::getAggregatedValueSize(const std::unique_ptr<KllQuantile>& kll) const {
+ size_t valueSize = 0;
+ // Index
+ valueSize += sizeof(int32_t);
+
+ // Value
+ valueSize += kll->SerializeToProto().ByteSizeLong();
+
+ return valueSize;
+}
+
size_t KllMetricProducer::byteSizeLocked() const {
+ sp<ConfigMetadataProvider> configMetadataProvider = getConfigMetadataProvider();
+ if (configMetadataProvider != nullptr && configMetadataProvider->useV2SoftMemoryCalculation()) {
+ bool dimensionGuardrailHit = StatsdStats::getInstance().hasHitDimensionGuardrail(mMetricId);
+ return computeOverheadSizeLocked(!mPastBuckets.empty() || !mSkippedBuckets.empty(),
+ dimensionGuardrailHit) +
+ mTotalDataSize;
+ }
size_t totalSize = 0;
for (const auto& [_, buckets] : mPastBuckets) {
totalSize += buckets.size() * kBucketSize;
diff --git a/statsd/src/metrics/KllMetricProducer.h b/statsd/src/metrics/KllMetricProducer.h
index 43ca6a4..dd5dcbd 100644
--- a/statsd/src/metrics/KllMetricProducer.h
+++ b/statsd/src/metrics/KllMetricProducer.h
@@ -48,7 +48,8 @@
const PullOptions& pullOptions, const BucketOptions& bucketOptions,
const WhatOptions& whatOptions, const ConditionOptions& conditionOptions,
const StateOptions& stateOptions, const ActivationOptions& activationOptions,
- const GuardrailOptions& guardrailOptions);
+ const GuardrailOptions& guardrailOptions,
+ const wp<ConfigMetadataProvider> configMetadataProvider);
inline MetricType getMetricType() const override {
return METRIC_TYPE_KLL;
@@ -102,6 +103,8 @@
const int sampleSize,
ProtoOutputStream* const protoOutput) const override;
+ size_t getAggregatedValueSize(const std::unique_ptr<KllQuantile>& kll) const override;
+
bool aggregateFields(const int64_t eventTimeNs, const MetricDimensionKey& eventKey,
const LogEvent& event, std::vector<Interval>& intervals,
Empty& empty) override;
diff --git a/statsd/src/metrics/MetricProducer.cpp b/statsd/src/metrics/MetricProducer.cpp
index 55c9adf..ac80a20 100644
--- a/statsd/src/metrics/MetricProducer.cpp
+++ b/statsd/src/metrics/MetricProducer.cpp
@@ -34,7 +34,6 @@
namespace os {
namespace statsd {
-
// for ActiveMetric
const int FIELD_ID_ACTIVE_METRIC_ID = 1;
const int FIELD_ID_ACTIVE_METRIC_ACTIVATION = 2;
@@ -53,7 +52,8 @@
eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap,
- const optional<bool> splitBucketForAppUpgrade)
+ const optional<bool> splitBucketForAppUpgrade,
+ const wp<ConfigMetadataProvider> configMetadataProvider)
: mMetricId(metricId),
mProtoHash(protoHash),
mConfigKey(key),
@@ -78,7 +78,8 @@
mSplitBucketForAppUpgrade(splitBucketForAppUpgrade),
mHasHitGuardrail(false),
mSampledWhatFields({}),
- mShardCount(0) {
+ mShardCount(0),
+ mConfigMetadataProvider(configMetadataProvider) {
}
optional<InvalidConfigReason> MetricProducer::onConfigUpdatedLocked(
@@ -185,6 +186,11 @@
statePrimaryKeys);
}
+void MetricProducer::onMatchedLogEventLostLocked(int32_t /*atomId*/, DataCorruptedReason reason) {
+ mDataCorruptedDueToSocketLoss |= reason == DATA_CORRUPTED_SOCKET_LOSS;
+ mDataCorruptedDueToQueueOverflow |= reason == DATA_CORRUPTED_EVENT_QUEUE_OVERFLOW;
+}
+
bool MetricProducer::evaluateActiveStateLocked(int64_t elapsedTimestampNs) {
bool isActive = mEventActivationMap.empty();
for (auto& it : mEventActivationMap) {
@@ -385,6 +391,69 @@
mShardCount);
}
+sp<ConfigMetadataProvider> MetricProducer::getConfigMetadataProvider() const {
+ sp<ConfigMetadataProvider> provider = mConfigMetadataProvider.promote();
+ if (provider == nullptr) {
+ ALOGE("Could not promote ConfigMetadataProvider");
+ StatsdStats::getInstance().noteConfigMetadataProviderPromotionFailed(mConfigKey);
+ }
+ return provider;
+}
+
+size_t MetricProducer::computeBucketSizeLocked(const bool isFullBucket,
+ const MetricDimensionKey& dimKey,
+ const bool isFirstBucket) const {
+ size_t bucketSize = 0;
+
+ // Bucket timestamps or bucket number
+ bucketSize += isFullBucket ? sizeof(int32_t) : 2 * sizeof(int64_t);
+
+ // Each dimension / state key can have multiple buckets. Add the size only for the first bucket.
+ if (isFirstBucket) {
+ bucketSize += dimKey.getSize(mShouldUseNestedDimensions);
+ }
+
+ return bucketSize;
+}
+
+size_t MetricProducer::computeOverheadSizeLocked(const bool hasPastBuckets,
+ const bool dimensionGuardrailHit) const {
+ size_t overheadSize = 0;
+
+ // MetricId + isActive
+ overheadSize += sizeof(int64_t) + sizeof(bool);
+
+ if (hasPastBuckets) {
+ if (dimensionGuardrailHit) {
+ overheadSize += sizeof(int32_t);
+ }
+
+ // estimated_memory_bytes
+ overheadSize += sizeof(int32_t);
+ // mTimeBase and mBucketSizeNs
+ overheadSize += 2 * sizeof(int64_t);
+
+ if (!mShouldUseNestedDimensions) {
+ // Assume dimensions data adds an additional atomTag + # of dimension fields
+ overheadSize += sizeof(int32_t);
+ overheadSize += sizeof(int32_t) * mDimensionsInWhat.size();
+ }
+ }
+ return overheadSize;
+}
+
+size_t MetricProducer::computeSkippedBucketSizeLocked(const SkippedBucket& skippedBucket) const {
+ size_t skippedBucketSize = 0;
+
+ // Bucket Start, Bucket End
+ skippedBucketSize += 2 * sizeof(int64_t);
+
+ // DropType, Drop Time
+ skippedBucketSize += (sizeof(int32_t) + sizeof(int64_t)) * skippedBucket.dropEvents.size();
+
+ return skippedBucketSize;
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/statsd/src/metrics/MetricProducer.h b/statsd/src/metrics/MetricProducer.h
index 133aa32..cb97ae5 100644
--- a/statsd/src/metrics/MetricProducer.h
+++ b/statsd/src/metrics/MetricProducer.h
@@ -18,6 +18,7 @@
#define METRIC_PRODUCER_H
#include <src/active_config_list.pb.h>
+#include <src/guardrail/stats_log_enums.pb.h>
#include <utils/RefBase.h>
#include <unordered_map>
@@ -27,6 +28,7 @@
#include "condition/ConditionTimer.h"
#include "condition/ConditionWizard.h"
#include "config/ConfigKey.h"
+#include "config/ConfigMetadataProvider.h"
#include "guardrail/StatsdStats.h"
#include "matchers/EventMatcherWizard.h"
#include "matchers/matcher_util.h"
@@ -36,6 +38,7 @@
#include "state/StateManager.h"
#include "utils/DbUtils.h"
#include "utils/ShardOffsetProvider.h"
+#include "utils/api_tracing.h"
namespace android {
namespace os {
@@ -136,7 +139,8 @@
eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap,
- const optional<bool> splitBucketForAppUpgrade);
+ const optional<bool> splitBucketForAppUpgrade,
+ const wp<ConfigMetadataProvider> configMetadataProvider);
virtual ~MetricProducer(){};
@@ -195,15 +199,22 @@
* Force a partial bucket split on boot complete.
*/
virtual void onStatsdInitCompleted(int64_t eventTimeNs) {
+ ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
flushLocked(eventTimeNs);
}
+
// Consume the parsed stats log entry that already matched the "what" of the metric.
void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) {
std::lock_guard<std::mutex> lock(mMutex);
onMatchedLogEventLocked(matcherIndex, event);
}
+ void onMatchedLogEventLost(int32_t atomId, DataCorruptedReason reason) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ onMatchedLogEventLostLocked(atomId, reason);
+ }
+
void onConditionChanged(const bool condition, int64_t eventTime) {
std::lock_guard<std::mutex> lock(mMutex);
onConditionChangedLocked(condition, eventTime);
@@ -232,8 +243,8 @@
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) {
std::lock_guard<std::mutex> lock(mMutex);
- return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, erase_data,
- dumpLatency, str_set, protoOutput);
+ onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, erase_data, dumpLatency,
+ str_set, protoOutput);
}
virtual optional<InvalidConfigReason> onConfigUpdatedLocked(
@@ -254,7 +265,7 @@
void clearPastBuckets(const int64_t dumpTimeNs) {
std::lock_guard<std::mutex> lock(mMutex);
- return clearPastBucketsLocked(dumpTimeNs);
+ clearPastBucketsLocked(dumpTimeNs);
}
void prepareFirstBucket() {
@@ -428,14 +439,14 @@
// Consume the parsed stats log entry that already matched the "what" of the metric.
virtual void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event);
+ virtual void onMatchedLogEventLostLocked(int32_t atomId, DataCorruptedReason reason);
virtual void onConditionChangedLocked(const bool condition, int64_t eventTime) = 0;
virtual void onSlicedConditionMayChangeLocked(bool overallCondition,
const int64_t eventTime) = 0;
virtual void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
- const bool erase_data,
- const DumpLatency dumpLatency,
- std::set<string> *str_set,
+ const bool erase_data, const DumpLatency dumpLatency,
+ std::set<string>* str_set,
android::util::ProtoOutputStream* protoOutput) = 0;
virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0;
virtual void prepareFirstBucketLocked(){};
@@ -446,6 +457,15 @@
void activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs);
void cancelEventActivationLocked(int deactivationTrackerIndex);
+ // Computes the size of a newly added bucket to this metric, taking into account any new
+ // dimensions that are introduced if necessary.
+ virtual size_t computeBucketSizeLocked(const bool isFullBucket,
+ const MetricDimensionKey& dimKey,
+ const bool isFirstBucket) const;
+ size_t computeOverheadSizeLocked(const bool hasPastBuckets,
+ const bool dimensionGuardrailHit) const;
+ size_t computeSkippedBucketSizeLocked(const SkippedBucket& skippedBucket) const;
+
bool evaluateActiveStateLocked(int64_t elapsedTimestampNs);
virtual void onActiveStateChangedLocked(const int64_t eventTimeNs, const bool isActive) {
@@ -577,6 +597,14 @@
int mShardCount;
+ sp<ConfigMetadataProvider> getConfigMetadataProvider() const;
+
+ wp<ConfigMetadataProvider> mConfigMetadataProvider;
+ bool mDataCorruptedDueToSocketLoss = false;
+ bool mDataCorruptedDueToQueueOverflow = false;
+
+ size_t mTotalDataSize = 0;
+
FRIEND_TEST(CountMetricE2eTest, TestSlicedState);
FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap);
FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates);
@@ -614,6 +642,9 @@
FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions);
FRIEND_TEST(ValueMetricE2eTest, TestInitialConditionChanges);
+ FRIEND_TEST(MetricsManagerTest, TestOnLogEventLossForAllowedFromAnyUidAtom);
+ FRIEND_TEST(MetricsManagerTest, TestOnLogEventLossForNotAllowedAtom);
+
FRIEND_TEST(MetricsManagerUtilTest, TestInitialConditions);
FRIEND_TEST(MetricsManagerUtilTest, TestSampledMetrics);
@@ -624,6 +655,10 @@
FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics);
FRIEND_TEST(ConfigUpdateTest, TestUpdateMetricsMultipleTypes);
FRIEND_TEST(ConfigUpdateTest, TestUpdateAlerts);
+
+ FRIEND_TEST(EventMetricProducerTest, TestCorruptedDataReasonSocketLoss_OnDumpReport);
+ FRIEND_TEST(EventMetricProducerTest, TestCorruptedDataReasonSocketLoss_OnDropData);
+ FRIEND_TEST(EventMetricProducerTest, TestCorruptedDataReasonSocketLoss_OnClearPastBuckets);
};
} // namespace statsd
diff --git a/statsd/src/metrics/MetricsManager.cpp b/statsd/src/metrics/MetricsManager.cpp
index 6ce8bce..1ab1e38 100644
--- a/statsd/src/metrics/MetricsManager.cpp
+++ b/statsd/src/metrics/MetricsManager.cpp
@@ -34,6 +34,7 @@
#include "stats_util.h"
#include "statslog_statsd.h"
#include "utils/DbUtils.h"
+#include "utils/api_tracing.h"
using android::util::FIELD_COUNT_REPEATED;
using android::util::FIELD_TYPE_INT32;
@@ -78,7 +79,8 @@
mPullerManager(pullerManager),
mWhitelistedAtomIds(config.whitelisted_atom_ids().begin(),
config.whitelisted_atom_ids().end()),
- mShouldPersistHistory(config.persist_locally()) {
+ mShouldPersistHistory(config.persist_locally()),
+ mUseV2SoftMemoryCalculation(config.statsd_config_options().use_v2_soft_memory_limit()) {
if (!isAtLeastU() && config.has_restricted_metrics_delegate_package_name()) {
mInvalidConfigReason =
InvalidConfigReason(INVALID_CONFIG_REASON_RESTRICTED_METRIC_NOT_ENABLED);
@@ -91,7 +93,7 @@
refreshTtl(timeBaseNs);
mInvalidConfigReason = initStatsdConfig(
key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseNs, currentTimeNs, mTagIdsToMatchersMap, mAllAtomMatchingTrackers,
+ timeBaseNs, currentTimeNs, this, mTagIdsToMatchersMap, mAllAtomMatchingTrackers,
mAtomMatchingTrackerMap, mAllConditionTrackers, mConditionTrackerMap,
mAllMetricProducers, mMetricProducerMap, mAllAnomalyTrackers, mAllPeriodicAlarmTrackers,
mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap,
@@ -162,7 +164,7 @@
mConfigKey, config, mUidMap, mPullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mMetricProducerMap,
- mAllAnomalyTrackers, mAlertTrackerMap, mStateProtoHashes, mTagIdsToMatchersMap,
+ mAllAnomalyTrackers, mAlertTrackerMap, mStateProtoHashes, this, mTagIdsToMatchersMap,
newAtomMatchingTrackers, newAtomMatchingTrackerMap, newConditionTrackers,
newConditionTrackerMap, newMetricProducers, newMetricProducerMap, newAnomalyTrackers,
newAlertTrackerMap, newPeriodicAlarmTrackers, mConditionToMetricMap,
@@ -191,6 +193,7 @@
config.whitelisted_atom_ids().end());
mShouldPersistHistory = config.persist_locally();
mPackageCertificateHashSizeBytes = config.package_certificate_hash_size_bytes();
+ mUseV2SoftMemoryCalculation = config.statsd_config_options().use_v2_soft_memory_limit();
// Store the sub-configs used.
mAnnotations.clear();
@@ -419,6 +422,7 @@
}
void MetricsManager::onStatsdInitCompleted(const int64_t eventTimeNs) {
+ ATRACE_CALL();
// Inform all metric producers.
for (const auto& it : mAllMetricProducers) {
it->onStatsdInitCompleted(eventTimeNs);
@@ -442,6 +446,10 @@
return uids;
}
+bool MetricsManager::useV2SoftMemoryCalculation() {
+ return mUseV2SoftMemoryCalculation;
+}
+
void MetricsManager::dumpStates(int out, bool verbose) {
dprintf(out, "ConfigKey %s, allowed source:", mConfigKey.ToString().c_str());
{
@@ -507,20 +515,19 @@
VLOG("=========================Metric Reports End==========================");
}
-bool MetricsManager::checkLogCredentials(const LogEvent& event) {
- if (mWhitelistedAtomIds.find(event.GetTagId()) != mWhitelistedAtomIds.end()) {
+bool MetricsManager::checkLogCredentials(const int32_t uid, const int32_t atomId) const {
+ if (mWhitelistedAtomIds.find(atomId) != mWhitelistedAtomIds.end()) {
return true;
}
- if (event.GetUid() == AID_ROOT ||
- (event.GetUid() >= AID_SYSTEM && event.GetUid() < AID_SHELL)) {
+ if (uid == AID_ROOT || (uid >= AID_SYSTEM && uid < AID_SHELL)) {
// enable atoms logged from pre-installed Android system services
return true;
}
std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
- if (mAllowedLogSources.find(event.GetUid()) == mAllowedLogSources.end()) {
- VLOG("log source %d not on the whitelist", event.GetUid());
+ if (mAllowedLogSources.find(uid) == mAllowedLogSources.end()) {
+ VLOG("log source %d not on the whitelist", uid);
return false;
}
return true;
@@ -532,11 +539,24 @@
return;
}
+ const int tagId = event.GetTagId();
+
+ if (tagId == util::STATS_SOCKET_LOSS_REPORTED) {
+ // Hard coded logic to handle socket loss info to highlight metric corruption reason
+ // STATS_SOCKET_LOSS_REPORTED might not be part of atoms allow list - but some of lost
+ // atoms can be always allowed - that is the reason to evaluate SocketLossInfo content prior
+ // the checkLogCredentials below
+ const std::optional<SocketLossInfo>& lossInfo = toSocketLossInfo(event);
+ if (lossInfo) {
+ onLogEventLost(*lossInfo);
+ }
+ // next, atom is going to be propagated to be consumed by metrics if any
+ }
+
if (!checkLogCredentials(event)) {
return;
}
- const int tagId = event.GetTagId();
const int64_t eventTimeNs = event.GetElapsedTimestampNs();
bool isActive = mIsAlwaysActive;
@@ -695,6 +715,48 @@
}
}
+void MetricsManager::onLogEventLost(const SocketLossInfo& socketLossInfo) {
+ // socketLossInfo stores atomId per UID - to eliminate duplicates using set
+ const set<int> uniqueLostAtomIds(socketLossInfo.atomIds.begin(), socketLossInfo.atomIds.end());
+
+ // pass lost atom id to all relevant metrics
+ for (const auto lostAtomId : uniqueLostAtomIds) {
+ /**
+ * Socket loss atom:
+ * - comes from a specific uid (originUid)
+ * - specifies the uid in the atom payload (socketLossInfo.uid)
+ * - provides a list of atom ids that are lost
+ *
+ * For atom id that is lost (lostAtomId below):
+ * - if that atom id is allowed from any uid, then always count this atom as lost
+ * - else, if the originUid (from ucred) (socketLossInfo.uid below - is the same for all
+ * uniqueLostAtomIds) is in the allowed log sources - count this atom as lost
+ */
+
+ if (!checkLogCredentials(socketLossInfo.uid, lostAtomId)) {
+ continue;
+ }
+
+ const auto matchersIt = mTagIdsToMatchersMap.find(lostAtomId);
+ if (matchersIt == mTagIdsToMatchersMap.end()) {
+ // atom is lost - but no metrics in config reference it
+ continue;
+ }
+ const auto& matchersIndexesListForLostAtom = matchersIt->second;
+ for (const auto matcherIndex : matchersIndexesListForLostAtom) {
+ auto it = mTrackerToMetricMap.find(matcherIndex);
+ if (it == mTrackerToMetricMap.end()) {
+ continue;
+ }
+ auto& metricsList = it->second;
+ for (const int metricIndex : metricsList) {
+ mAllMetricProducers[metricIndex]->onMatchedLogEventLost(lostAtomId,
+ DATA_CORRUPTED_SOCKET_LOSS);
+ }
+ }
+ }
+}
+
void MetricsManager::onAnomalyAlarmFired(
const int64_t timestampNs,
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet) {
diff --git a/statsd/src/metrics/MetricsManager.h b/statsd/src/metrics/MetricsManager.h
index 86cacf3..22d5ecf 100644
--- a/statsd/src/metrics/MetricsManager.h
+++ b/statsd/src/metrics/MetricsManager.h
@@ -23,6 +23,7 @@
#include "anomaly/AnomalyTracker.h"
#include "condition/ConditionTracker.h"
#include "config/ConfigKey.h"
+#include "config/ConfigMetadataProvider.h"
#include "external/StatsPullerManager.h"
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
@@ -37,7 +38,9 @@
namespace statsd {
// A MetricsManager is responsible for managing metrics from one single config source.
-class MetricsManager : public virtual RefBase, public virtual PullUidProvider {
+class MetricsManager : public virtual RefBase,
+ public virtual PullUidProvider,
+ public virtual ConfigMetadataProvider {
public:
MetricsManager(const ConfigKey& configKey, const StatsdConfig& config, int64_t timeBaseNs,
const int64_t currentTimeNs, const sp<UidMap>& uidMap,
@@ -54,8 +57,6 @@
// Return whether the configuration is valid.
bool isConfigValid() const;
- bool checkLogCredentials(const LogEvent& event);
-
virtual void onLogEvent(const LogEvent& event);
void onAnomalyAlarmFired(
@@ -78,6 +79,8 @@
vector<int32_t> getPullAtomUids(int32_t atomId) override;
+ bool useV2SoftMemoryCalculation() override;
+
bool shouldWriteToDisk() const {
return mNoReportMetricIds.size() != mAllMetricProducers.size();
}
@@ -247,6 +250,7 @@
std::list<std::pair<const int64_t, const int32_t>> mAnnotations;
bool mShouldPersistHistory;
+ bool mUseV2SoftMemoryCalculation;
// All event tags that are interesting to config metrics matchers.
std::unordered_map<int, std::vector<int>> mTagIdsToMatchersMap;
@@ -319,6 +323,12 @@
std::vector<int> mMetricIndexesWithActivation;
+ inline bool checkLogCredentials(const LogEvent& event) const {
+ return checkLogCredentials(event.GetUid(), event.GetTagId());
+ }
+
+ bool checkLogCredentials(int32_t uid, int32_t atomId) const;
+
void initAllowedLogSources();
void initPullAtomSources();
@@ -359,6 +369,8 @@
// metrics.
void setTriggerGetDataBytesFromConfig(const StatsdConfig& config);
+ void onLogEventLost(const SocketLossInfo& socketLossInfo);
+
// The memory limit in bytes for storing metrics
size_t mMaxMetricsBytes;
@@ -368,6 +380,8 @@
FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain);
+
+ FRIEND_TEST(GaugeMetricE2ePushedTest, TestDimensionalSampling);
FRIEND_TEST(GaugeMetricE2ePulledTest, TestFirstNSamplesPulledNoTrigger);
FRIEND_TEST(GaugeMetricE2ePulledTest, TestFirstNSamplesPulledNoTriggerWithActivation);
FRIEND_TEST(GaugeMetricE2ePushedTest, TestMultipleFieldsForPushedEvent);
@@ -398,7 +412,10 @@
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations);
FRIEND_TEST(MetricsManagerTest, TestLogSources);
+ FRIEND_TEST(MetricsManagerTest, TestCheckLogCredentialsWhitelistedAtom);
FRIEND_TEST(MetricsManagerTest, TestLogSourcesOnConfigUpdate);
+ FRIEND_TEST(MetricsManagerTest, TestOnLogEventLossForAllowedFromAnyUidAtom);
+ FRIEND_TEST(MetricsManagerTest, TestOnLogEventLossForNotAllowedAtom);
FRIEND_TEST(MetricsManagerTest_SPlus, TestRestrictedMetricsConfig);
FRIEND_TEST(MetricsManagerTest_SPlus, TestRestrictedMetricsConfigUpdate);
FRIEND_TEST(MetricsManagerUtilTest, TestSampledMetrics);
@@ -435,7 +452,8 @@
FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState);
FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithDimensions);
FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions);
- FRIEND_TEST(GaugeMetricE2ePushedTest, TestDimensionalSampling);
+ FRIEND_TEST(ValueMetricE2eTest, TestInitWithMultipleAggTypes);
+ FRIEND_TEST(ValueMetricE2eTest, TestInitWithDefaultAggType);
};
} // namespace statsd
diff --git a/statsd/src/metrics/NumericValueMetricProducer.cpp b/statsd/src/metrics/NumericValueMetricProducer.cpp
index 4024cce..ed5032b 100644
--- a/statsd/src/metrics/NumericValueMetricProducer.cpp
+++ b/statsd/src/metrics/NumericValueMetricProducer.cpp
@@ -22,6 +22,7 @@
#include <limits.h>
#include <stdlib.h>
+#include "FieldValue.h"
#include "guardrail/StatsdStats.h"
#include "metrics/parsing_utils/metrics_manager_util.h"
#include "stats_log_util.h"
@@ -66,11 +67,13 @@
const PullOptions& pullOptions, const BucketOptions& bucketOptions,
const WhatOptions& whatOptions, const ConditionOptions& conditionOptions,
const StateOptions& stateOptions, const ActivationOptions& activationOptions,
- const GuardrailOptions& guardrailOptions)
+ const GuardrailOptions& guardrailOptions,
+ const wp<ConfigMetadataProvider> configMetadataProvider)
: ValueMetricProducer(metric.id(), key, protoHash, pullOptions, bucketOptions, whatOptions,
- conditionOptions, stateOptions, activationOptions, guardrailOptions),
+ conditionOptions, stateOptions, activationOptions, guardrailOptions,
+ configMetadataProvider),
mUseAbsoluteValueOnReset(metric.use_absolute_value_on_reset()),
- mAggregationType(metric.aggregation_type()),
+ mAggregationTypes(whatOptions.aggregationTypes),
mIncludeSampleSize(metric.has_include_sample_size()
? metric.include_sample_size()
: metric.aggregation_type() == ValueMetric_AggregationType_AVG),
@@ -80,7 +83,8 @@
mUseZeroDefaultBase(metric.use_zero_default_base()),
mHasGlobalBase(false),
mMaxPullDelayNs(metric.has_max_pull_delay_sec() ? metric.max_pull_delay_sec() * NS_PER_SEC
- : StatsdStats::kPullMaxDelayNs) {
+ : StatsdStats::kPullMaxDelayNs),
+ mDedupedFieldMatchers(dedupFieldMatchers(whatOptions.fieldMatchers)) {
// TODO(b/186677791): Use initializer list to initialize mUploadThreshold.
if (metric.has_threshold()) {
mUploadThreshold = metric.threshold();
@@ -274,9 +278,9 @@
// Get dimensions_in_what key and value indices.
HashableDimensionKey dimensionsInWhat;
- vector<int> valueIndices(mFieldMatchers.size(), -1);
+ vector<int> valueIndices(mDedupedFieldMatchers.size(), -1);
const LogEvent& eventRef = transformedEvent == nullptr ? *data : *transformedEvent;
- if (!filterValues(mDimensionsInWhat, mFieldMatchers, eventRef.getValues(),
+ if (!filterValues(mDimensionsInWhat, mDedupedFieldMatchers, eventRef.getValues(),
dimensionsInWhat, valueIndices)) {
StatsdStats::getInstance().noteBadValueType(mMetricId);
}
@@ -478,7 +482,7 @@
}
if (interval.hasValue()) {
- switch (mAggregationType) {
+ switch (getAggregationTypeLocked(i)) {
case ValueMetric::SUM:
// for AVG, we add up and take average when flushing the bucket
case ValueMetric::AVG:
@@ -626,7 +630,30 @@
}
}
+// Estimate for the size of NumericValues.
+size_t NumericValueMetricProducer::getAggregatedValueSize(const Value& value) const {
+ size_t valueSize = 0;
+ // Index
+ valueSize += sizeof(int32_t);
+
+ // Value
+ valueSize += value.getSize();
+
+ // Sample Size
+ if (mIncludeSampleSize) {
+ valueSize += sizeof(int32_t);
+ }
+ return valueSize;
+}
+
size_t NumericValueMetricProducer::byteSizeLocked() const {
+ sp<ConfigMetadataProvider> configMetadataProvider = getConfigMetadataProvider();
+ if (configMetadataProvider != nullptr && configMetadataProvider->useV2SoftMemoryCalculation()) {
+ bool dimensionGuardrailHit = StatsdStats::getInstance().hasHitDimensionGuardrail(mMetricId);
+ return computeOverheadSizeLocked(!mPastBuckets.empty() || !mSkippedBuckets.empty(),
+ dimensionGuardrailHit) +
+ mTotalDataSize;
+ }
size_t totalSize = 0;
for (const auto& [_, buckets] : mPastBuckets) {
totalSize += buckets.size() * kBucketSize;
@@ -664,7 +691,7 @@
}
Value NumericValueMetricProducer::getFinalValue(const Interval& interval) const {
- if (mAggregationType != ValueMetric::AVG) {
+ if (getAggregationTypeLocked(interval.aggIndex) != ValueMetric::AVG) {
return interval.aggregate;
} else {
double sum = interval.aggregate.type == LONG ? (double)interval.aggregate.long_value
diff --git a/statsd/src/metrics/NumericValueMetricProducer.h b/statsd/src/metrics/NumericValueMetricProducer.h
index 775fc1a..8309aef 100644
--- a/statsd/src/metrics/NumericValueMetricProducer.h
+++ b/statsd/src/metrics/NumericValueMetricProducer.h
@@ -36,7 +36,8 @@
const ConditionOptions& conditionOptions,
const StateOptions& stateOptions,
const ActivationOptions& activationOptions,
- const GuardrailOptions& guardrailOptions);
+ const GuardrailOptions& guardrailOptions,
+ const wp<ConfigMetadataProvider> configMetadataProvider);
// Process data pulled on bucket boundary.
void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData, PullResult pullResult,
@@ -142,12 +143,18 @@
// Internal function to calculate the current used bytes.
size_t byteSizeLocked() const override;
- void combineValueFields(pair<LogEvent, vector<int>>& eventValues, const LogEvent& newEvent,
- const vector<int>& newValueIndices) const;
+ void combineValueFields(pair<LogEvent, std::vector<int>>& eventValues, const LogEvent& newEvent,
+ const std::vector<int>& newValueIndices) const;
+
+ ValueMetric::AggregationType getAggregationTypeLocked(int index) const {
+ return mAggregationTypes.size() == 1 ? mAggregationTypes[0] : mAggregationTypes[index];
+ }
+
+ size_t getAggregatedValueSize(const Value& value) const override;
const bool mUseAbsoluteValueOnReset;
- const ValueMetric::AggregationType mAggregationType;
+ const std::vector<ValueMetric::AggregationType> mAggregationTypes;
const bool mIncludeSampleSize;
@@ -171,6 +178,9 @@
const int64_t mMaxPullDelayNs;
+ // Deduped value fields for matching.
+ const std::vector<Matcher> mDedupedFieldMatchers;
+
// For anomaly detection.
std::unordered_map<MetricDimensionKey, int64_t> mCurrentFullBucket;
@@ -232,6 +242,8 @@
FRIEND_TEST(NumericValueMetricProducerTest,
TestSlicedStateWithMultipleDimensionsMissingDataInPull);
FRIEND_TEST(NumericValueMetricProducerTest, TestUploadThreshold);
+ FRIEND_TEST(NumericValueMetricProducerTest, TestMultipleAggTypesPulled);
+ FRIEND_TEST(NumericValueMetricProducerTest, TestMultipleAggTypesPushed);
FRIEND_TEST(NumericValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed);
FRIEND_TEST(NumericValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed);
diff --git a/statsd/src/metrics/RestrictedEventMetricProducer.cpp b/statsd/src/metrics/RestrictedEventMetricProducer.cpp
index f38e835..77682dd 100644
--- a/statsd/src/metrics/RestrictedEventMetricProducer.cpp
+++ b/statsd/src/metrics/RestrictedEventMetricProducer.cpp
@@ -35,13 +35,14 @@
const ConfigKey& key, const EventMetric& metric, const int conditionIndex,
const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
const uint64_t protoHash, const int64_t startTimeNs,
+ const wp<ConfigMetadataProvider> configMetadataProvider,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
: EventMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard, protoHash,
- startTimeNs, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
- stateGroupMap),
+ startTimeNs, configMetadataProvider, eventActivationMap,
+ eventDeactivationMap, slicedStateAtoms, stateGroupMap),
mRestrictedDataCategory(CATEGORY_UNKNOWN) {
}
@@ -57,11 +58,11 @@
StatsdStats::getInstance().noteRestrictedMetricCategoryChanged(mConfigKey, mMetricId);
deleteMetricTable();
mLogEvents.clear();
- mTotalSize = 0;
+ mTotalDataSize = 0;
}
mRestrictedDataCategory = event.getRestrictionCategory();
mLogEvents.push_back(event);
- mTotalSize += getSize(event.getValues()) + sizeof(event);
+ mTotalDataSize += getSize(event.getValues()) + sizeof(event);
}
void RestrictedEventMetricProducer::onDumpReportLocked(
@@ -93,7 +94,7 @@
void RestrictedEventMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
mLogEvents.clear();
- mTotalSize = 0;
+ mTotalDataSize = 0;
StatsdStats::getInstance().noteBucketDropped(mMetricId);
}
@@ -129,7 +130,7 @@
mConfigKey, mMetricId, getElapsedRealtimeNs() - flushStartNs);
}
mLogEvents.clear();
- mTotalSize = 0;
+ mTotalDataSize = 0;
}
bool RestrictedEventMetricProducer::writeMetricMetadataToProto(
diff --git a/statsd/src/metrics/RestrictedEventMetricProducer.h b/statsd/src/metrics/RestrictedEventMetricProducer.h
index 1f68387..7f9a5eb 100644
--- a/statsd/src/metrics/RestrictedEventMetricProducer.h
+++ b/statsd/src/metrics/RestrictedEventMetricProducer.h
@@ -16,6 +16,7 @@
const ConfigKey& key, const EventMetric& eventMetric, const int conditionIndex,
const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
const uint64_t protoHash, int64_t startTimeNs,
+ const wp<ConfigMetadataProvider> configMetadataProvider,
const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
eventDeactivationMap = {},
diff --git a/statsd/src/metrics/ValueMetricProducer.cpp b/statsd/src/metrics/ValueMetricProducer.cpp
index 732cccc..ff65792 100644
--- a/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/statsd/src/metrics/ValueMetricProducer.cpp
@@ -54,6 +54,7 @@
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
const int FIELD_ID_IS_ACTIVE = 14;
const int FIELD_ID_DIMENSION_GUARDRAIL_HIT = 17;
+const int FIELD_ID_ESTIMATED_MEMORY_BYTES = 18;
// for *MetricDataWrapper
const int FIELD_ID_DATA = 1;
const int FIELD_ID_SKIPPED = 2;
@@ -76,12 +77,14 @@
const PullOptions& pullOptions, const BucketOptions& bucketOptions,
const WhatOptions& whatOptions, const ConditionOptions& conditionOptions,
const StateOptions& stateOptions, const ActivationOptions& activationOptions,
- const GuardrailOptions& guardrailOptions)
+ const GuardrailOptions& guardrailOptions,
+ const wp<ConfigMetadataProvider> configMetadataProvider)
: MetricProducer(metricId, key, bucketOptions.timeBaseNs, conditionOptions.conditionIndex,
conditionOptions.initialConditionCache, conditionOptions.conditionWizard,
protoHash, activationOptions.eventActivationMap,
activationOptions.eventDeactivationMap, stateOptions.slicedStateAtoms,
- stateOptions.stateGroupMap, bucketOptions.splitBucketForAppUpgrade),
+ stateOptions.stateGroupMap, bucketOptions.splitBucketForAppUpgrade,
+ configMetadataProvider),
mWhatMatcherIndex(whatOptions.whatMatcherIndex),
mEventMatcherWizard(whatOptions.matcherWizard),
mPullerManager(pullOptions.pullerManager),
@@ -155,6 +158,7 @@
template <typename AggregatedValue, typename DimExtras>
void ValueMetricProducer<AggregatedValue, DimExtras>::onStatsdInitCompleted(
const int64_t eventTimeNs) {
+ ATRACE_CALL();
lock_guard<mutex> lock(mMutex);
if (isPulled() && mCondition == ConditionState::kTrue && mIsActive) {
@@ -222,10 +226,35 @@
}
template <typename AggregatedValue, typename DimExtras>
+size_t ValueMetricProducer<AggregatedValue, DimExtras>::computeValueBucketSizeLocked(
+ const bool isFullBucket, const MetricDimensionKey& dimKey, const bool isFirstBucket,
+ const PastBucket<AggregatedValue>& bucket) const {
+ size_t bucketSize =
+ MetricProducer::computeBucketSizeLocked(isFullBucket, dimKey, isFirstBucket);
+
+ for (const auto& value : bucket.aggregates) {
+ bucketSize += getAggregatedValueSize(value);
+ }
+
+ // ConditionTrueNanos
+ if (mConditionTrackerIndex >= 0 || !mSlicedStateAtoms.empty()) {
+ bucketSize += sizeof(int64_t);
+ }
+
+ // ConditionCorrectionNanos
+ if (getDumpProtoFields().conditionCorrectionNsFieldId.has_value() && isPulled() &&
+ mConditionCorrectionThresholdNs &&
+ (abs(bucket.mConditionCorrectionNs) >= mConditionCorrectionThresholdNs)) {
+ bucketSize += sizeof(int64_t);
+ }
+ return bucketSize;
+}
+
+template <typename AggregatedValue, typename DimExtras>
void ValueMetricProducer<AggregatedValue, DimExtras>::onStateChanged(
int64_t eventTimeNs, int32_t atomId, const HashableDimensionKey& primaryKey,
const FieldValue& oldState, const FieldValue& newState) {
- // TODO(b/189353769): Acquire lock.
+ std::lock_guard<std::mutex> lock(mMutex);
VLOG("ValueMetricProducer %lld onStateChanged time %lld, State %d, key %s, %d -> %d",
(long long)mMetricId, (long long)eventTimeNs, atomId, primaryKey.toString().c_str(),
oldState.mValue.int_value, newState.mValue.int_value);
@@ -287,6 +316,7 @@
const int64_t dumpTimeNs) {
mPastBuckets.clear();
mSkippedBuckets.clear();
+ mTotalDataSize = 0;
}
template <typename AggregatedValue, typename DimExtras>
@@ -324,6 +354,9 @@
return;
}
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ESTIMATED_MEMORY_BYTES,
+ (long long)byteSizeLocked());
+
if (StatsdStats::getInstance().hasHitDimensionGuardrail(mMetricId)) {
protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_DIMENSION_GUARDRAIL_HIT, true);
}
@@ -441,6 +474,7 @@
if (eraseData) {
mPastBuckets.clear();
mSkippedBuckets.clear();
+ mTotalDataSize = 0;
}
}
@@ -816,6 +850,9 @@
}
auto& bucketList = mPastBuckets[metricDimensionKey];
+ const bool isFirstBucket = bucketList.empty();
+ mTotalDataSize += computeValueBucketSizeLocked(
+ eventTimeNs >= fullBucketEndTimeNs, metricDimensionKey, isFirstBucket, bucket);
bucketList.push_back(std::move(bucket));
}
if (!bucketHasData) {
@@ -827,6 +864,7 @@
mCurrentSkippedBucket.bucketStartTimeNs = mCurrentBucketStartTimeNs;
mCurrentSkippedBucket.bucketEndTimeNs = bucketEndTimeNs;
mSkippedBuckets.push_back(mCurrentSkippedBucket);
+ mTotalDataSize += computeSkippedBucketSizeLocked(mCurrentSkippedBucket);
}
// This means that the current bucket was not flushed before a forced bucket split.
diff --git a/statsd/src/metrics/ValueMetricProducer.h b/statsd/src/metrics/ValueMetricProducer.h
index 92541029..78761eb 100644
--- a/statsd/src/metrics/ValueMetricProducer.h
+++ b/statsd/src/metrics/ValueMetricProducer.h
@@ -88,6 +88,7 @@
const sp<EventMatcherWizard>& matcherWizard;
const FieldMatcher& dimensionsInWhat;
const vector<Matcher>& fieldMatchers;
+ const vector<ValueMetric::AggregationType> aggregationTypes;
};
struct ConditionOptions {
@@ -138,7 +139,8 @@
const WhatOptions& whatOptions, const ConditionOptions& conditionOptions,
const StateOptions& stateOptions,
const ActivationOptions& activationOptions,
- const GuardrailOptions& guardrailOptions);
+ const GuardrailOptions& guardrailOptions,
+ const wp<ConfigMetadataProvider> configMetadataProvider);
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
@@ -230,6 +232,12 @@
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
std::vector<int>& metricsWithActivation) override;
+ size_t computeValueBucketSizeLocked(const bool isFullBucket, const MetricDimensionKey& dimKey,
+ const bool isFirstBucket,
+ const PastBucket<AggregatedValue>& bucket) const;
+
+ virtual size_t getAggregatedValueSize(const AggregatedValue& value) const = 0;
+
virtual optional<int64_t> getConditionIdForMetric(const StatsdConfig& config,
const int configIndex) const = 0;
diff --git a/statsd/src/metrics/duration_helper/DurationTracker.h b/statsd/src/metrics/duration_helper/DurationTracker.h
index f86197a..a6cbfff 100644
--- a/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -162,6 +162,8 @@
protected:
virtual bool hasStartedDuration() const = 0;
+ // Convenience to compute the current bucket's end time, which is always aligned with the
+ // start time of the metric.
int64_t getCurrentBucketEndTimeNs() const {
return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
}
@@ -207,12 +209,6 @@
}
}
- // Convenience to compute the current bucket's end time, which is always aligned with the
- // start time of the metric.
- int64_t getCurrentBucketEndTimeNs() {
- return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
- }
-
void setEventKey(const MetricDimensionKey& eventKey) {
mEventKey = eventKey;
}
diff --git a/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/statsd/src/metrics/parsing_utils/config_update_utils.cpp
index 18d7a32..a296dad 100644
--- a/statsd/src/metrics/parsing_utils/config_update_utils.cpp
+++ b/statsd/src/metrics/parsing_utils/config_update_utils.cpp
@@ -730,6 +730,7 @@
const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
const set<int64_t>& replacedStates, const unordered_map<int64_t, int>& oldMetricProducerMap,
const vector<sp<MetricProducer>>& oldMetricProducers,
+ const wp<ConfigMetadataProvider> configMetadataProvider,
unordered_map<int64_t, int>& newMetricProducerMap,
vector<sp<MetricProducer>>& newMetricProducers,
unordered_map<int, vector<int>>& conditionToMetricMap,
@@ -802,7 +803,7 @@
allStateGroupMaps, metricToActivationMap, trackerToMetricMap,
conditionToMetricMap, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
- invalidConfigReason);
+ invalidConfigReason, configMetadataProvider);
break;
}
default: {
@@ -844,7 +845,7 @@
allStateGroupMaps, metricToActivationMap, trackerToMetricMap,
conditionToMetricMap, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
- invalidConfigReason);
+ invalidConfigReason, configMetadataProvider);
break;
}
default: {
@@ -885,7 +886,7 @@
initialConditionCache, wizard, metricToActivationMap, trackerToMetricMap,
conditionToMetricMap, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
- invalidConfigReason);
+ invalidConfigReason, configMetadataProvider);
break;
}
default: {
@@ -928,7 +929,7 @@
stateAtomIdMap, allStateGroupMaps, metricToActivationMap,
trackerToMetricMap, conditionToMetricMap, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
- invalidConfigReason);
+ invalidConfigReason, configMetadataProvider);
break;
}
default: {
@@ -970,7 +971,7 @@
conditionTrackerMap, initialConditionCache, wizard, matcherWizard,
metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, invalidConfigReason);
+ metricsWithActivation, invalidConfigReason, configMetadataProvider);
break;
}
default: {
@@ -1014,7 +1015,7 @@
stateAtomIdMap, allStateGroupMaps, metricToActivationMap,
trackerToMetricMap, conditionToMetricMap, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
- invalidConfigReason);
+ invalidConfigReason, configMetadataProvider);
break;
}
default: {
@@ -1207,6 +1208,7 @@
const vector<sp<AnomalyTracker>>& oldAnomalyTrackers,
const unordered_map<int64_t, int>& oldAlertTrackerMap,
const map<int64_t, uint64_t>& oldStateProtoHashes,
+ const wp<ConfigMetadataProvider> configMetadataProvider,
std::unordered_map<int, std::vector<int>>& allTagIdsToMatchersMap,
vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
@@ -1268,9 +1270,10 @@
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, replacedConditions, newConditionTrackers, conditionCache,
stateAtomIdMap, allStateGroupMaps, replacedStates, oldMetricProducerMap,
- oldMetricProducers, newMetricProducerMap, newMetricProducers, conditionToMetricMap,
- trackerToMetricMap, noReportMetricIds, activationTrackerToMetricMap,
- deactivationTrackerToMetricMap, metricsWithActivation, replacedMetrics);
+ oldMetricProducers, configMetadataProvider, newMetricProducerMap, newMetricProducers,
+ conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
+ activationTrackerToMetricMap, deactivationTrackerToMetricMap, metricsWithActivation,
+ replacedMetrics);
if (invalidConfigReason.has_value()) {
ALOGE("updateMetrics failed");
return invalidConfigReason;
diff --git a/statsd/src/metrics/parsing_utils/config_update_utils.h b/statsd/src/metrics/parsing_utils/config_update_utils.h
index 8b6c784..a8915c2 100644
--- a/statsd/src/metrics/parsing_utils/config_update_utils.h
+++ b/statsd/src/metrics/parsing_utils/config_update_utils.h
@@ -21,6 +21,7 @@
#include "anomaly/AlarmMonitor.h"
#include "anomaly/AlarmTracker.h"
#include "condition/ConditionTracker.h"
+#include "config/ConfigMetadataProvider.h"
#include "external/StatsPullerManager.h"
#include "matchers/AtomMatchingTracker.h"
#include "metrics/MetricProducer.h"
@@ -179,6 +180,7 @@
const std::set<int64_t>& replacedStates,
const std::unordered_map<int64_t, int>& oldMetricProducerMap,
const std::vector<sp<MetricProducer>>& oldMetricProducers,
+ const wp<ConfigMetadataProvider> configMetadataProvider,
std::unordered_map<int64_t, int>& newMetricProducerMap,
std::vector<sp<MetricProducer>>& newMetricProducers,
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
@@ -245,6 +247,7 @@
const std::vector<sp<AnomalyTracker>>& oldAnomalyTrackers,
const std::unordered_map<int64_t, int>& oldAlertTrackerMap,
const std::map<int64_t, uint64_t>& oldStateProtoHashes,
+ const wp<ConfigMetadataProvider> configMetadataProvider,
std::unordered_map<int, std::vector<int>>& allTagIdsToMatchersMap,
std::vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
diff --git a/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp b/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
index 673ff45..43744d3 100644
--- a/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
+++ b/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
@@ -509,7 +509,8 @@
unordered_map<int, vector<int>>& conditionToMetricMap,
unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
- vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason) {
+ vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
+ const wp<ConfigMetadataProvider> configMetadataProvider) {
if (!metric.has_id() || !metric.has_what()) {
ALOGE("cannot find metric id or \"what\" in CountMetric \"%lld\"", (long long)metric.id());
invalidConfigReason =
@@ -597,10 +598,10 @@
return nullopt;
}
- sp<MetricProducer> metricProducer =
- new CountMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
- metricHash, timeBaseNs, currentTimeNs, eventActivationMap,
- eventDeactivationMap, slicedStateAtoms, stateGroupMap);
+ sp<MetricProducer> metricProducer = new CountMetricProducer(
+ key, metric, conditionIndex, initialConditionCache, wizard, metricHash, timeBaseNs,
+ currentTimeNs, configMetadataProvider, eventActivationMap, eventDeactivationMap,
+ slicedStateAtoms, stateGroupMap);
SamplingInfo samplingInfo;
if (metric.has_dimensional_sampling_info()) {
@@ -630,7 +631,8 @@
unordered_map<int, vector<int>>& conditionToMetricMap,
unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
- vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason) {
+ vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
+ const wp<ConfigMetadataProvider> configMetadataProvider) {
if (!metric.has_id() || !metric.has_what()) {
ALOGE("cannot find metric id or \"what\" in DurationMetric \"%lld\"",
(long long)metric.id());
@@ -778,8 +780,8 @@
sp<MetricProducer> metricProducer = new DurationMetricProducer(
key, metric, conditionIndex, initialConditionCache, whatIndex, startIndex, stopIndex,
stopAllIndex, nesting, wizard, metricHash, internalDimensions, timeBaseNs,
- currentTimeNs, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
- stateGroupMap);
+ currentTimeNs, configMetadataProvider, eventActivationMap, eventDeactivationMap,
+ slicedStateAtoms, stateGroupMap);
if (!metricProducer->isValid()) {
// TODO: Remove once invalidConfigReason is added to the DurationMetricProducer constructor
invalidConfigReason = InvalidConfigReason(
@@ -813,7 +815,8 @@
unordered_map<int, vector<int>>& conditionToMetricMap,
unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
- vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason) {
+ vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
+ const wp<ConfigMetadataProvider> configMetadataProvider) {
if (!metric.has_id() || !metric.has_what()) {
ALOGE("cannot find the metric name or what in config");
invalidConfigReason =
@@ -869,11 +872,11 @@
if (config.has_restricted_metrics_delegate_package_name()) {
return {new RestrictedEventMetricProducer(
key, metric, conditionIndex, initialConditionCache, wizard, metricHash, timeBaseNs,
- eventActivationMap, eventDeactivationMap)};
+ configMetadataProvider, eventActivationMap, eventDeactivationMap)};
}
return {new EventMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
- metricHash, timeBaseNs, eventActivationMap,
- eventDeactivationMap)};
+ metricHash, timeBaseNs, configMetadataProvider,
+ eventActivationMap, eventDeactivationMap)};
}
optional<sp<MetricProducer>> createNumericValueMetricProducerAndUpdateMetadata(
@@ -893,7 +896,8 @@
unordered_map<int, vector<int>>& conditionToMetricMap,
unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
- vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason) {
+ vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
+ const wp<ConfigMetadataProvider> configMetadataProvider) {
if (!metric.has_id() || !metric.has_what()) {
ALOGE("cannot find metric id or \"what\" in ValueMetric \"%lld\"", (long long)metric.id());
invalidConfigReason =
@@ -922,6 +926,27 @@
return nullopt;
}
+ std::vector<ValueMetric::AggregationType> aggregationTypes;
+ if (metric.aggregation_types_size() != 0) {
+ if (metric.has_aggregation_type()) {
+ invalidConfigReason = InvalidConfigReason(
+ INVALID_CONFIG_REASON_VALUE_METRIC_DEFINES_SINGLE_AND_MULTIPLE_AGG_TYPES,
+ metric.id());
+ return nullopt;
+ }
+ if (metric.aggregation_types_size() != (int)fieldMatchers.size()) {
+ invalidConfigReason = InvalidConfigReason(
+ INVALID_CONFIG_REASON_VALUE_METRIC_AGG_TYPES_DNE_VALUE_FIELDS_SIZE,
+ metric.id());
+ return nullopt;
+ }
+ for (int i = 0; i < metric.aggregation_types_size(); i++) {
+ aggregationTypes.push_back(metric.aggregation_types(i));
+ }
+ } else { // aggregation_type() is set or default is used.
+ aggregationTypes.push_back(metric.aggregation_type());
+ }
+
int trackerIndex;
invalidConfigReason = handleMetricWithAtomMatchingTrackers(
metric.what(), metric.id(), metricIndex,
@@ -1019,10 +1044,11 @@
{timeBaseNs, currentTimeNs, bucketSizeNs, metric.min_bucket_size_nanos(),
conditionCorrectionThresholdNs, getAppUpgradeBucketSplit(metric)},
{containsAnyPositionInDimensionsInWhat, shouldUseNestedDimensions, trackerIndex,
- matcherWizard, metric.dimensions_in_what(), fieldMatchers},
+ matcherWizard, metric.dimensions_in_what(), fieldMatchers, aggregationTypes},
{conditionIndex, metric.links(), initialConditionCache, wizard},
{metric.state_link(), slicedStateAtoms, stateGroupMap},
- {eventActivationMap, eventDeactivationMap}, {dimensionSoftLimit, dimensionHardLimit});
+ {eventActivationMap, eventDeactivationMap}, {dimensionSoftLimit, dimensionHardLimit},
+ configMetadataProvider);
SamplingInfo samplingInfo;
if (metric.has_dimensional_sampling_info()) {
@@ -1054,7 +1080,8 @@
unordered_map<int, vector<int>>& conditionToMetricMap,
unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
- vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason) {
+ vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
+ const wp<ConfigMetadataProvider> configMetadataProvider) {
if (!metric.has_id() || !metric.has_what()) {
ALOGE("cannot find metric id or \"what\" in KllMetric \"%lld\"", (long long)metric.id());
invalidConfigReason =
@@ -1171,11 +1198,17 @@
key, metric, metricHash, {/*pullTagId=*/-1, pullerManager},
{timeBaseNs, currentTimeNs, bucketSizeNs, metric.min_bucket_size_nanos(),
/*conditionCorrectionThresholdNs=*/nullopt, getAppUpgradeBucketSplit(metric)},
- {containsAnyPositionInDimensionsInWhat, shouldUseNestedDimensions, trackerIndex,
- matcherWizard, metric.dimensions_in_what(), fieldMatchers},
+ {containsAnyPositionInDimensionsInWhat,
+ shouldUseNestedDimensions,
+ trackerIndex,
+ matcherWizard,
+ metric.dimensions_in_what(),
+ fieldMatchers,
+ {}},
{conditionIndex, metric.links(), initialConditionCache, wizard},
{metric.state_link(), slicedStateAtoms, stateGroupMap},
- {eventActivationMap, eventDeactivationMap}, {dimensionSoftLimit, dimensionHardLimit});
+ {eventActivationMap, eventDeactivationMap}, {dimensionSoftLimit, dimensionHardLimit},
+ configMetadataProvider);
SamplingInfo samplingInfo;
if (metric.has_dimensional_sampling_info()) {
@@ -1205,7 +1238,8 @@
unordered_map<int, vector<int>>& conditionToMetricMap,
unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
- vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason) {
+ vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
+ const wp<ConfigMetadataProvider> configMetadataProvider) {
if (!metric.has_id() || !metric.has_what()) {
ALOGE("cannot find metric id or \"what\" in GaugeMetric \"%lld\"", (long long)metric.id());
invalidConfigReason =
@@ -1299,6 +1333,26 @@
return nullopt;
}
+ if (metric.pull_probability() < 1 || metric.pull_probability() > 100) {
+ invalidConfigReason = InvalidConfigReason(
+ INVALID_CONFIG_REASON_METRIC_INCORRECT_PULL_PROBABILITY, metric.id());
+ return nullopt;
+ }
+
+ if (metric.pull_probability() != 100) {
+ if (pullTagId == -1) {
+ invalidConfigReason = InvalidConfigReason(
+ INVALID_CONFIG_REASON_GAUGE_METRIC_PUSHED_WITH_PULL_PROBABILITY, metric.id());
+ return nullopt;
+ }
+ if (metric.sampling_type() == GaugeMetric::RANDOM_ONE_SAMPLE) {
+ invalidConfigReason = InvalidConfigReason(
+ INVALID_CONFIG_REASON_GAUGE_METRIC_RANDOM_ONE_SAMPLE_WITH_PULL_PROBABILITY,
+ metric.id());
+ return nullopt;
+ }
+ }
+
unordered_map<int, shared_ptr<Activation>> eventActivationMap;
unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
invalidConfigReason = handleMetricActivation(
@@ -1324,8 +1378,8 @@
sp<MetricProducer> metricProducer = new GaugeMetricProducer(
key, metric, conditionIndex, initialConditionCache, wizard, metricHash, trackerIndex,
matcherWizard, pullTagId, triggerAtomId, atomTagId, timeBaseNs, currentTimeNs,
- pullerManager, eventActivationMap, eventDeactivationMap, dimensionSoftLimit,
- dimensionHardLimit);
+ pullerManager, configMetadataProvider, eventActivationMap, eventDeactivationMap,
+ dimensionSoftLimit, dimensionHardLimit);
SamplingInfo samplingInfo;
std::vector<Matcher> dimensionsInWhat;
@@ -1533,7 +1587,8 @@
std::set<int64_t>& noReportMetricIds,
unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
- vector<int>& metricsWithActivation) {
+ vector<int>& metricsWithActivation,
+ const wp<ConfigMetadataProvider> configMetadataProvider) {
sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
sp<EventMatcherWizard> matcherWizard = new EventMatcherWizard(allAtomMatchingTrackers);
const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
@@ -1574,7 +1629,7 @@
conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap,
allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, invalidConfigReason);
+ metricsWithActivation, invalidConfigReason, configMetadataProvider);
if (!producer) {
return invalidConfigReason;
}
@@ -1593,7 +1648,7 @@
conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap,
allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, invalidConfigReason);
+ metricsWithActivation, invalidConfigReason, configMetadataProvider);
if (!producer) {
return invalidConfigReason;
}
@@ -1610,7 +1665,8 @@
atomMatchingTrackerMap, allConditionTrackers, conditionTrackerMap,
initialConditionCache, wizard, metricToActivationMap, trackerToMetricMap,
conditionToMetricMap, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, metricsWithActivation, invalidConfigReason);
+ deactivationAtomTrackerToMetricMap, metricsWithActivation, invalidConfigReason,
+ configMetadataProvider);
if (!producer) {
return invalidConfigReason;
}
@@ -1628,7 +1684,7 @@
conditionTrackerMap, initialConditionCache, wizard, matcherWizard, stateAtomIdMap,
allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, invalidConfigReason);
+ metricsWithActivation, invalidConfigReason, configMetadataProvider);
if (!producer) {
return invalidConfigReason;
}
@@ -1646,7 +1702,7 @@
conditionTrackerMap, initialConditionCache, wizard, matcherWizard, stateAtomIdMap,
allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, invalidConfigReason);
+ metricsWithActivation, invalidConfigReason, configMetadataProvider);
if (!producer) {
return invalidConfigReason;
}
@@ -1664,7 +1720,7 @@
conditionTrackerMap, initialConditionCache, wizard, matcherWizard,
metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, invalidConfigReason);
+ metricsWithActivation, invalidConfigReason, configMetadataProvider);
if (!producer) {
return invalidConfigReason;
}
@@ -1752,7 +1808,7 @@
const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
const sp<StatsPullerManager>& pullerManager, const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
- const int64_t currentTimeNs,
+ const int64_t currentTimeNs, const wp<ConfigMetadataProvider> configMetadataProvider,
std::unordered_map<int, std::vector<int>>& allTagIdsToMatchersMap,
vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
unordered_map<int64_t, int>& atomMatchingTrackerMap,
@@ -1808,7 +1864,7 @@
allConditionTrackers, initialConditionCache, allMetricProducers, conditionToMetricMap,
trackerToMetricMap, metricProducerMap, noReportMetricIds,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation);
+ metricsWithActivation, configMetadataProvider);
if (invalidConfigReason.has_value()) {
ALOGE("initMetricProducers failed");
return invalidConfigReason;
diff --git a/statsd/src/metrics/parsing_utils/metrics_manager_util.h b/statsd/src/metrics/parsing_utils/metrics_manager_util.h
index 41e8dc7..8a73ff0 100644
--- a/statsd/src/metrics/parsing_utils/metrics_manager_util.h
+++ b/statsd/src/metrics/parsing_utils/metrics_manager_util.h
@@ -22,6 +22,7 @@
#include "anomaly/AlarmTracker.h"
#include "condition/ConditionTracker.h"
+#include "config/ConfigMetadataProvider.h"
#include "external/StatsPullerManager.h"
#include "matchers/AtomMatchingTracker.h"
#include "metrics/MetricProducer.h"
@@ -111,8 +112,8 @@
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
- std::vector<int>& metricsWithActivation,
- optional<InvalidConfigReason>& invalidConfigReason);
+ std::vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
+ const wp<ConfigMetadataProvider> configMetadataProvider);
// Creates a DurationMetricProducer and updates the vectors/maps used by MetricsManager with
// the appropriate indices. Returns an sp to the producer, or nullopt if there was an error.
@@ -131,8 +132,8 @@
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
- std::vector<int>& metricsWithActivation,
- optional<InvalidConfigReason>& invalidConfigReason);
+ std::vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
+ const wp<ConfigMetadataProvider> configMetadataProvider);
// Creates an EventMetricProducer and updates the vectors/maps used by MetricsManager with
// the appropriate indices. Returns an sp to the producer, or nullopt if there was an error.
@@ -149,8 +150,8 @@
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
- std::vector<int>& metricsWithActivation,
- optional<InvalidConfigReason>& invalidConfigReason);
+ std::vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
+ const wp<ConfigMetadataProvider> configMetadataProvider);
// Creates a NumericValueMetricProducer and updates the vectors/maps used by MetricsManager with
// the appropriate indices. Returns an sp to the producer, or nullopt if there was an error.
@@ -171,8 +172,8 @@
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
- std::vector<int>& metricsWithActivation,
- optional<InvalidConfigReason>& invalidConfigReason);
+ std::vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
+ const wp<ConfigMetadataProvider> configMetadataProvider);
// Creates a GaugeMetricProducer and updates the vectors/maps used by MetricsManager with
// the appropriate indices. Returns an sp to the producer, or nullopt if there was an error.
@@ -191,8 +192,8 @@
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
- std::vector<int>& metricsWithActivation,
- optional<InvalidConfigReason>& invalidConfigReason);
+ std::vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
+ const wp<ConfigMetadataProvider> configMetadataProvider);
// Creates a KllMetricProducer and updates the vectors/maps used by MetricsManager with
// the appropriate indices. Returns an sp to the producer, or nullopt if there was an error.
@@ -213,7 +214,8 @@
unordered_map<int, vector<int>>& conditionToMetricMap,
unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
- vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason);
+ vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
+ const wp<ConfigMetadataProvider> configMetadataProvider);
// Creates an AnomalyTracker and adds it to the appropriate metric.
// Returns an sp to the AnomalyTracker, or nullopt if there was an error.
@@ -353,7 +355,8 @@
std::set<int64_t>& noReportMetricIds,
std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
- std::vector<int>& metricsWithActivation);
+ std::vector<int>& metricsWithActivation,
+ const wp<ConfigMetadataProvider> configMetadataProvider);
// Initialize alarms
// Is called both on initialize new configs and config updates since alarms do not have any state.
@@ -368,7 +371,7 @@
const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
const sp<StatsPullerManager>& pullerManager, const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& periodicAlarmMonitor, int64_t timeBaseNs,
- const int64_t currentTimeNs,
+ const int64_t currentTimeNs, const wp<ConfigMetadataProvider> configMetadataProvider,
std::unordered_map<int, std::vector<int>>& allTagIdsToMatchersMap,
std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
diff --git a/statsd/src/packages/UidMap.cpp b/statsd/src/packages/UidMap.cpp
index 3177225..79e8534 100644
--- a/statsd/src/packages/UidMap.cpp
+++ b/statsd/src/packages/UidMap.cpp
@@ -638,6 +638,7 @@
{"AID_SDK_SANDBOX", 1090},
{"AID_SECURITY_LOG_WRITER", 1091},
{"AID_PRNG_SEEDER", 1092},
+ {"AID_UPROBESTATS", 1093},
{"AID_SHELL", 2000},
{"AID_CACHE", 2001},
{"AID_DIAG", 2002},
diff --git a/statsd/src/shell/ShellSubscriber.cpp b/statsd/src/shell/ShellSubscriber.cpp
index 90ade1c..56c3ccd 100644
--- a/statsd/src/shell/ShellSubscriber.cpp
+++ b/statsd/src/shell/ShellSubscriber.cpp
@@ -24,6 +24,7 @@
#include "guardrail/StatsdStats.h"
#include "stats_log_util.h"
+#include "utils/api_tracing.h"
using aidl::android::os::IStatsSubscriptionCallback;
@@ -126,6 +127,7 @@
}
void ShellSubscriber::onLogEvent(const LogEvent& event) {
+ ATRACE_CALL();
// Skip if event is skipped
if (event.isParsedHeaderOnly()) {
return;
diff --git a/statsd/src/socket/StatsSocketListener.cpp b/statsd/src/socket/StatsSocketListener.cpp
index dd1013d..c9f8b89 100644
--- a/statsd/src/socket/StatsSocketListener.cpp
+++ b/statsd/src/socket/StatsSocketListener.cpp
@@ -33,6 +33,7 @@
#include "logd/logevent_util.h"
#include "stats_log_util.h"
#include "statslog_statsd.h"
+#include "utils/api_tracing.h"
namespace android {
namespace os {
@@ -46,6 +47,7 @@
}
bool StatsSocketListener::onDataAvailable(SocketClient* cli) {
+ ATRACE_CALL();
static bool name_set;
if (!name_set) {
prctl(PR_SET_NAME, "statsd.writer");
@@ -61,39 +63,61 @@
NULL, 0, &iov, 1, control, sizeof(control), 0,
};
- int socket = cli->getSocket();
-
- // To clear the entire buffer is secure/safe, but this contributes to 1.68%
- // overhead under logging load. We are safe because we check counts, but
- // still need to clear null terminator
- // memset(buffer, 0, sizeof(buffer));
- ssize_t n = recvmsg(socket, &hdr, 0);
- if (n <= (ssize_t)(sizeof(android_log_header_t))) {
- return false;
- }
-
- buffer[n] = 0;
-
- struct ucred* cred = NULL;
-
- struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
- while (cmsg != NULL) {
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) {
- cred = (struct ucred*)CMSG_DATA(cmsg);
- break;
+ const int socket = cli->getSocket();
+ int i = 0;
+ ssize_t n = 0;
+ while (n = recvmsg(socket, &hdr, MSG_DONTWAIT), n > 0) {
+ // To clear the entire buffer is secure/safe, but this contributes to 1.68%
+ // overhead under logging load. We are safe because we check counts, but
+ // still need to clear null terminator.
+ // Note that the memset, if needed, should happen before each read in the while loop.
+ // memset(buffer, 0, sizeof(buffer));
+ if (n <= (ssize_t)(sizeof(android_log_header_t))) {
+ return false;
}
- cmsg = CMSG_NXTHDR(&hdr, cmsg);
+ buffer[n] = 0;
+ i++;
+
+ struct ucred* cred = NULL;
+
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
+ while (cmsg != NULL) {
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) {
+ cred = (struct ucred*)CMSG_DATA(cmsg);
+ break;
+ }
+ cmsg = CMSG_NXTHDR(&hdr, cmsg);
+ }
+
+ struct ucred fake_cred;
+ if (cred == NULL) {
+ cred = &fake_cred;
+ cred->pid = 0;
+ cred->uid = DEFAULT_OVERFLOWUID;
+ }
+
+ const uint32_t uid = cred->uid;
+ const uint32_t pid = cred->pid;
+
+ processSocketMessage(buffer, n, uid, pid, *mQueue, *mLogEventFilter);
}
- struct ucred fake_cred;
- if (cred == NULL) {
- cred = &fake_cred;
- cred->pid = 0;
- cred->uid = DEFAULT_OVERFLOWUID;
+ StatsdStats::getInstance().noteBatchSocketRead(i);
+ return true;
+}
+
+void StatsSocketListener::processSocketMessage(const char* buffer, const uint32_t len, uint32_t uid,
+ uint32_t pid, LogEventQueue& queue,
+ const LogEventFilter& filter) {
+ ATRACE_CALL();
+ static const uint32_t kStatsEventTag = 1937006964;
+
+ if (len <= (ssize_t)(sizeof(android_log_header_t)) + sizeof(uint32_t)) {
+ return;
}
- uint8_t* ptr = ((uint8_t*)buffer) + sizeof(android_log_header_t);
- n -= sizeof(android_log_header_t);
+ const uint8_t* ptr = ((uint8_t*)buffer) + sizeof(android_log_header_t);
+ uint32_t bufferLen = len - sizeof(android_log_header_t);
// When a log failed to write to statsd socket (e.g., due ot EBUSY), a special message would
// be sent to statsd when the socket communication becomes available again.
@@ -102,8 +126,9 @@
// Note that all normal stats logs are in the format of event_list, so there won't be confusion.
//
// TODO(b/80538532): In addition to log it in StatsdStats, we should properly reset the config.
- if (n == sizeof(android_log_event_long_t)) {
- android_log_event_long_t* long_event = reinterpret_cast<android_log_event_long_t*>(ptr);
+ if (bufferLen == sizeof(android_log_event_long_t)) {
+ const android_log_event_long_t* long_event =
+ reinterpret_cast<const android_log_event_long_t*>(ptr);
if (long_event->payload.type == EVENT_TYPE_LONG) {
int64_t composed_long = long_event->payload.data;
@@ -113,33 +138,35 @@
int32_t last_atom_tag = (int32_t)((0xffffffff00000000 & (uint64_t)composed_long) >> 32);
ALOGE("Found dropped events: %d error %d last atom tag %d from uid %d", dropped_count,
- long_event->header.tag, last_atom_tag, cred->uid);
+ long_event->header.tag, last_atom_tag, uid);
StatsdStats::getInstance().noteLogLost((int32_t)getWallClockSec(), dropped_count,
- long_event->header.tag, last_atom_tag, cred->uid,
- cred->pid);
- return true;
+ long_event->header.tag, last_atom_tag, uid, pid);
+ return;
}
}
+ // test that received valid StatsEvent buffer
+ const uint32_t statsEventTag = *reinterpret_cast<const uint32_t*>(ptr);
+ if (statsEventTag != kStatsEventTag) {
+ return;
+ }
+
// move past the 4-byte StatsEventTag
const uint8_t* msg = ptr + sizeof(uint32_t);
- const uint32_t len = n - sizeof(uint32_t);
- const uint32_t uid = cred->uid;
- const uint32_t pid = cred->pid;
+ bufferLen -= sizeof(uint32_t);
- processMessage(msg, len, uid, pid, mQueue, mLogEventFilter);
-
- return true;
+ processStatsEventBuffer(msg, bufferLen, uid, pid, queue, filter);
}
-void StatsSocketListener::processMessage(const uint8_t* msg, uint32_t len, uint32_t uid,
- uint32_t pid, const std::shared_ptr<LogEventQueue>& queue,
- const std::shared_ptr<LogEventFilter>& filter) {
+void StatsSocketListener::processStatsEventBuffer(const uint8_t* msg, const uint32_t len,
+ uint32_t uid, uint32_t pid, LogEventQueue& queue,
+ const LogEventFilter& filter) {
+ ATRACE_CALL();
std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(uid, pid);
- if (filter->getFilteringEnabled()) {
+ if (filter.getFilteringEnabled()) {
const LogEvent::BodyBufferInfo bodyInfo = logEvent->parseHeader(msg, len);
- if (filter->isAtomInUse(logEvent->GetTagId())) {
+ if (filter.isAtomInUse(logEvent->GetTagId())) {
logEvent->parseBody(bodyInfo);
}
} else {
@@ -165,7 +192,7 @@
}
}
- const auto [success, oldestTimestamp, queueSize] = queue->push(std::move(logEvent));
+ const auto [success, oldestTimestamp, queueSize] = queue.push(std::move(logEvent));
if (success) {
StatsdStats::getInstance().noteEventQueueSize(queueSize, atomTimestamp);
} else {
diff --git a/statsd/src/socket/StatsSocketListener.h b/statsd/src/socket/StatsSocketListener.h
index fcff2c2..2142e9e 100644
--- a/statsd/src/socket/StatsSocketListener.h
+++ b/statsd/src/socket/StatsSocketListener.h
@@ -50,6 +50,21 @@
static int getLogSocket();
/**
+ * @brief Helper API to parse raw socket data buffer, make the LogEvent & submit it into the
+ * queue. Performs preliminary data validation.
+ * Created as a separate API to be easily tested without StatsSocketListener instance
+ *
+ * @param buffer buffer to parse
+ * @param len size of buffer in bytes
+ * @param uid arguments for LogEvent constructor
+ * @param pid arguments for LogEvent constructor
+ * @param queue queue to submit the event
+ * @param filter to be used for event evaluation
+ */
+ static void processSocketMessage(const char* buffer, uint32_t len, uint32_t uid, uint32_t pid,
+ LogEventQueue& queue, const LogEventFilter& filter);
+
+ /**
* @brief Helper API to parse buffer, make the LogEvent & submit it into the queue
* Created as a separate API to be easily tested without StatsSocketListener instance
*
@@ -60,9 +75,9 @@
* @param queue queue to submit the event
* @param filter to be used for event evaluation
*/
- static void processMessage(const uint8_t* msg, uint32_t len, uint32_t uid, uint32_t pid,
- const std::shared_ptr<LogEventQueue>& queue,
- const std::shared_ptr<LogEventFilter>& filter);
+ static void processStatsEventBuffer(const uint8_t* msg, uint32_t len, uint32_t uid,
+ uint32_t pid, LogEventQueue& queue,
+ const LogEventFilter& filter);
/**
* Who is going to get the events when they're read.
@@ -71,10 +86,11 @@
std::shared_ptr<LogEventFilter> mLogEventFilter;
+ friend void fuzzSocket(const uint8_t* data, size_t size);
+
friend class SocketParseMessageTest;
- friend void generateAtomLogging(const std::shared_ptr<LogEventQueue>& queue,
- const std::shared_ptr<LogEventFilter>& filter, int eventCount,
- int startAtomId);
+ friend void generateAtomLogging(LogEventQueue& queue, const LogEventFilter& filter,
+ int eventCount, int startAtomId);
FRIEND_TEST(SocketParseMessageTest, TestProcessMessage);
FRIEND_TEST(SocketParseMessageTest, TestProcessMessageEmptySetExplicitSet);
diff --git a/statsd/src/state/StateTracker.h b/statsd/src/state/StateTracker.h
index 0fd504d..8e8f27f 100644
--- a/statsd/src/state/StateTracker.h
+++ b/statsd/src/state/StateTracker.h
@@ -16,13 +16,14 @@
#pragma once
#include <utils/RefBase.h>
+
+#include <set>
+#include <unordered_map>
+
#include "HashableDimensionKey.h"
#include "logd/LogEvent.h"
-
#include "state/StateListener.h"
-#include <unordered_map>
-
namespace android {
namespace os {
namespace statsd {
diff --git a/statsd/src/stats_log.proto b/statsd/src/stats_log.proto
index 7354f37..93b0d8c 100644
--- a/statsd/src/stats_log.proto
+++ b/statsd/src/stats_log.proto
@@ -318,6 +318,10 @@
optional bool dimension_guardrail_hit = 17;
+ optional int64 estimated_data_bytes = 18;
+
+ repeated DataCorruptedReason data_corrupted_reason = 19;
+
// Do not use.
reserved 13, 15;
}
@@ -403,6 +407,8 @@
reserved 10;
repeated DataCorruptedReason data_corrupted_reason = 11;
+
+ optional int64 estimated_data_bytes = 12;
}
message ConfigMetricsReportList {
@@ -499,6 +505,7 @@
optional int32 db_deletion_too_old = 35;
optional int32 db_deletion_config_removed = 36;
optional int32 db_deletion_config_updated = 37;
+ optional int32 config_metadata_provider_promotion_failed = 38;
}
repeated ConfigStats config_stats = 3;
@@ -691,6 +698,17 @@
}
optional EventQueueStats event_queue_stats = 25;
+
+ // Tracks info about reads from the socket.
+ message SocketReadStats {
+ // This is a histogram of sizes of the batched reads. The bins are as follows:
+ // [0, 1, 2, 3, 4, 5-9, 10-19, 20-29, 30-39, 40-49, 50-59, 60-69, 70-79, 80-89, 90-99,
+ // 100-199, 200-299, 300-399, 400-499, 500-599, 600-699, 700-799, 800-899, 900-999,
+ // 1000-1199, 1200-1399, 1400-1599, 1600-1799, 1800-1999, 2000+]
+ repeated int64 batched_read_size = 1;
+ }
+
+ optional SocketReadStats socket_read_stats = 26;
}
message AlertTriggerDetails {
diff --git a/statsd/src/stats_log_util.cpp b/statsd/src/stats_log_util.cpp
index 6d47344..f7c9996 100644
--- a/statsd/src/stats_log_util.cpp
+++ b/statsd/src/stats_log_util.cpp
@@ -554,6 +554,18 @@
protoOutput->end(token);
}
+void writeDataCorruptedReasons(ProtoOutputStream& proto, int fieldIdDataCorruptedReason,
+ bool hasQueueOverflow, bool hasSocketLoss) {
+ if (hasQueueOverflow) {
+ proto.write(FIELD_TYPE_INT32 | FIELD_COUNT_REPEATED | fieldIdDataCorruptedReason,
+ DATA_CORRUPTED_EVENT_QUEUE_OVERFLOW);
+ }
+ if (hasSocketLoss) {
+ proto.write(FIELD_TYPE_INT32 | FIELD_COUNT_REPEATED | fieldIdDataCorruptedReason,
+ DATA_CORRUPTED_SOCKET_LOSS);
+ }
+}
+
int64_t getElapsedRealtimeNs() {
return ::android::elapsedRealtimeNano();
}
diff --git a/statsd/src/stats_log_util.h b/statsd/src/stats_log_util.h
index 16cdb35..5aa4c0b 100644
--- a/statsd/src/stats_log_util.h
+++ b/statsd/src/stats_log_util.h
@@ -92,6 +92,9 @@
void writeAtomMetricStatsToStream(const std::pair<int64_t, StatsdStats::AtomMetricStats> &pair,
ProtoOutputStream *protoOutput);
+void writeDataCorruptedReasons(ProtoOutputStream& proto, int fieldIdDataCorruptedReason,
+ bool hasQueueOverflow, bool hasSocketLoss);
+
template<class T>
bool parseProtoOutputStream(ProtoOutputStream& protoOutput, T* message) {
std::string pbBytes;
diff --git a/statsd/src/statsd_config.proto b/statsd/src/statsd_config.proto
index a7eef69..8d48df0 100644
--- a/statsd/src/statsd_config.proto
+++ b/statsd/src/statsd_config.proto
@@ -358,6 +358,8 @@
optional int32 sampling_percentage = 17 [default = 100];
+ optional int32 pull_probability = 18 [default = 100];
+
reserved 100;
reserved 101;
}
@@ -393,6 +395,8 @@
}
optional AggregationType aggregation_type = 8 [default = SUM];
+ repeated AggregationType aggregation_types = 25;
+
optional bool include_sample_size = 22;
optional int64 min_bucket_size_nanos = 10;
@@ -509,6 +513,15 @@
optional bytes trace_config = 1;
}
+message UprobestatsDetails {
+ // The |config| field is a proto-encoded message of type
+ // uprobestats.protos.UprobestatsConfig defined in
+ // //packages/modules/UprobeStats/src/config.proto. On device,
+ // statsd doesn't need to deserialize the message as it's just
+ // passed binary-encoded to the Uprobestats API.
+ optional bytes config = 1;
+}
+
message BroadcastSubscriberDetails {
optional int64 subscriber_id = 1;
repeated string cookie = 2;
@@ -530,6 +543,7 @@
IncidentdDetails incidentd_details = 4;
PerfettoDetails perfetto_details = 5;
BroadcastSubscriberDetails broadcast_subscriber_details = 6;
+ UprobestatsDetails uprobestats_details = 9;
}
optional float probability_of_informing = 7 [default = 1.1];
@@ -628,6 +642,12 @@
optional int32 soft_metrics_memory_kb = 29;
+ message StatsdConfigOptions {
+ optional bool use_v2_soft_memory_limit = 1;
+ }
+
+ optional StatsdConfigOptions statsd_config_options = 30;
+
// Do not use.
reserved 1000, 1001;
}
diff --git a/statsd/src/utils/api_tracing.h b/statsd/src/utils/api_tracing.h
new file mode 100644
index 0000000..69edeae
--- /dev/null
+++ b/statsd/src/utils/api_tracing.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#define ATRACE_TAG ATRACE_TAG_APP
+
+#include <utils/Trace.h>
diff --git a/statsd/tests/FieldValue_test.cpp b/statsd/tests/FieldValue_test.cpp
index cf1e5a5..8e9f789 100644
--- a/statsd/tests/FieldValue_test.cpp
+++ b/statsd/tests/FieldValue_test.cpp
@@ -542,6 +542,124 @@
}
}
+TEST(AtomMatcherTest, TestDedupFieldMatchersAllDifferent) {
+ // Matchers: Fields 1, 2, 3
+ FieldMatcher matcher1;
+ matcher1.set_field(10);
+ FieldMatcher* child = matcher1.add_child();
+ child->set_field(1);
+ child = matcher1.add_child();
+ child->set_field(2);
+ child = matcher1.add_child();
+ child->set_field(3);
+
+ vector<Matcher> fieldMatchers;
+ translateFieldMatcher(matcher1, &fieldMatchers);
+ ASSERT_EQ(3, fieldMatchers.size());
+
+ // Deduped Matchers: Fields 1, 2, 3
+ std::vector<Matcher> dedupedFieldMatchers = dedupFieldMatchers(fieldMatchers);
+ ASSERT_EQ((size_t)3, dedupedFieldMatchers.size());
+ EXPECT_EQ(fieldMatchers[0], dedupedFieldMatchers[0]);
+ EXPECT_EQ(fieldMatchers[1], dedupedFieldMatchers[1]);
+ EXPECT_EQ(fieldMatchers[2], dedupedFieldMatchers[2]);
+}
+
+TEST(AtomMatcherTest, TestDedupFieldMatchersAllSame) {
+ // Matcher: Fields 1, 1, 1
+ FieldMatcher matcher1;
+ matcher1.set_field(10);
+ FieldMatcher* child = matcher1.add_child();
+ child->set_field(1);
+ child = matcher1.add_child();
+ child->set_field(1);
+ child = matcher1.add_child();
+ child->set_field(1);
+
+ vector<Matcher> fieldMatchers;
+ translateFieldMatcher(matcher1, &fieldMatchers);
+ ASSERT_EQ(3, fieldMatchers.size());
+
+ // Deduped Matchers: Fields 1, 1, 1
+ std::vector<Matcher> dedupedFieldMatchers = dedupFieldMatchers(fieldMatchers);
+ ASSERT_EQ((size_t)1, dedupedFieldMatchers.size());
+ EXPECT_EQ(fieldMatchers[0], dedupedFieldMatchers[0]);
+}
+
+TEST(AtomMatcherTest, TestDedupFieldMatcherMixOfFields) {
+ // Matcher: Fields 2, 2, 1, 3, 2, 1, 3
+ FieldMatcher matcher1;
+ matcher1.set_field(10);
+ FieldMatcher* child = matcher1.add_child();
+ child->set_field(2);
+ child = matcher1.add_child();
+ child->set_field(2);
+ child = matcher1.add_child();
+ child->set_field(1);
+ child = matcher1.add_child();
+ child->set_field(3);
+ child = matcher1.add_child();
+ child->set_field(2);
+ child = matcher1.add_child();
+ child->set_field(1);
+ child = matcher1.add_child();
+ child->set_field(3);
+
+ vector<Matcher> fieldMatchers;
+ translateFieldMatcher(matcher1, &fieldMatchers);
+ ASSERT_EQ(7, fieldMatchers.size());
+
+ // Deduped Matchers: Fields 2, 1, 3
+ std::vector<Matcher> dedupedFieldMatchers = dedupFieldMatchers(fieldMatchers);
+ ASSERT_EQ((size_t)3, dedupedFieldMatchers.size());
+ EXPECT_EQ(fieldMatchers[0], dedupedFieldMatchers[0]);
+ EXPECT_EQ(fieldMatchers[2], dedupedFieldMatchers[1]);
+ EXPECT_EQ(fieldMatchers[3], dedupedFieldMatchers[2]);
+}
+
+TEST(AtomMatcherTest, TestDedupFieldMatcherDifferentPositionSameFields) {
+ // Matcher: Fields 3, 1.1(FIRST), 1.2(FIRST), 1.1(FIRST), 1.1(LAST), 1.2(FIRST), 2
+ FieldMatcher matcher1;
+ matcher1.set_field(10);
+ FieldMatcher* child = matcher1.add_child();
+ child->set_field(3);
+ child = matcher1.add_child();
+ child->set_field(1);
+ child->set_position(Position::FIRST);
+ child->add_child()->set_field(1);
+ child = matcher1.add_child();
+ child->set_field(1);
+ child->set_position(Position::FIRST);
+ child->add_child()->set_field(2);
+ child = matcher1.add_child();
+ child->set_field(1);
+ child->set_position(Position::FIRST);
+ child->add_child()->set_field(1);
+ child = matcher1.add_child();
+ child->set_field(1);
+ child->set_position(Position::LAST);
+ child->add_child()->set_field(1);
+ child = matcher1.add_child();
+ child->set_field(1);
+ child->set_position(Position::FIRST);
+ child->add_child()->set_field(2);
+ child = matcher1.add_child();
+ child->set_field(2);
+
+ vector<Matcher> fieldMatchers;
+ translateFieldMatcher(matcher1, &fieldMatchers);
+ ASSERT_EQ(7, fieldMatchers.size());
+
+ // Deduped Matchers: Fields 3, 1.1(FIRST), 1.2(FIRST), 1.1(LAST) 2
+ std::vector<Matcher> dedupedFieldMatchers = dedupFieldMatchers(fieldMatchers);
+ ASSERT_EQ((size_t)5, dedupedFieldMatchers.size());
+ EXPECT_EQ(fieldMatchers[0], dedupedFieldMatchers[0]);
+ EXPECT_EQ(fieldMatchers[1], dedupedFieldMatchers[1]);
+ EXPECT_EQ(fieldMatchers[2], dedupedFieldMatchers[2]);
+ EXPECT_EQ(fieldMatchers[4], dedupedFieldMatchers[3]);
+ EXPECT_EQ(fieldMatchers[6], dedupedFieldMatchers[4]);
+}
+
void checkAttributionNodeInDimensionsValueParcel(StatsDimensionsValueParcel& attributionNodeParcel,
int32_t nodeDepthInAttributionChain,
int32_t uid, string tag) {
diff --git a/statsd/tests/MetricsManager_test.cpp b/statsd/tests/MetricsManager_test.cpp
index d86e975..a45fa24 100644
--- a/statsd/tests/MetricsManager_test.cpp
+++ b/statsd/tests/MetricsManager_test.cpp
@@ -32,6 +32,7 @@
#include "src/state/StateManager.h"
#include "src/statsd_config.pb.h"
#include "statsd_test_util.h"
+#include "statslog_statsdtest.h"
using namespace testing;
using android::sp;
@@ -53,10 +54,12 @@
const long timeBaseSec = 1000;
-StatsdConfig buildGoodRestrictedConfig() {
+StatsdConfig buildEventConfig(bool isRestricted) {
StatsdConfig config;
config.set_id(kConfigId);
- config.set_restricted_metrics_delegate_package_name("delegate");
+ if (isRestricted) {
+ config.set_restricted_metrics_delegate_package_name("delegate");
+ }
AtomMatcher* eventMatcher = config.add_atom_matcher();
eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
@@ -69,6 +72,14 @@
return config;
}
+StatsdConfig buildGoodRestrictedConfig() {
+ return buildEventConfig(/*isRestricted*/ true);
+}
+
+StatsdConfig buildGoodEventConfig() {
+ return buildEventConfig(/*isRestricted*/ false);
+}
+
set<int32_t> unionSet(const vector<set<int32_t>> sets) {
set<int32_t> toRet;
for (const set<int32_t>& s : sets) {
@@ -76,6 +87,36 @@
}
return toRet;
}
+
+SocketLossInfo createSocketLossInfo(int32_t uid, int32_t atomId) {
+ SocketLossInfo lossInfo;
+ lossInfo.uid = uid;
+ lossInfo.errors.push_back(-11);
+ lossInfo.atomIds.push_back(atomId);
+ lossInfo.counts.push_back(1);
+ return lossInfo;
+}
+
+// helper API to create STATS_SOCKET_LOSS_REPORTED LogEvent
+LogEvent createSocketLossInfoLogEvent(int32_t uid, int32_t lossAtomId) {
+ const SocketLossInfo lossInfo = createSocketLossInfo(uid, lossAtomId);
+
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, util::STATS_SOCKET_LOSS_REPORTED);
+ AStatsEvent_writeInt32(statsEvent, lossInfo.uid);
+ AStatsEvent_addBoolAnnotation(statsEvent, ASTATSLOG_ANNOTATION_ID_IS_UID, true);
+ AStatsEvent_writeInt64(statsEvent, lossInfo.firstLossTsNanos);
+ AStatsEvent_writeInt64(statsEvent, lossInfo.lastLossTsNanos);
+ AStatsEvent_writeInt32(statsEvent, lossInfo.overflowCounter);
+ AStatsEvent_writeInt32Array(statsEvent, lossInfo.errors.data(), lossInfo.errors.size());
+ AStatsEvent_writeInt32Array(statsEvent, lossInfo.atomIds.data(), lossInfo.atomIds.size());
+ AStatsEvent_writeInt32Array(statsEvent, lossInfo.counts.data(), lossInfo.counts.size());
+
+ LogEvent event(uid /* uid */, 0 /* pid */);
+ parseStatsEventToLogEvent(statsEvent, &event);
+ return event;
+}
+
} // anonymous namespace
TEST(MetricsManagerTest, TestLogSources) {
@@ -299,6 +340,69 @@
EXPECT_TRUE(metricsManager.checkLogCredentials(event));
}
+TEST(MetricsManagerTest, TestOnLogEventLossForAllowedFromAnyUidAtom) {
+ sp<UidMap> uidMap;
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+
+ StatsdConfig config = buildGoodEventConfig();
+ config.add_whitelisted_atom_ids(2);
+
+ MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
+ pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
+
+ const int32_t customAppUid = AID_APP_START + 1;
+ LogEvent eventOfInterest(customAppUid /* uid */, 0 /* pid */);
+ CreateNoValuesLogEvent(&eventOfInterest, 2 /* atom id */, 0 /* timestamp */);
+ EXPECT_TRUE(metricsManager.checkLogCredentials(eventOfInterest));
+ EXPECT_FALSE(metricsManager.mAllMetricProducers[0]->mDataCorruptedDueToSocketLoss);
+
+ LogEvent eventSocketLossReported = createSocketLossInfoLogEvent(customAppUid, 2);
+
+ // the STATS_SOCKET_LOSS_REPORTED on its own will not be propagated/consumed by any metric
+ EXPECT_FALSE(metricsManager.checkLogCredentials(eventSocketLossReported));
+
+ // the loss info for an atom of interest (2) will be evaluated even when
+ // STATS_SOCKET_LOSS_REPORTED atom is not explicitly in allowed list
+ metricsManager.onLogEvent(eventSocketLossReported);
+
+ // check that corresponding event metric was updated with loss info
+ // the invariant is there is only one metric in the config
+ EXPECT_TRUE(metricsManager.mAllMetricProducers[0]->mDataCorruptedDueToSocketLoss);
+}
+
+TEST(MetricsManagerTest, TestOnLogEventLossForNotAllowedAtom) {
+ sp<UidMap> uidMap;
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+
+ StatsdConfig config = buildGoodEventConfig();
+
+ MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
+ pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
+
+ const int32_t customAppUid = AID_APP_START + 1;
+ LogEvent eventOfInterest(customAppUid /* uid */, 0 /* pid */);
+ CreateNoValuesLogEvent(&eventOfInterest, 2 /* atom id */, 0 /* timestamp */);
+ EXPECT_FALSE(metricsManager.checkLogCredentials(eventOfInterest));
+ EXPECT_FALSE(metricsManager.mAllMetricProducers[0]->mDataCorruptedDueToSocketLoss);
+
+ LogEvent eventSocketLossReported = createSocketLossInfoLogEvent(customAppUid, 2);
+
+ // the STATS_SOCKET_LOSS_REPORTED on its own will not be propagated/consumed by any metric
+ EXPECT_FALSE(metricsManager.checkLogCredentials(eventSocketLossReported));
+
+ // the loss info for an atom of interest (2) will not be evaluated since atom of interest does
+ // not pass credential check
+ metricsManager.onLogEvent(eventSocketLossReported);
+
+ // check that corresponding event metric was not updated with loss info
+ // the invariant is there is only one metric in the config
+ EXPECT_FALSE(metricsManager.mAllMetricProducers[0]->mDataCorruptedDueToSocketLoss);
+}
+
TEST(MetricsManagerTest, TestWhitelistedAtomStateTracker) {
sp<UidMap> uidMap;
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
diff --git a/statsd/tests/SocketListener_test.cpp b/statsd/tests/SocketListener_test.cpp
index 3636508..cc5475e 100644
--- a/statsd/tests/SocketListener_test.cpp
+++ b/statsd/tests/SocketListener_test.cpp
@@ -55,27 +55,24 @@
} // namespace
-void generateAtomLogging(const std::shared_ptr<LogEventQueue>& queue,
- const std::shared_ptr<LogEventFilter>& filter, int eventCount,
+void generateAtomLogging(LogEventQueue& queue, const LogEventFilter& filter, int eventCount,
int startAtomId) {
// create number of AStatsEvent
for (int i = 0; i < eventCount; i++) {
AStatsEventWrapper event(startAtomId + i);
auto [buf, size] = event.getBuffer();
- StatsSocketListener::processMessage(buf, size, kTestUid, kTestPid, queue, filter);
+ StatsSocketListener::processStatsEventBuffer(buf, size, kTestUid, kTestPid, queue, filter);
}
}
class SocketParseMessageTest : public testing::TestWithParam<bool> {
protected:
- std::shared_ptr<LogEventQueue> mEventQueue;
- std::shared_ptr<LogEventFilter> mLogEventFilter;
+ LogEventQueue mEventQueue;
+ LogEventFilter mLogEventFilter;
public:
- SocketParseMessageTest()
- : mEventQueue(std::make_shared<LogEventQueue>(kEventCount /*buffer limit*/)),
- mLogEventFilter(std::make_shared<LogEventFilter>()) {
- mLogEventFilter->setFilteringEnabled(GetParam());
+ SocketParseMessageTest() : mEventQueue(kEventCount /*buffer limit*/) {
+ mLogEventFilter.setFilteringEnabled(GetParam());
}
static std::string ToString(testing::TestParamInfo<bool> info) {
@@ -93,9 +90,9 @@
int64_t lastEventTs = 0;
// check content of the queue
- EXPECT_EQ(kEventCount, mEventQueue->mQueue.size());
+ EXPECT_EQ(kEventCount, mEventQueue.mQueue.size());
for (int i = 0; i < kEventCount; i++) {
- auto logEvent = mEventQueue->waitPop();
+ auto logEvent = mEventQueue.waitPop();
EXPECT_TRUE(logEvent->isValid());
EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
EXPECT_EQ(logEvent->isParsedHeaderOnly(), GetParam());
@@ -108,13 +105,13 @@
TEST_P(SocketParseMessageTest, TestProcessMessageEmptySetExplicitSet) {
LogEventFilter::AtomIdSet idsList;
- mLogEventFilter->setAtomIds(idsList, nullptr);
+ mLogEventFilter.setAtomIds(idsList, nullptr);
generateAtomLogging(mEventQueue, mLogEventFilter, kEventCount, kAtomId);
// check content of the queue
- EXPECT_EQ(kEventCount, mEventQueue->mQueue.size());
+ EXPECT_EQ(kEventCount, mEventQueue.mQueue.size());
for (int i = 0; i < kEventCount; i++) {
- auto logEvent = mEventQueue->waitPop();
+ auto logEvent = mEventQueue.waitPop();
EXPECT_TRUE(logEvent->isValid());
EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
EXPECT_EQ(logEvent->isParsedHeaderOnly(), GetParam());
@@ -122,23 +119,22 @@
}
TEST(SocketParseMessageTest, TestProcessMessageFilterCompleteSet) {
- std::shared_ptr<LogEventQueue> eventQueue =
- std::make_shared<LogEventQueue>(kEventCount /*buffer limit*/);
+ LogEventQueue eventQueue(kEventCount /*buffer limit*/);
- std::shared_ptr<LogEventFilter> logEventFilter = std::make_shared<LogEventFilter>();
+ LogEventFilter logEventFilter;
LogEventFilter::AtomIdSet idsList;
for (int i = 0; i < kEventCount; i++) {
idsList.insert(kAtomId + i);
}
- logEventFilter->setAtomIds(idsList, nullptr);
+ logEventFilter.setAtomIds(idsList, nullptr);
generateAtomLogging(eventQueue, logEventFilter, kEventCount, kAtomId);
// check content of the queue
- EXPECT_EQ(kEventCount, eventQueue->mQueue.size());
+ EXPECT_EQ(kEventCount, eventQueue.mQueue.size());
for (int i = 0; i < kEventCount; i++) {
- auto logEvent = eventQueue->waitPop();
+ auto logEvent = eventQueue.waitPop();
EXPECT_TRUE(logEvent->isValid());
EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
EXPECT_FALSE(logEvent->isParsedHeaderOnly());
@@ -146,30 +142,29 @@
}
TEST(SocketParseMessageTest, TestProcessMessageFilterPartialSet) {
- std::shared_ptr<LogEventQueue> eventQueue =
- std::make_shared<LogEventQueue>(kEventCount /*buffer limit*/);
+ LogEventQueue eventQueue(kEventCount /*buffer limit*/);
- std::shared_ptr<LogEventFilter> logEventFilter = std::make_shared<LogEventFilter>();
+ LogEventFilter logEventFilter;
LogEventFilter::AtomIdSet idsList;
for (int i = 0; i < kEventFilteredCount; i++) {
idsList.insert(kAtomId + i);
}
- logEventFilter->setAtomIds(idsList, nullptr);
+ logEventFilter.setAtomIds(idsList, nullptr);
generateAtomLogging(eventQueue, logEventFilter, kEventCount, kAtomId);
// check content of the queue
- EXPECT_EQ(kEventCount, eventQueue->mQueue.size());
+ EXPECT_EQ(kEventCount, eventQueue.mQueue.size());
for (int i = 0; i < kEventFilteredCount; i++) {
- auto logEvent = eventQueue->waitPop();
+ auto logEvent = eventQueue.waitPop();
EXPECT_TRUE(logEvent->isValid());
EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
EXPECT_FALSE(logEvent->isParsedHeaderOnly());
}
for (int i = kEventFilteredCount; i < kEventCount; i++) {
- auto logEvent = eventQueue->waitPop();
+ auto logEvent = eventQueue.waitPop();
EXPECT_TRUE(logEvent->isValid());
EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
EXPECT_TRUE(logEvent->isParsedHeaderOnly());
@@ -177,41 +172,40 @@
}
TEST(SocketParseMessageTest, TestProcessMessageFilterToggle) {
- std::shared_ptr<LogEventQueue> eventQueue =
- std::make_shared<LogEventQueue>(kEventCount * 3 /*buffer limit*/);
+ LogEventQueue eventQueue(kEventCount * 3 /*buffer limit*/);
- std::shared_ptr<LogEventFilter> logEventFilter = std::make_shared<LogEventFilter>();
+ LogEventFilter logEventFilter;
LogEventFilter::AtomIdSet idsList;
for (int i = 0; i < kEventFilteredCount; i++) {
idsList.insert(kAtomId + i);
}
// events with ids from kAtomId to kAtomId + kEventFilteredCount should not be skipped
- logEventFilter->setAtomIds(idsList, nullptr);
+ logEventFilter.setAtomIds(idsList, nullptr);
generateAtomLogging(eventQueue, logEventFilter, kEventCount, kAtomId);
- logEventFilter->setFilteringEnabled(false);
+ logEventFilter.setFilteringEnabled(false);
// since filtering is disabled - events with any ids should not be skipped
// will generate events with ids [kAtomId + kEventCount, kAtomId + kEventCount * 2]
generateAtomLogging(eventQueue, logEventFilter, kEventCount, kAtomId + kEventCount);
- logEventFilter->setFilteringEnabled(true);
+ logEventFilter.setFilteringEnabled(true);
LogEventFilter::AtomIdSet idsList2;
for (int i = kEventFilteredCount; i < kEventCount; i++) {
idsList2.insert(kAtomId + kEventCount * 2 + i);
}
// events with idsList2 ids should not be skipped
- logEventFilter->setAtomIds(idsList2, nullptr);
+ logEventFilter.setAtomIds(idsList2, nullptr);
// will generate events with ids [kAtomId + kEventCount * 2, kAtomId + kEventCount * 3]
generateAtomLogging(eventQueue, logEventFilter, kEventCount, kAtomId + kEventCount * 2);
// check content of the queue
- EXPECT_EQ(kEventCount * 3, eventQueue->mQueue.size());
+ EXPECT_EQ(kEventCount * 3, eventQueue.mQueue.size());
// events with ids from kAtomId to kAtomId + kEventFilteredCount should not be skipped
for (int i = 0; i < kEventFilteredCount; i++) {
- auto logEvent = eventQueue->waitPop();
+ auto logEvent = eventQueue.waitPop();
EXPECT_TRUE(logEvent->isValid());
EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
EXPECT_FALSE(logEvent->isParsedHeaderOnly());
@@ -219,7 +213,7 @@
// all events above kAtomId + kEventFilteredCount to kAtomId + kEventCount should be skipped
for (int i = kEventFilteredCount; i < kEventCount; i++) {
- auto logEvent = eventQueue->waitPop();
+ auto logEvent = eventQueue.waitPop();
EXPECT_TRUE(logEvent->isValid());
EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
EXPECT_TRUE(logEvent->isParsedHeaderOnly());
@@ -228,7 +222,7 @@
// events with ids [kAtomId + kEventCount, kAtomId + kEventCount * 2] should not be skipped
// since wiltering was disabled at that time
for (int i = 0; i < kEventCount; i++) {
- auto logEvent = eventQueue->waitPop();
+ auto logEvent = eventQueue.waitPop();
EXPECT_TRUE(logEvent->isValid());
EXPECT_EQ(kAtomId + kEventCount + i, logEvent->GetTagId());
EXPECT_FALSE(logEvent->isParsedHeaderOnly());
@@ -237,7 +231,7 @@
// first half events with ids [kAtomId + kEventCount * 2, kAtomId + kEventCount * 3]
// should be skipped
for (int i = 0; i < kEventFilteredCount; i++) {
- auto logEvent = eventQueue->waitPop();
+ auto logEvent = eventQueue.waitPop();
EXPECT_TRUE(logEvent->isValid());
EXPECT_EQ(kAtomId + kEventCount * 2 + i, logEvent->GetTagId());
EXPECT_TRUE(logEvent->isParsedHeaderOnly());
@@ -246,7 +240,7 @@
// second half events with ids [kAtomId + kEventCount * 2, kAtomId + kEventCount * 3]
// should be processed
for (int i = kEventFilteredCount; i < kEventCount; i++) {
- auto logEvent = eventQueue->waitPop();
+ auto logEvent = eventQueue.waitPop();
EXPECT_TRUE(logEvent->isValid());
EXPECT_EQ(kAtomId + kEventCount * 2 + i, logEvent->GetTagId());
EXPECT_FALSE(logEvent->isParsedHeaderOnly());
diff --git a/statsd/tests/e2e/CountMetric_e2e_test.cpp b/statsd/tests/e2e/CountMetric_e2e_test.cpp
index a35312f..f7e5aea 100644
--- a/statsd/tests/e2e/CountMetric_e2e_test.cpp
+++ b/statsd/tests/e2e/CountMetric_e2e_test.cpp
@@ -251,6 +251,7 @@
ASSERT_EQ(1, reports.reports_size());
ASSERT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_estimated_data_bytes());
EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
StatsLogReport::CountMetricDataWrapper countMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
diff --git a/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/statsd/tests/e2e/DurationMetric_e2e_test.cpp
index a6d50d9..308ef52 100644
--- a/statsd/tests/e2e/DurationMetric_e2e_test.cpp
+++ b/statsd/tests/e2e/DurationMetric_e2e_test.cpp
@@ -94,6 +94,7 @@
backfillStartEndTimestamp(&reports);
ASSERT_EQ(1, reports.reports_size());
ASSERT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_estimated_data_bytes());
EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
diff --git a/statsd/tests/e2e/EventMetric_e2e_test.cpp b/statsd/tests/e2e/EventMetric_e2e_test.cpp
index 0432f3c..6909dc2 100644
--- a/statsd/tests/e2e/EventMetric_e2e_test.cpp
+++ b/statsd/tests/e2e/EventMetric_e2e_test.cpp
@@ -84,8 +84,10 @@
ASSERT_EQ(reports.reports_size(), 1);
ConfigMetricsReport report = reports.reports(0);
+ EXPECT_TRUE(report.has_estimated_data_bytes());
ASSERT_EQ(report.metrics_size(), 1);
StatsLogReport wakelockEventMetricReport = report.metrics(0);
+ EXPECT_TRUE(wakelockEventMetricReport.has_estimated_data_bytes());
EXPECT_EQ(wakelockEventMetricReport.metric_id(), wakelockEventMetric.id());
EXPECT_TRUE(wakelockEventMetricReport.has_event_metrics());
ASSERT_EQ(wakelockEventMetricReport.event_metrics().data_size(), 3);
diff --git a/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index e58f813..e9d5b0e 100644
--- a/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -145,6 +145,7 @@
backfillAggregatedAtoms(&reports);
ASSERT_EQ(1, reports.reports_size());
ASSERT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_estimated_data_bytes());
StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
ASSERT_GT((int)gaugeMetrics.data_size(), 1);
@@ -955,6 +956,420 @@
EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
}
+TEST(GaugeMetricE2ePulledTest, TestGaugeMetricPullProbabilityWithTriggerEvent) {
+ // Initiating StatsdStats at the start of this test, so it doesn't call rand() during the test.
+ StatsdStats::getInstance();
+ // Set srand seed to make rand deterministic for testing.
+ srand(0);
+
+ auto config = CreateStatsdConfig(GaugeMetric::FIRST_N_SAMPLES, /*useCondition=*/false);
+ auto gaugeMetric = config.mutable_gauge_metric(0);
+ gaugeMetric->set_pull_probability(50);
+ auto triggerEventMatcher = CreateScreenTurnedOnAtomMatcher();
+ gaugeMetric->set_trigger_event(triggerEventMatcher.id());
+ gaugeMetric->set_max_num_gauge_atoms_per_bucket(200);
+ gaugeMetric->set_bucket(ONE_HOUR);
+
+ int64_t configAddedTimeNs = 60 * NS_PER_SEC;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor =
+ CreateStatsLogProcessor(configAddedTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ // First bucket events.
+ for (int i = 0; i < 30; i++) {
+ events.push_back(CreateScreenStateChangedEvent(configAddedTimeNs + (i * 10 * NS_PER_SEC),
+ android::view::DISPLAY_STATE_ON));
+ }
+ // Second bucket events.
+ for (int i = 0; i < 30; i++) {
+ events.push_back(CreateScreenStateChangedEvent(
+ configAddedTimeNs + bucketSizeNs + (i * 10 * NS_PER_SEC),
+ android::view::DISPLAY_STATE_ON));
+ }
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ backfillAggregatedAtoms(&reports);
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ ASSERT_EQ((int)gaugeMetrics.data_size(), 2); // 2 sets of data for each pull.
+
+ // Data 1
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ("subsystem_name_1",
+ data.dimensions_in_what().value_tuple().dimensions_value(0).value_str());
+ ASSERT_EQ(2, data.bucket_info_size());
+
+ // Data 1, Bucket 1
+ ASSERT_EQ(13, data.bucket_info(0).atom_size());
+ ValidateGaugeBucketTimes(
+ data.bucket_info(0), configAddedTimeNs, configAddedTimeNs + bucketSizeNs,
+ {(int64_t)60 * NS_PER_SEC, (int64_t)80 * NS_PER_SEC, (int64_t)90 * NS_PER_SEC,
+ (int64_t)130 * NS_PER_SEC, (int64_t)150 * NS_PER_SEC, (int64_t)170 * NS_PER_SEC,
+ (int64_t)190 * NS_PER_SEC, (int64_t)200 * NS_PER_SEC, (int64_t)240 * NS_PER_SEC,
+ (int64_t)250 * NS_PER_SEC, (int64_t)300 * NS_PER_SEC, (int64_t)330 * NS_PER_SEC,
+ (int64_t)340 * NS_PER_SEC});
+
+ // Data 1, Bucket 2
+ ASSERT_EQ(18, data.bucket_info(1).atom_size());
+ ValidateGaugeBucketTimes(
+ data.bucket_info(1), configAddedTimeNs + bucketSizeNs,
+ configAddedTimeNs + 2 * bucketSizeNs,
+ {(int64_t)3660 * NS_PER_SEC, (int64_t)3680 * NS_PER_SEC, (int64_t)3700 * NS_PER_SEC,
+ (int64_t)3710 * NS_PER_SEC, (int64_t)3720 * NS_PER_SEC, (int64_t)3740 * NS_PER_SEC,
+ (int64_t)3780 * NS_PER_SEC, (int64_t)3790 * NS_PER_SEC, (int64_t)3820 * NS_PER_SEC,
+ (int64_t)3850 * NS_PER_SEC, (int64_t)3860 * NS_PER_SEC, (int64_t)3870 * NS_PER_SEC,
+ (int64_t)3880 * NS_PER_SEC, (int64_t)3900 * NS_PER_SEC, (int64_t)3910 * NS_PER_SEC,
+ (int64_t)3920 * NS_PER_SEC, (int64_t)3930 * NS_PER_SEC, (int64_t)3940 * NS_PER_SEC});
+
+ // Data 2
+ data = gaugeMetrics.data(1);
+ EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ("subsystem_name_2",
+ data.dimensions_in_what().value_tuple().dimensions_value(0).value_str());
+ ASSERT_EQ(2, data.bucket_info_size());
+
+ // Data 2, Bucket 1
+ ASSERT_EQ(13, data.bucket_info(0).atom_size());
+ ValidateGaugeBucketTimes(
+ data.bucket_info(0), configAddedTimeNs, configAddedTimeNs + bucketSizeNs,
+ {(int64_t)60 * NS_PER_SEC, (int64_t)80 * NS_PER_SEC, (int64_t)90 * NS_PER_SEC,
+ (int64_t)130 * NS_PER_SEC, (int64_t)150 * NS_PER_SEC, (int64_t)170 * NS_PER_SEC,
+ (int64_t)190 * NS_PER_SEC, (int64_t)200 * NS_PER_SEC, (int64_t)240 * NS_PER_SEC,
+ (int64_t)250 * NS_PER_SEC, (int64_t)300 * NS_PER_SEC, (int64_t)330 * NS_PER_SEC,
+ (int64_t)340 * NS_PER_SEC});
+
+ // Data 2, Bucket 2
+ ASSERT_EQ(18, data.bucket_info(1).atom_size());
+ ValidateGaugeBucketTimes(
+ data.bucket_info(1), configAddedTimeNs + bucketSizeNs,
+ configAddedTimeNs + 2 * bucketSizeNs,
+ {(int64_t)3660 * NS_PER_SEC, (int64_t)3680 * NS_PER_SEC, (int64_t)3700 * NS_PER_SEC,
+ (int64_t)3710 * NS_PER_SEC, (int64_t)3720 * NS_PER_SEC, (int64_t)3740 * NS_PER_SEC,
+ (int64_t)3780 * NS_PER_SEC, (int64_t)3790 * NS_PER_SEC, (int64_t)3820 * NS_PER_SEC,
+ (int64_t)3850 * NS_PER_SEC, (int64_t)3860 * NS_PER_SEC, (int64_t)3870 * NS_PER_SEC,
+ (int64_t)3880 * NS_PER_SEC, (int64_t)3900 * NS_PER_SEC, (int64_t)3910 * NS_PER_SEC,
+ (int64_t)3920 * NS_PER_SEC, (int64_t)3930 * NS_PER_SEC, (int64_t)3940 * NS_PER_SEC});
+}
+
+TEST(GaugeMetricE2ePulledTest, TestGaugeMetricPullProbabilityWithBucketBoundaryAlarm) {
+ // Initiating StatsdStats at the start of this test, so it doesn't call rand() during the test.
+ StatsdStats::getInstance();
+ // Set srand seed to make rand deterministic for testing.
+ srand(0);
+
+ auto config = CreateStatsdConfig(GaugeMetric::FIRST_N_SAMPLES, /*useCondition=*/false);
+ auto gaugeMetric = config.mutable_gauge_metric(0);
+ gaugeMetric->set_pull_probability(50);
+ gaugeMetric->set_max_num_gauge_atoms_per_bucket(200);
+
+ int64_t baseTimeNs = 5 * 60 * NS_PER_SEC;
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor =
+ CreateStatsLogProcessor(configAddedTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+
+ // Pulling alarm arrives on time and resets the sequential pulling alarm.
+ for (int i = 1; i < 31; i++) {
+ processor->informPullAlarmFired(configAddedTimeNs + i * bucketSizeNs);
+ }
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 32 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ backfillAggregatedAtoms(&reports);
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ ASSERT_EQ((int)gaugeMetrics.data_size(), 2);
+
+ // Data 1
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ("subsystem_name_1",
+ data.dimensions_in_what().value_tuple().dimensions_value(0).value_str());
+ ASSERT_EQ(14, data.bucket_info_size());
+
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(0), configAddedTimeNs,
+ configAddedTimeNs + bucketSizeNs, {configAddedTimeNs});
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(1), configAddedTimeNs + 2 * bucketSizeNs,
+ configAddedTimeNs + 3 * bucketSizeNs,
+ {configAddedTimeNs + 2 * bucketSizeNs}); // 1200000000000ns
+
+ EXPECT_EQ(1, data.bucket_info(2).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(2), configAddedTimeNs + 3 * bucketSizeNs,
+ configAddedTimeNs + 4 * bucketSizeNs,
+ {(int64_t)configAddedTimeNs + 3 * bucketSizeNs}); // 1500000000000ns
+
+ EXPECT_EQ(1, data.bucket_info(3).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(3), configAddedTimeNs + 7 * bucketSizeNs,
+ configAddedTimeNs + 8 * bucketSizeNs,
+ {configAddedTimeNs + 7 * bucketSizeNs}); // 2700000000000ns
+
+ EXPECT_EQ(1, data.bucket_info(4).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(4), configAddedTimeNs + 9 * bucketSizeNs,
+ configAddedTimeNs + 10 * bucketSizeNs,
+ {configAddedTimeNs + 9 * bucketSizeNs}); // 3300000000000ns
+
+ EXPECT_EQ(1, data.bucket_info(5).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(5), configAddedTimeNs + 11 * bucketSizeNs,
+ configAddedTimeNs + 12 * bucketSizeNs,
+ {configAddedTimeNs + 11 * bucketSizeNs}); // 3900000000000ns
+
+ EXPECT_EQ(1, data.bucket_info(6).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(6), configAddedTimeNs + 13 * bucketSizeNs,
+ configAddedTimeNs + 14 * bucketSizeNs,
+ {configAddedTimeNs + 13 * bucketSizeNs}); // 4500000000000ns
+
+ EXPECT_EQ(1, data.bucket_info(7).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(7), configAddedTimeNs + 14 * bucketSizeNs,
+ configAddedTimeNs + 15 * bucketSizeNs,
+ {configAddedTimeNs + 14 * bucketSizeNs}); // 4800000000000ns
+
+ EXPECT_EQ(1, data.bucket_info(8).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(8), configAddedTimeNs + 18 * bucketSizeNs,
+ configAddedTimeNs + 19 * bucketSizeNs,
+ {configAddedTimeNs + 18 * bucketSizeNs}); // 6000000000000ns
+
+ EXPECT_EQ(1, data.bucket_info(9).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(9), configAddedTimeNs + 19 * bucketSizeNs,
+ configAddedTimeNs + 20 * bucketSizeNs,
+ {configAddedTimeNs + 19 * bucketSizeNs}); // 6300000000000ns
+
+ EXPECT_EQ(1, data.bucket_info(10).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(10), configAddedTimeNs + 24 * bucketSizeNs,
+ configAddedTimeNs + 25 * bucketSizeNs,
+ {configAddedTimeNs + 24 * bucketSizeNs}); // 7800000000000ns
+
+ EXPECT_EQ(1, data.bucket_info(11).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(11), configAddedTimeNs + 27 * bucketSizeNs,
+ configAddedTimeNs + 28 * bucketSizeNs,
+ {configAddedTimeNs + 27 * bucketSizeNs}); // 8700000000000ns
+
+ EXPECT_EQ(1, data.bucket_info(12).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(12), configAddedTimeNs + 28 * bucketSizeNs,
+ configAddedTimeNs + 29 * bucketSizeNs,
+ {configAddedTimeNs + 28 * bucketSizeNs}); // 9000000000000ns
+
+ EXPECT_EQ(1, data.bucket_info(13).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(13), configAddedTimeNs + 30 * bucketSizeNs,
+ configAddedTimeNs + 31 * bucketSizeNs,
+ {configAddedTimeNs + 30 * bucketSizeNs}); // 9600000000000ns
+
+ // Data 2
+ data = gaugeMetrics.data(1);
+ EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ("subsystem_name_2",
+ data.dimensions_in_what().value_tuple().dimensions_value(0).value_str());
+ ASSERT_EQ(14, data.bucket_info_size());
+
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(0), configAddedTimeNs,
+ configAddedTimeNs + bucketSizeNs, {configAddedTimeNs});
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(1), configAddedTimeNs + 2 * bucketSizeNs,
+ configAddedTimeNs + 3 * bucketSizeNs,
+ {configAddedTimeNs + 2 * bucketSizeNs});
+
+ EXPECT_EQ(1, data.bucket_info(2).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(2), configAddedTimeNs + 3 * bucketSizeNs,
+ configAddedTimeNs + 4 * bucketSizeNs,
+ {(int64_t)configAddedTimeNs + 3 * bucketSizeNs});
+
+ EXPECT_EQ(1, data.bucket_info(3).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(3), configAddedTimeNs + 7 * bucketSizeNs,
+ configAddedTimeNs + 8 * bucketSizeNs,
+ {configAddedTimeNs + 7 * bucketSizeNs});
+
+ EXPECT_EQ(1, data.bucket_info(4).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(4), configAddedTimeNs + 9 * bucketSizeNs,
+ configAddedTimeNs + 10 * bucketSizeNs,
+ {configAddedTimeNs + 9 * bucketSizeNs});
+
+ EXPECT_EQ(1, data.bucket_info(5).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(5), configAddedTimeNs + 11 * bucketSizeNs,
+ configAddedTimeNs + 12 * bucketSizeNs,
+ {configAddedTimeNs + 11 * bucketSizeNs});
+
+ EXPECT_EQ(1, data.bucket_info(6).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(6), configAddedTimeNs + 13 * bucketSizeNs,
+ configAddedTimeNs + 14 * bucketSizeNs,
+ {configAddedTimeNs + 13 * bucketSizeNs});
+
+ EXPECT_EQ(1, data.bucket_info(7).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(7), configAddedTimeNs + 14 * bucketSizeNs,
+ configAddedTimeNs + 15 * bucketSizeNs,
+ {configAddedTimeNs + 14 * bucketSizeNs});
+
+ EXPECT_EQ(1, data.bucket_info(8).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(8), configAddedTimeNs + 18 * bucketSizeNs,
+ configAddedTimeNs + 19 * bucketSizeNs,
+ {configAddedTimeNs + 18 * bucketSizeNs});
+
+ EXPECT_EQ(1, data.bucket_info(9).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(9), configAddedTimeNs + 19 * bucketSizeNs,
+ configAddedTimeNs + 20 * bucketSizeNs,
+ {configAddedTimeNs + 19 * bucketSizeNs});
+
+ EXPECT_EQ(1, data.bucket_info(10).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(10), configAddedTimeNs + 24 * bucketSizeNs,
+ configAddedTimeNs + 25 * bucketSizeNs,
+ {configAddedTimeNs + 24 * bucketSizeNs});
+
+ EXPECT_EQ(1, data.bucket_info(11).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(11), configAddedTimeNs + 27 * bucketSizeNs,
+ configAddedTimeNs + 28 * bucketSizeNs,
+ {configAddedTimeNs + 27 * bucketSizeNs});
+
+ EXPECT_EQ(1, data.bucket_info(12).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(12), configAddedTimeNs + 28 * bucketSizeNs,
+ configAddedTimeNs + 29 * bucketSizeNs,
+ {configAddedTimeNs + 28 * bucketSizeNs});
+
+ EXPECT_EQ(1, data.bucket_info(13).atom_size());
+ ValidateGaugeBucketTimes(data.bucket_info(13), configAddedTimeNs + 30 * bucketSizeNs,
+ configAddedTimeNs + 31 * bucketSizeNs,
+ {configAddedTimeNs + 30 * bucketSizeNs});
+}
+
+TEST(GaugeMetricE2ePulledTest, TestGaugeMetricPullProbabilityWithCondition) {
+ // Initiating StatsdStats at the start of this test, so it doesn't call rand() during the test.
+ StatsdStats::getInstance();
+ // Set srand seed to make rand deterministic for testing.
+ srand(0);
+
+ auto config = CreateStatsdConfig(GaugeMetric::CONDITION_CHANGE_TO_TRUE, /*useCondition=*/true);
+ auto gaugeMetric = config.mutable_gauge_metric(0);
+ gaugeMetric->set_pull_probability(50);
+ gaugeMetric->set_max_num_gauge_atoms_per_bucket(200);
+ gaugeMetric->set_bucket(ONE_HOUR);
+
+ int64_t configAddedTimeNs = 60 * NS_PER_SEC;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor =
+ CreateStatsLogProcessor(configAddedTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ // First bucket events.
+ for (int i = 0; i < 30; i++) {
+ events.push_back(CreateScreenStateChangedEvent(configAddedTimeNs + (i * 10 * NS_PER_SEC),
+ android::view::DISPLAY_STATE_OFF));
+ events.push_back(CreateScreenStateChangedEvent(configAddedTimeNs + (i * 11 * NS_PER_SEC),
+ android::view::DISPLAY_STATE_ON));
+ }
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 2 * bucketSizeNs, false, true, ADB_DUMP,
+ FAST, &buffer);
+
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ backfillAggregatedAtoms(&reports);
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ ASSERT_EQ((int)gaugeMetrics.data_size(), 2); // 2 sets of data for each pull.
+
+ // Data 1
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ("subsystem_name_1",
+ data.dimensions_in_what().value_tuple().dimensions_value(0).value_str());
+ ASSERT_EQ(1, data.bucket_info_size());
+
+ // Data 1, Bucket 1
+ ASSERT_EQ(13, data.bucket_info(0).atom_size());
+ ValidateGaugeBucketTimes(
+ data.bucket_info(0), configAddedTimeNs, configAddedTimeNs + bucketSizeNs,
+ {(int64_t)60 * NS_PER_SEC, (int64_t)80 * NS_PER_SEC, (int64_t)90 * NS_PER_SEC,
+ (int64_t)130 * NS_PER_SEC, (int64_t)150 * NS_PER_SEC, (int64_t)170 * NS_PER_SEC,
+ (int64_t)190 * NS_PER_SEC, (int64_t)200 * NS_PER_SEC, (int64_t)240 * NS_PER_SEC,
+ (int64_t)250 * NS_PER_SEC, (int64_t)300 * NS_PER_SEC, (int64_t)330 * NS_PER_SEC,
+ (int64_t)340 * NS_PER_SEC});
+
+ // Data 2
+ data = gaugeMetrics.data(1);
+ EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ("subsystem_name_2",
+ data.dimensions_in_what().value_tuple().dimensions_value(0).value_str());
+ ASSERT_EQ(1, data.bucket_info_size());
+
+ // Data 2, Bucket 1
+ ASSERT_EQ(13, data.bucket_info(0).atom_size());
+ ValidateGaugeBucketTimes(
+ data.bucket_info(0), configAddedTimeNs, configAddedTimeNs + bucketSizeNs,
+ {(int64_t)60 * NS_PER_SEC, (int64_t)80 * NS_PER_SEC, (int64_t)90 * NS_PER_SEC,
+ (int64_t)130 * NS_PER_SEC, (int64_t)150 * NS_PER_SEC, (int64_t)170 * NS_PER_SEC,
+ (int64_t)190 * NS_PER_SEC, (int64_t)200 * NS_PER_SEC, (int64_t)240 * NS_PER_SEC,
+ (int64_t)250 * NS_PER_SEC, (int64_t)300 * NS_PER_SEC, (int64_t)330 * NS_PER_SEC,
+ (int64_t)340 * NS_PER_SEC});
+}
+
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index b852d7f..1f35564 100644
--- a/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -195,6 +195,7 @@
backfillAggregatedAtoms(&reports);
ASSERT_EQ(1, reports.reports_size());
ASSERT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_estimated_data_bytes());
StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(),
&gaugeMetrics);
diff --git a/statsd/tests/e2e/KllMetric_e2e_test.cpp b/statsd/tests/e2e/KllMetric_e2e_test.cpp
index a4f7cc4..7cb5807 100644
--- a/statsd/tests/e2e/KllMetric_e2e_test.cpp
+++ b/statsd/tests/e2e/KllMetric_e2e_test.cpp
@@ -91,6 +91,7 @@
ConfigMetricsReport report = reports.reports(0);
ASSERT_EQ(report.metrics_size(), 1);
StatsLogReport metricReport = report.metrics(0);
+ EXPECT_TRUE(metricReport.has_estimated_data_bytes());
EXPECT_EQ(metricReport.metric_id(), metric.id());
EXPECT_TRUE(metricReport.has_kll_metrics());
ASSERT_EQ(metricReport.kll_metrics().data_size(), 1);
diff --git a/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index ab0e8ea..323ed17 100644
--- a/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -274,6 +274,7 @@
ASSERT_EQ(1, reports.reports_size());
ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::ValueMetricDataWrapper valueMetrics;
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_estimated_data_bytes());
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
ASSERT_GT((int)valueMetrics.data_size(), 1);
@@ -830,6 +831,76 @@
ASSERT_EQ(0, processor->mMetricsManagers.size());
}
+TEST(ValueMetricE2eTest, TestInitWithMultipleAggTypes) {
+ // Create config.
+ StatsdConfig config;
+
+ AtomMatcher testAtomReportedMatcher =
+ CreateSimpleAtomMatcher("TestAtomReportedMatcher", util::TEST_ATOM_REPORTED);
+ *config.add_atom_matcher() = testAtomReportedMatcher;
+
+ // Create value metric.
+ int64_t metricId = 123456;
+ ValueMetric* valueMetric = config.add_value_metric();
+ valueMetric->set_id(metricId);
+ valueMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+ valueMetric->set_what(testAtomReportedMatcher.id());
+ *valueMetric->mutable_value_field() = CreateDimensions(
+ util::TEST_ATOM_REPORTED, {2 /*int_field*/, 2 /*int_field*/, 3 /*long_field*/,
+ 3 /*long_field*/, 3 /*long_field*/});
+ valueMetric->add_aggregation_types(ValueMetric::SUM);
+ valueMetric->add_aggregation_types(ValueMetric::MIN);
+ valueMetric->add_aggregation_types(ValueMetric::MAX);
+ valueMetric->add_aggregation_types(ValueMetric::AVG);
+ valueMetric->add_aggregation_types(ValueMetric::MIN);
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+ ASSERT_EQ(1, processor->mMetricsManagers.size());
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ ASSERT_EQ(1, metricsManager->mAllMetricProducers.size());
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+}
+
+TEST(ValueMetricE2eTest, TestInitWithDefaultAggType) {
+ // Create config.
+ StatsdConfig config;
+
+ AtomMatcher testAtomReportedMatcher =
+ CreateSimpleAtomMatcher("TestAtomReportedMatcher", util::TEST_ATOM_REPORTED);
+ *config.add_atom_matcher() = testAtomReportedMatcher;
+
+ // Create value metric.
+ int64_t metricId = 123456;
+ ValueMetric* valueMetric = config.add_value_metric();
+ valueMetric->set_id(metricId);
+ valueMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+ valueMetric->set_what(testAtomReportedMatcher.id());
+ *valueMetric->mutable_value_field() =
+ CreateDimensions(util::TEST_ATOM_REPORTED, {3 /*long_field*/, 2 /*int_field*/});
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+ ASSERT_EQ(1, processor->mMetricsManagers.size());
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ ASSERT_EQ(1, metricsManager->mAllMetricProducers.size());
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+}
+
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/statsd/tests/guardrail/StatsdStats_test.cpp b/statsd/tests/guardrail/StatsdStats_test.cpp
index 1d56caa..9232f5b 100644
--- a/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -88,6 +88,20 @@
EXPECT_FALSE(configReport.has_deletion_time_sec());
}
+TEST(StatsdStatsTest, TestConfigMetadataProviderPromotionFailed) {
+ StatsdStats stats;
+ ConfigKey key(0, 12345);
+ stats.noteConfigReceived(key, /*metricsCount=*/0, /*conditionsCount=*/0, /*matchersCount=*/0,
+ /*alertCount=*/0, /*annotations=*/{}, nullopt /*valid config*/);
+
+ stats.noteConfigMetadataProviderPromotionFailed(key);
+
+ StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
+ ASSERT_EQ(1, report.config_stats_size());
+ const auto& configReport = report.config_stats(0);
+ EXPECT_EQ(1, configReport.config_metadata_provider_promotion_failed());
+}
+
TEST(StatsdStatsTest, TestInvalidConfigAdd) {
StatsdStats stats;
ConfigKey key(0, 12345);
@@ -1100,6 +1114,47 @@
}
}
+TEST(StatsdStatsTest, TestSocketBatchReadStats) {
+ StatsdStats stats;
+ stats.noteBatchSocketRead(1); // bin 1
+ stats.noteBatchSocketRead(2); // bin 2
+ stats.noteBatchSocketRead(2); // bin 2
+ stats.noteBatchSocketRead(4); // bin 4
+ stats.noteBatchSocketRead(5); // bin 5
+ stats.noteBatchSocketRead(9); // bin 5
+ stats.noteBatchSocketRead(9); // bin 5
+ stats.noteBatchSocketRead(10); // bin 6
+ stats.noteBatchSocketRead(19); // bin 6
+ stats.noteBatchSocketRead(30); // bin 8
+ stats.noteBatchSocketRead(32); // bin 8
+ stats.noteBatchSocketRead(39); // bin 8
+ stats.noteBatchSocketRead(90); // bin 14
+ stats.noteBatchSocketRead(99); // bin 14
+ stats.noteBatchSocketRead(100); // bin 15
+ stats.noteBatchSocketRead(100); // bin 15
+ stats.noteBatchSocketRead(199); // bin 15
+ stats.noteBatchSocketRead(200); // bin 16
+ stats.noteBatchSocketRead(299); // bin 16
+ stats.noteBatchSocketRead(999); // bin 23
+ stats.noteBatchSocketRead(1000); // bin 24
+ stats.noteBatchSocketRead(1199); // bin 24
+ stats.noteBatchSocketRead(1200); // bin 25
+ stats.noteBatchSocketRead(1800); // bin 28
+ stats.noteBatchSocketRead(1999); // bin 28
+ stats.noteBatchSocketRead(2000); // bin 29
+ stats.noteBatchSocketRead(1200000); // bin 29
+
+ StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
+ EXPECT_THAT(report.socket_read_stats().batched_read_size(),
+ ElementsAre(0, 1, 2, 0, 1, 3, 2, 0, 3, 0, 0, 0, 0, 0, 2, 3, 2, 0, 0, 0, 0, 0, 0, 1,
+ 2, 1, 0, 0, 2, 2));
+
+ stats.reset();
+ report = getStatsdStatsReport(stats, /* reset stats */ false);
+ EXPECT_THAT(report.socket_read_stats().batched_read_size(),
+ AllOf(SizeIs(StatsdStats::kNumBinsInSocketBatchReadHistogram), Each(0)));
+}
+
TEST_P(StatsdStatsTest_GetAtomDimensionKeySizeLimit_InMap, TestGetAtomDimensionKeySizeLimits) {
const auto& [atomId, defaultHardLimit] = GetParam();
EXPECT_EQ(StatsdStats::getAtomDimensionKeySizeLimits(atomId, defaultHardLimit),
diff --git a/statsd/tests/log_event/LogEventQueue_test.cpp b/statsd/tests/log_event/LogEventQueue_test.cpp
index acc9c5d..fe6a27a 100644
--- a/statsd/tests/log_event/LogEventQueue_test.cpp
+++ b/statsd/tests/log_event/LogEventQueue_test.cpp
@@ -118,9 +118,9 @@
TEST(LogEventQueue_test, TestQueueMaxSize) {
StatsdStats::getInstance().reset();
- std::shared_ptr<LogEventQueue> queue(std::make_shared<LogEventQueue>(50));
- std::shared_ptr<LogEventFilter> filter(std::make_shared<LogEventFilter>());
- filter->setFilteringEnabled(false);
+ LogEventQueue queue(50);
+ LogEventFilter filter;
+ filter.setFilteringEnabled(false);
int64_t eventTimeNs = 100;
int64_t oldestEventNs = 0;
@@ -129,7 +129,7 @@
auto statsEvent = makeStatsEvent(eventTimeNs);
size_t bufferSize;
const uint8_t* buffer = AStatsEvent_getBuffer(statsEvent, &bufferSize);
- StatsSocketListener::processMessage(buffer, bufferSize, 0, 0, queue, filter);
+ StatsSocketListener::processStatsEventBuffer(buffer, bufferSize, 0, 0, queue, filter);
AStatsEvent_release(statsEvent);
EXPECT_EQ(StatsdStats::getInstance().mEventQueueMaxSizeObserved, i + 1);
EXPECT_EQ(StatsdStats::getInstance().mEventQueueMaxSizeObservedElapsedNanos, eventTimeNs);
@@ -142,7 +142,7 @@
// consumer reads the entire queue
int64_t nextEventTs = 100;
for (int i = 0; i < 30; i++, nextEventTs++) {
- auto event = queue->waitPop();
+ auto event = queue.waitPop();
EXPECT_TRUE(event != nullptr);
// All events are in right order.
EXPECT_EQ(nextEventTs, event->GetElapsedTimestampNs());
@@ -154,7 +154,7 @@
auto statsEvent = makeStatsEvent(eventTimeNs);
size_t bufferSize;
const uint8_t* buffer = AStatsEvent_getBuffer(statsEvent, &bufferSize);
- StatsSocketListener::processMessage(buffer, bufferSize, 0, 0, queue, filter);
+ StatsSocketListener::processStatsEventBuffer(buffer, bufferSize, 0, 0, queue, filter);
AStatsEvent_release(statsEvent);
EXPECT_EQ(StatsdStats::getInstance().mEventQueueMaxSizeObserved, lastMaxSizeObserved);
EXPECT_EQ(StatsdStats::getInstance().mEventQueueMaxSizeObservedElapsedNanos,
@@ -163,7 +163,7 @@
}
for (int i = 0; i < 1; i++, nextEventTs++) {
- auto event = queue->waitPop();
+ auto event = queue.waitPop();
EXPECT_TRUE(event != nullptr);
// All events are in right order.
EXPECT_EQ(nextEventTs, event->GetElapsedTimestampNs());
@@ -176,7 +176,7 @@
auto statsEvent = makeStatsEvent(eventTimeNs);
size_t bufferSize;
const uint8_t* buffer = AStatsEvent_getBuffer(statsEvent, &bufferSize);
- StatsSocketListener::processMessage(buffer, bufferSize, 0, 0, queue, filter);
+ StatsSocketListener::processStatsEventBuffer(buffer, bufferSize, 0, 0, queue, filter);
AStatsEvent_release(statsEvent);
EXPECT_EQ(StatsdStats::getInstance().mEventQueueMaxSizeObserved, lastMaxSizeObserved);
EXPECT_EQ(StatsdStats::getInstance().mEventQueueMaxSizeObservedElapsedNanos,
@@ -188,7 +188,7 @@
auto statsEvent = makeStatsEvent(eventTimeNs);
size_t bufferSize;
const uint8_t* buffer = AStatsEvent_getBuffer(statsEvent, &bufferSize);
- StatsSocketListener::processMessage(buffer, bufferSize, 0, 0, queue, filter);
+ StatsSocketListener::processStatsEventBuffer(buffer, bufferSize, 0, 0, queue, filter);
AStatsEvent_release(statsEvent);
EXPECT_EQ(StatsdStats::getInstance().mEventQueueMaxSizeObserved,
lastMaxSizeObserved + i + 1);
diff --git a/statsd/tests/metrics/CountMetricProducer_test.cpp b/statsd/tests/metrics/CountMetricProducer_test.cpp
index 32c48b0..8db5bce 100644
--- a/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -75,8 +75,10 @@
metric.set_bucket(ONE_MINUTE);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, protoHash, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2);
+ wizard, protoHash, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2,
+ provider);
EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, countProducer.mCurrentBucketNum);
EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs());
@@ -94,9 +96,10 @@
metric.set_bucket(ONE_MINUTE);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, protoHash, bucketStartTimeNs, bucketStartTimeNs);
+ wizard, protoHash, bucketStartTimeNs, bucketStartTimeNs,
+ provider);
// 2 events in bucket 1.
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -158,8 +161,9 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
CountMetricProducer countProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard,
- protoHash, bucketStartTimeNs, bucketStartTimeNs);
+ protoHash, bucketStartTimeNs, bucketStartTimeNs, provider);
assertConditionTimer(countProducer.mConditionTimer, false, 0, 0);
countProducer.onConditionChanged(true, bucketStartTimeNs);
@@ -229,9 +233,10 @@
EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
CountMetricProducer countProducer(kConfigKey, metric, 0 /*condition tracker index*/,
{ConditionState::kUnknown}, wizard, protoHash,
- bucketStartTimeNs, bucketStartTimeNs);
+ bucketStartTimeNs, bucketStartTimeNs, provider);
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
@@ -268,9 +273,9 @@
alert.set_trigger_if_sum_gt(2);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, {}, wizard,
- protoHash, bucketStartTimeNs, bucketStartTimeNs);
+ protoHash, bucketStartTimeNs, bucketStartTimeNs, provider);
sp<AnomalyTracker> anomalyTracker =
countProducer.addAnomalyTracker(alert, alarmMonitor, UPDATE_NEW, bucketStartTimeNs);
@@ -337,9 +342,9 @@
metric.set_split_bucket_for_app_upgrade(true);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, {}, wizard,
- protoHash, bucketStartTimeNs, bucketStartTimeNs);
+ protoHash, bucketStartTimeNs, bucketStartTimeNs, provider);
// Bucket is flushed yet.
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -399,8 +404,9 @@
alert.set_trigger_if_sum_gt(2);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, {}, wizard,
- protoHash, bucketStartTimeNs, bucketStartTimeNs);
+ protoHash, bucketStartTimeNs, bucketStartTimeNs, provider);
sp<AnomalyTracker> anomalyTracker =
countProducer.addAnomalyTracker(alert, alarmMonitor, UPDATE_NEW, bucketStartTimeNs);
@@ -467,9 +473,10 @@
metric.set_bucket(ONE_MINUTE);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, protoHash, bucketStartTimeNs, bucketStartTimeNs);
+ wizard, protoHash, bucketStartTimeNs, bucketStartTimeNs,
+ provider);
sp<AnomalyTracker> anomalyTracker =
countProducer.addAnomalyTracker(alert, alarmMonitor, UPDATE_NEW, bucketStartTimeNs);
@@ -531,8 +538,9 @@
int64_t oneDayNs = 24 * 60 * 60 * 1e9;
int64_t fiveWeeksNs = 5 * 7 * oneDayNs;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
CountMetricProducer countProducer(kConfigKey, metric, -1 /* meaning no condition */, {}, wizard,
- protoHash, oneDayNs, fiveWeeksNs);
+ protoHash, oneDayNs, fiveWeeksNs, provider);
int64_t fiveWeeksOneDayNs = fiveWeeksNs + oneDayNs;
diff --git a/statsd/tests/metrics/DurationMetricProducer_test.cpp b/statsd/tests/metrics/DurationMetricProducer_test.cpp
index 3b24d85..5cf0221 100644
--- a/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -71,11 +71,12 @@
metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
FieldMatcher dimensions;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /*no condition*/, {}, -1 /*what index not needed*/,
1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
- wizard, protoHash, dimensions, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2);
+ wizard, protoHash, dimensions, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2, provider);
EXPECT_EQ(600500000000, durationProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, durationProducer.mCurrentBucketNum);
@@ -99,11 +100,12 @@
makeLogEvent(&event2, bucketStartTimeNs + bucketSizeNs + 2, tagId);
FieldMatcher dimensions;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /*no condition*/, {}, -1 /*what index not needed*/,
1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
- wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs, provider);
durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
@@ -142,12 +144,13 @@
makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId);
FieldMatcher dimensions;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
DurationMetricProducer durationProducer(
kConfigKey, metric, 0 /* condition index */, {ConditionState::kUnknown},
-1 /*what index not needed*/, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ bucketStartTimeNs, bucketStartTimeNs, provider);
durationProducer.mCondition = ConditionState::kFalse;
assertConditionTimer(durationProducer.mConditionTimer, false, 0, 0);
@@ -200,12 +203,13 @@
makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId);
FieldMatcher dimensions;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
DurationMetricProducer durationProducer(
kConfigKey, metric, 0 /* condition index */, {ConditionState::kUnknown},
-1 /*what index not needed*/, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ bucketStartTimeNs, bucketStartTimeNs, provider);
EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
EXPECT_FALSE(durationProducer.isConditionSliced());
@@ -248,11 +252,12 @@
metric.set_split_bucket_for_app_upgrade(true);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
- wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs, provider);
int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -312,11 +317,12 @@
metric.set_split_bucket_for_app_upgrade(true);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
- wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs, provider);
int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -377,11 +383,12 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
- wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs, provider);
sp<AnomalyTracker> anomalyTracker =
durationProducer.addAnomalyTracker(alert, alarmMonitor, UPDATE_NEW, bucketStartTimeNs);
@@ -425,11 +432,12 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
- wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs, provider);
int64_t startTimeNs = bucketStartTimeNs + 1;
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -480,11 +488,12 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
- wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs, provider);
int64_t startTimeNs = bucketStartTimeNs + 1;
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -542,11 +551,12 @@
metric.set_split_bucket_for_app_upgrade(false);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
- wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs, provider);
int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -585,6 +595,7 @@
metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeLogEvent(&event1, bucketStartTimeNs + 50, tagId);
@@ -599,7 +610,7 @@
kConfigKey, metric, 0 /* condition index */, {ConditionState::kUnknown},
-1 /*what index not needed*/, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ bucketStartTimeNs, bucketStartTimeNs, provider);
durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + 5);
durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
diff --git a/statsd/tests/metrics/EventMetricProducer_test.cpp b/statsd/tests/metrics/EventMetricProducer_test.cpp
index d5fe932..a789f3b 100644
--- a/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -53,6 +53,7 @@
parseStatsEventToLogEvent(statsEvent, logEvent);
}
+
} // anonymous namespace
class EventMetricProducerTest : public ::testing::Test {
@@ -80,9 +81,10 @@
CreateNoValuesLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 2);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, protoHash, bucketStartTimeNs);
+ wizard, protoHash, bucketStartTimeNs, provider);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
@@ -117,10 +119,11 @@
CreateNoValuesLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 10);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EventMetricProducer eventProducer(kConfigKey, metric, 0 /*condition index*/,
{ConditionState::kUnknown}, wizard, protoHash,
- bucketStartTimeNs);
+ bucketStartTimeNs, provider);
eventProducer.onConditionChanged(true /*condition*/, bucketStartTimeNs);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
@@ -174,10 +177,11 @@
EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
// Condition is true for second event.
EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EventMetricProducer eventProducer(kConfigKey, metric, 0 /*condition index*/,
{ConditionState::kUnknown}, wizard, protoHash,
- bucketStartTimeNs);
+ bucketStartTimeNs, provider);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
@@ -213,8 +217,9 @@
makeLogEvent(&event4, tagId, bucketStartTimeNs + 40, "222");
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, protoHash, bucketStartTimeNs);
+ wizard, protoHash, bucketStartTimeNs, provider);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
@@ -265,8 +270,9 @@
makeLogEvent(&event4, tagId, bucketStartTimeNs + 40, "111", &bytesField2);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, protoHash, bucketStartTimeNs);
+ wizard, protoHash, bucketStartTimeNs, provider);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
@@ -314,8 +320,9 @@
makeLogEvent(&event3, tagId2, bucketStartTimeNs + 40, "222");
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, protoHash, bucketStartTimeNs);
+ wizard, protoHash, bucketStartTimeNs, provider);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
@@ -343,6 +350,107 @@
}
}
}
+
+TEST_F(EventMetricProducerTest, TestCorruptedDataReasonSocketLoss_OnDumpReport) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int tagId = 1;
+
+ EventMetric metric;
+ metric.set_id(1);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, tagId, bucketStartTimeNs + 10, "111");
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+ EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, protoHash, bucketStartTimeNs, provider);
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
+
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToSocketLoss);
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToQueueOverflow);
+
+ eventProducer.onMatchedLogEventLost(tagId, DATA_CORRUPTED_SOCKET_LOSS);
+
+ EXPECT_TRUE(eventProducer.mDataCorruptedDueToSocketLoss);
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToQueueOverflow);
+
+ // Check dump report content.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ eventProducer.onDumpReport(bucketStartTimeNs + 50, true /*include current partial bucket*/,
+ true /*erase data*/, FAST, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_event_metrics());
+ ASSERT_EQ(1, report.event_metrics().data_size());
+ ASSERT_EQ(1, report.data_corrupted_reason_size());
+ ASSERT_EQ(DATA_CORRUPTED_SOCKET_LOSS, report.data_corrupted_reason()[0]);
+
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToSocketLoss);
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToQueueOverflow);
+}
+
+TEST_F(EventMetricProducerTest, TestCorruptedDataReasonSocketLoss_OnDropData) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int tagId = 1;
+
+ EventMetric metric;
+ metric.set_id(1);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, tagId, bucketStartTimeNs + 10, "111");
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+ EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, protoHash, bucketStartTimeNs, provider);
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
+
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToSocketLoss);
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToQueueOverflow);
+
+ eventProducer.onMatchedLogEventLost(tagId, DATA_CORRUPTED_SOCKET_LOSS);
+
+ EXPECT_TRUE(eventProducer.mDataCorruptedDueToSocketLoss);
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToQueueOverflow);
+
+ eventProducer.dropData(bucketStartTimeNs + 100);
+
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToSocketLoss);
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToQueueOverflow);
+}
+
+TEST_F(EventMetricProducerTest, TestCorruptedDataReasonSocketLoss_OnClearPastBuckets) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int tagId = 1;
+
+ EventMetric metric;
+ metric.set_id(1);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, tagId, bucketStartTimeNs + 10, "111");
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+ EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, protoHash, bucketStartTimeNs, provider);
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
+
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToSocketLoss);
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToQueueOverflow);
+
+ eventProducer.onMatchedLogEventLost(tagId, DATA_CORRUPTED_SOCKET_LOSS);
+
+ EXPECT_TRUE(eventProducer.mDataCorruptedDueToSocketLoss);
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToQueueOverflow);
+
+ eventProducer.clearPastBuckets(bucketStartTimeNs + 100);
+
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToSocketLoss);
+ EXPECT_FALSE(eventProducer.mDataCorruptedDueToQueueOverflow);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index aa8af8f..ff3d8d1 100644
--- a/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -98,13 +98,14 @@
createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
// statsd started long ago.
// The metric starts in the middle of the bucket
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-1, -1, tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2,
- pullerManager);
+ pullerManager, provider);
gaugeProducer.prepareFirstBucket();
EXPECT_EQ(600500000000, gaugeProducer.mCurrentBucketStartTimeNs);
@@ -140,10 +141,12 @@
return true;
}));
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ pullerManager, provider);
gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -228,10 +231,12 @@
sp<EventMatcherWizard> eventMatcherWizard =
createEventMatcherWizard(tagId, logEventMatcherIndex);
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
- bucketStartTimeNs, pullerManager);
+ bucketStartTimeNs, pullerManager, provider);
gaugeProducer.prepareFirstBucket();
sp<AnomalyTracker> anomalyTracker =
@@ -310,6 +315,8 @@
sp<EventMatcherWizard> eventMatcherWizard =
createEventMatcherWizard(tagId, logEventMatcherIndex);
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
@@ -326,7 +333,7 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ pullerManager, provider);
gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -392,10 +399,12 @@
EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
.WillOnce(Return(false));
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ pullerManager, provider);
gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -446,10 +455,12 @@
return true;
}));
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, 0 /*condition index*/,
- {ConditionState::kUnknown}, wizard, protoHash,
- logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+
+ GaugeMetricProducer gaugeProducer(
+ kConfigKey, metric, 0 /*condition index*/, {ConditionState::kUnknown}, wizard,
+ protoHash, logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager, provider);
gaugeProducer.prepareFirstBucket();
gaugeProducer.onConditionChanged(true, conditionChangeNs);
@@ -534,10 +545,12 @@
return true;
}));
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, 0 /*condition index*/,
- {ConditionState::kUnknown}, wizard, protoHash,
- logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+
+ GaugeMetricProducer gaugeProducer(
+ kConfigKey, metric, 0 /*condition index*/, {ConditionState::kUnknown}, wizard,
+ protoHash, logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager, provider);
gaugeProducer.prepareFirstBucket();
gaugeProducer.onSlicedConditionMayChange(true, sliceConditionChangeNs);
@@ -579,10 +592,12 @@
sp<EventMatcherWizard> eventMatcherWizard =
createEventMatcherWizard(tagId, logEventMatcherIndex);
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ pullerManager, provider);
gaugeProducer.prepareFirstBucket();
Alert alert;
@@ -679,10 +694,12 @@
.WillOnce(Return(true));
int triggerId = 5;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ pullerManager, provider);
gaugeProducer.prepareFirstBucket();
ASSERT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
@@ -737,10 +754,12 @@
return true;
}));
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
tagId, /*triggerId=*/-1, tagId, bucketStartTimeNs,
- bucketStartTimeNs, pullerManager);
+ bucketStartTimeNs, pullerManager, provider);
EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
gaugeProducer.prepareFirstBucket();
@@ -808,10 +827,12 @@
.WillOnce(Return(true));
int triggerId = 5;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ pullerManager, provider);
gaugeProducer.prepareFirstBucket();
LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
@@ -878,10 +899,12 @@
}));
int triggerId = 5;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ pullerManager, provider);
gaugeProducer.prepareFirstBucket();
LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
@@ -950,11 +973,11 @@
data->push_back(makeUidLogEvent(tagId, bucketStartTimeNs + 20, 1003, 18, 10));
return true;
}));
-
- GaugeMetricProducer gaugeProducer(kConfigKey, sampledGaugeMetric,
- -1 /*-1 meaning no condition*/, {}, wizard, protoHash,
- logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
- tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+ GaugeMetricProducer gaugeProducer(
+ kConfigKey, sampledGaugeMetric, -1 /*-1 meaning no condition*/, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, tagId, triggerId, tagId, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager, provider);
SamplingInfo samplingInfo;
samplingInfo.shardCount = shardCount;
translateFieldMatcher(sampledGaugeMetric.dimensional_sampling_info().sampled_what_field(),
diff --git a/statsd/tests/metrics/KllMetricProducer_test.cpp b/statsd/tests/metrics/KllMetricProducer_test.cpp
index 0e2d4c2..58d8a73 100644
--- a/statsd/tests/metrics/KllMetricProducer_test.cpp
+++ b/statsd/tests/metrics/KllMetricProducer_test.cpp
@@ -137,6 +137,7 @@
initialConditionCache.push_back(initialCondition.value());
}
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
return new KllMetricProducer(
kConfigKey, metric, protoHash, {/*pullAtomId=*/-1, /*pullerManager=*/nullptr},
{timeBaseNs, startTimeNs, bucketSizeNs, metric.min_bucket_size_nanos(),
@@ -147,7 +148,7 @@
{conditionIndex, metric.links(), initialConditionCache, wizard},
{metric.state_link(), slicedStateAtoms, stateGroupMap},
{/*eventActivationMap=*/{}, /*eventDeactivationMap=*/{}},
- {dimensionSoftLimit, dimensionHardLimit});
+ {dimensionSoftLimit, dimensionHardLimit}, provider);
}
static KllMetric createMetric() {
diff --git a/statsd/tests/metrics/NumericValueMetricProducer_test.cpp b/statsd/tests/metrics/NumericValueMetricProducer_test.cpp
index 2381f04..972dc85 100644
--- a/statsd/tests/metrics/NumericValueMetricProducer_test.cpp
+++ b/statsd/tests/metrics/NumericValueMetricProducer_test.cpp
@@ -215,17 +215,27 @@
? optional<int64_t>(metric.condition_correction_threshold_nanos())
: nullopt;
+ std::vector<ValueMetric::AggregationType> aggregationTypes;
+ if (metric.aggregation_types_size() != 0) {
+ for (int i = 0; i < metric.aggregation_types_size(); i++) {
+ aggregationTypes.push_back(metric.aggregation_types(i));
+ }
+ } else { // aggregation_type() is set or default is used.
+ aggregationTypes.push_back(metric.aggregation_type());
+ }
+
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
sp<NumericValueMetricProducer> valueProducer = new NumericValueMetricProducer(
kConfigKey, metric, protoHash, {pullAtomId, pullerManager},
{timeBaseNs, startTimeNs, bucketSizeNs, metric.min_bucket_size_nanos(),
conditionCorrectionThresholdNs, metric.split_bucket_for_app_upgrade()},
{containsAnyPositionInDimensionsInWhat, shouldUseNestedDimensions,
logEventMatcherIndex, eventMatcherWizard, metric.dimensions_in_what(),
- fieldMatchers},
+ fieldMatchers, aggregationTypes},
{conditionIndex, metric.links(), initialConditionCache, wizard},
{metric.state_link(), slicedStateAtoms, stateGroupMap},
{/*eventActivationMap=*/{}, /*eventDeactivationMap=*/{}},
- {dimensionSoftLimit, dimensionHardLimit});
+ {dimensionSoftLimit, dimensionHardLimit}, provider);
valueProducer->prepareFirstBucket();
if (conditionAfterFirstBucketPrepared) {
@@ -7734,6 +7744,266 @@
0); // Diff of 15 and 18
}
+TEST(NumericValueMetricProducerTest, TestMultipleAggTypesPulled) {
+ ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
+ // createMetricWithCondition() adds field 2 as first value field.
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.mutable_value_field()->add_child()->set_field(1);
+ metric.add_aggregation_types(ValueMetric::MIN);
+ metric.add_aggregation_types(ValueMetric::MAX);
+ metric.add_aggregation_types(ValueMetric::SUM);
+ metric.add_aggregation_types(ValueMetric::AVG);
+ metric.add_aggregation_types(ValueMetric::SUM);
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ // Screen On Pull 1.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(
+ CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 30 * NS_PER_SEC, 1, 2));
+ data->push_back(
+ CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 30 * NS_PER_SEC, 2, 4));
+ return true;
+ }))
+ // Screen Off Pull 2.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(
+ CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC, 3, 5));
+ data->push_back(
+ CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC, 4, 9));
+ return true;
+ }))
+ // Screen On Pull 3.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(
+ CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 5, 10));
+ data->push_back(
+ CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 6, 20));
+ return true;
+ }))
+ // Dump report pull.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 55 * NS_PER_SEC,
+ 25, 60));
+ data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 55 * NS_PER_SEC,
+ 35, 80));
+
+ return true;
+ }));
+
+ sp<NumericValueMetricProducer> valueProducer =
+ NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
+ pullerManager, metric, ConditionState::kFalse);
+
+ EXPECT_EQ(5, valueProducer->mFieldMatchers.size());
+ ASSERT_EQ(5, valueProducer->mAggregationTypes.size());
+ EXPECT_EQ(ValueMetric::MIN, valueProducer->mAggregationTypes[0]);
+ EXPECT_EQ(ValueMetric::MAX, valueProducer->mAggregationTypes[1]);
+ EXPECT_EQ(ValueMetric::SUM, valueProducer->mAggregationTypes[2]);
+ EXPECT_EQ(ValueMetric::AVG, valueProducer->mAggregationTypes[3]);
+ EXPECT_EQ(ValueMetric::SUM, valueProducer->mAggregationTypes[4]);
+
+ // Screen On. Pull 1.
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 30 * NS_PER_SEC);
+
+ // Screen Off.
+ valueProducer->onConditionChanged(false, bucketStartTimeNs + 40 * NS_PER_SEC);
+
+ // Screen On. Pull 2.
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 50 * NS_PER_SEC);
+
+ // Bucket 2 start. Pull 4.
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs, 15, 30));
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs, 20, 40));
+ valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
+
+ // Check dump report.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ int64_t dumpReportTimeNs = bucket2StartTimeNs + 55 * NS_PER_SEC;
+ valueProducer->onDumpReport(dumpReportTimeNs, true /* include current buckets */, true,
+ NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ backfillDimensionPath(&report);
+ backfillStartEndTimestamp(&report);
+ EXPECT_TRUE(report.has_value_metrics());
+ StatsLogReport::ValueMetricDataWrapper valueMetrics;
+ sortMetricDataByDimensionsValue(report.value_metrics(), &valueMetrics);
+ ASSERT_EQ(1, valueMetrics.data_size());
+ EXPECT_EQ(0, report.value_metrics().skipped_size());
+
+ // Bucket 1.
+ // Value field 1
+ // Diff from pulls 1 and 2: (3+4)-(1+2) = 4
+ // Diff from pulls 3 and 4: (15+20)-(5+6) = 24
+
+ // Value field 2
+ // Diff from pulls 1 and 2: (5+9)-(2+4) = 8
+ // Diff from pulls 3 and 4: (30+40)-(10+20) = 40
+
+ // Bucket 2
+ // Value field 1
+ // Diff from pulls 4 and 5: (25+35)-(15+20) = 25
+
+ // Value field 2
+ // Diff from pulls 4 and 5: (60+80)-(30+40) = 70
+
+ // Output values are calculated for these agg type - value field combinations
+ // MIN-2, MAX-2, SUM-2, AVG-2, SUM-1
+ ValueMetricData data = valueMetrics.data(0);
+ ASSERT_EQ(2, data.bucket_info_size());
+ ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs,
+ {8, 40, 48, 24, 28}, 20 * NS_PER_SEC, 0);
+ ValidateValueBucket(data.bucket_info(1), bucket2StartTimeNs, dumpReportTimeNs,
+ {70, 70, 70, 70, 25}, 55 * NS_PER_SEC, 0);
+}
+
+TEST(NumericValueMetricProducerTest, TestMultipleAggTypesPushed) {
+ ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
+ metric.mutable_dimensions_in_what()->set_field(tagId);
+ metric.mutable_dimensions_in_what()->add_child()->set_field(1);
+ // createMetric() adds field 2 as first value field.
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.mutable_value_field()->add_child()->set_field(3);
+ metric.add_aggregation_types(ValueMetric::MIN);
+ metric.add_aggregation_types(ValueMetric::MAX);
+ metric.add_aggregation_types(ValueMetric::SUM);
+ metric.add_aggregation_types(ValueMetric::AVG);
+ metric.add_aggregation_types(ValueMetric::SUM);
+
+ sp<EventMatcherWizard> eventMatcherWizard =
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ sp<NumericValueMetricProducer> valueProducer =
+ NumericValueMetricProducerTestHelper::createValueProducerNoConditions(
+ pullerManager, metric, /*pullAtomId=*/-1);
+
+ EXPECT_EQ(5, valueProducer->mFieldMatchers.size());
+ ASSERT_EQ(5, valueProducer->mAggregationTypes.size());
+ EXPECT_EQ(ValueMetric::MIN, valueProducer->mAggregationTypes[0]);
+ EXPECT_EQ(ValueMetric::MAX, valueProducer->mAggregationTypes[1]);
+ EXPECT_EQ(ValueMetric::SUM, valueProducer->mAggregationTypes[2]);
+ EXPECT_EQ(ValueMetric::AVG, valueProducer->mAggregationTypes[3]);
+ EXPECT_EQ(ValueMetric::SUM, valueProducer->mAggregationTypes[4]);
+
+ // Bucket 1 events.
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 5, 10);
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 6, 8);
+
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event3, tagId, bucketStartTimeNs + 40, 2, 3, 10);
+
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event4, tagId, bucketStartTimeNs + 50, 2, 4, 6);
+
+ LogEvent event5(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event5, tagId, bucketStartTimeNs + 30, 1, 19, 9);
+
+ LogEvent event6(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event6, tagId, bucketStartTimeNs + 60, 2, 20, 8);
+
+ // Bucket 2 events.
+ LogEvent event7(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event7, tagId, bucket2StartTimeNs + 10, 2, 7, 41);
+
+ LogEvent event8(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event8, tagId, bucket2StartTimeNs + 20, 1, 21, 40);
+
+ LogEvent event9(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event9, tagId, bucket2StartTimeNs + 30, 1, 10, 4);
+
+ LogEvent event10(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event10, tagId, bucket2StartTimeNs + 40, 2, 3, 50);
+
+ LogEvent event11(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event11, tagId, bucket2StartTimeNs + 50, 1, 20, 7);
+
+ LogEvent event12(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event12, tagId, bucket2StartTimeNs + 60, 2, 20, 2);
+
+ valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event1);
+ valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event2);
+ valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event3);
+ valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event4);
+ valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event5);
+ valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event6);
+ valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event7);
+ valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event8);
+ valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event9);
+ valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event10);
+ valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event11);
+ valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event12);
+
+ // Check dump report.
+ ProtoOutputStream output;
+ valueProducer->onDumpReport(bucket3StartTimeNs + 10000, false /* include recent buckets */,
+ true, FAST /* dumpLatency */, nullptr, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ backfillDimensionPath(&report);
+ backfillStartEndTimestamp(&report);
+ EXPECT_TRUE(report.has_value_metrics());
+ StatsLogReport::ValueMetricDataWrapper valueMetrics;
+ sortMetricDataByDimensionsValue(report.value_metrics(), &valueMetrics);
+ ASSERT_EQ(2, valueMetrics.data_size());
+ EXPECT_EQ(0, report.value_metrics().skipped_size());
+
+ // Bucket 1.
+ // Value field 2
+ // dim 1 pushed values: 5, 6, 19
+ // dim 2 pushed values: 3, 4, 20
+
+ // Value field 3
+ // dim 1 pushed values: 10, 8, 9
+ // dim 2 pushed values: 10, 6, 8
+
+ // Bucket 2
+ // Value field 2
+ // dim 1 pushed values: 21, 10, 20
+ // dim 2 pushed values: 7, 3, 20
+
+ // Value field 3
+ // dim 1 pushed values: 40, 4, 7
+ // dim 2 pushed values: 41, 50, 2
+
+ // Output values are calculated for these agg type - value field combinations
+ // MIN-2, MAX-2, SUM-2, AVG-2, SUM-1
+ ValueMetricData data = valueMetrics.data(0);
+ ASSERT_EQ(2, data.bucket_info_size());
+ ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs,
+ {5, 19, 30, 10, 27}, 0, 0);
+ ValidateValueBucket(data.bucket_info(1), bucket2StartTimeNs, bucket3StartTimeNs,
+ {10, 21, 51, 17, 51}, 0, 0);
+
+ data = valueMetrics.data(1);
+ ASSERT_EQ(2, data.bucket_info_size());
+ ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs,
+ {3, 20, 27, 9, 24}, 0, 0);
+ ValidateValueBucket(data.bucket_info(1), bucket2StartTimeNs, bucket3StartTimeNs,
+ {3, 20, 30, 10, 93}, 0, 0);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/statsd/tests/metrics/RestrictedEventMetricProducer_test.cpp b/statsd/tests/metrics/RestrictedEventMetricProducer_test.cpp
index 44b812f..2085e11 100644
--- a/statsd/tests/metrics/RestrictedEventMetricProducer_test.cpp
+++ b/statsd/tests/metrics/RestrictedEventMetricProducer_test.cpp
@@ -54,11 +54,12 @@
TEST_F(RestrictedEventMetricProducerTest, TestOnMatchedLogEventMultipleEvents) {
EventMetric metric;
metric.set_id(metricId1);
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
RestrictedEventMetricProducer producer(configKey, metric,
/*conditionIndex=*/-1,
/*initialConditionCache=*/{}, new ConditionWizard(),
/*protoHash=*/0x1234567890,
- /*startTimeNs=*/0);
+ /*startTimeNs=*/0, provider);
std::unique_ptr<LogEvent> event1 = CreateRestrictedLogEvent(/*atomTag=*/123, /*timestampNs=*/1);
std::unique_ptr<LogEvent> event2 = CreateRestrictedLogEvent(/*atomTag=*/123, /*timestampNs=*/3);
@@ -87,11 +88,12 @@
TEST_F(RestrictedEventMetricProducerTest, TestOnMatchedLogEventMultipleFields) {
EventMetric metric;
metric.set_id(metricId2);
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
RestrictedEventMetricProducer producer(configKey, metric,
/*conditionIndex=*/-1,
/*initialConditionCache=*/{}, new ConditionWizard(),
/*protoHash=*/0x1234567890,
- /*startTimeNs=*/0);
+ /*startTimeNs=*/0, provider);
AStatsEvent* statsEvent = AStatsEvent_obtain();
AStatsEvent_setAtomId(statsEvent, 1);
AStatsEvent_addInt32Annotation(statsEvent, ASTATSLOG_ANNOTATION_ID_RESTRICTION_CATEGORY,
@@ -129,12 +131,13 @@
EventMetric metric;
metric.set_id(metricId1);
metric.set_condition(StringToId("SCREEN_ON"));
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
RestrictedEventMetricProducer producer(configKey, metric,
/*conditionIndex=*/0,
/*initialConditionCache=*/{ConditionState::kUnknown},
new ConditionWizard(),
/*protoHash=*/0x1234567890,
- /*startTimeNs=*/0);
+ /*startTimeNs=*/0, provider);
std::unique_ptr<LogEvent> event1 = CreateRestrictedLogEvent(/*atomTag=*/123, /*timestampNs=*/1);
std::unique_ptr<LogEvent> event2 = CreateRestrictedLogEvent(/*atomTag=*/123, /*timestampNs=*/3);
@@ -162,11 +165,12 @@
TEST_F(RestrictedEventMetricProducerTest, TestOnDumpReportNoOp) {
EventMetric metric;
metric.set_id(metricId1);
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
RestrictedEventMetricProducer producer(configKey, metric,
/*conditionIndex=*/-1,
/*initialConditionCache=*/{}, new ConditionWizard(),
/*protoHash=*/0x1234567890,
- /*startTimeNs=*/0);
+ /*startTimeNs=*/0, provider);
std::unique_ptr<LogEvent> event1 = CreateRestrictedLogEvent(/*timestampNs=*/1);
producer.onMatchedLogEvent(/*matcherIndex=*/1, *event1);
ProtoOutputStream output;
@@ -182,11 +186,12 @@
TEST_F(RestrictedEventMetricProducerTest, TestOnMetricRemove) {
EventMetric metric;
metric.set_id(metricId1);
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
RestrictedEventMetricProducer producer(configKey, metric,
/*conditionIndex=*/-1,
/*initialConditionCache=*/{}, new ConditionWizard(),
/*protoHash=*/0x1234567890,
- /*startTimeNs=*/0);
+ /*startTimeNs=*/0, provider);
EXPECT_FALSE(metricTableExist(metricId1));
std::unique_ptr<LogEvent> event1 = CreateRestrictedLogEvent(/*timestampNs=*/1);
@@ -201,11 +206,12 @@
TEST_F(RestrictedEventMetricProducerTest, TestRestrictedEventMetricTtlDeletesFirstEvent) {
EventMetric metric;
metric.set_id(metricId1);
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
RestrictedEventMetricProducer producer(configKey, metric,
/*conditionIndex=*/-1,
/*initialConditionCache=*/{}, new ConditionWizard(),
/*protoHash=*/0x1234567890,
- /*startTimeNs=*/0);
+ /*startTimeNs=*/0, provider);
int64_t currentTimeNs = getWallClockNs();
int64_t eightDaysAgo = currentTimeNs - 8 * 24 * 3600 * NS_PER_SEC;
@@ -243,11 +249,12 @@
metricMetadata.set_restricted_category(1); // CATEGORY_DIAGNOSTIC
EventMetric metric;
metric.set_id(metricId1);
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
RestrictedEventMetricProducer producer(configKey, metric,
/*conditionIndex=*/-1,
/*initialConditionCache=*/{}, new ConditionWizard(),
/*protoHash=*/0x1234567890,
- /*startTimeNs=*/0);
+ /*startTimeNs=*/0, provider);
producer.loadMetricMetadataFromProto(metricMetadata);
diff --git a/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp b/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
index b32d5d3..0861812 100644
--- a/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
+++ b/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
@@ -64,6 +64,7 @@
/*minDiffToUpdateRegisteredAlarmTimeSec=*/0,
[](const shared_ptr<IStatsCompanionService>&, int64_t) {},
[](const shared_ptr<IStatsCompanionService>&) {});
+sp<ConfigMetadataProvider> configMetadataProvider;
unordered_map<int, vector<int>> allTagIdsToMatchersMap;
vector<sp<AtomMatchingTracker>> oldAtomMatchingTrackers;
unordered_map<int64_t, int> oldAtomMatchingTrackerMap;
@@ -87,10 +88,11 @@
// initStatsdConfig returns nullopt if config is valid
return !initStatsdConfig(
key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseNs, timeBaseNs, allTagIdsToMatchersMap, oldAtomMatchingTrackers,
- oldAtomMatchingTrackerMap, oldConditionTrackers, oldConditionTrackerMap,
- oldMetricProducers, oldMetricProducerMap, oldAnomalyTrackers, oldAlarmTrackers,
- tmpConditionToMetricMap, tmpTrackerToMetricMap, tmpTrackerToConditionMap,
+ timeBaseNs, timeBaseNs, configMetadataProvider, allTagIdsToMatchersMap,
+ oldAtomMatchingTrackers, oldAtomMatchingTrackerMap, oldConditionTrackers,
+ oldConditionTrackerMap, oldMetricProducers, oldMetricProducerMap,
+ oldAnomalyTrackers, oldAlarmTrackers, tmpConditionToMetricMap,
+ tmpTrackerToMetricMap, tmpTrackerToConditionMap,
tmpActivationAtomTrackerToMetricMap, tmpDeactivationAtomTrackerToMetricMap,
oldAlertTrackerMap, metricsWithActivation, oldStateHashes, noReportMetricIds)
.has_value();
@@ -1974,16 +1976,17 @@
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, replacedConditions, newConditionTrackers,
conditionCache, /*stateAtomIdMap=*/{}, /*allStateGroupMaps=*/{},
/*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers,
- newMetricProducerMap, newMetricProducers, conditionToMetricMap,
- trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, metricsWithActivation,
- replacedMetrics),
+ provider, newMetricProducerMap, newMetricProducers,
+ conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation, replacedMetrics),
nullopt);
unordered_map<int64_t, int> expectedMetricProducerMap = {
@@ -2207,14 +2210,15 @@
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, /*replacedConditions=*/{}, newConditionTrackers,
conditionCache, stateAtomIdMap, allStateGroupMaps, replacedStates,
- oldMetricProducerMap, oldMetricProducers, newMetricProducerMap,
- newMetricProducers, conditionToMetricMap, trackerToMetricMap,
- noReportMetricIds, activationAtomTrackerToMetricMap,
+ oldMetricProducerMap, oldMetricProducers, provider,
+ newMetricProducerMap, newMetricProducers, conditionToMetricMap,
+ trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
replacedMetrics),
nullopt);
@@ -2420,16 +2424,17 @@
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, /*replacedConditions=*/{}, newConditionTrackers,
conditionCache, /*stateAtomIdMap=*/{}, /*allStateGroupMaps=*/{},
/*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers,
- newMetricProducerMap, newMetricProducers, conditionToMetricMap,
- trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, metricsWithActivation,
- replacedMetrics),
+ provider, newMetricProducerMap, newMetricProducers,
+ conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation, replacedMetrics),
nullopt);
unordered_map<int64_t, int> expectedMetricProducerMap = {
@@ -2743,12 +2748,13 @@
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, /*replacedMatchers=*/{},
newAtomMatchingTrackers, newConditionTrackerMap, replacedConditions,
newConditionTrackers, conditionCache, stateAtomIdMap, allStateGroupMaps,
- replacedStates, oldMetricProducerMap, oldMetricProducers,
+ replacedStates, oldMetricProducerMap, oldMetricProducers, provider,
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
@@ -3011,12 +3017,13 @@
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, /*replacedMatchers=*/{},
newAtomMatchingTrackers, newConditionTrackerMap, replacedConditions,
newConditionTrackers, conditionCache, stateAtomIdMap, allStateGroupMaps,
- replacedStates, oldMetricProducerMap, oldMetricProducers,
+ replacedStates, oldMetricProducerMap, oldMetricProducers, provider,
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
@@ -3228,13 +3235,14 @@
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(
key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, /*replacedMatchers=*/{}, newAtomMatchingTrackers,
newConditionTrackerMap, replacedConditions, newConditionTrackers,
conditionCache, /*stateAtomIdMap=*/{}, /*allStateGroupMaps=*/{},
- /*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers,
+ /*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers, provider,
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation, replacedMetrics),
@@ -3401,16 +3409,17 @@
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, config, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, replacedConditions, newConditionTrackers,
conditionCache, /*stateAtomIdMap=*/{}, /*allStateGroupMaps=*/{},
/*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers,
- newMetricProducerMap, newMetricProducers, conditionToMetricMap,
- trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, metricsWithActivation,
- replacedMetrics),
+ provider, newMetricProducerMap, newMetricProducers,
+ conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation, replacedMetrics),
nullopt);
// Verify event activation/deactivation maps.
@@ -3563,16 +3572,17 @@
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, /*replacedConditions=*/{}, newConditionTrackers,
conditionCache, /*stateAtomIdMap*/ {}, /*allStateGroupMaps=*/{},
/*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers,
- newMetricProducerMap, newMetricProducers, conditionToMetricMap,
- trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, metricsWithActivation,
- replacedMetrics),
+ provider, newMetricProducerMap, newMetricProducers,
+ conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation, replacedMetrics),
nullopt);
unordered_map<int64_t, int> expectedMetricProducerMap = {
@@ -3794,13 +3804,14 @@
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
int64_t currentTimeNs = 12345;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(
key, config, /*timeBaseNs=*/123, currentTimeNs, new StatsPullerManager(),
oldAtomMatchingTrackerMap, oldAtomMatchingTrackerMap, /*replacedMatchers*/ {},
oldAtomMatchingTrackers, oldConditionTrackerMap, /*replacedConditions=*/{},
oldConditionTrackers, {ConditionState::kUnknown}, /*stateAtomIdMap*/ {},
/*allStateGroupMaps=*/{},
- /*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers,
+ /*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers, provider,
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation, replacedMetrics),
@@ -3983,14 +3994,15 @@
set<int64_t> replacedMatchers;
set<int64_t> replacedConditions;
set<int64_t> replacedStates;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, config, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, replacedConditions, newConditionTrackers,
conditionCache, stateAtomIdMap, allStateGroupMaps, replacedStates,
- oldMetricProducerMap, oldMetricProducers, newMetricProducerMap,
- newMetricProducers, conditionToMetricMap, trackerToMetricMap,
- noReportMetricIds, activationAtomTrackerToMetricMap,
+ oldMetricProducerMap, oldMetricProducers, provider,
+ newMetricProducerMap, newMetricProducers, conditionToMetricMap,
+ trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
replacedMetrics),
InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_HAS_MULTIPLE_ACTIVATIONS, metricId));
@@ -4020,14 +4032,15 @@
set<int64_t> replacedMatchers;
set<int64_t> replacedConditions;
set<int64_t> replacedStates;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, config, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, replacedConditions, newConditionTrackers,
conditionCache, stateAtomIdMap, allStateGroupMaps, replacedStates,
- oldMetricProducerMap, oldMetricProducers, newMetricProducerMap,
- newMetricProducers, conditionToMetricMap, trackerToMetricMap,
- noReportMetricIds, activationAtomTrackerToMetricMap,
+ oldMetricProducerMap, oldMetricProducers, provider,
+ newMetricProducerMap, newMetricProducers, conditionToMetricMap,
+ trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
replacedMetrics),
InvalidConfigReason(INVALID_CONFIG_REASON_NO_REPORT_METRIC_NOT_FOUND, metricId));
@@ -4064,6 +4077,7 @@
set<int64_t> replacedMatchers;
set<int64_t> replacedConditions;
set<int64_t> replacedStates;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
newAtomMatchingTrackerMap[StringToId("ScreenTurnedOn")] = 0;
stateAtomIdMap[StringToId("ScreenState")] = util::SCREEN_STATE_CHANGED;
@@ -4074,7 +4088,7 @@
replacedMatchers, newAtomMatchingTrackers, newConditionTrackerMap,
replacedConditions, newConditionTrackers, conditionCache, stateAtomIdMap,
allStateGroupMaps, replacedStates, oldMetricProducerMap, oldMetricProducers,
- newMetricProducerMap, newMetricProducers, conditionToMetricMap,
+ provider, newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation, replacedMetrics),
InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_SLICED_STATE_ATOM_ALLOWED_FROM_ANY_UID,
@@ -4145,15 +4159,16 @@
set<int64_t> replacedMatchers;
set<int64_t> replacedConditions;
set<int64_t> replacedStates;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, config, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, replacedConditions, newConditionTrackers,
conditionCache, stateAtomIdMap, allStateGroupMaps, replacedStates,
- oldMetricProducerMap, oldMetricProducers, newMetricProducerMap,
- newMetricProducers, conditionToMetricMap, trackerToMetricMap,
- noReportMetricIds, activationAtomTrackerToMetricMap,
+ oldMetricProducerMap, oldMetricProducers, provider,
+ newMetricProducerMap, newMetricProducers, conditionToMetricMap,
+ trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
replacedMetrics),
InvalidConfigReason(INVALID_CONFIG_REASON_RESTRICTED_METRIC_NOT_SUPPORTED));
@@ -4196,13 +4211,14 @@
vector<int> metricsWithActivation;
vector<sp<MetricProducer>> newMetricProducers;
set<int64_t> replacedMetrics;
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(
key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
oldAtomMatchingTrackerMap, /*replacedMatchers=*/{}, oldAtomMatchingTrackers,
oldConditionTrackerMap, /*replacedConditions=*/{}, oldConditionTrackers,
/*conditionCache=*/{}, /*stateAtomIdMap=*/{}, /*allStateGroupMaps=*/{},
- /*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers,
+ /*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers, provider,
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation, replacedMetrics),
diff --git a/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp b/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
index da678b4..1a64c20 100644
--- a/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
+++ b/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
@@ -60,6 +60,7 @@
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> periodicAlarmMonitor;
+sp<ConfigMetadataProvider> configMetadataProvider;
unordered_map<int, vector<int>> allTagIdsToMatchersMap;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
unordered_map<int64_t, int> atomMatchingTrackerMap;
@@ -83,12 +84,12 @@
// initStatsdConfig returns nullopt if config is valid
return initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIdsToMatchersMap, allAtomMatchingTrackers,
- atomMatchingTrackerMap, allConditionTrackers, conditionTrackerMap, allMetricProducers,
- metricProducerMap, allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
- stateProtoHashes, noReportMetricIds);
+ timeBaseSec, timeBaseSec, configMetadataProvider, allTagIdsToMatchersMap,
+ allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
+ conditionTrackerMap, allMetricProducers, metricProducerMap, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
+ metricsWithActivation, stateProtoHashes, noReportMetricIds);
}
StatsdConfig buildCircleMatchers() {
@@ -707,6 +708,79 @@
StringToId("Gauge")));
}
+TEST_F(MetricsManagerUtilTest, TestGaugeMetricInvalidPullProbability) {
+ StatsdConfig config;
+ GaugeMetric* metric = config.add_gauge_metric();
+ *metric = createGaugeMetric(/*name=*/"Gauge", /*what=*/StringToId("SubsystemSleep"),
+ GaugeMetric::FIRST_N_SAMPLES,
+ /*condition=*/nullopt, /*triggerEvent=*/nullopt);
+ metric->set_pull_probability(101);
+ *config.add_atom_matcher() =
+ CreateSimpleAtomMatcher("SubsystemSleep", util::SUBSYSTEM_SLEEP_STATE);
+
+ EXPECT_EQ(initConfig(config),
+ InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_INCORRECT_PULL_PROBABILITY,
+ StringToId("Gauge")));
+}
+
+TEST_F(MetricsManagerUtilTest, TestGaugeMetricInvalidPullProbabilityZero) {
+ StatsdConfig config;
+ GaugeMetric* metric = config.add_gauge_metric();
+ *metric = createGaugeMetric(/*name=*/"Gauge", /*what=*/StringToId("SubsystemSleep"),
+ GaugeMetric::FIRST_N_SAMPLES,
+ /*condition=*/nullopt, /*triggerEvent=*/nullopt);
+ metric->set_pull_probability(0);
+ *config.add_atom_matcher() =
+ CreateSimpleAtomMatcher("SubsystemSleep", util::SUBSYSTEM_SLEEP_STATE);
+
+ EXPECT_EQ(initConfig(config),
+ InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_INCORRECT_PULL_PROBABILITY,
+ StringToId("Gauge")));
+}
+
+TEST_F(MetricsManagerUtilTest, TestGaugeMetricValidPullProbability) {
+ StatsdConfig config;
+ GaugeMetric* metric = config.add_gauge_metric();
+ *metric = createGaugeMetric(/*name=*/"Gauge", /*what=*/StringToId("SubsystemSleep"),
+ GaugeMetric::FIRST_N_SAMPLES,
+ /*condition=*/nullopt, /*triggerEvent=*/nullopt);
+ metric->set_pull_probability(50);
+ *config.add_atom_matcher() =
+ CreateSimpleAtomMatcher("SubsystemSleep", util::SUBSYSTEM_SLEEP_STATE);
+
+ EXPECT_EQ(initConfig(config), nullopt);
+}
+
+TEST_F(MetricsManagerUtilTest, TestPushedGaugeMetricWithPullProbability) {
+ StatsdConfig config;
+ GaugeMetric* metric = config.add_gauge_metric();
+ *metric = createGaugeMetric(/*name=*/"Gauge", /*what=*/StringToId("ScreenTurnedOn"),
+ GaugeMetric::FIRST_N_SAMPLES,
+ /*condition=*/nullopt, /*triggerEvent=*/nullopt);
+ metric->set_pull_probability(50);
+ *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+
+ EXPECT_EQ(initConfig(config),
+ InvalidConfigReason(INVALID_CONFIG_REASON_GAUGE_METRIC_PUSHED_WITH_PULL_PROBABILITY,
+ StringToId("Gauge")));
+}
+
+TEST_F(MetricsManagerUtilTest, TestGaugeMetricRandomOneSampleWithPullProbability) {
+ StatsdConfig config;
+ GaugeMetric* metric = config.add_gauge_metric();
+ *metric = createGaugeMetric(/*name=*/"Gauge", /*what=*/StringToId("SubsystemSleep"),
+ GaugeMetric::RANDOM_ONE_SAMPLE,
+ /*condition=*/nullopt, /*triggerEvent=*/nullopt);
+ metric->set_pull_probability(50);
+ *config.add_atom_matcher() =
+ CreateSimpleAtomMatcher("SubsystemSleep", util::SUBSYSTEM_SLEEP_STATE);
+
+ EXPECT_EQ(initConfig(config),
+ InvalidConfigReason(
+ INVALID_CONFIG_REASON_GAUGE_METRIC_RANDOM_ONE_SAMPLE_WITH_PULL_PROBABILITY,
+ StringToId("Gauge")));
+}
+
TEST_F(MetricsManagerUtilTest, TestNumericValueMetricMissingIdOrWhat) {
StatsdConfig config;
int64_t metricId = 1;
@@ -732,6 +806,88 @@
StringToId("NumericValue")));
}
+TEST_F(MetricsManagerUtilTest, TestNumericValueMetricHasBothSingleAndMultipleAggTypes) {
+ StatsdConfig config;
+ *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+
+ ValueMetric* metric = config.add_value_metric();
+ *metric = createValueMetric(/*name=*/"NumericValue", /*what=*/CreateScreenTurnedOnAtomMatcher(),
+ /*valueField=*/2, /*condition=*/nullopt, /*states=*/{});
+ metric->set_aggregation_type(ValueMetric::SUM);
+ metric->add_aggregation_types(ValueMetric::SUM);
+ metric->add_aggregation_types(ValueMetric::MIN);
+
+ EXPECT_EQ(initConfig(config),
+ InvalidConfigReason(
+ INVALID_CONFIG_REASON_VALUE_METRIC_DEFINES_SINGLE_AND_MULTIPLE_AGG_TYPES,
+ StringToId("NumericValue")));
+}
+
+TEST_F(MetricsManagerUtilTest, TestNumericValueMetricMoreAggTypesThanValueFields) {
+ StatsdConfig config;
+ *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+
+ ValueMetric* metric = config.add_value_metric();
+ *metric = createValueMetric(/*name=*/"NumericValue", /*what=*/CreateScreenTurnedOnAtomMatcher(),
+ /*valueField=*/2, /*condition=*/nullopt, /*states=*/{});
+ metric->add_aggregation_types(ValueMetric::SUM);
+ metric->add_aggregation_types(ValueMetric::MIN);
+
+ EXPECT_EQ(
+ initConfig(config),
+ InvalidConfigReason(INVALID_CONFIG_REASON_VALUE_METRIC_AGG_TYPES_DNE_VALUE_FIELDS_SIZE,
+ StringToId("NumericValue")));
+}
+
+TEST_F(MetricsManagerUtilTest, TestNumericValueMetricMoreValueFieldsThanAggTypes) {
+ StatsdConfig config;
+ *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+
+ ValueMetric* metric = config.add_value_metric();
+ *metric = createValueMetric(/*name=*/"NumericValue", /*what=*/CreateScreenTurnedOnAtomMatcher(),
+ /*valueField=*/2, /*condition=*/nullopt, /*states=*/{});
+ // This only fails if the repeated aggregation field is used. If the single field is used,
+ // we will apply this aggregation type to all value fields.
+ metric->add_aggregation_types(ValueMetric::SUM);
+ metric->add_aggregation_types(ValueMetric::MIN);
+ *metric->mutable_value_field() = CreateDimensions(
+ util::SUBSYSTEM_SLEEP_STATE, {3 /* count */, 4 /* time_millis */, 3 /* count */});
+
+ EXPECT_EQ(
+ initConfig(config),
+ InvalidConfigReason(INVALID_CONFIG_REASON_VALUE_METRIC_AGG_TYPES_DNE_VALUE_FIELDS_SIZE,
+ StringToId("NumericValue")));
+}
+
+TEST_F(MetricsManagerUtilTest, TestNumericValueMetricDefaultAggTypeOutOfOrderFields) {
+ StatsdConfig config;
+ *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+
+ ValueMetric* metric = config.add_value_metric();
+ *metric = createValueMetric(/*name=*/"NumericValue", /*what=*/CreateScreenTurnedOnAtomMatcher(),
+ /*valueField=*/2, /*condition=*/nullopt, /*states=*/{});
+ *metric->mutable_value_field() =
+ CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time_millis */, 3 /* count */});
+
+ EXPECT_EQ(initConfig(config), nullopt);
+}
+
+TEST_F(MetricsManagerUtilTest, TestNumericValueMetricMultipleAggTypesOutOfOrderFields) {
+ StatsdConfig config;
+ *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+
+ ValueMetric* metric = config.add_value_metric();
+ *metric = createValueMetric(/*name=*/"NumericValue", /*what=*/CreateScreenTurnedOnAtomMatcher(),
+ /*valueField=*/2, /*condition=*/nullopt, /*states=*/{});
+ metric->add_aggregation_types(ValueMetric::SUM);
+ metric->add_aggregation_types(ValueMetric::MIN);
+ metric->add_aggregation_types(ValueMetric::SUM);
+ *metric->mutable_value_field() = CreateDimensions(
+ util::SUBSYSTEM_SLEEP_STATE, {3 /* count */, 4 /* time_millis */, 3 /* count */});
+
+ EXPECT_EQ(initConfig(config), nullopt);
+}
+
TEST_F(MetricsManagerUtilTest, TestKllMetricMissingIdOrWhat) {
StatsdConfig config;
int64_t metricId = 1;
@@ -1383,8 +1539,10 @@
metric.set_id(metricId);
metric.set_bucket(ONE_MINUTE);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<sp<MetricProducer>> metricProducers({new CountMetricProducer(
- kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, 0x0123456789, 0, 0)});
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+ vector<sp<MetricProducer>> metricProducers(
+ {new CountMetricProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard,
+ 0x0123456789, 0, 0, provider)});
sp<AlarmMonitor> anomalyAlarmMonitor;
optional<InvalidConfigReason> invalidConfigReason;
EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, UPDATE_NEW, /*updateTime=*/123,
@@ -1406,8 +1564,10 @@
metric.set_id(metricId);
metric.set_bucket(ONE_MINUTE);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<sp<MetricProducer>> metricProducers({new CountMetricProducer(
- kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, 0x0123456789, 0, 0)});
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+ vector<sp<MetricProducer>> metricProducers(
+ {new CountMetricProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard,
+ 0x0123456789, 0, 0, provider)});
sp<AlarmMonitor> anomalyAlarmMonitor;
optional<InvalidConfigReason> invalidConfigReason;
EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, UPDATE_NEW, /*updateTime=*/123,
@@ -1430,8 +1590,10 @@
metric.set_id(metricId);
metric.set_bucket(ONE_MINUTE);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<sp<MetricProducer>> metricProducers({new CountMetricProducer(
- kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, 0x0123456789, 0, 0)});
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
+ vector<sp<MetricProducer>> metricProducers(
+ {new CountMetricProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard,
+ 0x0123456789, 0, 0, provider)});
sp<AlarmMonitor> anomalyAlarmMonitor;
optional<InvalidConfigReason> invalidConfigReason;
EXPECT_NE(createAnomalyTracker(alert, anomalyAlarmMonitor, UPDATE_NEW, /*updateTime=*/123,
@@ -1455,10 +1617,11 @@
metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
FieldMatcher dimensions;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
vector<sp<MetricProducer>> metricProducers({new DurationMetricProducer(
kConfigKey, metric, -1 /*no condition*/, {}, -1 /* what index not needed*/,
1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
- wizard, 0x0123456789, dimensions, 0, 0)});
+ wizard, 0x0123456789, dimensions, 0, 0, provider)});
sp<AlarmMonitor> anomalyAlarmMonitor;
optional<InvalidConfigReason> invalidConfigReason;
EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, UPDATE_NEW, /*updateTime=*/123,
diff --git a/statsd/tests/statsd_test_util.cpp b/statsd/tests/statsd_test_util.cpp
index 8e80a20..539c890 100644
--- a/statsd/tests/statsd_test_util.cpp
+++ b/statsd/tests/statsd_test_util.cpp
@@ -2314,6 +2314,13 @@
return config;
}
+
+sp<MockConfigMetadataProvider> makeMockConfigMetadataProvider(bool enabled) {
+ sp<MockConfigMetadataProvider> metadataProvider = new StrictMock<MockConfigMetadataProvider>();
+ EXPECT_CALL(*metadataProvider, useV2SoftMemoryCalculation()).Times(AnyNumber());
+ EXPECT_CALL(*metadataProvider, useV2SoftMemoryCalculation()).WillRepeatedly(Return(enabled));
+ return nullptr;
+}
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/statsd/tests/statsd_test_util.h b/statsd/tests/statsd_test_util.h
index d2d10b2..8fe6440 100644
--- a/statsd/tests/statsd_test_util.h
+++ b/statsd/tests/statsd_test_util.h
@@ -837,6 +837,13 @@
StatsdConfig buildGoodConfig(int configId, int alertId);
+class MockConfigMetadataProvider : public ConfigMetadataProvider {
+public:
+ MOCK_METHOD(bool, useV2SoftMemoryCalculation, (), (override));
+};
+
+sp<MockConfigMetadataProvider> makeMockConfigMetadataProvider(bool enabled);
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/statsd/tools/localtools/src/com/android/statsd/shelltools/ExtensionAtomsRegistry.java b/statsd/tools/localtools/src/com/android/statsd/shelltools/ExtensionAtomsRegistry.java
index 0061cd4..489288e 100644
--- a/statsd/tools/localtools/src/com/android/statsd/shelltools/ExtensionAtomsRegistry.java
+++ b/statsd/tools/localtools/src/com/android/statsd/shelltools/ExtensionAtomsRegistry.java
@@ -22,6 +22,7 @@
import com.android.os.adservices.AdservicesExtensionAtoms;
import com.android.os.art.ArtExtensionAtoms;
import com.android.os.automotive.caruilib.AutomotiveCaruilibAtoms;
+import com.android.os.bluetooth.BluetoothExtensionAtoms;
import com.android.os.devicelogs.DeviceLogsAtoms;
import com.android.os.dnd.DndAtoms;
import com.android.os.dnd.DndExtensionAtoms;
@@ -61,6 +62,7 @@
import android.os.statsd.media.MediaCodecExtensionAtoms;
import com.android.os.credentials.CredentialsExtensionAtoms;
import com.android.os.sdksandbox.SdksandboxExtensionAtoms;
+import com.android.os.apex.ApexExtensionAtoms;
import com.google.protobuf.ExtensionRegistry;
@@ -96,6 +98,7 @@
ShellConfig.registerAllExtensions(extensionRegistry);
AdservicesExtensionAtoms.registerAllExtensions(extensionRegistry);
AutomotiveCaruilibAtoms.registerAllExtensions(extensionRegistry);
+ BluetoothExtensionAtoms.registerAllExtensions(extensionRegistry);
DeviceLogsAtoms.registerAllExtensions(extensionRegistry);
DndAtoms.registerAllExtensions(extensionRegistry);
DndExtensionAtoms.registerAllExtensions(extensionRegistry);
@@ -136,5 +139,6 @@
CredentialsExtensionAtoms.registerAllExtensions(extensionRegistry);
SdksandboxExtensionAtoms.registerAllExtensions(extensionRegistry);
ArtExtensionAtoms.registerAllExtensions(extensionRegistry);
+ ApexExtensionAtoms.registerAllExtensions(extensionRegistry);
}
}
diff --git a/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java b/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
index 448536e..05b7fb5 100644
--- a/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
+++ b/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
@@ -99,6 +99,9 @@
"com.google.android.healthconnect.controller",
"com.android.telephony.qns",
"com.android.car",
+ "com.android.ondevicepersonalization.services",
+ "com.google.android.ondevicepersonalization.services",
+ "AID_UPROBESTATS",
};
private static final String[] DEFAULT_PULL_SOURCES = {
"AID_KEYSTORE", "AID_RADIO", "AID_SYSTEM",
@@ -155,7 +158,8 @@
LOGGER.severe("-e");
LOGGER.severe("\tWait for Enter key press before collecting report");
LOGGER.severe("-d delay_ms");
- LOGGER.severe("\tWait for delay_ms before collecting report, default is 60000 ms");
+ LOGGER.severe("\tWait for delay_ms before collecting report, default is 60000 ms. Only");
+ LOGGER.severe("\taffects collection of pushed atoms.");
LOGGER.severe("-v");
LOGGER.severe("\tDebug logging level");
}
diff --git a/tests/Android.bp b/tests/Android.bp
index e67a76c..71784a9 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -42,6 +42,7 @@
static_libs: [
"core_cts_test_resources",
"perfetto_config-full",
+ "cts-statsd-atom-host-test-utils",
],
data: [
"**/*.pbtxt",
diff --git a/tests/src/android/cts/statsd/alarm/AlarmTests.java b/tests/src/android/cts/statsd/alarm/AlarmTests.java
index 032297e..0f49e9a 100644
--- a/tests/src/android/cts/statsd/alarm/AlarmTests.java
+++ b/tests/src/android/cts/statsd/alarm/AlarmTests.java
@@ -17,21 +17,29 @@
import static com.google.common.truth.Truth.assertThat;
-import android.cts.statsd.atom.AtomTestCase;
+import android.cts.statsd.metric.MetricsUtils;
+import android.cts.statsdatom.lib.AtomTestUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
-import com.android.internal.os.StatsdConfigProto;
import com.android.internal.os.StatsdConfigProto.Alarm;
import com.android.internal.os.StatsdConfigProto.IncidentdDetails;
import com.android.internal.os.StatsdConfigProto.StatsdConfig;
import com.android.internal.os.StatsdConfigProto.Subscription;
+import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.RunUtil;
-import java.util.List;
+import java.text.SimpleDateFormat;
+import java.util.Date;
/**
* Statsd Anomaly Detection tests.
*/
-public class AlarmTests extends AtomTestCase {
+public class AlarmTests extends DeviceTestCase implements IBuildReceiver {
private static final String TAG = "Statsd.AnomalyDetectionTests";
@@ -42,36 +50,61 @@
private static final int SUBSCRIPTION_ID_INCIDENTD = 41;
private static final int INCIDENTD_SECTION = -1;
+ private IBuildInfo mCtsBuild;
+
@Override
protected void setUp() throws Exception {
super.setUp();
+ assertThat(mCtsBuild).isNotNull();
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ DeviceUtils.installTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_APK,
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, mCtsBuild);
if (!INCIDENTD_TESTS_ENABLED) {
CLog.w(TAG, TAG + " alarm tests are disabled by a flag. Change flag to true to run");
}
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ DeviceUtils.uninstallTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
}
public void testAlarm() throws Exception {
StatsdConfig.Builder config = getBaseConfig();
- turnScreenOn();
- uploadConfig(config);
+ DeviceUtils.turnScreenOn(getDevice());
+ ConfigUtils.uploadConfig(getDevice(), config);
- String markTime = getCurrentLogcatDate();
- Thread.sleep(9_000);
+ String markTime = MetricsUtils.getCurrentLogcatDate(getDevice());
+ RunUtil.getDefault().sleep(9_000);
- if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isTrue();
+ if (INCIDENTD_TESTS_ENABLED) {
+ assertThat(MetricsUtils.didIncidentdFireSince(getDevice(), markTime)).isTrue();
+ }
}
private final StatsdConfig.Builder getBaseConfig() throws Exception {
- return createConfigBuilder()
- .addAlarm(Alarm.newBuilder().setId(ALARM_ID).setOffsetMillis(2).setPeriodMillis(
- 5_000) // every 5 seconds.
- )
- .addSubscription(Subscription.newBuilder()
- .setId(SUBSCRIPTION_ID_INCIDENTD)
- .setRuleType(Subscription.RuleType.ALARM)
- .setRuleId(ALARM_ID)
- .setIncidentdDetails(
- IncidentdDetails.newBuilder().addSection(INCIDENTD_SECTION)));
+ return ConfigUtils.createConfigBuilder(MetricsUtils.DEVICE_SIDE_TEST_PACKAGE)
+ .addAlarm(Alarm.newBuilder()
+ .setId(ALARM_ID)
+ .setOffsetMillis(2)
+ .setPeriodMillis(5_000) // every 5 seconds.
+ )
+ .addSubscription(Subscription.newBuilder()
+ .setId(SUBSCRIPTION_ID_INCIDENTD)
+ .setRuleType(Subscription.RuleType.ALARM)
+ .setRuleId(ALARM_ID)
+ .setIncidentdDetails(IncidentdDetails.newBuilder()
+ .addSection(INCIDENTD_SECTION)));
}
}
diff --git a/tests/src/android/cts/statsd/alert/AnomalyDetectionTests.java b/tests/src/android/cts/statsd/alert/AnomalyDetectionTests.java
index ea47cc3..74fe1b5 100644
--- a/tests/src/android/cts/statsd/alert/AnomalyDetectionTests.java
+++ b/tests/src/android/cts/statsd/alert/AnomalyDetectionTests.java
@@ -18,7 +18,11 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-import android.cts.statsd.atom.AtomTestCase;
+import android.cts.statsd.metric.MetricsUtils;
+import android.cts.statsdatom.lib.AtomTestUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
import com.android.internal.os.StatsdConfigProto;
import com.android.internal.os.StatsdConfigProto.Alert;
@@ -38,13 +42,30 @@
import com.android.os.AtomsProto.Atom;
import com.android.os.AtomsProto.DebugElapsedClock;
import com.android.os.StatsLog.EventMetricData;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.log.LogUtil;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
+import com.android.tradefed.util.RunUtil;
+
+import com.google.protobuf.ByteString;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.List;
+import java.util.Random;
+
+import perfetto.protos.PerfettoConfig.DataSourceConfig;
+import perfetto.protos.PerfettoConfig.FtraceConfig;
+import perfetto.protos.PerfettoConfig.TraceConfig;
/**
* Statsd Anomaly Detection tests.
*/
-public class AnomalyDetectionTests extends AtomTestCase {
+public class AnomalyDetectionTests extends DeviceTestCase implements IBuildReceiver {
private static final String TAG = "Statsd.AnomalyDetectionTests";
@@ -53,6 +74,8 @@
private static final int WAIT_AFTER_BREADCRUMB_MS = 2000;
+ private static final int SHELL_UID = 2000;
+
// Config constants
private static final int APP_BREADCRUMB_REPORTED_MATCH_START_ID = 1;
private static final int APP_BREADCRUMB_REPORTED_MATCH_STOP_ID = 2;
@@ -66,14 +89,22 @@
private boolean defaultSystemTracingConfigurationHasChanged = false;
+ private IBuildInfo mCtsBuild;
+
@Override
protected void setUp() throws Exception {
super.setUp();
+ assertThat(mCtsBuild).isNotNull();
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ DeviceUtils.installTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_APK,
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, mCtsBuild);
if (!INCIDENTD_TESTS_ENABLED) {
CLog.w(TAG, TAG + " anomaly tests are disabled by a flag. Change flag to true to run");
}
if (PERFETTO_TESTS_ENABLED) {
- // Default Android configuration can only change for device type that doesn't require SystemTracingEnabled
+ // Default Android configuration can only change for device type that doesn't require
+ // SystemTracingEnabled
// by default in CDD.
String chars = getDevice().getProperty("ro.build.characteristics");
if (!isSystemTracingEnabled() && chars.contains("automotive")) {
@@ -81,11 +112,20 @@
defaultSystemTracingConfigurationHasChanged = true;
}
}
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ DeviceUtils.uninstallTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
if (PERFETTO_TESTS_ENABLED) {
// Disable SystemTracing if previously enabled at test setUp()
if (defaultSystemTracingConfigurationHasChanged) {
@@ -95,11 +135,12 @@
final long deadLine = System.currentTimeMillis() + 10000;
while (isSystemTracingEnabled()) {
if (System.currentTimeMillis() > deadLine) {
- CLog.w("/sys/kernel/debug/tracing/tracing_on is still 1 after 10 secs : " + isSystemTracingEnabled());
+ CLog.w("/sys/kernel/debug/tracing/tracing_on is still 1 after 10 secs : "
+ + isSystemTracingEnabled());
break;
}
CLog.d("Waiting to finish collecting traces. ");
- Thread.sleep(WAIT_TIME_SHORT);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT);
}
}
}
@@ -120,34 +161,50 @@
)
)
);
- uploadConfig(config);
+ ConfigUtils.uploadConfig(getDevice(), config);
- String markTime = getCurrentLogcatDate();
+ String markTime = MetricsUtils.getCurrentLogcatDate(getDevice());
// count(label=6) -> 1 (not an anomaly, since not "greater than 2")
- doAppBreadcrumbReportedStart(6);
- Thread.sleep(500);
- assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty();
- if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isFalse();
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 6);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT);
+ assertWithMessage("Premature anomaly").that(
+ ReportUtils.getEventMetricDataList(getDevice())).isEmpty();
+ if (INCIDENTD_TESTS_ENABLED) {
+ assertThat(MetricsUtils.didIncidentdFireSince(getDevice(), markTime)).isFalse();
+ }
// count(label=6) -> 2 (not an anomaly, since not "greater than 2")
- doAppBreadcrumbReportedStart(6);
- Thread.sleep(500);
- assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty();
- if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isFalse();
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 6);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT);
+ assertWithMessage("Premature anomaly").that(
+ ReportUtils.getEventMetricDataList(getDevice())).isEmpty();
+ if (INCIDENTD_TESTS_ENABLED) {
+ assertThat(MetricsUtils.didIncidentdFireSince(getDevice(), markTime)).isFalse();
+ }
// count(label=12) -> 1 (not an anomaly, since not "greater than 2")
- doAppBreadcrumbReportedStart(12);
- Thread.sleep(1000);
- assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty();
- if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isFalse();
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 12);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
+ assertWithMessage("Premature anomaly").that(
+ ReportUtils.getEventMetricDataList(getDevice())).isEmpty();
+ if (INCIDENTD_TESTS_ENABLED) {
+ assertThat(MetricsUtils.didIncidentdFireSince(getDevice(), markTime)).isFalse();
+ }
- doAppBreadcrumbReportedStart(6); // count(label=6) -> 3 (anomaly, since "greater than 2"!)
- Thread.sleep(WAIT_AFTER_BREADCRUMB_MS);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(),
+ 6); // count(label=6) -> 3 (anomaly, since "greater than 2"!)
+ RunUtil.getDefault().sleep(WAIT_AFTER_BREADCRUMB_MS);
- List<EventMetricData> data = getEventMetricDataList();
+ List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
assertWithMessage("Expected anomaly").that(data).hasSize(1);
assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID);
- if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isTrue();
+ if (INCIDENTD_TESTS_ENABLED) {
+ assertThat(MetricsUtils.didIncidentdFireSince(getDevice(), markTime)).isTrue();
+ }
}
// Tests that anomaly detection for duration works.
@@ -169,49 +226,64 @@
.setStop(APP_BREADCRUMB_REPORTED_MATCH_STOP_ID)
)
);
- uploadConfig(config);
+ ConfigUtils.uploadConfig(getDevice(), config);
// Since timing is crucial and checking logcat for incidentd is slow, we don't test for it.
// Test that alarm doesn't fire early.
- String markTime = getCurrentLogcatDate();
- doAppBreadcrumbReportedStart(1);
- Thread.sleep(6_000); // Recorded duration at end: 6s
- assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty();
+ String markTime = MetricsUtils.getCurrentLogcatDate(getDevice());
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 1);
+ RunUtil.getDefault().sleep(6_000); // Recorded duration at end: 6s
+ assertWithMessage("Premature anomaly").that(
+ ReportUtils.getEventMetricDataList(getDevice())).isEmpty();
- doAppBreadcrumbReportedStop(1);
- Thread.sleep(4_000); // Recorded duration at end: 6s
- assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty();
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 1);
+ RunUtil.getDefault().sleep(4_000); // Recorded duration at end: 6s
+ assertWithMessage("Premature anomaly").that(
+ ReportUtils.getEventMetricDataList(getDevice())).isEmpty();
// Test that alarm does fire when it is supposed to (after 4s, plus up to 5s alarm delay).
- doAppBreadcrumbReportedStart(1);
- Thread.sleep(9_000); // Recorded duration at end: 13s
- doAppBreadcrumbReported(2);
- List<EventMetricData> data = getEventMetricDataList();
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 1);
+ RunUtil.getDefault().sleep(9_000); // Recorded duration at end: 13s
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 2);
+ List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
assertWithMessage("Expected anomaly").that(data).hasSize(1);
assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID);
// Now test that the refractory period is obeyed.
- markTime = getCurrentLogcatDate();
- doAppBreadcrumbReportedStop(1);
- doAppBreadcrumbReportedStart(1);
- Thread.sleep(3_000); // Recorded duration at end: 13s
+ markTime = MetricsUtils.getCurrentLogcatDate(getDevice());
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 1);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 1);
+ RunUtil.getDefault().sleep(3_000); // Recorded duration at end: 13s
// NB: the previous getEventMetricDataList also removes the report, so size is back to 0.
- assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty();
+ assertWithMessage("Premature anomaly").that(
+ ReportUtils.getEventMetricDataList(getDevice())).isEmpty();
// Test that detection works again after refractory period finishes.
- doAppBreadcrumbReportedStop(1);
- Thread.sleep(8_000); // Recorded duration at end: 9s
- doAppBreadcrumbReportedStart(1);
- Thread.sleep(15_000); // Recorded duration at end: 15s
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 1);
+ RunUtil.getDefault().sleep(8_000); // Recorded duration at end: 9s
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 1);
+ RunUtil.getDefault().sleep(15_000); // Recorded duration at end: 15s
// We can do an incidentd test now that all the timing issues are done.
- doAppBreadcrumbReported(2);
- data = getEventMetricDataList();
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 2);
+ data = ReportUtils.getEventMetricDataList(getDevice());
assertWithMessage("Expected anomaly").that(data).hasSize(1);
assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID);
- if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isTrue();
+ if (INCIDENTD_TESTS_ENABLED) {
+ assertThat(MetricsUtils.didIncidentdFireSince(getDevice(), markTime)).isTrue();
+ }
- doAppBreadcrumbReportedStop(1);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 1);
}
// Tests that anomaly detection for duration works even when the alarm fires too late.
@@ -233,24 +305,29 @@
.setStop(APP_BREADCRUMB_REPORTED_MATCH_STOP_ID)
)
);
- uploadConfig(config);
+ ConfigUtils.uploadConfig(getDevice(), config);
- doAppBreadcrumbReportedStart(1);
- Thread.sleep(5_000);
- doAppBreadcrumbReportedStop(1);
- Thread.sleep(2_000);
- assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty();
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 1);
+ RunUtil.getDefault().sleep(5_000);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 1);
+ RunUtil.getDefault().sleep(2_000);
+ assertWithMessage("Premature anomaly").that(
+ ReportUtils.getEventMetricDataList(getDevice())).isEmpty();
// Test that alarm does fire when it is supposed to.
// The anomaly occurs in 1s, but alarms won't fire that quickly.
// It is likely that the alarm will only fire after this period is already over, but the
// anomaly should nonetheless be detected when the event stops.
- doAppBreadcrumbReportedStart(1);
- Thread.sleep(1_200);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 1);
+ RunUtil.getDefault().sleep(1_200);
// Anomaly should be detected here if the alarm didn't fire yet.
- doAppBreadcrumbReportedStop(1);
- Thread.sleep(200);
- List<EventMetricData> data = getEventMetricDataList();
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 1);
+ RunUtil.getDefault().sleep(200);
+ List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
if (data.size() == 2) {
// Although we expect that the alarm won't fire, we certainly cannot demand that.
CLog.w(TAG, "The anomaly was detected twice. Presumably the alarm did manage to fire.");
@@ -274,28 +351,37 @@
)
);
- uploadConfig(config);
+ ConfigUtils.uploadConfig(getDevice(), config);
- String markTime = getCurrentLogcatDate();
- doAppBreadcrumbReportedStart(6); // value = 6, which is NOT > trigger
- Thread.sleep(WAIT_AFTER_BREADCRUMB_MS);
- assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty();
- if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isFalse();
+ String markTime = MetricsUtils.getCurrentLogcatDate(getDevice());
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(),
+ 6); // value = 6, which is NOT > trigger
+ RunUtil.getDefault().sleep(WAIT_AFTER_BREADCRUMB_MS);
+ assertWithMessage("Premature anomaly").that(
+ ReportUtils.getEventMetricDataList(getDevice())).isEmpty();
+ if (INCIDENTD_TESTS_ENABLED) {
+ assertThat(MetricsUtils.didIncidentdFireSince(getDevice(), markTime)).isFalse();
+ }
- doAppBreadcrumbReportedStart(14); // value = 14 > trigger
- Thread.sleep(WAIT_AFTER_BREADCRUMB_MS);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(),
+ 14); // value = 14 > trigger
+ RunUtil.getDefault().sleep(WAIT_AFTER_BREADCRUMB_MS);
- List<EventMetricData> data = getEventMetricDataList();
+ List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
assertWithMessage("Expected anomaly").that(data).hasSize(1);
assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID);
- if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isTrue();
+ if (INCIDENTD_TESTS_ENABLED) {
+ assertThat(MetricsUtils.didIncidentdFireSince(getDevice(), markTime)).isTrue();
+ }
}
// Test that anomaly detection integrates with perfetto properly.
public void testPerfetto() throws Exception {
String chars = getDevice().getProperty("ro.build.characteristics");
if (chars.contains("watch")) {
- return;
+ return;
}
if (PERFETTO_TESTS_ENABLED) resetPerfettoGuardrails();
@@ -320,32 +406,38 @@
)
);
- uploadConfig(config);
+ ConfigUtils.uploadConfig(getDevice(), config);
- String markTime = getCurrentLogcatDate();
- doAppBreadcrumbReportedStart(6); // value = 6, which is NOT > trigger
- Thread.sleep(WAIT_AFTER_BREADCRUMB_MS);
- assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty();
+ String markTime = MetricsUtils.getCurrentLogcatDate(getDevice());
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(),
+ 6); // value = 6, which is NOT > trigger
+ RunUtil.getDefault().sleep(WAIT_AFTER_BREADCRUMB_MS);
+ assertWithMessage("Premature anomaly").that(
+ ReportUtils.getEventMetricDataList(getDevice())).isEmpty();
if (PERFETTO_TESTS_ENABLED) assertThat(isSystemTracingEnabled()).isFalse();
- doAppBreadcrumbReportedStart(14); // value = 14 > trigger
- Thread.sleep(WAIT_AFTER_BREADCRUMB_MS);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(),
+ 14); // value = 14 > trigger
+ RunUtil.getDefault().sleep(WAIT_AFTER_BREADCRUMB_MS);
- List<EventMetricData> data = getEventMetricDataList();
+ List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
assertWithMessage("Expected anomaly").that(data).hasSize(1);
assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID);
- // Pool a few times to allow for statsd <-> traced <-> traced_probes communication to happen.
+ // Pool a few times to allow for statsd <-> traced <-> traced_probes communication to
+ // happen.
if (PERFETTO_TESTS_ENABLED) {
- boolean tracingEnabled = false;
- for (int i = 0; i < 5; i++) {
- if (isSystemTracingEnabled()) {
- tracingEnabled = true;
- break;
- }
- Thread.sleep(1000);
+ boolean tracingEnabled = false;
+ for (int i = 0; i < 5; i++) {
+ if (isSystemTracingEnabled()) {
+ tracingEnabled = true;
+ break;
}
- assertThat(tracingEnabled).isTrue();
+ RunUtil.getDefault().sleep(1000);
+ }
+ assertThat(tracingEnabled).isTrue();
}
}
@@ -365,22 +457,32 @@
)
)
);
- uploadConfig(config);
+ ConfigUtils.uploadConfig(getDevice(), config);
- String markTime = getCurrentLogcatDate();
- doAppBreadcrumbReportedStart(6); // gauge = 6, which is NOT > trigger
- Thread.sleep(Math.max(WAIT_AFTER_BREADCRUMB_MS, 1_100)); // Must be >1s to push next bucket.
- assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty();
- if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isFalse();
+ String markTime = MetricsUtils.getCurrentLogcatDate(getDevice());
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(),
+ 6); // gauge = 6, which is NOT > trigger
+ RunUtil.getDefault().sleep(
+ Math.max(WAIT_AFTER_BREADCRUMB_MS, 1_100)); // Must be >1s to push next bucket.
+ assertWithMessage("Premature anomaly").that(
+ ReportUtils.getEventMetricDataList(getDevice())).isEmpty();
+ if (INCIDENTD_TESTS_ENABLED) {
+ assertThat(MetricsUtils.didIncidentdFireSince(getDevice(), markTime)).isFalse();
+ }
// We waited for >1s above, so we are now in the next bucket (which is essential).
- doAppBreadcrumbReportedStart(14); // gauge = 14 > trigger
- Thread.sleep(WAIT_AFTER_BREADCRUMB_MS);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(),
+ 14); // gauge = 14 > trigger
+ RunUtil.getDefault().sleep(WAIT_AFTER_BREADCRUMB_MS);
- List<EventMetricData> data = getEventMetricDataList();
+ List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
assertWithMessage("Expected anomaly").that(data).hasSize(1);
assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID);
- if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isTrue();
+ if (INCIDENTD_TESTS_ENABLED) {
+ assertThat(MetricsUtils.didIncidentdFireSince(getDevice(), markTime)).isTrue();
+ }
}
// Test that anomaly detection for pulled metrics work.
@@ -410,73 +512,165 @@
)
)
);
- uploadConfig(config);
+ ConfigUtils.uploadConfig(getDevice(), config);
- Thread.sleep(6_000); // Wait long enough to ensure AlarmManager signals >= 1 pull
+ RunUtil.getDefault().sleep(
+ 6_000); // Wait long enough to ensure AlarmManager signals >= 1 pull
- List<EventMetricData> data = getEventMetricDataList();
+ List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
assertThat(data.size()).isEqualTo(1);
assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID);
}
private final StatsdConfig.Builder getBaseConfig(int numBuckets,
- int refractorySecs,
- long triggerIfSumGt) throws Exception {
- return createConfigBuilder()
- // Items of relevance for detecting the anomaly:
- .addAtomMatcher(
- StatsdConfigProto.AtomMatcher.newBuilder()
- .setId(APP_BREADCRUMB_REPORTED_MATCH_START_ID)
- .setSimpleAtomMatcher(
- StatsdConfigProto.SimpleAtomMatcher.newBuilder()
- .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
- // Event only when the uid is this app's uid.
- .addFieldValueMatcher(createFvm(AppBreadcrumbReported.UID_FIELD_NUMBER)
- .setEqInt(getHostUid()))
- .addFieldValueMatcher(
- createFvm(AppBreadcrumbReported.STATE_FIELD_NUMBER)
- .setEqInt(AppBreadcrumbReported.State.START.ordinal()))))
- .addAtomMatcher(
- StatsdConfigProto.AtomMatcher.newBuilder()
- .setId(APP_BREADCRUMB_REPORTED_MATCH_STOP_ID)
- .setSimpleAtomMatcher(
- StatsdConfigProto.SimpleAtomMatcher.newBuilder()
- .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
- // Event only when the uid is this app's uid.
- .addFieldValueMatcher(createFvm(AppBreadcrumbReported.UID_FIELD_NUMBER)
- .setEqInt(getHostUid()))
- .addFieldValueMatcher(
- createFvm(AppBreadcrumbReported.STATE_FIELD_NUMBER)
- .setEqInt(AppBreadcrumbReported.State.STOP.ordinal()))))
- .addAlert(Alert.newBuilder()
+ int refractorySecs,
+ long triggerIfSumGt) throws Exception {
+ return ConfigUtils.createConfigBuilder(MetricsUtils.DEVICE_SIDE_TEST_PACKAGE)
+ // Items of relevance for detecting the anomaly:
+ .addAtomMatcher(StatsdConfigProto.AtomMatcher.newBuilder()
+ .setId(APP_BREADCRUMB_REPORTED_MATCH_START_ID)
+ .setSimpleAtomMatcher(StatsdConfigProto.SimpleAtomMatcher.newBuilder()
+ .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER) // Event
+ // only when the uid is this app's uid.
+ .addFieldValueMatcher(ConfigUtils
+ .createFvm(AppBreadcrumbReported.UID_FIELD_NUMBER)
+ .setEqInt(SHELL_UID))
+ .addFieldValueMatcher(ConfigUtils
+ .createFvm(AppBreadcrumbReported.STATE_FIELD_NUMBER)
+ .setEqInt(AppBreadcrumbReported.State.START.getNumber()))))
+ .addAtomMatcher(StatsdConfigProto.AtomMatcher.newBuilder()
+ .setId(APP_BREADCRUMB_REPORTED_MATCH_STOP_ID)
+ .setSimpleAtomMatcher(StatsdConfigProto.SimpleAtomMatcher.newBuilder()
+ .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
+ // Event only when the uid is this app's uid.
+ .addFieldValueMatcher(ConfigUtils
+ .createFvm(AppBreadcrumbReported.UID_FIELD_NUMBER)
+ .setEqInt(SHELL_UID))
+ .addFieldValueMatcher(ConfigUtils
+ .createFvm(AppBreadcrumbReported.STATE_FIELD_NUMBER)
+ .setEqInt(AppBreadcrumbReported.State.STOP.getNumber()))))
+ .addAlert(Alert.newBuilder()
.setId(ALERT_ID)
.setMetricId(METRIC_ID) // The metric itself must yet be added by the test.
.setNumBuckets(numBuckets)
.setRefractoryPeriodSecs(refractorySecs)
.setTriggerIfSumGt(triggerIfSumGt))
- .addSubscription(
- Subscription.newBuilder()
- .setId(SUBSCRIPTION_ID_INCIDENTD)
- .setRuleType(Subscription.RuleType.ALERT)
- .setRuleId(ALERT_ID)
- .setIncidentdDetails(IncidentdDetails.newBuilder().addSection(INCIDENTD_SECTION)))
- // We want to trigger anomalies on METRIC_ID, but don't want the actual data.
- .addNoReportMetric(METRIC_ID)
+ .addSubscription(Subscription.newBuilder()
+ .setId(SUBSCRIPTION_ID_INCIDENTD)
+ .setRuleType(Subscription.RuleType.ALERT)
+ .setRuleId(ALERT_ID)
+ .setIncidentdDetails(IncidentdDetails.newBuilder().addSection(
+ INCIDENTD_SECTION)))
+ // We want to trigger anomalies on METRIC_ID, but don't want the actual data.
+ .addNoReportMetric(METRIC_ID)
- // Items of relevance to reporting the anomaly (we do want this data):
- .addAtomMatcher(
- StatsdConfigProto.AtomMatcher.newBuilder()
- .setId(ANOMALY_DETECT_MATCH_ID)
- .setSimpleAtomMatcher(
- StatsdConfigProto.SimpleAtomMatcher.newBuilder()
- .setAtomId(Atom.ANOMALY_DETECTED_FIELD_NUMBER)
- .addFieldValueMatcher(createFvm(AnomalyDetected.CONFIG_UID_FIELD_NUMBER)
- .setEqInt(getHostUid()))
- .addFieldValueMatcher(createFvm(AnomalyDetected.CONFIG_ID_FIELD_NUMBER)
- .setEqInt(CONFIG_ID))))
- .addEventMetric(StatsdConfigProto.EventMetric.newBuilder()
- .setId(ANOMALY_EVENT_ID)
- .setWhat(ANOMALY_DETECT_MATCH_ID));
+ // Items of relevance to reporting the anomaly (we do want this data):
+ .addAtomMatcher(StatsdConfigProto.AtomMatcher.newBuilder()
+ .setId(ANOMALY_DETECT_MATCH_ID)
+ .setSimpleAtomMatcher(StatsdConfigProto.SimpleAtomMatcher.newBuilder()
+ .setAtomId(Atom.ANOMALY_DETECTED_FIELD_NUMBER)
+ .addFieldValueMatcher(ConfigUtils
+ .createFvm(AnomalyDetected.CONFIG_UID_FIELD_NUMBER)
+ .setEqInt(SHELL_UID))
+ .addFieldValueMatcher(ConfigUtils
+ .createFvm(AnomalyDetected.CONFIG_ID_FIELD_NUMBER)
+ .setEqInt(ConfigUtils.CONFIG_ID))))
+ .addEventMetric(StatsdConfigProto.EventMetric.newBuilder()
+ .setId(ANOMALY_EVENT_ID)
+ .setWhat(ANOMALY_DETECT_MATCH_ID));
+ }
+
+ /**
+ * Determines whether perfetto enabled the kernel ftrace tracer.
+ */
+ protected boolean isSystemTracingEnabled() throws Exception {
+ final String traceFsPath = "/sys/kernel/tracing/tracing_on";
+ String tracing_on = probe(traceFsPath);
+ if (tracing_on.startsWith("0")) return false;
+ if (tracing_on.startsWith("1")) return true;
+
+ // fallback to debugfs
+ LogUtil.CLog.d("Unexpected state for %s = %s. Falling back to debugfs", traceFsPath,
+ tracing_on);
+
+ final String debugFsPath = "/sys/kernel/debug/tracing/tracing_on";
+ tracing_on = probe(debugFsPath);
+ if (tracing_on.startsWith("0")) return false;
+ if (tracing_on.startsWith("1")) return true;
+ throw new Exception(String.format("Unexpected state for %s = %s", traceFsPath, tracing_on));
+ }
+
+ private String probe(String path) throws Exception {
+ return getDevice().executeShellCommand("if [ -e " + path + " ] ; then"
+ + " cat " + path + " ; else echo -1 ; fi");
+ }
+
+ protected void enableSystemTracing() throws Exception {
+ getDevice().executeShellCommand("setprop persist.traced.enable 1");
+ }
+
+ protected void disableSystemTracing() throws Exception {
+ getDevice().executeShellCommand("setprop persist.traced.enable 0");
+ }
+
+ /**
+ * Resets the state of the Perfetto guardrails. This avoids that the test fails if it's
+ * run too close of for too many times and hits the upload limit.
+ */
+ private void resetPerfettoGuardrails() throws Exception {
+ final String cmd = "perfetto --reset-guardrails";
+ CommandResult cr = getDevice().executeShellV2Command(cmd);
+ if (cr.getStatus() != CommandStatus.SUCCESS) {
+ throw new Exception(
+ String.format("Error while executing %s: %s %s", cmd, cr.getStdout(),
+ cr.getStderr()));
+ }
+ }
+
+ /**
+ * Returns a protobuf-encoded perfetto config that enables the kernel
+ * ftrace tracer with sched_switch for 10 seconds.
+ */
+ private ByteString getPerfettoConfig() {
+ TraceConfig.Builder builder = TraceConfig.newBuilder();
+
+ TraceConfig.BufferConfig buffer = TraceConfig.BufferConfig
+ .newBuilder()
+ .setSizeKb(128)
+ .build();
+ builder.addBuffers(buffer);
+
+ FtraceConfig ftraceConfig = FtraceConfig.newBuilder()
+ .addFtraceEvents("sched/sched_switch")
+ .build();
+ DataSourceConfig dataSourceConfig = DataSourceConfig.newBuilder()
+ .setName("linux.ftrace")
+ .setTargetBuffer(0)
+ .setFtraceConfig(ftraceConfig)
+ .build();
+ TraceConfig.DataSource dataSource = TraceConfig.DataSource
+ .newBuilder()
+ .setConfig(dataSourceConfig)
+ .build();
+ builder.addDataSources(dataSource);
+
+ builder.setDurationMs(10000);
+ builder.setAllowUserBuildTracing(true);
+
+ TraceConfig.IncidentReportConfig incident = TraceConfig.IncidentReportConfig
+ .newBuilder()
+ .setSkipIncidentd(true)
+ .build();
+ builder.setIncidentReportConfig(incident);
+
+ // To avoid being hit with guardrails firing in multiple test runs back
+ // to back, we set a unique session key for each config.
+ Random random = new Random();
+ StringBuilder sessionNameBuilder = new StringBuilder("statsd-cts-");
+ sessionNameBuilder.append(random.nextInt() & Integer.MAX_VALUE);
+ builder.setUniqueSessionName(sessionNameBuilder.toString());
+
+ return builder.build().toByteString();
}
}
diff --git a/tests/src/android/cts/statsd/apex/BootstrapApexTests.java b/tests/src/android/cts/statsd/apex/BootstrapApexTests.java
index ab6093f..2db635a 100644
--- a/tests/src/android/cts/statsd/apex/BootstrapApexTests.java
+++ b/tests/src/android/cts/statsd/apex/BootstrapApexTests.java
@@ -18,11 +18,12 @@
import static com.google.common.truth.Truth.assertThat;
-import android.cts.statsd.atom.BaseTestCase;
import com.android.apex.ApexInfo;
import com.android.apex.XmlParser;
import com.android.compatibility.common.util.ApiLevelUtil;
import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.testtype.DeviceTestCase;
+
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
@@ -30,7 +31,7 @@
/**
* Verify statsd is not in the bootstrap apexes
*/
-public class BootstrapApexTests extends BaseTestCase {
+public class BootstrapApexTests extends DeviceTestCase {
private static final String TAG = "Statsd.BootstrapApexTests";
// Constants for the paths to apex-info-list.xml
@@ -39,6 +40,7 @@
// - legacy location
private static final String BOOTSTRAP_APEX_FILE2 = "/apex/.bootstrap-apex-info-list.xml";
+
private boolean sdkLevelAtLeast(int sdkLevel, String codename) throws Exception {
return ApiLevelUtil.isAtLeast(getDevice(), sdkLevel)
|| ApiLevelUtil.codenameEquals(getDevice(), codename);
diff --git a/tests/src/android/cts/statsd/atom/AtomTestCase.java b/tests/src/android/cts/statsd/atom/AtomTestCase.java
deleted file mode 100644
index b0825a7..0000000
--- a/tests/src/android/cts/statsd/atom/AtomTestCase.java
+++ /dev/null
@@ -1,1265 +0,0 @@
-/*
- * Copyright (C) 2017 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.atom;
-
-import static android.cts.statsd.atom.DeviceAtomTestCase.DEVICE_SIDE_TEST_APK;
-import static android.cts.statsd.atom.DeviceAtomTestCase.DEVICE_SIDE_TEST_PACKAGE;
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.os.BatteryStatsProto;
-import android.os.StatsDataDumpProto;
-import android.service.battery.BatteryServiceDumpProto;
-import android.service.batterystats.BatteryStatsServiceDumpProto;
-import android.service.procstats.ProcessStatsServiceDumpProto;
-
-import com.android.annotations.Nullable;
-import com.android.internal.os.StatsdConfigProto.AtomMatcher;
-import com.android.internal.os.StatsdConfigProto.EventMetric;
-import com.android.internal.os.StatsdConfigProto.FieldFilter;
-import com.android.internal.os.StatsdConfigProto.FieldMatcher;
-import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
-import com.android.internal.os.StatsdConfigProto.GaugeMetric;
-import com.android.internal.os.StatsdConfigProto.Predicate;
-import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
-import com.android.internal.os.StatsdConfigProto.SimplePredicate;
-import com.android.internal.os.StatsdConfigProto.StatsdConfig;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-import com.android.os.AtomsProto.AppBreadcrumbReported;
-import com.android.os.AtomsProto.Atom;
-import com.android.os.AtomsProto.ProcessStatsPackageProto;
-import com.android.os.AtomsProto.ProcessStatsProto;
-import com.android.os.AtomsProto.ProcessStatsStateProto;
-import com.android.os.StatsLog;
-import com.android.os.StatsLog.ConfigMetricsReport;
-import com.android.os.StatsLog.ConfigMetricsReportList;
-import com.android.os.StatsLog.CountMetricData;
-import com.android.os.StatsLog.DurationMetricData;
-import com.android.os.StatsLog.EventMetricData;
-import com.android.os.StatsLog.GaugeBucketInfo;
-import com.android.os.StatsLog.GaugeMetricData;
-import com.android.os.StatsLog.StatsLogReport;
-import com.android.os.StatsLog.StatsLogReport.GaugeMetricDataWrapper;
-import com.android.os.StatsLog.ValueMetricData;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.log.LogUtil;
-import com.android.tradefed.util.CommandResult;
-import com.android.tradefed.util.CommandStatus;
-import com.android.tradefed.util.Pair;
-
-import com.google.common.collect.Range;
-import com.google.common.io.Files;
-import com.google.protobuf.ByteString;
-import java.io.File;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Queue;
-import java.util.Random;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.function.Function;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import perfetto.protos.PerfettoConfig.DataSourceConfig;
-import perfetto.protos.PerfettoConfig.FtraceConfig;
-import perfetto.protos.PerfettoConfig.TraceConfig;
-
-/**
- * Base class for testing Statsd atoms.
- * Validates reporting of statsd logging based on different events
- */
-public class AtomTestCase extends BaseTestCase {
-
- /**
- * Run tests that are optional; they are not valid CTS tests per se, since not all devices can
- * be expected to pass them, but can be run, if desired, to ensure they work when appropriate.
- */
- public static final boolean OPTIONAL_TESTS_ENABLED = false;
-
- public static final String UPDATE_CONFIG_CMD = "cmd stats config update";
- public static final String DUMP_REPORT_CMD = "cmd stats dump-report";
- public static final String DUMP_BATTERY_CMD = "dumpsys battery";
- public static final String DUMP_BATTERYSTATS_CMD = "dumpsys batterystats";
- public static final String DUMPSYS_STATS_CMD = "dumpsys stats";
- public static final String DUMP_PROCSTATS_CMD = "dumpsys procstats";
- public static final String REMOVE_CONFIG_CMD = "cmd stats config remove";
- /** ID of the config, which evaluates to -1572883457. */
- public static final long CONFIG_ID = "cts_config".hashCode();
-
- public static final String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output";
- public static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
- public static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
- public static final String FEATURE_BLUETOOTH_LE = "android.hardware.bluetooth_le";
- public static final String FEATURE_CAMERA = "android.hardware.camera";
- public static final String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
- public static final String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
- public static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
- public static final String FEATURE_LOCATION_GPS = "android.hardware.location.gps";
- public static final String FEATURE_PC = "android.hardware.type.pc";
- public static final String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
- public static final String FEATURE_TELEPHONY = "android.hardware.telephony";
- public static final String FEATURE_WATCH = "android.hardware.type.watch";
- public static final String FEATURE_WIFI = "android.hardware.wifi";
- public static final String FEATURE_INCREMENTAL_DELIVERY =
- "android.software.incremental_delivery";
-
- public static final int SHELL_UID = 2000;
-
- // Telephony phone types
- public static final int PHONE_TYPE_GSM = 1;
- public static final int PHONE_TYPE_CDMA = 2;
- public static final int PHONE_TYPE_CDMA_LTE = 6;
-
- protected static final int WAIT_TIME_SHORT = 500;
- protected static final int WAIT_TIME_LONG = 2_000;
-
- protected static final long SCREEN_STATE_CHANGE_TIMEOUT = 4000;
- protected static final long SCREEN_STATE_POLLING_INTERVAL = 500;
-
- protected static final long NS_PER_SEC = (long) 1E+9;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- // Uninstall to clear the history in case it's still on the device.
- removeConfig(CONFIG_ID);
- getReportList(); // Clears data.
- }
-
- @Override
- protected void tearDown() throws Exception {
- removeConfig(CONFIG_ID);
- getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE);
- super.tearDown();
- }
-
- /**
- * Determines whether logcat indicates that incidentd fired since the given device date.
- */
- protected boolean didIncidentdFireSince(String date) throws Exception {
- final String INCIDENTD_TAG = "incidentd";
- final String INCIDENTD_STARTED_STRING = "reportIncident";
- // TODO: Do something more robust than this in case of delayed logging.
- Thread.sleep(1000);
- String log = getLogcatSince(date, String.format(
- "-s %s -e %s", INCIDENTD_TAG, INCIDENTD_STARTED_STRING));
- return log.contains(INCIDENTD_STARTED_STRING);
- }
-
- protected boolean checkDeviceFor(String methodName) throws Exception {
- try {
- installPackage(DEVICE_SIDE_TEST_APK, true);
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".Checkers", methodName);
- // Test passes, meaning that the answer is true.
- LogUtil.CLog.d(methodName + "() indicates true.");
- return true;
- } catch (AssertionError e) {
- // Method is designed to fail if the answer is false.
- LogUtil.CLog.d(methodName + "() indicates false.");
- return false;
- }
- }
-
- /**
- * Returns a protobuf-encoded perfetto config that enables the kernel
- * ftrace tracer with sched_switch for 10 seconds.
- */
- protected ByteString getPerfettoConfig() {
- TraceConfig.Builder builder = TraceConfig.newBuilder();
-
- TraceConfig.BufferConfig buffer = TraceConfig.BufferConfig
- .newBuilder()
- .setSizeKb(128)
- .build();
- builder.addBuffers(buffer);
-
- FtraceConfig ftraceConfig = FtraceConfig.newBuilder()
- .addFtraceEvents("sched/sched_switch")
- .build();
- DataSourceConfig dataSourceConfig = DataSourceConfig.newBuilder()
- .setName("linux.ftrace")
- .setTargetBuffer(0)
- .setFtraceConfig(ftraceConfig)
- .build();
- TraceConfig.DataSource dataSource = TraceConfig.DataSource
- .newBuilder()
- .setConfig(dataSourceConfig)
- .build();
- builder.addDataSources(dataSource);
-
- builder.setDurationMs(10000);
- builder.setAllowUserBuildTracing(true);
-
- TraceConfig.IncidentReportConfig incident = TraceConfig.IncidentReportConfig
- .newBuilder()
- .setSkipIncidentd(true)
- .build();
- builder.setIncidentReportConfig(incident);
-
- // To avoid being hit with guardrails firing in multiple test runs back
- // to back, we set a unique session key for each config.
- Random random = new Random();
- StringBuilder sessionNameBuilder = new StringBuilder("statsd-cts-");
- sessionNameBuilder.append(random.nextInt() & Integer.MAX_VALUE);
- builder.setUniqueSessionName(sessionNameBuilder.toString());
-
- return builder.build().toByteString();
- }
-
- /**
- * Resets the state of the Perfetto guardrails. This avoids that the test fails if it's
- * run too close of for too many times and hits the upload limit.
- */
- protected void resetPerfettoGuardrails() throws Exception {
- final String cmd = "perfetto --reset-guardrails";
- CommandResult cr = getDevice().executeShellV2Command(cmd);
- if (cr.getStatus() != CommandStatus.SUCCESS)
- throw new Exception(String.format("Error while executing %s: %s %s", cmd, cr.getStdout(), cr.getStderr()));
- }
-
- private String probe(String path) throws Exception {
- return getDevice().executeShellCommand("if [ -e " + path + " ] ; then"
- + " cat " + path + " ; else echo -1 ; fi");
- }
-
- protected void enableSystemTracing() throws Exception {
- getDevice().executeShellCommand("setprop persist.traced.enable 1");
- }
-
- protected void disableSystemTracing() throws Exception {
- getDevice().executeShellCommand("setprop persist.traced.enable 0");
- }
-
- /**
- * Determines whether perfetto enabled the kernel ftrace tracer.
- */
- protected boolean isSystemTracingEnabled() throws Exception {
- final String traceFsPath = "/sys/kernel/tracing/tracing_on";
- String tracing_on = probe(traceFsPath);
- if (tracing_on.startsWith("0")) return false;
- if (tracing_on.startsWith("1")) return true;
-
- // fallback to debugfs
- LogUtil.CLog.d("Unexpected state for %s = %s. Falling back to debugfs", traceFsPath,
- tracing_on);
-
- final String debugFsPath = "/sys/kernel/debug/tracing/tracing_on";
- tracing_on = probe(debugFsPath);
- if (tracing_on.startsWith("0")) return false;
- if (tracing_on.startsWith("1")) return true;
- throw new Exception(String.format("Unexpected state for %s = %s", traceFsPath, tracing_on));
- }
-
- protected static StatsdConfig.Builder createConfigBuilder() {
- return StatsdConfig.newBuilder()
- .setId(CONFIG_ID)
- .addAllowedLogSource("AID_SYSTEM")
- .addAllowedLogSource("AID_BLUETOOTH")
- // TODO(b/134091167): Fix bluetooth source name issue in Auto platform.
- .addAllowedLogSource("com.android.bluetooth")
- .addAllowedLogSource("AID_LMKD")
- .addAllowedLogSource("AID_RADIO")
- .addAllowedLogSource("AID_ROOT")
- .addAllowedLogSource("AID_STATSD")
- .addAllowedLogSource("com.android.systemui")
- .addAllowedLogSource(DeviceAtomTestCase.DEVICE_SIDE_TEST_PACKAGE)
- .addDefaultPullPackages("AID_RADIO")
- .addDefaultPullPackages("AID_SYSTEM")
- .addWhitelistedAtomIds(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER);
- }
-
- protected void createAndUploadConfig(int atomTag) throws Exception {
- StatsdConfig.Builder conf = createConfigBuilder();
- addAtomEvent(conf, atomTag);
- uploadConfig(conf);
- }
-
- protected void uploadConfig(StatsdConfig.Builder config) throws Exception {
- uploadConfig(config.build());
- }
-
- protected void uploadConfig(StatsdConfig config) throws Exception {
- LogUtil.CLog.d("Uploading the following config:\n" + config.toString());
- File configFile = File.createTempFile("statsdconfig", ".config");
- try {
- Files.write(config.toByteArray(), configFile);
- String remotePath = "/data/local/tmp/" + configFile.getName();
- getDevice().pushFile(configFile, remotePath);
- getDevice().executeShellCommand(String.join(" ", "cat", remotePath, "|",
- UPDATE_CONFIG_CMD, String.valueOf(SHELL_UID), String.valueOf(CONFIG_ID)));
- getDevice().executeShellCommand("rm " + remotePath);
- } finally {
- configFile.delete();
- }
- }
-
- protected void removeConfig(long configId) throws Exception {
- getDevice().executeShellCommand(
- String.join(" ", REMOVE_CONFIG_CMD,
- String.valueOf(SHELL_UID), String.valueOf(configId)));
- }
-
- /** Gets the statsd report and sorts it. Note that this also deletes that report from statsd. */
- protected List<EventMetricData> getEventMetricDataList() throws Exception {
- ConfigMetricsReportList reportList = getReportList();
- return getEventMetricDataList(reportList);
- }
-
- /**
- * Gets a List of sorted ConfigMetricsReports from ConfigMetricsReportList.
- */
- protected List<ConfigMetricsReport> getSortedConfigMetricsReports(
- ConfigMetricsReportList configMetricsReportList) {
- return configMetricsReportList.getReportsList().stream()
- .sorted(Comparator.comparing(ConfigMetricsReport::getCurrentReportWallClockNanos))
- .collect(Collectors.toList());
- }
-
- /**
- * Extracts and sorts the EventMetricData from the given ConfigMetricsReportList (which must
- * contain a single report).
- */
- protected List<EventMetricData> getEventMetricDataList(ConfigMetricsReportList reportList)
- throws Exception {
- assertThat(reportList.getReportsCount()).isEqualTo(1);
- ConfigMetricsReport report = reportList.getReports(0);
-
- List<EventMetricData> data = new ArrayList<>();
- for (StatsLogReport metric : report.getMetricsList()) {
- for (EventMetricData metricData :
- metric.getEventMetrics().getDataList()) {
- if (metricData.hasAtom()) {
- data.add(metricData);
- } else {
- data.addAll(backfillAggregatedAtomsInEventMetric(metricData));
- }
- }
- }
- data.sort(Comparator.comparing(EventMetricData::getElapsedTimestampNanos));
-
- LogUtil.CLog.d("Get EventMetricDataList as following:\n");
- for (EventMetricData d : data) {
- LogUtil.CLog.d("Atom at " + d.getElapsedTimestampNanos() + ":\n" + d.getAtom().toString());
- }
- return data;
- }
-
- protected List<Atom> getGaugeMetricDataList() throws Exception {
- return getGaugeMetricDataList(/*checkTimestampTruncated=*/false);
- }
-
- protected List<Atom> getGaugeMetricDataList(boolean checkTimestampTruncated) throws Exception {
- ConfigMetricsReportList reportList = getReportList();
- assertThat(reportList.getReportsCount()).isEqualTo(1);
-
- // only config
- ConfigMetricsReport report = reportList.getReports(0);
- assertThat(report.getMetricsCount()).isEqualTo(1);
-
- List<Atom> data = new ArrayList<>();
- for (GaugeMetricData gaugeMetricData :
- report.getMetrics(0).getGaugeMetrics().getDataList()) {
- assertThat(gaugeMetricData.getBucketInfoCount()).isEqualTo(1);
- GaugeBucketInfo bucketInfo = gaugeMetricData.getBucketInfo(0);
- if (bucketInfo.getAtomCount() != 0) {
- for (Atom atom : bucketInfo.getAtomList()) {
- data.add(atom);
- }
- } else {
- backFillGaugeBucketAtoms(bucketInfo.getAggregatedAtomInfoList());
- }
- if (checkTimestampTruncated) {
- for (long timestampNs : bucketInfo.getElapsedTimestampNanosList()) {
- assertTimestampIsTruncated(timestampNs);
- }
- }
- }
-
- LogUtil.CLog.d("Get GaugeMetricDataList as following:\n");
- for (Atom d : data) {
- LogUtil.CLog.d("Atom:\n" + d.toString());
- }
- return data;
- }
-
- private List<Atom> backFillGaugeBucketAtoms(
- List<StatsLog.AggregatedAtomInfo> atomInfoList) {
- List<Pair<Atom, Long>> atomTimestamp = new ArrayList<>();
- for (StatsLog.AggregatedAtomInfo atomInfo : atomInfoList) {
- for (long timestampNs : atomInfo.getElapsedTimestampNanosList()) {
- atomTimestamp.add(Pair.create(atomInfo.getAtom(), timestampNs));
- }
- }
- atomTimestamp.sort(Comparator.comparing(o -> o.second));
- return atomTimestamp.stream().map(p -> p.first).collect(Collectors.toList());
- }
-
- protected GaugeMetricDataWrapper backfillGaugeMetricData(GaugeMetricDataWrapper dataWrapper) {
- GaugeMetricDataWrapper.Builder dataWrapperBuilder = dataWrapper.toBuilder();
- List<GaugeMetricData> backfilledMetricData = new ArrayList<>();
- for (GaugeMetricData gaugeMetricData : dataWrapperBuilder.getDataList()) {
- GaugeMetricData.Builder gaugeMetricDataBuilder = gaugeMetricData.toBuilder();
- List<GaugeBucketInfo> backfilledBuckets = new ArrayList<>();
- for (GaugeBucketInfo bucketInfo : gaugeMetricData.getBucketInfoList()) {
- backfilledBuckets.add(backfillGaugeBucket(bucketInfo.toBuilder()));
- }
- gaugeMetricDataBuilder.clearBucketInfo();
- gaugeMetricDataBuilder.addAllBucketInfo(backfilledBuckets);
- backfilledMetricData.add(gaugeMetricDataBuilder.build());
- }
- dataWrapperBuilder.clearData();
- dataWrapperBuilder.addAllData(backfilledMetricData);
- return dataWrapperBuilder.build();
- }
-
- private GaugeBucketInfo backfillGaugeBucket(GaugeBucketInfo.Builder bucketInfoBuilder) {
- if (bucketInfoBuilder.getAtomCount() != 0) {
- return bucketInfoBuilder.build();
- }
- List<Pair<Atom, Long>> atomTimestampData = new ArrayList<>();
- for (StatsLog.AggregatedAtomInfo atomInfo : bucketInfoBuilder.getAggregatedAtomInfoList()) {
- for (long timestampNs : atomInfo.getElapsedTimestampNanosList()) {
- atomTimestampData.add(Pair.create(atomInfo.getAtom(), timestampNs));
- }
- }
- atomTimestampData.sort(Comparator.comparing(o -> o.second));
- bucketInfoBuilder.clearAggregatedAtomInfo();
- for (Pair<Atom, Long> atomTimestamp : atomTimestampData) {
- bucketInfoBuilder.addAtom(atomTimestamp.first);
- bucketInfoBuilder.addElapsedTimestampNanos(atomTimestamp.second);
- }
- return bucketInfoBuilder.build();
- }
-
- /**
- * Gets the statsd report and extract duration metric data.
- * Note that this also deletes that report from statsd.
- */
- protected List<DurationMetricData> getDurationMetricDataList() throws Exception {
- ConfigMetricsReportList reportList = getReportList();
- assertThat(reportList.getReportsCount()).isEqualTo(1);
- ConfigMetricsReport report = reportList.getReports(0);
-
- List<DurationMetricData> data = new ArrayList<>();
- for (StatsLogReport metric : report.getMetricsList()) {
- data.addAll(metric.getDurationMetrics().getDataList());
- }
-
- LogUtil.CLog.d("Got DurationMetricDataList as following:\n");
- for (DurationMetricData d : data) {
- LogUtil.CLog.d("Duration " + d);
- }
- return data;
- }
-
- /**
- * Gets the statsd report and extract count metric data.
- * Note that this also deletes that report from statsd.
- */
- protected List<CountMetricData> getCountMetricDataList() throws Exception {
- ConfigMetricsReportList reportList = getReportList();
- assertThat(reportList.getReportsCount()).isEqualTo(1);
- ConfigMetricsReport report = reportList.getReports(0);
-
- List<CountMetricData> data = new ArrayList<>();
- for (StatsLogReport metric : report.getMetricsList()) {
- data.addAll(metric.getCountMetrics().getDataList());
- }
-
- LogUtil.CLog.d("Got CountMetricDataList as following:\n");
- for (CountMetricData d : data) {
- LogUtil.CLog.d("Count " + d);
- }
- return data;
- }
-
- /**
- * Gets the statsd report and extract value metric data.
- * Note that this also deletes that report from statsd.
- */
- protected List<ValueMetricData> getValueMetricDataList() throws Exception {
- ConfigMetricsReportList reportList = getReportList();
- assertThat(reportList.getReportsCount()).isEqualTo(1);
- ConfigMetricsReport report = reportList.getReports(0);
-
- List<ValueMetricData> data = new ArrayList<>();
- for (StatsLogReport metric : report.getMetricsList()) {
- data.addAll(metric.getValueMetrics().getDataList());
- }
-
- LogUtil.CLog.d("Got ValueMetricDataList as following:\n");
- for (ValueMetricData d : data) {
- LogUtil.CLog.d("Value " + d);
- }
- return data;
- }
-
- protected StatsLogReport getStatsLogReport() throws Exception {
- ConfigMetricsReport report = getConfigMetricsReport();
- assertThat(report.hasUidMap()).isTrue();
- assertThat(report.getMetricsCount()).isEqualTo(1);
- return report.getMetrics(0);
- }
-
- protected ConfigMetricsReport getConfigMetricsReport() throws Exception {
- ConfigMetricsReportList reportList = getReportList();
- assertThat(reportList.getReportsCount()).isEqualTo(1);
- return reportList.getReports(0);
- }
-
- /** Gets the statsd report. Note that this also deletes that report from statsd. */
- protected ConfigMetricsReportList getReportList() throws Exception {
- try {
- ConfigMetricsReportList reportList = getDump(ConfigMetricsReportList.parser(),
- String.join(" ", DUMP_REPORT_CMD, String.valueOf(SHELL_UID),
- String.valueOf(CONFIG_ID), "--include_current_bucket", "--proto"));
- return reportList;
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- LogUtil.CLog.e("Failed to fetch and parse the statsd output report. "
- + "Perhaps there is not a valid statsd config for the requested "
- + "uid=" + getHostUid() + ", id=" + CONFIG_ID + ".");
- throw (e);
- }
- }
-
- protected BatteryStatsProto getBatteryStatsProto() throws Exception {
- try {
- BatteryStatsProto batteryStatsProto = getDump(BatteryStatsServiceDumpProto.parser(),
- String.join(" ", DUMP_BATTERYSTATS_CMD,
- "--proto")).getBatterystats();
- LogUtil.CLog.d("Got batterystats:\n " + batteryStatsProto.toString());
- return batteryStatsProto;
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- LogUtil.CLog.e("Failed to dump batterystats proto");
- throw (e);
- }
- }
-
- /** Gets reports from the statsd data incident section from the stats dumpsys. */
- protected List<ConfigMetricsReportList> getReportsFromStatsDataDumpProto() throws Exception {
- try {
- StatsDataDumpProto statsProto = getDump(StatsDataDumpProto.parser(),
- String.join(" ", DUMPSYS_STATS_CMD, "--proto"));
- // statsProto holds repeated bytes, which we must parse into ConfigMetricsReportLists.
- List<ConfigMetricsReportList> reports
- = new ArrayList<>(statsProto.getConfigMetricsReportListCount());
- for (ByteString reportListBytes : statsProto.getConfigMetricsReportListList()) {
- reports.add(ConfigMetricsReportList.parseFrom(reportListBytes));
- }
- LogUtil.CLog.d("Got dumpsys stats output:\n " + reports.toString());
- return reports;
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- LogUtil.CLog.e("Failed to dumpsys stats proto");
- throw (e);
- }
- }
-
- protected List<ProcessStatsProto> getProcStatsProto() throws Exception {
- try {
-
- List<ProcessStatsProto> processStatsProtoList =
- new ArrayList<ProcessStatsProto>();
- android.service.procstats.ProcessStatsSectionProto sectionProto = getDump(
- ProcessStatsServiceDumpProto.parser(),
- String.join(" ", DUMP_PROCSTATS_CMD,
- "--proto")).getProcstatsNow();
- for (android.service.procstats.ProcessStatsProto stats :
- sectionProto.getProcessStatsList()) {
- ProcessStatsProto procStats = ProcessStatsProto.parser().parseFrom(
- stats.toByteArray());
- processStatsProtoList.add(procStats);
- }
- LogUtil.CLog.d("Got procstats:\n ");
- for (ProcessStatsProto processStatsProto : processStatsProtoList) {
- LogUtil.CLog.d(processStatsProto.toString());
- }
- return processStatsProtoList;
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- LogUtil.CLog.e("Failed to dump procstats proto");
- throw (e);
- }
- }
-
- /*
- * Get all procstats package data in proto
- */
- protected List<ProcessStatsPackageProto> getAllProcStatsProto() throws Exception {
- try {
- android.service.procstats.ProcessStatsSectionProto sectionProto = getDump(
- ProcessStatsServiceDumpProto.parser(),
- String.join(" ", DUMP_PROCSTATS_CMD,
- "--proto")).getProcstatsOver24Hrs();
- List<ProcessStatsPackageProto> processStatsProtoList =
- new ArrayList<ProcessStatsPackageProto>();
- for (android.service.procstats.ProcessStatsPackageProto pkgStast :
- sectionProto.getPackageStatsList()) {
- ProcessStatsPackageProto pkgAtom =
- ProcessStatsPackageProto.parser().parseFrom(pkgStast.toByteArray());
- processStatsProtoList.add(pkgAtom);
- }
- LogUtil.CLog.d("Got procstats:\n ");
- for (ProcessStatsPackageProto processStatsProto : processStatsProtoList) {
- LogUtil.CLog.d(processStatsProto.toString());
- }
- return processStatsProtoList;
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- LogUtil.CLog.e("Failed to dump procstats proto");
- throw (e);
- }
- }
-
- /*
- * Get all processes' procstats statsd data in proto
- */
- protected List<android.service.procstats.ProcessStatsProto> getAllProcStatsProtoForStatsd()
- throws Exception {
- try {
- android.service.procstats.ProcessStatsSectionProto sectionProto = getDump(
- android.service.procstats.ProcessStatsSectionProto.parser(),
- String.join(" ", DUMP_PROCSTATS_CMD,
- "--statsd"));
- List<android.service.procstats.ProcessStatsProto> processStatsProtoList
- = sectionProto.getProcessStatsList();
- LogUtil.CLog.d("Got procstats:\n ");
- for (android.service.procstats.ProcessStatsProto processStatsProto
- : processStatsProtoList) {
- LogUtil.CLog.d(processStatsProto.toString());
- }
- return processStatsProtoList;
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- LogUtil.CLog.e("Failed to dump procstats proto");
- throw (e);
- }
- }
-
- protected boolean hasBattery() throws Exception {
- try {
- BatteryServiceDumpProto batteryProto = getDump(BatteryServiceDumpProto.parser(),
- String.join(" ", DUMP_BATTERY_CMD, "--proto"));
- LogUtil.CLog.d("Got battery service dump:\n " + batteryProto.toString());
- return batteryProto.getIsPresent();
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- LogUtil.CLog.e("Failed to dump batteryservice proto");
- throw (e);
- }
- }
-
- /** Creates a FieldValueMatcher.Builder corresponding to the given field. */
- protected static FieldValueMatcher.Builder createFvm(int field) {
- return FieldValueMatcher.newBuilder().setField(field);
- }
-
- protected void addAtomEvent(StatsdConfig.Builder conf, int atomTag) throws Exception {
- addAtomEvent(conf, atomTag, new ArrayList<FieldValueMatcher.Builder>());
- }
-
- /**
- * Adds an event to the config for an atom that matches the given key.
- *
- * @param conf configuration
- * @param atomTag atom tag (from atoms.proto)
- * @param fvm FieldValueMatcher.Builder for the relevant key
- */
- protected void addAtomEvent(StatsdConfig.Builder conf, int atomTag,
- FieldValueMatcher.Builder fvm)
- throws Exception {
- addAtomEvent(conf, atomTag, Arrays.asList(fvm));
- }
-
- /**
- * Adds an event to the config for an atom that matches the given keys.
- *
- * @param conf configuration
- * @param atomId atom tag (from atoms.proto)
- * @param fvms list of FieldValueMatcher.Builders to attach to the atom. May be null.
- */
- protected void addAtomEvent(StatsdConfig.Builder conf, int atomId,
- List<FieldValueMatcher.Builder> fvms) throws Exception {
-
- final String atomName = "Atom" + System.nanoTime();
- final String eventName = "Event" + System.nanoTime();
-
- SimpleAtomMatcher.Builder sam = SimpleAtomMatcher.newBuilder().setAtomId(atomId);
- if (fvms != null) {
- for (FieldValueMatcher.Builder fvm : fvms) {
- sam.addFieldValueMatcher(fvm);
- }
- }
- conf.addAtomMatcher(AtomMatcher.newBuilder()
- .setId(atomName.hashCode())
- .setSimpleAtomMatcher(sam));
- conf.addEventMetric(EventMetric.newBuilder()
- .setId(eventName.hashCode())
- .setWhat(atomName.hashCode()));
- }
-
- /**
- * Adds an atom to a gauge metric of a config
- *
- * @param conf configuration
- * @param atomId atom id (from atoms.proto)
- * @param gaugeMetric the gauge metric to add
- */
- protected void addGaugeAtom(StatsdConfig.Builder conf, int atomId,
- GaugeMetric.Builder gaugeMetric) throws Exception {
- final String atomName = "Atom" + System.nanoTime();
- final String gaugeName = "Gauge" + System.nanoTime();
- final String predicateName = "APP_BREADCRUMB";
- SimpleAtomMatcher.Builder sam = SimpleAtomMatcher.newBuilder().setAtomId(atomId);
- conf.addAtomMatcher(AtomMatcher.newBuilder()
- .setId(atomName.hashCode())
- .setSimpleAtomMatcher(sam));
- final String predicateTrueName = "APP_BREADCRUMB_1";
- final String predicateFalseName = "APP_BREADCRUMB_2";
- conf.addAtomMatcher(AtomMatcher.newBuilder()
- .setId(predicateTrueName.hashCode())
- .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
- .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
- .addFieldValueMatcher(FieldValueMatcher.newBuilder()
- .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER)
- .setEqInt(1)
- )
- )
- )
- // Used to trigger predicate
- .addAtomMatcher(AtomMatcher.newBuilder()
- .setId(predicateFalseName.hashCode())
- .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
- .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
- .addFieldValueMatcher(FieldValueMatcher.newBuilder()
- .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER)
- .setEqInt(2)
- )
- )
- );
- conf.addPredicate(Predicate.newBuilder()
- .setId(predicateName.hashCode())
- .setSimplePredicate(SimplePredicate.newBuilder()
- .setStart(predicateTrueName.hashCode())
- .setStop(predicateFalseName.hashCode())
- .setCountNesting(false)
- )
- );
- gaugeMetric
- .setId(gaugeName.hashCode())
- .setWhat(atomName.hashCode())
- .setCondition(predicateName.hashCode());
- conf.addGaugeMetric(gaugeMetric.build());
- }
-
- /**
- * Adds an atom to a gauge metric of a config
- *
- * @param conf configuration
- * @param atomId atom id (from atoms.proto)
- * @param dimension dimension is needed for most pulled atoms
- */
- protected void addGaugeAtomWithDimensions(StatsdConfig.Builder conf, int atomId,
- @Nullable FieldMatcher.Builder dimension) throws Exception {
- GaugeMetric.Builder gaugeMetric = GaugeMetric.newBuilder()
- .setGaugeFieldsFilter(FieldFilter.newBuilder().setIncludeAll(true).build())
- .setSamplingType(GaugeMetric.SamplingType.CONDITION_CHANGE_TO_TRUE)
- .setMaxNumGaugeAtomsPerBucket(10000)
- .setBucket(TimeUnit.CTS);
- if (dimension != null) {
- gaugeMetric.setDimensionsInWhat(dimension.build());
- }
- addGaugeAtom(conf, atomId, gaugeMetric);
- }
-
- /**
- * Asserts that each set of states in stateSets occurs at least once in data.
- * Asserts that the states in data occur in the same order as the sets in stateSets.
- *
- * @param stateSets A list of set of states, where each set represents an equivalent
- * state of the device for the purpose of CTS.
- * @param data list of EventMetricData from statsd, produced by
- * getReportMetricListData()
- * @param wait expected duration (in ms) between state changes; asserts that the
- * actual wait
- * time was wait/2 <= actual_wait <= 5*wait. Use 0 to ignore this
- * assertion.
- * @param getStateFromAtom expression that takes in an Atom and returns the state it contains
- */
- public void assertStatesOccurred(List<Set<Integer>> stateSets, List<EventMetricData> data,
- int wait, Function<Atom, Integer> getStateFromAtom) {
- // Sometimes, there are more events than there are states.
- // Eg: When the screen turns off, it may go into OFF and then DOZE immediately.
- assertWithMessage("Too few states found").that(data.size()).isAtLeast(stateSets.size());
- int stateSetIndex = 0; // Tracks which state set we expect the data to be in.
- for (int dataIndex = 0; dataIndex < data.size(); dataIndex++) {
- Atom atom = data.get(dataIndex).getAtom();
- int state = getStateFromAtom.apply(atom);
- // If state is in the current state set, we do not assert anything.
- // If it is not, we expect to have transitioned to the next state set.
- if (stateSets.get(stateSetIndex).contains(state)) {
- // No need to assert anything. Just log it.
- LogUtil.CLog.i("The following atom at dataIndex=" + dataIndex + " is "
- + "in stateSetIndex " + stateSetIndex + ":\n"
- + data.get(dataIndex).getAtom().toString());
- } else {
- stateSetIndex += 1;
- LogUtil.CLog.i("Assert that the following atom at dataIndex=" + dataIndex + " is"
- + " in stateSetIndex " + stateSetIndex + ":\n"
- + data.get(dataIndex).getAtom().toString());
- assertWithMessage("Missed first state").that(dataIndex).isNotEqualTo(0);
- assertWithMessage("Too many states").that(stateSetIndex)
- .isLessThan(stateSets.size());
- assertWithMessage(String.format("Is in wrong state (%d)", state))
- .that(stateSets.get(stateSetIndex)).contains(state);
- if (wait > 0) {
- assertTimeDiffBetween(data.get(dataIndex - 1), data.get(dataIndex),
- wait / 2, wait * 5);
- }
- }
- }
- assertWithMessage("Too few states").that(stateSetIndex).isEqualTo(stateSets.size() - 1);
- }
-
- /**
- * Removes all elements from data prior to the first occurrence of an element of state. After
- * this method is called, the first element of data (if non-empty) is guaranteed to be an
- * element in state.
- *
- * @param getStateFromAtom expression that takes in an Atom and returns the state it contains
- */
- public void popUntilFind(List<EventMetricData> data, Set<Integer> state,
- Function<Atom, Integer> getStateFromAtom) {
- int firstStateIdx;
- for (firstStateIdx = 0; firstStateIdx < data.size(); firstStateIdx++) {
- Atom atom = data.get(firstStateIdx).getAtom();
- if (state.contains(getStateFromAtom.apply(atom))) {
- break;
- }
- }
- if (firstStateIdx == 0) {
- // First first element already is in state, so there's nothing to do.
- return;
- }
- data.subList(0, firstStateIdx).clear();
- }
-
- /**
- * Removes all elements from data after to the last occurrence of an element of state. After
- * this method is called, the last element of data (if non-empty) is guaranteed to be an
- * element in state.
- *
- * @param getStateFromAtom expression that takes in an Atom and returns the state it contains
- */
- public void popUntilFindFromEnd(List<EventMetricData> data, Set<Integer> state,
- Function<Atom, Integer> getStateFromAtom) {
- int lastStateIdx;
- for (lastStateIdx = data.size() - 1; lastStateIdx >= 0; lastStateIdx--) {
- Atom atom = data.get(lastStateIdx).getAtom();
- if (state.contains(getStateFromAtom.apply(atom))) {
- break;
- }
- }
- if (lastStateIdx == data.size()-1) {
- // Last element already is in state, so there's nothing to do.
- return;
- }
- data.subList(lastStateIdx+1, data.size()).clear();
- }
-
- /** Returns the UID of the host, which should always either be SHELL (2000). */
- protected int getHostUid() throws DeviceNotAvailableException {
- return SHELL_UID;
- }
-
- protected String getProperty(String prop) throws Exception {
- return getDevice().executeShellCommand("getprop " + prop).replace("\n", "");
- }
-
- protected void turnScreenOn() throws Exception {
- getDevice().executeShellCommand("input keyevent KEYCODE_WAKEUP");
- getDevice().executeShellCommand("wm dismiss-keyguard");
- }
-
- protected void turnScreenOff() throws Exception {
- getDevice().executeShellCommand("input keyevent KEYCODE_SLEEP");
- }
-
- protected void setChargingState(int state) throws Exception {
- getDevice().executeShellCommand("cmd battery set status " + state);
- }
-
- protected void unplugDevice() throws Exception {
- // On batteryless devices on Android P or above, the 'unplug' command
- // alone does not simulate the really unplugged state.
- //
- // This is because charging state is left as "unknown". Unless a valid
- // state like 3 = BatteryManager.BATTERY_STATUS_DISCHARGING is set,
- // framework does not consider the device as running on battery.
- setChargingState(3);
-
- getDevice().executeShellCommand("cmd battery unplug");
- }
-
- protected void plugInAc() throws Exception {
- getDevice().executeShellCommand("cmd battery set ac 1");
- }
-
- protected void plugInUsb() throws Exception {
- getDevice().executeShellCommand("cmd battery set usb 1");
- }
-
- protected void plugInWireless() throws Exception {
- getDevice().executeShellCommand("cmd battery set wireless 1");
- }
-
- protected void enableLooperStats() throws Exception {
- getDevice().executeShellCommand("cmd looper_stats enable");
- }
-
- protected void resetLooperStats() throws Exception {
- getDevice().executeShellCommand("cmd looper_stats reset");
- }
-
- protected void disableLooperStats() throws Exception {
- getDevice().executeShellCommand("cmd looper_stats disable");
- }
-
- protected void enableBinderStats() throws Exception {
- getDevice().executeShellCommand("dumpsys binder_calls_stats --enable");
- }
-
- protected void resetBinderStats() throws Exception {
- getDevice().executeShellCommand("dumpsys binder_calls_stats --reset");
- }
-
- protected void disableBinderStats() throws Exception {
- getDevice().executeShellCommand("dumpsys binder_calls_stats --disable");
- }
-
- protected void binderStatsNoSampling() throws Exception {
- getDevice().executeShellCommand("dumpsys binder_calls_stats --no-sampling");
- }
-
- protected void setUpLooperStats() throws Exception {
- getDevice().executeShellCommand("cmd looper_stats enable");
- getDevice().executeShellCommand("cmd looper_stats sampling_interval 1");
- getDevice().executeShellCommand("cmd looper_stats reset");
- }
-
- protected void cleanUpLooperStats() throws Exception {
- getDevice().executeShellCommand("cmd looper_stats disable");
- }
-
- public void setAppBreadcrumbPredicate() throws Exception {
- doAppBreadcrumbReportedStart(1);
- }
-
- public void clearAppBreadcrumbPredicate() throws Exception {
- doAppBreadcrumbReportedStart(2);
- }
-
- public void doAppBreadcrumbReportedStart(int label) throws Exception {
- doAppBreadcrumbReported(label, AppBreadcrumbReported.State.START.ordinal());
- }
-
- public void doAppBreadcrumbReportedStop(int label) throws Exception {
- doAppBreadcrumbReported(label, AppBreadcrumbReported.State.STOP.ordinal());
- }
-
- public void doAppBreadcrumbReported(int label) throws Exception {
- doAppBreadcrumbReported(label, AppBreadcrumbReported.State.UNSPECIFIED.ordinal());
- }
-
- public void doAppBreadcrumbReported(int label, int state) throws Exception {
- getDevice().executeShellCommand(String.format(
- "cmd stats log-app-breadcrumb %d %d %d", SHELL_UID, label, state));
- }
-
- protected void setBatteryLevel(int level) throws Exception {
- getDevice().executeShellCommand("cmd battery set level " + level);
- }
-
- protected void resetBatteryStatus() throws Exception {
- getDevice().executeShellCommand("cmd battery reset");
- }
-
- protected int getScreenBrightness() throws Exception {
- return Integer.parseInt(
- getDevice().executeShellCommand("settings get system screen_brightness").trim());
- }
-
- protected void setScreenBrightness(int brightness) throws Exception {
- getDevice().executeShellCommand("settings put system screen_brightness " + brightness);
- }
-
- // Gets whether "Always on Display" setting is enabled.
- // In rare cases, this is different from whether the device can enter SCREEN_STATE_DOZE.
- protected String getAodState() throws Exception {
- return getDevice().executeShellCommand("settings get secure doze_always_on");
- }
-
- protected void setAodState(String state) throws Exception {
- getDevice().executeShellCommand("settings put secure doze_always_on " + state);
- }
-
- protected boolean isScreenBrightnessModeManual() throws Exception {
- String mode = getDevice().executeShellCommand("settings get system screen_brightness_mode");
- return Integer.parseInt(mode.trim()) == 0;
- }
-
- protected void setScreenBrightnessMode(boolean manual) throws Exception {
- getDevice().executeShellCommand(
- "settings put system screen_brightness_mode " + (manual ? 0 : 1));
- }
-
- protected void enterDozeModeLight() throws Exception {
- getDevice().executeShellCommand("dumpsys deviceidle force-idle light");
- }
-
- protected void enterDozeModeDeep() throws Exception {
- getDevice().executeShellCommand("dumpsys deviceidle force-idle deep");
- }
-
- protected void leaveDozeMode() throws Exception {
- getDevice().executeShellCommand("dumpsys deviceidle unforce");
- getDevice().executeShellCommand("dumpsys deviceidle disable");
- getDevice().executeShellCommand("dumpsys deviceidle enable");
- }
-
- protected void turnBatterySaverOn() throws Exception {
- unplugDevice();
- getDevice().executeShellCommand("settings put global low_power 1");
- }
-
- protected void turnBatterySaverOff() throws Exception {
- getDevice().executeShellCommand("settings put global low_power 0");
- getDevice().executeShellCommand("cmd battery reset");
- }
-
- protected void turnBatteryStatsAutoResetOn() throws Exception {
- getDevice().executeShellCommand("dumpsys batterystats enable no-auto-reset");
- }
-
- protected void turnBatteryStatsAutoResetOff() throws Exception {
- getDevice().executeShellCommand("dumpsys batterystats enable no-auto-reset");
- }
-
- protected void flushBatteryStatsHandlers() throws Exception {
- // Dumping batterystats will flush everything in the batterystats handler threads.
- getDevice().executeShellCommand(DUMP_BATTERYSTATS_CMD);
- }
-
- protected void rebootDevice() throws Exception {
- getDevice().rebootUntilOnline();
- }
-
- /**
- * Asserts that the two events are within the specified range of each other.
- *
- * @param d0 the event that should occur first
- * @param d1 the event that should occur second
- * @param minDiffMs d0 should precede d1 by at least this amount
- * @param maxDiffMs d0 should precede d1 by at most this amount
- */
- public static void assertTimeDiffBetween(EventMetricData d0, EventMetricData d1,
- int minDiffMs, int maxDiffMs) {
- long diffMs = (d1.getElapsedTimestampNanos() - d0.getElapsedTimestampNanos()) / 1_000_000;
- assertWithMessage("Illegal time difference")
- .that(diffMs).isIn(Range.closed((long) minDiffMs, (long) maxDiffMs));
- }
-
- protected String getCurrentLogcatDate() throws Exception {
- // TODO: Do something more robust than this for getting logcat markers.
- long timestampMs = getDevice().getDeviceDate();
- return new SimpleDateFormat("MM-dd HH:mm:ss.SSS")
- .format(new Date(timestampMs));
- }
-
- protected String getLogcatSince(String date, String logcatParams) throws Exception {
- return getDevice().executeShellCommand(String.format(
- "logcat -v threadtime -t '%s' -d %s", date, logcatParams));
- }
-
- // TODO: Remove this and migrate all usages to createConfigBuilder()
- protected StatsdConfig.Builder getPulledConfig() {
- return createConfigBuilder();
- }
- /**
- * Determines if the device has the given feature.
- * Prints a warning if its value differs from requiredAnswer.
- */
- protected boolean hasFeature(String featureName, boolean requiredAnswer) throws Exception {
- final String features = getDevice().executeShellCommand("pm list features");
- StringTokenizer featureToken = new StringTokenizer(features, "\n");
- boolean hasIt = false;
-
- while (featureToken.hasMoreTokens()) {
- if (("feature:" + featureName).equals(featureToken.nextToken())) {
- hasIt = true;
- break;
- }
- }
-
- if (hasIt != requiredAnswer) {
- LogUtil.CLog.w("Device does " + (requiredAnswer ? "not " : "") + "have feature "
- + featureName);
- }
- return hasIt == requiredAnswer;
- }
-
- /**
- * Determines if the device has |file|.
- */
- protected boolean doesFileExist(String file) throws Exception {
- return getDevice().doesFileExist(file);
- }
-
- protected void turnOnAirplaneMode() throws Exception {
- getDevice().executeShellCommand("cmd connectivity airplane-mode enable");
- }
-
- protected void turnOffAirplaneMode() throws Exception {
- getDevice().executeShellCommand("cmd connectivity airplane-mode disable");
- }
-
- /**
- * Returns a list of fields and values for {@code className} from {@link TelephonyDebugService}
- * output.
- *
- * <p>Telephony dumpsys output does not support proto at the moment. This method provides
- * limited support for parsing its output. Specifically, it does not support arrays or
- * multi-line values.
- */
- private List<Map<String, String>> getTelephonyDumpEntries(String className) throws Exception {
- // Matches any line with indentation, except for lines with only spaces
- Pattern indentPattern = Pattern.compile("^(\\s*)[^ ].*$");
- // Matches pattern for class, e.g. " Phone:"
- Pattern classNamePattern = Pattern.compile("^(\\s*)" + Pattern.quote(className) + ":.*$");
- // Matches pattern for key-value pairs, e.g. " mPhoneId=1"
- Pattern keyValuePattern = Pattern.compile("^(\\s*)([a-zA-Z]+[a-zA-Z0-9_]*)\\=(.+)$");
- String response =
- getDevice().executeShellCommand("dumpsys activity service TelephonyDebugService");
- Queue<String> responseLines = new LinkedList<>(Arrays.asList(response.split("[\\r\\n]+")));
-
- List<Map<String, String>> results = new ArrayList<>();
- while (responseLines.peek() != null) {
- Matcher matcher = classNamePattern.matcher(responseLines.poll());
- if (matcher.matches()) {
- final int classIndentLevel = matcher.group(1).length();
- final Map<String, String> instanceEntries = new HashMap<>();
- while (responseLines.peek() != null) {
- // Skip blank lines
- matcher = indentPattern.matcher(responseLines.peek());
- if (responseLines.peek().length() == 0 || !matcher.matches()) {
- responseLines.poll();
- continue;
- }
- // Finish (without consuming the line) if already parsed past this instance
- final int indentLevel = matcher.group(1).length();
- if (indentLevel <= classIndentLevel) {
- break;
- }
- // Parse key-value pair if it belongs to the instance directly
- matcher = keyValuePattern.matcher(responseLines.poll());
- if (indentLevel == classIndentLevel + 1 && matcher.matches()) {
- instanceEntries.put(matcher.group(2), matcher.group(3));
- }
- }
- results.add(instanceEntries);
- }
- }
- return results;
- }
-
- protected int getActiveSimSlotCount() throws Exception {
- List<Map<String, String>> slots = getTelephonyDumpEntries("UiccSlot");
- long count = slots.stream().filter(slot -> "true".equals(slot.get("mActive"))).count();
- return Math.toIntExact(count);
- }
-
- /**
- * Returns the upper bound of active SIM profile count.
- *
- * <p>The value is an upper bound as eSIMs without profiles are also counted in.
- */
- protected int getActiveSimCountUpperBound() throws Exception {
- List<Map<String, String>> slots = getTelephonyDumpEntries("UiccSlot");
- long count = slots.stream().filter(slot ->
- "true".equals(slot.get("mActive"))
- && "CARDSTATE_PRESENT".equals(slot.get("mCardState"))).count();
- return Math.toIntExact(count);
- }
-
- /**
- * Returns the upper bound of active eSIM profile count.
- *
- * <p>The value is an upper bound as eSIMs without profiles are also counted in.
- */
- protected int getActiveEsimCountUpperBound() throws Exception {
- List<Map<String, String>> slots = getTelephonyDumpEntries("UiccSlot");
- long count = slots.stream().filter(slot ->
- "true".equals(slot.get("mActive"))
- && "CARDSTATE_PRESENT".equals(slot.get("mCardState"))
- && "true".equals(slot.get("mIsEuicc"))).count();
- return Math.toIntExact(count);
- }
-
- protected boolean hasGsmPhone() throws Exception {
- // Not using log entries or ServiceState in the dump since they may or may not be present,
- // which can make the test flaky
- return getTelephonyDumpEntries("Phone").stream()
- .anyMatch(phone ->
- String.format("%d", PHONE_TYPE_GSM).equals(phone.get("getPhoneType()")));
- }
-
- protected boolean hasCdmaPhone() throws Exception {
- // Not using log entries or ServiceState in the dump due to the same reason as hasGsmPhone()
- return getTelephonyDumpEntries("Phone").stream()
- .anyMatch(phone ->
- String.format("%d", PHONE_TYPE_CDMA).equals(phone.get("getPhoneType()"))
- || String.format("%d", PHONE_TYPE_CDMA_LTE)
- .equals(phone.get("getPhoneType()")));
- }
-
- // Checks that a timestamp has been truncated to be a multiple of 5 min
- protected void assertTimestampIsTruncated(long timestampNs) {
- long fiveMinutesInNs = NS_PER_SEC * 5 * 60;
- assertWithMessage("Timestamp is not truncated")
- .that(timestampNs % fiveMinutesInNs).isEqualTo(0);
- }
-
- protected List<EventMetricData> backfillAggregatedAtomsInEventMetric(
- EventMetricData metricData) {
- if (!metricData.hasAggregatedAtomInfo()) {
- return Collections.singletonList(metricData);
- }
- List<EventMetricData> data = new ArrayList<>();
- StatsLog.AggregatedAtomInfo atomInfo = metricData.getAggregatedAtomInfo();
- for (long timestamp : atomInfo.getElapsedTimestampNanosList()) {
- data.add(EventMetricData.newBuilder()
- .setAtom(atomInfo.getAtom())
- .setElapsedTimestampNanos(timestamp)
- .build());
- }
- return data;
- }
-}
diff --git a/tests/src/android/cts/statsd/atom/BaseTestCase.java b/tests/src/android/cts/statsd/atom/BaseTestCase.java
deleted file mode 100644
index 0c9921e..0000000
--- a/tests/src/android/cts/statsd/atom/BaseTestCase.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2016 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.atom;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.cts.statsd.validation.ValidationTestUtil;
-
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
-import com.android.ddmlib.testrunner.TestResult.TestStatus;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.CollectingByteOutputReceiver;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.result.CollectingTestListener;
-import com.android.tradefed.result.TestDescription;
-import com.android.tradefed.result.TestResult;
-import com.android.tradefed.result.TestRunResult;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protobuf.MessageLite;
-import com.google.protobuf.Parser;
-
-import java.io.FileNotFoundException;
-import java.util.Map;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-// Largely copied from incident's ProtoDumpTestCase
-public class BaseTestCase extends DeviceTestCase implements IBuildReceiver {
-
- protected IBuildInfo mCtsBuild;
-
- private static final String TEST_RUNNER = "androidx.test.runner.AndroidJUnitRunner";
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- assertThat(mCtsBuild).isNotNull();
- }
-
- @Override
- public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = buildInfo;
- }
-
- public IBuildInfo getBuild() {
- return mCtsBuild;
- }
-
- /**
- * Create and return {@link ValidationTestUtil} and give it the current build.
- */
- public ValidationTestUtil createValidationUtil() {
- ValidationTestUtil util = new ValidationTestUtil();
- util.setBuild(getBuild());
- return util;
- }
-
- /**
- * Call onto the device with an adb shell command and get the results of
- * that as a proto of the given type.
- *
- * @param parser A protobuf parser object. e.g. MyProto.parser()
- * @param command The adb shell command to run. e.g. "dumpsys fingerprint --proto"
- *
- * @throws DeviceNotAvailableException If there was a problem communicating with
- * the test device.
- * @throws InvalidProtocolBufferException If there was an error parsing
- * the proto. Note that a 0 length buffer is not necessarily an error.
- */
- public <T extends MessageLite> T getDump(Parser<T> parser, String command)
- throws DeviceNotAvailableException, InvalidProtocolBufferException {
- final CollectingByteOutputReceiver receiver = new CollectingByteOutputReceiver();
- getDevice().executeShellCommand(command, receiver);
- if (false) {
- CLog.d("Command output while parsing " + parser.getClass().getCanonicalName()
- + " for command: " + command + "\n"
- + BufferDebug.debugString(receiver.getOutput(), -1));
- }
- try {
- return parser.parseFrom(receiver.getOutput());
- } catch (Exception ex) {
- CLog.d("Error parsing " + parser.getClass().getCanonicalName() + " for command: "
- + command
- + BufferDebug.debugString(receiver.getOutput(), 16384));
- throw ex;
- }
- }
-
- /**
- * Install a device side test package.
- *
- * @param appFileName Apk file name, such as "CtsNetStatsApp.apk".
- * @param grantPermissions whether to give runtime permissions.
- */
- protected void installPackage(String appFileName, boolean grantPermissions)
- throws FileNotFoundException, DeviceNotAvailableException {
- CLog.d("Installing app " + appFileName);
- CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
- final String result = getDevice().installPackage(
- buildHelper.getTestFile(appFileName), true, grantPermissions);
- assertWithMessage(String.format("Failed to install %s: %s", appFileName, result))
- .that(result).isNull();
- }
-
- protected CompatibilityBuildHelper getBuildHelper() {
- return new CompatibilityBuildHelper(mCtsBuild);
- }
-
- /**
- * Run a device side test.
- *
- * @param pkgName Test package name, such as "com.android.server.cts.netstats".
- * @param testClassName Test class name; either a fully qualified name, or "." + a class name.
- * @param testMethodName Test method name.
- * @return {@link TestRunResult} of this invocation.
- * @throws DeviceNotAvailableException
- */
- @Nonnull
- protected TestRunResult runDeviceTests(@Nonnull String pkgName,
- @Nullable String testClassName, @Nullable String testMethodName)
- throws DeviceNotAvailableException {
- if (testClassName != null && testClassName.startsWith(".")) {
- testClassName = pkgName + testClassName;
- }
-
- RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
- pkgName, TEST_RUNNER, getDevice().getIDevice());
- if (testClassName != null && testMethodName != null) {
- testRunner.setMethodName(testClassName, testMethodName);
- } else if (testClassName != null) {
- testRunner.setClassName(testClassName);
- }
-
- CollectingTestListener listener = new CollectingTestListener();
- assertThat(getDevice().runInstrumentationTests(testRunner, listener)).isTrue();
-
- final TestRunResult result = listener.getCurrentRunResults();
- if (result.isRunFailure()) {
- throw new Error("Failed to successfully run device tests for "
- + result.getName() + ": " + result.getRunFailureMessage());
- }
- if (result.getNumTests() == 0) {
- throw new Error("No tests were run on the device");
- }
-
- if (result.hasFailedTests()) {
- // build a meaningful error message
- StringBuilder errorBuilder = new StringBuilder("On-device tests failed:\n");
- for (Map.Entry<TestDescription, TestResult> resultEntry :
- result.getTestResults().entrySet()) {
- if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) {
- errorBuilder.append(resultEntry.getKey().toString());
- errorBuilder.append(":\n");
- errorBuilder.append(resultEntry.getValue().getStackTrace());
- }
- }
- throw new AssertionError(errorBuilder.toString());
- }
-
- return result;
- }
-}
diff --git a/tests/src/android/cts/statsd/atom/DeviceAtomTestCase.java b/tests/src/android/cts/statsd/atom/DeviceAtomTestCase.java
deleted file mode 100644
index d641ebc..0000000
--- a/tests/src/android/cts/statsd/atom/DeviceAtomTestCase.java
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (C) 2017 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.atom;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
-import com.android.internal.os.StatsdConfigProto.MessageMatcher;
-import com.android.internal.os.StatsdConfigProto.Position;
-import com.android.internal.os.StatsdConfigProto.StatsdConfig;
-import com.android.os.StatsLog.EventMetricData;
-import com.android.tradefed.log.LogUtil;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Base class for testing Statsd atoms that report a uid. Tests are performed via a device-side app.
- */
-public class DeviceAtomTestCase extends AtomTestCase {
-
- public static final String DEVICE_SIDE_TEST_APK = "CtsStatsdApp.apk";
- public static final String DEVICE_SIDE_TEST_PACKAGE =
- "com.android.server.cts.device.statsd";
- public static final long DEVICE_SIDE_TEST_PACKAGE_VERSION = 10;
- public static final String DEVICE_SIDE_TEST_FOREGROUND_SERVICE_NAME =
- "com.android.server.cts.device.statsd.StatsdCtsForegroundService";
- private static final String DEVICE_SIDE_BG_SERVICE_COMPONENT =
- "com.android.server.cts.device.statsd/.StatsdCtsBackgroundService";
- public static final long DEVICE_SIDE_TEST_PKG_HASH =
- Long.parseUnsignedLong("15694052924544098582");
-
- // Constants from device side tests (not directly accessible here).
- public static final String KEY_ACTION = "action";
- public static final String ACTION_LMK = "action.lmk";
-
- public static final String CONFIG_NAME = "cts_config";
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE);
- installTestApp();
- Thread.sleep(1000);
- }
-
- @Override
- protected void tearDown() throws Exception {
- getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE);
- super.tearDown();
- }
-
- /**
- * Performs a device-side test by calling a method on the app and returns its stats events.
- * @param methodName the name of the method in the app's AtomTests to perform
- * @param atom atom tag (from atoms.proto)
- * @param key atom's field corresponding to state
- * @param stateOn 'on' value
- * @param stateOff 'off' value
- * @param minTimeDiffMs max allowed time between start and stop
- * @param maxTimeDiffMs min allowed time between start and stop
- * @param demandExactlyTwo whether there must be precisely two events logged (1 start, 1 stop)
- * @return list of events with the app's uid matching the configuration defined by the params.
- */
- protected List<EventMetricData> doDeviceMethodOnOff(
- String methodName, int atom, int key, int stateOn, int stateOff,
- int minTimeDiffMs, int maxTimeDiffMs, boolean demandExactlyTwo) throws Exception {
- StatsdConfig.Builder conf = createConfigBuilder();
- addAtomEvent(conf, atom, createFvm(key).setEqInt(stateOn));
- addAtomEvent(conf, atom, createFvm(key).setEqInt(stateOff));
- List<EventMetricData> data = doDeviceMethod(methodName, conf);
-
- if (demandExactlyTwo) {
- assertThat(data).hasSize(2);
- } else {
- assertThat(data.size()).isAtLeast(2);
- }
- assertTimeDiffBetween(data.get(0), data.get(1), minTimeDiffMs, maxTimeDiffMs);
- return data;
- }
-
- /**
- *
- * @param methodName the name of the method in the app's AtomTests to perform
- * @param cfg statsd configuration
- * @return list of events with the app's uid matching the configuration.
- */
- protected List<EventMetricData> doDeviceMethod(String methodName, StatsdConfig.Builder cfg)
- throws Exception {
- removeConfig(CONFIG_ID);
- getReportList(); // Clears previous data on disk.
- uploadConfig(cfg);
- int appUid = getUid();
- LogUtil.CLog.d("\nPerforming device-side test of " + methodName + " for uid " + appUid);
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", methodName);
-
- return getEventMetricDataList();
- }
-
- protected void createAndUploadConfig(int atomTag, boolean useAttribution) throws Exception {
- StatsdConfig.Builder conf = createConfigBuilder();
- addAtomEvent(conf, atomTag, useAttribution);
- uploadConfig(conf);
- }
-
- /**
- * Adds an event to the config for an atom that matches the given key AND has the app's uid.
- * @param conf configuration
- * @param atomTag atom tag (from atoms.proto)
- * @param fvm FieldValueMatcher.Builder for the relevant key
- */
- @Override
- protected void addAtomEvent(StatsdConfig.Builder conf, int atomTag, FieldValueMatcher.Builder fvm)
- throws Exception {
-
- final int UID_KEY = 1;
- FieldValueMatcher.Builder fvmUid = createAttributionFvm(UID_KEY);
- addAtomEvent(conf, atomTag, Arrays.asList(fvm, fvmUid));
- }
-
- /**
- * Adds an event to the config for an atom that matches the app's uid.
- * @param conf configuration
- * @param atomTag atom tag (from atoms.proto)
- * @param useAttribution If true, the atom has a uid within an attribution node. Else, the atom
- * has a uid but not in an attribution node.
- */
- protected void addAtomEvent(StatsdConfig.Builder conf, int atomTag,
- boolean useAttribution) throws Exception {
- final int UID_KEY = 1;
- FieldValueMatcher.Builder fvmUid;
- if (useAttribution) {
- fvmUid = createAttributionFvm(UID_KEY);
- } else {
- fvmUid = createFvm(UID_KEY).setEqString(DEVICE_SIDE_TEST_PACKAGE);
- }
- addAtomEvent(conf, atomTag, Arrays.asList(fvmUid));
- }
-
- /**
- * Creates a FieldValueMatcher for atoms that use AttributionNode
- */
- protected FieldValueMatcher.Builder createAttributionFvm(int field) {
- final int ATTRIBUTION_NODE_UID_KEY = 1;
- return createFvm(field).setPosition(Position.ANY)
- .setMatchesTuple(MessageMatcher.newBuilder()
- .addFieldValueMatcher(createFvm(ATTRIBUTION_NODE_UID_KEY)
- .setEqString(DEVICE_SIDE_TEST_PACKAGE)));
- }
-
- /**
- * Gets the uid of the test app.
- */
- protected int getUid() throws Exception {
- int currentUser = getDevice().getCurrentUser();
- final String packages = getDevice().executeShellCommand("cmd package list packages -U"
- + " --user " + currentUser + " " + DEVICE_SIDE_TEST_PACKAGE);
-
- // Split package list by lines
- // Sample packages response:
- // package:com.android.server.cts.device.statsd.host uid:1010033
- // package:com.android.server.cts.device.statsd uid:1010034
- final String[] lines = packages.split("[\\r\\n]+");
- for (final String line : lines) {
- if (line.startsWith("package:" + DEVICE_SIDE_TEST_PACKAGE + " ")) {
- final int uidIndex = line.lastIndexOf(":") + 1;
- final int uid = Integer.parseInt(line.substring(uidIndex).trim());
- assertThat(uid).isGreaterThan(10_000);
- return uid;
- }
- }
- throw new Error(
- String.format("Could not find installed package: %s", DEVICE_SIDE_TEST_PACKAGE));
- }
-
- /**
- * Installs the test apk.
- */
- protected void installTestApp() throws Exception {
- installPackage(DEVICE_SIDE_TEST_APK, true);
- LogUtil.CLog.i("Installing device-side test app with uid " + getUid());
- allowBackgroundServices();
- }
-
- /**
- * Uninstalls the test apk.
- */
- protected void uninstallPackage() throws Exception{
- getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE);
- }
-
- /**
- * Required to successfully start a background service from adb in Android O.
- */
- protected void allowBackgroundServices() throws Exception {
- getDevice().executeShellCommand(String.format(
- "cmd deviceidle tempwhitelist %s", DEVICE_SIDE_TEST_PACKAGE));
- }
-
- /**
- * Runs a (background) service to perform the given action.
- * @param actionValue the action code constants indicating the desired action to perform.
- */
- protected void executeBackgroundService(String actionValue) throws Exception {
- allowBackgroundServices();
- getDevice().executeShellCommand(String.format(
- "am startservice -n '%s' -e %s %s",
- DEVICE_SIDE_BG_SERVICE_COMPONENT,
- KEY_ACTION, actionValue));
- }
-
-
- /** Make the test app standby-active so it can run syncs and jobs immediately. */
- protected void allowImmediateSyncs() throws Exception {
- getDevice().executeShellCommand("am set-standby-bucket "
- + DEVICE_SIDE_TEST_PACKAGE + " active");
- }
-
- /**
- * Runs the specified activity.
- */
- protected void runActivity(String activity, String actionKey, String actionValue)
- throws Exception {
- runActivity(activity, actionKey, actionValue, WAIT_TIME_LONG);
- }
-
- /**
- * Runs the specified activity.
- */
- protected void runActivity(String activity, String actionKey, String actionValue,
- long waitTime) throws Exception {
- try (AutoCloseable a = withActivity(activity, actionKey, actionValue)) {
- Thread.sleep(waitTime);
- }
- }
-
- /**
- * Starts the specified activity and returns an {@link AutoCloseable} that stops the activity
- * when closed.
- *
- * <p>Example usage:
- * <pre>
- * try (AutoClosable a = withActivity("activity", "action", "action-value")) {
- * doStuff();
- * }
- * </pre>
- */
- protected AutoCloseable withActivity(String activity, String actionKey, String actionValue)
- throws Exception {
- String intentString = null;
- if (actionKey != null && actionValue != null) {
- intentString = actionKey + " " + actionValue;
- }
- if (intentString == null) {
- getDevice().executeShellCommand(
- "am start -n " + DEVICE_SIDE_TEST_PACKAGE + "/." + activity);
- } else {
- getDevice().executeShellCommand(
- "am start -n " + DEVICE_SIDE_TEST_PACKAGE + "/." + activity + " -e " +
- intentString);
- }
- return () -> {
- getDevice().executeShellCommand(
- "am force-stop " + DEVICE_SIDE_TEST_PACKAGE);
- Thread.sleep(WAIT_TIME_SHORT);
- };
- }
-
- protected void resetBatteryStats() throws Exception {
- getDevice().executeShellCommand("dumpsys batterystats --reset");
- }
-
- protected void clearProcStats() throws Exception {
- getDevice().executeShellCommand("dumpsys procstats --clear");
- }
-
- protected void startProcStatsTesting() throws Exception {
- getDevice().executeShellCommand("dumpsys procstats --start-testing");
- }
-
- protected void stopProcStatsTesting() throws Exception {
- getDevice().executeShellCommand("dumpsys procstats --stop-testing");
- }
-
- protected void commitProcStatsToDisk() throws Exception {
- getDevice().executeShellCommand("dumpsys procstats --commit");
- }
-
- protected void rebootDeviceAndWaitUntilReady() throws Exception {
- rebootDevice();
- // Wait for 5 mins.
- assertWithMessage("Device failed to boot")
- .that(getDevice().waitForBootComplete(300_000)).isTrue();
- assertWithMessage("Stats service failed to start")
- .that(waitForStatsServiceStart(60_000)).isTrue();
- Thread.sleep(2_000);
- }
-
- protected boolean waitForStatsServiceStart(final long waitTime) throws Exception {
- LogUtil.CLog.i("Waiting %d ms for stats service to start", waitTime);
- int counter = 1;
- long startTime = System.currentTimeMillis();
- while ((System.currentTimeMillis() - startTime) < waitTime) {
- if ("running".equals(getProperty("init.svc.statsd"))) {
- return true;
- }
- Thread.sleep(Math.min(200 * counter, 2_000));
- counter++;
- }
- LogUtil.CLog.w("Stats service did not start after %d ms", waitTime);
- return false;
- }
-
- boolean getNetworkStatsCombinedSubTypeEnabled() throws Exception {
- final String output = getDevice().executeShellCommand(
- "settings get global netstats_combine_subtype_enabled").trim();
- return output.equals("1");
- }
-
- void setNetworkStatsCombinedSubTypeEnabled(boolean enable) throws Exception {
- getDevice().executeShellCommand("settings put global netstats_combine_subtype_enabled "
- + (enable ? "1" : "0"));
- }
-}
diff --git a/tests/src/android/cts/statsd/atom/ProcStateTestCase.java b/tests/src/android/cts/statsd/atom/ProcStateTestCase.java
index 2fa4233..09c508b 100644
--- a/tests/src/android/cts/statsd/atom/ProcStateTestCase.java
+++ b/tests/src/android/cts/statsd/atom/ProcStateTestCase.java
@@ -15,10 +15,20 @@
*/
package android.cts.statsd.atom;
+import static com.google.common.truth.Truth.assertThat;
+
import android.app.ProcessStateEnum; // From enums.proto for atoms.proto's UidProcessStateChanged.
+import android.cts.statsd.metric.MetricsUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
import com.android.os.AtomsProto.Atom;
import com.android.os.StatsLog.EventMetricData;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.RunUtil;
import java.util.Arrays;
import java.util.HashSet;
@@ -31,46 +41,74 @@
/**
* Base class for manipulating process states
*/
-public class ProcStateTestCase extends DeviceAtomTestCase {
+public class ProcStateTestCase extends DeviceTestCase implements IBuildReceiver {
- private static final String TAG = "Statsd.ProcStateTestCase";
+ private static final String TAG = "Statsd.ProcStateTestCase";
- private static final String DEVICE_SIDE_FG_ACTIVITY_COMPONENT
- = "com.android.server.cts.device.statsd/.StatsdCtsForegroundActivity";
- private static final String DEVICE_SIDE_FG_SERVICE_COMPONENT
- = "com.android.server.cts.device.statsd/.StatsdCtsForegroundService";
+ private static final String DEVICE_SIDE_FG_ACTIVITY_COMPONENT
+ = "com.android.server.cts.device.statsd/.StatsdCtsForegroundActivity";
+ private static final String DEVICE_SIDE_FG_SERVICE_COMPONENT
+ = "com.android.server.cts.device.statsd/.StatsdCtsForegroundService";
- // Constants from the device-side tests (not directly accessible here).
- public static final String ACTION_END_IMMEDIATELY = "action.end_immediately";
- public static final String ACTION_BACKGROUND_SLEEP = "action.background_sleep";
- public static final String ACTION_SLEEP_WHILE_TOP = "action.sleep_top";
- public static final String ACTION_LONG_SLEEP_WHILE_TOP = "action.long_sleep_top";
- public static final String ACTION_SHOW_APPLICATION_OVERLAY = "action.show_application_overlay";
+ private static final String KEY_ACTION = "action";
- // Sleep times (ms) that actions invoke device-side.
- public static final int SLEEP_OF_ACTION_SLEEP_WHILE_TOP = 2_000;
- public static final int SLEEP_OF_ACTION_LONG_SLEEP_WHILE_TOP = 60_000;
- public static final int SLEEP_OF_ACTION_BACKGROUND_SLEEP = 2_000;
- public static final int SLEEP_OF_FOREGROUND_SERVICE = 2_000;
+ // Constants from the device-side tests (not directly accessible here).
+ public static final String ACTION_END_IMMEDIATELY = "action.end_immediately";
+ public static final String ACTION_BACKGROUND_SLEEP = "action.background_sleep";
+ public static final String ACTION_SLEEP_WHILE_TOP = "action.sleep_top";
+ public static final String ACTION_LONG_SLEEP_WHILE_TOP = "action.long_sleep_top";
+ public static final String ACTION_SHOW_APPLICATION_OVERLAY = "action.show_application_overlay";
+ // Sleep times (ms) that actions invoke device-side.
+ public static final int SLEEP_OF_ACTION_SLEEP_WHILE_TOP = 2_000;
+ public static final int SLEEP_OF_ACTION_LONG_SLEEP_WHILE_TOP = 60_000;
+ public static final int SLEEP_OF_ACTION_BACKGROUND_SLEEP = 2_000;
+ public static final int SLEEP_OF_FOREGROUND_SERVICE = 2_000;
- /**
- * Runs an activity (in the foreground) to perform the given action.
- * @param actionValue the action code constants indicating the desired action to perform.
- */
- protected void executeForegroundActivity(String actionValue) throws Exception {
- getDevice().executeShellCommand(String.format(
- "am start -n '%s' -e %s %s",
- DEVICE_SIDE_FG_ACTIVITY_COMPONENT,
- KEY_ACTION, actionValue));
- }
+ protected IBuildInfo mCtsBuild;
- /**
- * Runs a simple foreground service.
- */
- protected void executeForegroundService() throws Exception {
- executeForegroundActivity(ACTION_END_IMMEDIATELY);
- getDevice().executeShellCommand(String.format(
- "am startservice -n '%s'", DEVICE_SIDE_FG_SERVICE_COMPONENT));
- }
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ assertThat(mCtsBuild).isNotNull();
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ DeviceUtils.installTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_APK,
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, mCtsBuild);
+ RunUtil.getDefault().sleep(1000);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ DeviceUtils.uninstallTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ super.tearDown();
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
+ }
+
+ /**
+ * Runs an activity (in the foreground) to perform the given action.
+ *
+ * @param actionValue the action code constants indicating the desired action to perform.
+ */
+ protected void executeForegroundActivity(String actionValue) throws Exception {
+ getDevice().executeShellCommand(String.format(
+ "am start -n '%s' -e %s %s",
+ DEVICE_SIDE_FG_ACTIVITY_COMPONENT,
+ KEY_ACTION, actionValue));
+ }
+
+ /**
+ * Runs a simple foreground service.
+ */
+ protected void executeForegroundService() throws Exception {
+ executeForegroundActivity(ACTION_END_IMMEDIATELY);
+ getDevice().executeShellCommand(String.format(
+ "am startservice -n '%s'", DEVICE_SIDE_FG_SERVICE_COMPONENT));
+ }
}
diff --git a/tests/src/android/cts/statsd/metadata/MetadataTestCase.java b/tests/src/android/cts/statsd/metadata/MetadataTestCase.java
index ca50270..1f0e5a1 100644
--- a/tests/src/android/cts/statsd/metadata/MetadataTestCase.java
+++ b/tests/src/android/cts/statsd/metadata/MetadataTestCase.java
@@ -16,22 +16,37 @@
package android.cts.statsd.metadata;
-import android.cts.statsd.atom.AtomTestCase;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.cts.statsd.atom.BufferDebug;
+import android.cts.statsd.metric.MetricsUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
import com.android.internal.os.StatsdConfigProto.StatsdConfig;
import com.android.os.AtomsProto.Atom;
import com.android.os.StatsLog.StatsdStatsReport;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.CollectingByteOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.RunUtil;
-public class MetadataTestCase extends AtomTestCase {
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.MessageLite;
+import com.google.protobuf.Parser;
+
+public class MetadataTestCase extends DeviceTestCase implements IBuildReceiver {
public static final String DUMP_METADATA_CMD = "cmd stats print-stats";
- public static final String DEVICE_SIDE_TEST_APK = "CtsStatsdApp.apk";
- public static final String DEVICE_SIDE_TEST_PACKAGE = "com.android.server.cts.device.statsd";
+ protected IBuildInfo mCtsBuild;
protected StatsdStatsReport getStatsdStatsReport() throws Exception {
try {
- StatsdStatsReport report = getDump(StatsdStatsReport.parser(),
+ StatsdStatsReport report = MetricsUtils.getDump(getDevice(), StatsdStatsReport.parser(),
String.join(" ", DUMP_METADATA_CMD, "--proto"));
return report;
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -41,16 +56,33 @@
}
protected final StatsdConfig.Builder getBaseConfig() throws Exception {
- StatsdConfig.Builder builder = createConfigBuilder();
- addAtomEvent(builder, Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER);
- return builder;
+ StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ ConfigUtils.addEventMetric(builder, Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER);
+ return builder;
}
@Override
protected void setUp() throws Exception {
super.setUp();
- getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE);
- installPackage(DEVICE_SIDE_TEST_APK, true);
- Thread.sleep(1000);
+ assertThat(mCtsBuild).isNotNull();
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ DeviceUtils.installTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_APK,
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, mCtsBuild);
+ RunUtil.getDefault().sleep(1000);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ DeviceUtils.uninstallTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ super.tearDown();
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
}
}
diff --git a/tests/src/android/cts/statsd/metadata/MetadataTests.java b/tests/src/android/cts/statsd/metadata/MetadataTests.java
index 4b6433e..1f498f9 100644
--- a/tests/src/android/cts/statsd/metadata/MetadataTests.java
+++ b/tests/src/android/cts/statsd/metadata/MetadataTests.java
@@ -18,16 +18,23 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import android.cts.statsd.metric.MetricsUtils;
+import android.cts.statsdatom.lib.AtomTestUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+
import com.android.compatibility.common.util.ApiLevelUtil;
import com.android.internal.os.StatsdConfigProto.StatsdConfig;
+import com.android.os.AtomsProto;
import com.android.os.AtomsProto.Atom;
import com.android.os.StatsLog.StatsdStatsReport;
import com.android.os.StatsLog.StatsdStatsReport.ConfigStats;
import com.android.os.StatsLog.StatsdStatsReport.LogLossStats;
-import com.android.os.StatsLog.StatsdStatsReport.SocketLossStats;
import com.android.os.StatsLog.StatsdStatsReport.SocketLossStats.LossStatsPerUid;
import com.android.os.StatsLog.StatsdStatsReport.SocketLossStats.LossStatsPerUid.AtomIdLossStats;
import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.util.RunUtil;
+
import java.util.HashSet;
/**
@@ -37,24 +44,28 @@
private static final String TAG = "Statsd.MetadataTests";
+ private static final int SHELL_UID = 2000;
+
// Tests that the statsd config is reset after the specified ttl.
public void testConfigTtl() throws Exception {
final int TTL_TIME_SEC = 8;
StatsdConfig.Builder config = getBaseConfig();
config.setTtlInSeconds(TTL_TIME_SEC); // should reset in this many seconds.
- uploadConfig(config);
+ ConfigUtils.uploadConfig(getDevice(), config);
long startTime = System.currentTimeMillis();
- Thread.sleep(WAIT_TIME_SHORT);
- doAppBreadcrumbReportedStart(/* irrelevant val */ 6); // Event, within < TTL_TIME_SEC secs.
- Thread.sleep(WAIT_TIME_SHORT);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AtomsProto.AppBreadcrumbReported.State.START.getNumber(), /* irrelevant val */
+ 6); // Event, within < TTL_TIME_SEC secs.
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT);
StatsdStatsReport report = getStatsdStatsReport(); // Has only been 1 second
LogUtil.CLog.d("got following statsdstats report: " + report.toString());
boolean foundActiveConfig = false;
int creationTime = 0;
- for (ConfigStats stats: report.getConfigStatsList()) {
- if (stats.getId() == CONFIG_ID && stats.getUid() == getHostUid()) {
- if(!stats.hasDeletionTimeSec()) {
+ for (ConfigStats stats : report.getConfigStatsList()) {
+ if (stats.getId() == ConfigUtils.CONFIG_ID && stats.getUid() == SHELL_UID) {
+ if (!stats.hasDeletionTimeSec()) {
assertWithMessage("Found multiple active CTS configs!")
.that(foundActiveConfig).isFalse();
foundActiveConfig = true;
@@ -64,17 +75,19 @@
}
assertWithMessage("Did not find an active CTS config").that(foundActiveConfig).isTrue();
- while(System.currentTimeMillis() - startTime < 8_000) {
- Thread.sleep(10);
+ while (System.currentTimeMillis() - startTime < 8_000) {
+ RunUtil.getDefault().sleep(10);
}
- doAppBreadcrumbReportedStart(/* irrelevant val */ 6); // Event, after TTL_TIME_SEC secs.
- Thread.sleep(WAIT_TIME_LONG);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AtomsProto.AppBreadcrumbReported.State.START.getNumber(), /* irrelevant val */
+ 6); // Event, after TTL_TIME_SEC secs.
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT);
report = getStatsdStatsReport();
LogUtil.CLog.d("got following statsdstats report: " + report.toString());
foundActiveConfig = false;
int expectedTime = creationTime + TTL_TIME_SEC;
- for (ConfigStats stats: report.getConfigStatsList()) {
- if (stats.getId() == CONFIG_ID && stats.getUid() == getHostUid()) {
+ for (ConfigStats stats : report.getConfigStatsList()) {
+ if (stats.getId() == ConfigUtils.CONFIG_ID && stats.getUid() == SHELL_UID) {
// Original config should be TTL'd
if (stats.getCreationTimeSec() == creationTime) {
assertWithMessage("Config should have TTL'd but is still active")
@@ -84,7 +97,7 @@
).that(Math.abs(stats.getDeletionTimeSec() - expectedTime)).isAtMost(2);
}
// There should still be one active config, that is marked as reset.
- if(!stats.hasDeletionTimeSec()) {
+ if (!stats.hasDeletionTimeSec()) {
assertWithMessage("Found multiple active CTS configs!")
.that(foundActiveConfig).isFalse();
foundActiveConfig = true;
@@ -108,7 +121,8 @@
/** Tests that logging many atoms back to back leads to socket overflow and data loss. */
public void testAtomLossInfoCollection() throws Exception {
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".StatsdStressLogging", "testLogAtomsBackToBack");
+ DeviceUtils.runDeviceTests(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE,
+ ".StatsdStressLogging", "testLogAtomsBackToBack");
StatsdStatsReport report = getStatsdStatsReport();
assertThat(report).isNotNull();
@@ -134,11 +148,12 @@
for (int i = 0; i < EVENT_STORM_ITERATIONS_COUNT; i++) {
LogUtil.CLog.d("testSystemServerLossErrorCode iteration #" + i);
// logging back to back many atoms to force socket overflow
- runDeviceTests(
- DEVICE_SIDE_TEST_PACKAGE, ".StatsdStressLogging", "testLogAtomsBackToBack");
+ DeviceUtils.runDeviceTests(
+ getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, ".StatsdStressLogging",
+ "testLogAtomsBackToBack");
// Delay to allow statsd socket recover after overflow
- Thread.sleep(500);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT);
// There is some un-deterministic component in AtomLossStats propagation:
// - the dumpAtomsLossStats() from the libstatssocket happens ONLY after the
@@ -146,10 +161,12 @@
// - to avoid socket flood there is also cooldown timer incorporated. If no new atoms -
// loss info will not be propagated, which is intention by design.
// Log atoms into socket successfully to trigger libstatsocket dumpAtomsLossStats()
- doAppBreadcrumbReportedStart(6);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AtomsProto.AppBreadcrumbReported.State.START.getNumber(), /* irrelevant val */
+ 6); // Event, after TTL_TIME_SEC secs.
// Delay to allow libstatssocket loss info to be propagated to statsdstats
- Thread.sleep(1000);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
StatsdStatsReport report = getStatsdStatsReport();
assertThat(report).isNotNull();
@@ -198,15 +215,16 @@
final String appTestPkg = "com.android.statsd.app.atomstorm";
final String app2TestPkg = "com.android.statsd.app.atomstorm.copy";
- getDevice().uninstallPackage(appTestPkg);
- getDevice().uninstallPackage(app2TestPkg);
- installPackage(appTestApk, true);
- installPackage(app2TestApk, true);
+ DeviceUtils.uninstallTestApp(getDevice(), appTestPkg);
+ DeviceUtils.uninstallTestApp(getDevice(), app2TestPkg);
+
+ DeviceUtils.installTestApp(getDevice(), appTestApk, appTestPkg, mCtsBuild);
+ DeviceUtils.installTestApp(getDevice(), app2TestApk, app2TestPkg, mCtsBuild);
// run reference test app with UID 1
- runDeviceTests(appTestPkg, null, null);
+ DeviceUtils.runDeviceTests(getDevice(), appTestPkg, null, null);
// run reference test app with UID 2
- runDeviceTests(app2TestPkg, null, null);
+ DeviceUtils.runDeviceTests(getDevice(), app2TestPkg, null, null);
StatsdStatsReport report = getStatsdStatsReport();
assertThat(report).isNotNull();
diff --git a/tests/src/android/cts/statsd/metric/CountMetricsTests.java b/tests/src/android/cts/statsd/metric/CountMetricsTests.java
index f65c48e..8e9b5a3 100644
--- a/tests/src/android/cts/statsd/metric/CountMetricsTests.java
+++ b/tests/src/android/cts/statsd/metric/CountMetricsTests.java
@@ -18,48 +18,83 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-import android.cts.statsd.atom.DeviceAtomTestCase;
+import android.cts.statsdatom.lib.AtomTestUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
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.BleScanStateChanged;
import com.android.os.AtomsProto.WakelockStateChanged;
import com.android.os.AttributionNode;
-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.build.IBuildInfo;
import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.RunUtil;
-import java.util.Arrays;
+import com.google.protobuf.ExtensionRegistry;
+
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
-public class CountMetricsTests extends DeviceAtomTestCase {
+public class CountMetricsTests extends DeviceTestCase implements IBuildReceiver {
+
+ private IBuildInfo mCtsBuild;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ assertThat(mCtsBuild).isNotNull();
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ DeviceUtils.installTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_APK,
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, mCtsBuild);
+ RunUtil.getDefault().sleep(1000);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ DeviceUtils.uninstallTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ super.tearDown();
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
+ }
public void testSimpleEventCountMetric() throws Exception {
int matcherId = 1;
- StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder();
+ StatsdConfigProto.StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
builder.addCountMetric(StatsdConfigProto.CountMetric.newBuilder()
- .setId(MetricsUtils.COUNT_METRIC_ID)
- .setBucket(StatsdConfigProto.TimeUnit.CTS)
- .setWhat(matcherId))
+ .setId(MetricsUtils.COUNT_METRIC_ID)
+ .setBucket(StatsdConfigProto.TimeUnit.ONE_MINUTE)
+ .setWhat(matcherId))
.addAtomMatcher(MetricsUtils.simpleAtomMatcher(matcherId));
- uploadConfig(builder);
+ ConfigUtils.uploadConfig(getDevice(), builder);
- doAppBreadcrumbReportedStart(0);
- Thread.sleep(100);
- doAppBreadcrumbReportedStop(0);
- Thread.sleep(2000); // Wait for the metrics to propagate to statsd.
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 0);
+ RunUtil.getDefault().sleep(100);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 0);
+ RunUtil.getDefault().sleep(2000); // Wait for the metrics to propagate to statsd.
- StatsLogReport metricReport = getStatsLogReport();
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
LogUtil.CLog.d("Got the following stats log report: \n" + metricReport.toString());
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.COUNT_METRIC_ID);
assertThat(metricReport.hasCountMetrics()).isTrue();
@@ -69,6 +104,7 @@
assertThat(countData.getDataCount()).isGreaterThan(0);
assertThat(countData.getData(0).getBucketInfo(0).getCount()).isEqualTo(2);
}
+
public void testEventCountWithCondition() throws Exception {
int startMatcherId = 1;
int endMatcherId = 2;
@@ -76,7 +112,7 @@
int conditionId = 4;
StatsdConfigProto.AtomMatcher whatMatcher =
- MetricsUtils.unspecifiedAtomMatcher(whatMatcherId);
+ MetricsUtils.unspecifiedAtomMatcher(whatMatcherId);
StatsdConfigProto.AtomMatcher predicateStartMatcher =
MetricsUtils.startAtomMatcher(startMatcherId);
@@ -92,7 +128,8 @@
.setId(conditionId)
.build();
- StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder()
+ StatsdConfigProto.StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE)
.addCountMetric(StatsdConfigProto.CountMetric.newBuilder()
.setId(MetricsUtils.COUNT_METRIC_ID)
.setBucket(StatsdConfigProto.TimeUnit.CTS)
@@ -103,20 +140,26 @@
.addAtomMatcher(predicateEndMatcher)
.addPredicate(p);
- uploadConfig(builder);
+ ConfigUtils.uploadConfig(getDevice(), 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.
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 0);
+ RunUtil.getDefault().sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 0);
+ RunUtil.getDefault().sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 0);
+ RunUtil.getDefault().sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 0);
+ RunUtil.getDefault().sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 0);
+ RunUtil.getDefault().sleep(2000); // Wait for the metrics to propagate to statsd.
- StatsLogReport metricReport = getStatsLogReport();
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.COUNT_METRIC_ID);
assertThat(metricReport.hasCountMetrics()).isTrue();
@@ -149,7 +192,7 @@
StatsdConfigProto.AtomMatcher activationMatcher =
MetricsUtils.appBreadcrumbMatcherWithLabel(activationMatcherId,
- activationMatcherLabel);
+ activationMatcherLabel);
StatsdConfigProto.Predicate p = StatsdConfigProto.Predicate.newBuilder()
.setSimplePredicate(StatsdConfigProto.SimplePredicate.newBuilder()
@@ -159,7 +202,8 @@
.setId(conditionId)
.build();
- StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder()
+ StatsdConfigProto.StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE)
.addCountMetric(StatsdConfigProto.CountMetric.newBuilder()
.setId(MetricsUtils.COUNT_METRIC_ID)
.setBucket(StatsdConfigProto.TimeUnit.ONE_MINUTE)
@@ -178,66 +222,79 @@
.setAtomMatcherId(activationMatcherId)
.setTtlSeconds(ttlSec)));
- uploadConfig(builder);
+ ConfigUtils.uploadConfig(getDevice(), builder);
// Activate the metric.
- doAppBreadcrumbReported(activationMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), activationMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Set the condition to true.
- doAppBreadcrumbReportedStart(startMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), startMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Log an event that should be counted. Bucket 1 Count 1.
- doAppBreadcrumbReported(whatMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), whatMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Log an event that should be counted. Bucket 1 Count 2.
- doAppBreadcrumbReported(whatMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), whatMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Set the condition to false.
- doAppBreadcrumbReportedStop(endMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), endMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Log an event that should not be counted because condition is false.
- doAppBreadcrumbReported(whatMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), whatMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Let the metric deactivate.
- Thread.sleep(ttlSec * 1000);
+ RunUtil.getDefault().sleep(ttlSec * 1000);
// Log an event that should not be counted.
- doAppBreadcrumbReported(whatMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), whatMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Condition to true again.
- doAppBreadcrumbReportedStart(startMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), startMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Event should not be counted, metric is still not active.
- doAppBreadcrumbReported(whatMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), whatMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Activate the metric.
- doAppBreadcrumbReported(activationMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), activationMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Log an event that should be counted.
- doAppBreadcrumbReported(whatMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), whatMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Let the metric deactivate.
- Thread.sleep(ttlSec * 1000);
+ RunUtil.getDefault().sleep(ttlSec * 1000);
// Log an event that should not be counted.
- doAppBreadcrumbReported(whatMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), whatMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Wait for the metrics to propagate to statsd.
- Thread.sleep(2000);
+ RunUtil.getDefault().sleep(2000);
- StatsLogReport metricReport = getStatsLogReport();
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.COUNT_METRIC_ID);
LogUtil.CLog.d("Received the following data: " + metricReport.toString());
assertThat(metricReport.hasCountMetrics()).isTrue();
@@ -252,27 +309,30 @@
public void testPartialBucketCountMetric() throws Exception {
int matcherId = 1;
- StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder();
- builder
- .addCountMetric(
- StatsdConfigProto.CountMetric.newBuilder()
- .setId(MetricsUtils.COUNT_METRIC_ID)
- .setBucket(StatsdConfigProto.TimeUnit.ONE_DAY) // Ensures partial bucket.
- .setWhat(matcherId)
- .setSplitBucketForAppUpgrade(true))
- .addAtomMatcher(MetricsUtils.simpleAtomMatcher(matcherId));
- uploadConfig(builder);
+ StatsdConfigProto.StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE)
+ .addCountMetric(StatsdConfigProto.CountMetric.newBuilder()
+ .setId(MetricsUtils.COUNT_METRIC_ID)
+ .setBucket(StatsdConfigProto.TimeUnit.ONE_DAY) // Ensures partial bucket.
+ .setWhat(matcherId)
+ .setSplitBucketForAppUpgrade(true))
+ .addAtomMatcher(MetricsUtils.simpleAtomMatcher(matcherId));
+ ConfigUtils.uploadConfig(getDevice(), builder);
- doAppBreadcrumbReportedStart(0);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 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.
+ ConfigUtils.uploadConfig(getDevice(), builder); // The count metric had a partial bucket.
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 0);
+ RunUtil.getDefault().sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 0);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); // Finish the current bucket.
- ConfigMetricsReportList reports = getReportList();
+ ConfigMetricsReportList reports = ReportUtils.getReportList(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
LogUtil.CLog.d("Got following report list: " + reports.toString());
assertThat(reports.getReportsCount()).isEqualTo(2);
@@ -285,9 +345,9 @@
assertThat(report.getMetrics(0).getCountMetrics().getDataCount()).isEqualTo(1);
}
CountMetricData data1 =
- reports.getReports(inOrder? 0 : 1).getMetrics(0).getCountMetrics().getData(0);
+ reports.getReports(inOrder ? 0 : 1).getMetrics(0).getCountMetrics().getData(0);
CountMetricData data2 =
- reports.getReports(inOrder? 1 : 0).getMetrics(0).getCountMetrics().getData(0);
+ 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);
@@ -326,90 +386,93 @@
.build();
StatsdConfigProto.State state = StatsdConfigProto.State.newBuilder()
- .setId(stateId)
- .setAtomId(Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER)
- .setMap(StatsdConfigProto.StateMap.newBuilder()
- .addGroup(StatsdConfigProto.StateMap.StateGroup.newBuilder()
- .setGroupId(onStateGroupId)
- .addValue(WakelockStateChanged.State.ACQUIRE_VALUE)
- .addValue(WakelockStateChanged.State.CHANGE_ACQUIRE_VALUE)
- )
- .addGroup(StatsdConfigProto.StateMap.StateGroup.newBuilder()
- .setGroupId(offStateGroupId)
- .addValue(WakelockStateChanged.State.RELEASE_VALUE)
- .addValue(WakelockStateChanged.State.CHANGE_RELEASE_VALUE)
- )
- )
- .build();
+ .setId(stateId)
+ .setAtomId(Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER)
+ .setMap(StatsdConfigProto.StateMap.newBuilder()
+ .addGroup(StatsdConfigProto.StateMap.StateGroup.newBuilder()
+ .setGroupId(onStateGroupId)
+ .addValue(WakelockStateChanged.State.ACQUIRE_VALUE)
+ .addValue(WakelockStateChanged.State.CHANGE_ACQUIRE_VALUE)
+ )
+ .addGroup(StatsdConfigProto.StateMap.StateGroup.newBuilder()
+ .setGroupId(offStateGroupId)
+ .addValue(WakelockStateChanged.State.RELEASE_VALUE)
+ .addValue(WakelockStateChanged.State.CHANGE_RELEASE_VALUE)
+ )
+ )
+ .build();
StatsdConfigProto.MetricStateLink stateLink = StatsdConfigProto.MetricStateLink.newBuilder()
- .setStateAtomId(Atom.WAKELOCK_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)
- )
- )
- .setFieldsInState(FieldMatcher.newBuilder()
- .setField(Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER)
- .addChild(FieldMatcher.newBuilder()
- .setField(WakelockStateChanged.ATTRIBUTION_NODE_FIELD_NUMBER)
- .setPosition(Position.FIRST)
- .addChild(FieldMatcher.newBuilder()
- .setField(AttributionNode.UID_FIELD_NUMBER)
- )
- )
- .addChild(FieldMatcher.newBuilder()
- .setField(WakelockStateChanged.TYPE_FIELD_NUMBER)
- )
- .addChild(FieldMatcher.newBuilder()
- .setField(WakelockStateChanged.TAG_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)
- .setDimensionsInWhat(
- 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)
+ .setStateAtomId(Atom.WAKELOCK_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)
+ )
+ )
+ .setFieldsInState(FieldMatcher.newBuilder()
+ .setField(Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER)
+ .addChild(FieldMatcher.newBuilder()
+ .setField(WakelockStateChanged.ATTRIBUTION_NODE_FIELD_NUMBER)
+ .setPosition(Position.FIRST)
+ .addChild(FieldMatcher.newBuilder()
+ .setField(AttributionNode.UID_FIELD_NUMBER)
+ )
+ )
+ .addChild(FieldMatcher.newBuilder()
+ .setField(WakelockStateChanged.TYPE_FIELD_NUMBER)
+ )
+ .addChild(FieldMatcher.newBuilder()
+ .setField(WakelockStateChanged.TAG_FIELD_NUMBER)
+ )
+ )
+ .build();
+
+ StatsdConfigProto.StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE)
+ .addCountMetric(StatsdConfigProto.CountMetric.newBuilder()
+ .setId(MetricsUtils.COUNT_METRIC_ID)
+ .setBucket(StatsdConfigProto.TimeUnit.CTS)
+ .setWhat(whatMatcherId)
+ .addSliceByState(stateId)
+ .addStateLink(stateLink)
+ .setDimensionsInWhat(
+ 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)
+ )
+ )
)
.addAtomMatcher(whatMatcher)
.addState(state);
- uploadConfig(builder);
+ ConfigUtils.uploadConfig(getDevice(), builder);
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSliceByWakelockState");
+ DeviceUtils.runDeviceTests(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, ".AtomTests",
+ "testSliceByWakelockState");
- StatsLogReport metricReport = getStatsLogReport();
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
LogUtil.CLog.d("Got the following stats log report: \n" + metricReport.toString());
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.COUNT_METRIC_ID);
assertThat(metricReport.hasCountMetrics()).isTrue();
@@ -420,10 +483,10 @@
List<CountMetricData> sortedDataList = IntStream.range(0, dataWrapper.getDataCount())
.mapToObj(i -> {
- CountMetricData data = dataWrapper.getData(i);
- assertWithMessage("Unexpected SliceByState count for data[%s]", "" + i)
- .that(data.getSliceByStateCount()).isEqualTo(1);
- return data;
+ CountMetricData data = dataWrapper.getData(i);
+ assertWithMessage("Unexpected SliceByState count for data[%s]", "" + i)
+ .that(data.getSliceByStateCount()).isEqualTo(1);
+ return data;
})
.sorted((data1, data2) ->
Long.compare(data1.getSliceByState(0).getGroupId(),
diff --git a/tests/src/android/cts/statsd/metric/DurationMetricsTests.java b/tests/src/android/cts/statsd/metric/DurationMetricsTests.java
index 65cef95..89c9bbc 100644
--- a/tests/src/android/cts/statsd/metric/DurationMetricsTests.java
+++ b/tests/src/android/cts/statsd/metric/DurationMetricsTests.java
@@ -17,45 +17,62 @@
import static com.google.common.truth.Truth.assertThat;
-import android.cts.statsd.atom.DeviceAtomTestCase;
+import android.cts.statsdatom.lib.AtomTestUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
import com.android.internal.os.StatsdConfigProto;
import com.android.internal.os.StatsdConfigProto.AtomMatcher;
import com.android.internal.os.StatsdConfigProto.FieldMatcher;
-import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
-import com.android.internal.os.StatsdConfigProto.Position;
import com.android.internal.os.StatsdConfigProto.Predicate;
-import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
import com.android.internal.os.StatsdConfigProto.SimplePredicate;
import com.android.os.AtomsProto.AppBreadcrumbReported;
import com.android.os.AtomsProto.Atom;
-import com.android.os.StatsLog.ConfigMetricsReport;
-import com.android.os.StatsLog.ConfigMetricsReportList;
import com.android.os.StatsLog.DurationBucketInfo;
import com.android.os.StatsLog.StatsLogReport;
-import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.util.RunUtil;
import com.google.common.collect.Range;
+import com.google.protobuf.ExtensionRegistry;
-import java.util.List;
-public class DurationMetricsTests extends DeviceAtomTestCase {
+public class DurationMetricsTests extends DeviceTestCase {
private static final int APP_BREADCRUMB_REPORTED_A_MATCH_START_ID = 0;
private static final int APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID = 1;
private static final int APP_BREADCRUMB_REPORTED_B_MATCH_START_ID = 2;
private static final int APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID = 3;
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ RunUtil.getDefault().sleep(1000);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ super.tearDown();
+ }
+
public void testDurationMetric() throws Exception {
final int label = 1;
// Add AtomMatchers.
AtomMatcher startAtomMatcher =
- MetricsUtils.startAtomMatcherWithLabel(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID, label);
+ MetricsUtils.startAtomMatcherWithLabel(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID,
+ label);
AtomMatcher stopAtomMatcher =
- MetricsUtils.stopAtomMatcherWithLabel(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID, label);
+ MetricsUtils.stopAtomMatcherWithLabel(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID,
+ label);
- StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder();
+ StatsdConfigProto.StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
builder.addAtomMatcher(startAtomMatcher);
builder.addAtomMatcher(stopAtomMatcher);
@@ -65,31 +82,33 @@
.setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID)
.build();
Predicate predicate = Predicate.newBuilder()
- .setId(MetricsUtils.StringToId("Predicate"))
- .setSimplePredicate(simplePredicate)
- .build();
+ .setId(MetricsUtils.StringToId("Predicate"))
+ .setSimplePredicate(simplePredicate)
+ .build();
builder.addPredicate(predicate);
// Add DurationMetric.
- builder.addDurationMetric(
- StatsdConfigProto.DurationMetric.newBuilder()
+ builder.addDurationMetric(StatsdConfigProto.DurationMetric.newBuilder()
.setId(MetricsUtils.DURATION_METRIC_ID)
.setWhat(predicate.getId())
.setAggregationType(StatsdConfigProto.DurationMetric.AggregationType.SUM)
.setBucket(StatsdConfigProto.TimeUnit.CTS));
// Upload config.
- uploadConfig(builder);
+ ConfigUtils.uploadConfig(getDevice(), builder);
// Create AppBreadcrumbReported Start/Stop events.
- doAppBreadcrumbReportedStart(label);
- Thread.sleep(2000);
- doAppBreadcrumbReportedStop(label);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), label);
+ RunUtil.getDefault().sleep(2000);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), label);
// Wait for the metrics to propagate to statsd.
- Thread.sleep(2000);
+ RunUtil.getDefault().sleep(2000);
- StatsLogReport metricReport = getStatsLogReport();
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.DURATION_METRIC_ID);
LogUtil.CLog.d("Received the following data: " + metricReport.toString());
assertThat(metricReport.hasDurationMetrics()).isTrue();
@@ -97,7 +116,7 @@
= metricReport.getDurationMetrics();
assertThat(durationData.getDataCount()).isEqualTo(1);
assertThat(durationData.getData(0).getBucketInfo(0).getDurationNanos())
- .isIn(Range.open(0L, (long)1e9));
+ .isIn(Range.open(0L, (long) 1e9));
}
public void testDurationMetricWithCondition() throws Exception {
@@ -114,7 +133,8 @@
AtomMatcher conditionStopAtomMatcher = MetricsUtils.stopAtomMatcherWithLabel(
APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID, conditionLabel);
- StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder()
+ StatsdConfigProto.StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ DeviceUtils.STATSD_ATOM_TEST_PKG)
.addAtomMatcher(startAtomMatcher)
.addAtomMatcher(stopAtomMatcher)
.addAtomMatcher(conditionStartAtomMatcher)
@@ -126,76 +146,82 @@
.setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID)
.build();
Predicate predicate = Predicate.newBuilder()
- .setId(MetricsUtils.StringToId("Predicate"))
- .setSimplePredicate(simplePredicate)
- .build();
+ .setId(MetricsUtils.StringToId("Predicate"))
+ .setSimplePredicate(simplePredicate)
+ .build();
SimplePredicate conditionSimplePredicate = SimplePredicate.newBuilder()
.setStart(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
.setStop(APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID)
.build();
Predicate conditionPredicate = Predicate.newBuilder()
- .setId(MetricsUtils.StringToId("ConditionPredicate"))
- .setSimplePredicate(conditionSimplePredicate)
- .build();
+ .setId(MetricsUtils.StringToId("ConditionPredicate"))
+ .setSimplePredicate(conditionSimplePredicate)
+ .build();
- builder
- .addPredicate(predicate)
- .addPredicate(conditionPredicate);
+ builder.addPredicate(predicate).addPredicate(conditionPredicate);
// Add DurationMetric.
- builder
- .addDurationMetric(StatsdConfigProto.DurationMetric.newBuilder()
- .setId(MetricsUtils.DURATION_METRIC_ID)
- .setWhat(predicate.getId())
- .setAggregationType(StatsdConfigProto.DurationMetric.AggregationType.SUM)
- .setBucket(StatsdConfigProto.TimeUnit.CTS)
- .setCondition(conditionPredicate.getId())
- );
+ builder.addDurationMetric(StatsdConfigProto.DurationMetric.newBuilder()
+ .setId(MetricsUtils.DURATION_METRIC_ID)
+ .setWhat(predicate.getId())
+ .setAggregationType(StatsdConfigProto.DurationMetric.AggregationType.SUM)
+ .setBucket(StatsdConfigProto.TimeUnit.CTS)
+ .setCondition(conditionPredicate.getId())
+ );
// Upload config.
- uploadConfig(builder);
+ ConfigUtils.uploadConfig(getDevice(), builder);
// Start uncounted duration.
- doAppBreadcrumbReportedStart(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
- Thread.sleep(2_000);
+ RunUtil.getDefault().sleep(2_000);
// Stop uncounted duration.
- doAppBreadcrumbReportedStop(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
// Set the condition to true.
- doAppBreadcrumbReportedStart(conditionLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), conditionLabel);
+ RunUtil.getDefault().sleep(10);
// Start counted duration.
- doAppBreadcrumbReportedStart(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
- Thread.sleep(2_000);
+ RunUtil.getDefault().sleep(2_000);
// Stop counted duration.
- doAppBreadcrumbReportedStop(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
// Set the condition to false.
- doAppBreadcrumbReportedStop(conditionLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), conditionLabel);
+ RunUtil.getDefault().sleep(10);
// Start uncounted duration.
- doAppBreadcrumbReportedStart(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
- Thread.sleep(2_000);
+ RunUtil.getDefault().sleep(2_000);
// Stop uncounted duration.
- doAppBreadcrumbReportedStop(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
- Thread.sleep(2_000);
- StatsLogReport metricReport = getStatsLogReport();
+ RunUtil.getDefault().sleep(2_000);
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.DURATION_METRIC_ID);
LogUtil.CLog.d("Received the following data: " + metricReport.toString());
assertThat(metricReport.hasDurationMetrics()).isTrue();
@@ -204,9 +230,9 @@
assertThat(durationData.getDataCount()).isEqualTo(1);
long totalDuration = durationData.getData(0).getBucketInfoList().stream()
.mapToLong(bucketInfo -> bucketInfo.getDurationNanos())
- .peek(durationNs -> assertThat(durationNs).isIn(Range.openClosed(0L, (long)1e9)))
+ .peek(durationNs -> assertThat(durationNs).isIn(Range.openClosed(0L, (long) 1e9)))
.sum();
- assertThat(totalDuration).isIn(Range.open((long)2e9, (long)3e9));
+ assertThat(totalDuration).isIn(Range.open((long) 2e9, (long) 3e9));
}
public void testDurationMetricWithActivation() throws Exception {
@@ -222,9 +248,10 @@
APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID, durationLabel);
StatsdConfigProto.AtomMatcher activationMatcher =
MetricsUtils.appBreadcrumbMatcherWithLabel(activationMatcherId,
- activationMatcherLabel);
+ activationMatcherLabel);
- StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder()
+ StatsdConfigProto.StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE)
.addAtomMatcher(startAtomMatcher)
.addAtomMatcher(stopAtomMatcher)
.addAtomMatcher(activationMatcher);
@@ -235,19 +262,17 @@
.setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID)
.build();
Predicate predicate = Predicate.newBuilder()
- .setId(MetricsUtils.StringToId("Predicate"))
- .setSimplePredicate(simplePredicate)
- .build();
+ .setId(MetricsUtils.StringToId("Predicate"))
+ .setSimplePredicate(simplePredicate)
+ .build();
builder.addPredicate(predicate);
// Add DurationMetric.
- builder
- .addDurationMetric(StatsdConfigProto.DurationMetric.newBuilder()
+ builder.addDurationMetric(StatsdConfigProto.DurationMetric.newBuilder()
.setId(MetricsUtils.DURATION_METRIC_ID)
.setWhat(predicate.getId())
.setAggregationType(StatsdConfigProto.DurationMetric.AggregationType.SUM)
- .setBucket(StatsdConfigProto.TimeUnit.CTS)
- )
+ .setBucket(StatsdConfigProto.TimeUnit.CTS))
.addMetricActivation(StatsdConfigProto.MetricActivation.newBuilder()
.setMetricId(MetricsUtils.DURATION_METRIC_ID)
.addEventActivation(StatsdConfigProto.EventActivation.newBuilder()
@@ -257,34 +282,40 @@
.setTtlSeconds(ttlSec)));
// Upload config.
- uploadConfig(builder);
+ ConfigUtils.uploadConfig(getDevice(), builder);
// Start uncounted duration.
- doAppBreadcrumbReportedStart(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
- Thread.sleep(2_000);
+ RunUtil.getDefault().sleep(2_000);
// Stop uncounted duration.
- doAppBreadcrumbReportedStop(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
// Activate the metric.
- doAppBreadcrumbReported(activationMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), activationMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Start counted duration.
- doAppBreadcrumbReportedStart(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
- Thread.sleep(2_000);
+ RunUtil.getDefault().sleep(2_000);
// Stop counted duration.
- doAppBreadcrumbReportedStop(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
- Thread.sleep(2_000);
- StatsLogReport metricReport = getStatsLogReport();
+ RunUtil.getDefault().sleep(2_000);
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.DURATION_METRIC_ID);
LogUtil.CLog.d("Received the following data: " + metricReport.toString());
assertThat(metricReport.hasDurationMetrics()).isTrue();
@@ -293,9 +324,9 @@
assertThat(durationData.getDataCount()).isEqualTo(1);
long totalDuration = durationData.getData(0).getBucketInfoList().stream()
.mapToLong(bucketInfo -> bucketInfo.getDurationNanos())
- .peek(durationNs -> assertThat(durationNs).isIn(Range.openClosed(0L, (long)1e9)))
+ .peek(durationNs -> assertThat(durationNs).isIn(Range.openClosed(0L, (long) 1e9)))
.sum();
- assertThat(totalDuration).isIn(Range.open((long)2e9, (long)3e9));
+ assertThat(totalDuration).isIn(Range.open((long) 2e9, (long) 3e9));
}
public void testDurationMetricWithConditionAndActivation() throws Exception {
@@ -316,9 +347,10 @@
APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID, conditionLabel);
StatsdConfigProto.AtomMatcher activationMatcher =
MetricsUtils.appBreadcrumbMatcherWithLabel(activationMatcherId,
- activationMatcherLabel);
+ activationMatcherLabel);
- StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder()
+ StatsdConfigProto.StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE)
.addAtomMatcher(startAtomMatcher)
.addAtomMatcher(stopAtomMatcher)
.addAtomMatcher(conditionStartAtomMatcher)
@@ -331,9 +363,9 @@
.setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID)
.build();
Predicate predicate = Predicate.newBuilder()
- .setId(MetricsUtils.StringToId("Predicate"))
- .setSimplePredicate(simplePredicate)
- .build();
+ .setId(MetricsUtils.StringToId("Predicate"))
+ .setSimplePredicate(simplePredicate)
+ .build();
builder.addPredicate(predicate);
SimplePredicate conditionSimplePredicate = SimplePredicate.newBuilder()
@@ -341,20 +373,18 @@
.setStop(APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID)
.build();
Predicate conditionPredicate = Predicate.newBuilder()
- .setId(MetricsUtils.StringToId("ConditionPredicate"))
- .setSimplePredicate(conditionSimplePredicate)
- .build();
+ .setId(MetricsUtils.StringToId("ConditionPredicate"))
+ .setSimplePredicate(conditionSimplePredicate)
+ .build();
builder.addPredicate(conditionPredicate);
// Add DurationMetric.
- builder
- .addDurationMetric(StatsdConfigProto.DurationMetric.newBuilder()
+ builder.addDurationMetric(StatsdConfigProto.DurationMetric.newBuilder()
.setId(MetricsUtils.DURATION_METRIC_ID)
.setWhat(predicate.getId())
.setAggregationType(StatsdConfigProto.DurationMetric.AggregationType.SUM)
.setBucket(StatsdConfigProto.TimeUnit.CTS)
- .setCondition(conditionPredicate.getId())
- )
+ .setCondition(conditionPredicate.getId()))
.addMetricActivation(StatsdConfigProto.MetricActivation.newBuilder()
.setMetricId(MetricsUtils.DURATION_METRIC_ID)
.addEventActivation(StatsdConfigProto.EventActivation.newBuilder()
@@ -364,100 +394,118 @@
.setTtlSeconds(ttlSec)));
// Upload config.
- uploadConfig(builder);
+ ConfigUtils.uploadConfig(getDevice(), builder);
// Activate the metric.
- doAppBreadcrumbReported(activationMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), activationMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Set the condition to true.
- doAppBreadcrumbReportedStart(conditionLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), conditionLabel);
+ RunUtil.getDefault().sleep(10);
// Start counted duration.
- doAppBreadcrumbReportedStart(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
- Thread.sleep(2_000);
+ RunUtil.getDefault().sleep(2_000);
// Stop counted duration.
- doAppBreadcrumbReportedStop(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
// Set the condition to false.
- doAppBreadcrumbReportedStop(conditionLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), conditionLabel);
+ RunUtil.getDefault().sleep(10);
// Start uncounted duration.
- doAppBreadcrumbReportedStart(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
- Thread.sleep(2_000);
+ RunUtil.getDefault().sleep(2_000);
// Stop uncounted duration.
- doAppBreadcrumbReportedStop(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
// Let the metric deactivate.
- Thread.sleep(ttlSec * 1000);
+ RunUtil.getDefault().sleep(ttlSec * 1000);
//doAppBreadcrumbReported(99); // TODO: maybe remove?
- //Thread.sleep(10);
+ //RunUtil.getDefault().sleep(10);
// Start uncounted duration.
- doAppBreadcrumbReportedStart(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
- Thread.sleep(2_000);
+ RunUtil.getDefault().sleep(2_000);
// Stop uncounted duration.
- doAppBreadcrumbReportedStop(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
// Set condition to true again.
- doAppBreadcrumbReportedStart(conditionLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), conditionLabel);
+ RunUtil.getDefault().sleep(10);
- // Start uncounted duration.
- doAppBreadcrumbReportedStart(durationLabel);
- Thread.sleep(10);
+ // Start uncounted duration
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
- Thread.sleep(2_000);
+ RunUtil.getDefault().sleep(2_000);
// Stop uncounted duration.
- doAppBreadcrumbReportedStop(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
// Activate the metric.
- doAppBreadcrumbReported(activationMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), activationMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Start counted duration.
- doAppBreadcrumbReportedStart(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
- Thread.sleep(2_000);
+ RunUtil.getDefault().sleep(2_000);
// Stop counted duration.
- doAppBreadcrumbReportedStop(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
// Let the metric deactivate.
- Thread.sleep(ttlSec * 1000);
+ RunUtil.getDefault().sleep(ttlSec * 1000);
// Start uncounted duration.
- doAppBreadcrumbReportedStart(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
- Thread.sleep(2_000);
+ RunUtil.getDefault().sleep(2_000);
// Stop uncounted duration.
- doAppBreadcrumbReportedStop(durationLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), durationLabel);
+ RunUtil.getDefault().sleep(10);
// Wait for the metrics to propagate to statsd.
- Thread.sleep(2000);
+ RunUtil.getDefault().sleep(2000);
- StatsLogReport metricReport = getStatsLogReport();
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
LogUtil.CLog.d("Received the following data: " + metricReport.toString());
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.DURATION_METRIC_ID);
assertThat(metricReport.hasDurationMetrics()).isTrue();
@@ -466,23 +514,24 @@
assertThat(durationData.getDataCount()).isEqualTo(1);
long totalDuration = durationData.getData(0).getBucketInfoList().stream()
.mapToLong(bucketInfo -> bucketInfo.getDurationNanos())
- .peek(durationNs -> assertThat(durationNs).isIn(Range.openClosed(0L, (long)1e9)))
+ .peek(durationNs -> assertThat(durationNs).isIn(Range.openClosed(0L, (long) 1e9)))
.sum();
- assertThat(totalDuration).isIn(Range.open((long)4e9, (long)5e9));
+ assertThat(totalDuration).isIn(Range.open((long) 4e9, (long) 5e9));
}
public void testDurationMetricWithDimension() throws Exception {
// Add AtomMatchers.
AtomMatcher startAtomMatcherA =
- MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID);
+ MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID);
AtomMatcher stopAtomMatcherA =
- MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID);
+ MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID);
AtomMatcher startAtomMatcherB =
- MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID);
+ MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID);
AtomMatcher stopAtomMatcherB =
- MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID);
+ MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID);
- StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder();
+ StatsdConfigProto.StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
builder.addAtomMatcher(startAtomMatcherA);
builder.addAtomMatcher(stopAtomMatcherA);
builder.addAtomMatcher(startAtomMatcherB);
@@ -494,9 +543,9 @@
.setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID)
.build();
Predicate predicateA = Predicate.newBuilder()
- .setId(MetricsUtils.StringToId("Predicate_A"))
- .setSimplePredicate(simplePredicateA)
- .build();
+ .setId(MetricsUtils.StringToId("Predicate_A"))
+ .setSimplePredicate(simplePredicateA)
+ .build();
builder.addPredicate(predicateA);
FieldMatcher.Builder dimensionsBuilder = FieldMatcher.newBuilder()
@@ -504,47 +553,50 @@
dimensionsBuilder
.addChild(FieldMatcher.newBuilder().setField(
AppBreadcrumbReported.LABEL_FIELD_NUMBER));
- Predicate predicateB =
- Predicate.newBuilder()
+ Predicate predicateB = Predicate.newBuilder()
.setId(MetricsUtils.StringToId("Predicate_B"))
.setSimplePredicate(SimplePredicate.newBuilder()
- .setStart(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
- .setStop(APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID)
- .setDimensions(dimensionsBuilder.build())
- .build())
+ .setStart(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
+ .setStop(APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID)
+ .setDimensions(dimensionsBuilder.build())
+ .build())
.build();
builder.addPredicate(predicateB);
// Add DurationMetric.
- builder.addDurationMetric(
- StatsdConfigProto.DurationMetric.newBuilder()
+ builder.addDurationMetric(StatsdConfigProto.DurationMetric.newBuilder()
.setId(MetricsUtils.DURATION_METRIC_ID)
.setWhat(predicateB.getId())
.setCondition(predicateA.getId())
.setAggregationType(StatsdConfigProto.DurationMetric.AggregationType.SUM)
.setBucket(StatsdConfigProto.TimeUnit.CTS)
.setDimensionsInWhat(
- FieldMatcher.newBuilder()
- .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
- .addChild(FieldMatcher.newBuilder().setField(
- AppBreadcrumbReported.LABEL_FIELD_NUMBER))));
+ FieldMatcher.newBuilder()
+ .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
+ .addChild(FieldMatcher.newBuilder().setField(
+ AppBreadcrumbReported.LABEL_FIELD_NUMBER))));
// Upload config.
- uploadConfig(builder);
+ ConfigUtils.uploadConfig(getDevice(), builder);
// Trigger events.
- doAppBreadcrumbReportedStart(1);
- Thread.sleep(2000);
- doAppBreadcrumbReportedStart(2);
- Thread.sleep(2000);
- doAppBreadcrumbReportedStop(1);
- Thread.sleep(2000);
- doAppBreadcrumbReportedStop(2);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 1);
+ RunUtil.getDefault().sleep(2000);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 2);
+ RunUtil.getDefault().sleep(2000);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 1);
+ RunUtil.getDefault().sleep(2000);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 2);
// Wait for the metrics to propagate to statsd.
- Thread.sleep(2000);
+ RunUtil.getDefault().sleep(2000);
- StatsLogReport metricReport = getStatsLogReport();
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.DURATION_METRIC_ID);
assertThat(metricReport.hasDurationMetrics()).isTrue();
StatsLogReport.DurationMetricDataWrapper durationData
diff --git a/tests/src/android/cts/statsd/metric/GaugeMetricsTests.java b/tests/src/android/cts/statsd/metric/GaugeMetricsTests.java
index db6a818..a037a69 100644
--- a/tests/src/android/cts/statsd/metric/GaugeMetricsTests.java
+++ b/tests/src/android/cts/statsd/metric/GaugeMetricsTests.java
@@ -17,7 +17,9 @@
import static com.google.common.truth.Truth.assertThat;
-import android.cts.statsd.atom.DeviceAtomTestCase;
+import android.cts.statsdatom.lib.AtomTestUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.ReportUtils;
import com.android.internal.os.StatsdConfigProto;
import com.android.internal.os.StatsdConfigProto.ActivationType;
@@ -25,7 +27,6 @@
import com.android.internal.os.StatsdConfigProto.EventActivation;
import com.android.internal.os.StatsdConfigProto.FieldFilter;
import com.android.internal.os.StatsdConfigProto.FieldMatcher;
-import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
import com.android.internal.os.StatsdConfigProto.GaugeMetric;
import com.android.internal.os.StatsdConfigProto.MetricActivation;
import com.android.internal.os.StatsdConfigProto.Predicate;
@@ -35,166 +36,205 @@
import com.android.internal.os.StatsdConfigProto.TimeUnit;
import com.android.os.AtomsProto.AppBreadcrumbReported;
import com.android.os.AtomsProto.Atom;
+import com.android.os.StatsLog;
import com.android.os.StatsLog.GaugeBucketInfo;
import com.android.os.StatsLog.GaugeMetricData;
import com.android.os.StatsLog.StatsLogReport;
import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.util.Pair;
+import com.android.tradefed.util.RunUtil;
-public class GaugeMetricsTests extends DeviceAtomTestCase {
+import com.google.protobuf.ExtensionRegistry;
- private static final int APP_BREADCRUMB_REPORTED_A_MATCH_START_ID = 0;
- private static final int APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID = 1;
- private static final int APP_BREADCRUMB_REPORTED_B_MATCH_START_ID = 2;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
- public void testGaugeMetric() throws Exception {
- // Add AtomMatcher's.
- AtomMatcher startAtomMatcher =
- MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID);
- AtomMatcher stopAtomMatcher =
- MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID);
- AtomMatcher atomMatcher =
- MetricsUtils.simpleAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID);
+public class GaugeMetricsTests extends DeviceTestCase {
- StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder();
- builder.addAtomMatcher(startAtomMatcher);
- builder.addAtomMatcher(stopAtomMatcher);
- builder.addAtomMatcher(atomMatcher);
+ private static final int APP_BREADCRUMB_REPORTED_A_MATCH_START_ID = 0;
+ private static final int APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID = 1;
+ private static final int APP_BREADCRUMB_REPORTED_B_MATCH_START_ID = 2;
- // Add Predicate's.
- SimplePredicate simplePredicate = SimplePredicate.newBuilder()
- .setStart(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID)
- .setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID)
- .build();
- Predicate predicate = Predicate.newBuilder()
- .setId(MetricsUtils.StringToId("Predicate"))
- .setSimplePredicate(simplePredicate)
- .build();
- builder.addPredicate(predicate);
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ RunUtil.getDefault().sleep(1000);
+ }
- // Add GaugeMetric.
- FieldMatcher fieldMatcher =
- FieldMatcher.newBuilder().setField(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID).build();
- builder.addGaugeMetric(
- StatsdConfigProto.GaugeMetric.newBuilder()
- .setId(MetricsUtils.GAUGE_METRIC_ID)
- .setWhat(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
- .setCondition(predicate.getId())
- .setGaugeFieldsFilter(
- FieldFilter.newBuilder().setIncludeAll(false).setFields(fieldMatcher).build())
- .setDimensionsInWhat(
- FieldMatcher.newBuilder()
- .setField(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
- .addChild(FieldMatcher.newBuilder()
- .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
- .build())
- .build())
- .setBucket(StatsdConfigProto.TimeUnit.CTS)
- .build());
+ @Override
+ protected void tearDown() throws Exception {
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ super.tearDown();
+ }
- // Upload config.
- uploadConfig(builder);
+ public void testGaugeMetric() throws Exception {
+ // Add AtomMatcher's.
+ AtomMatcher startAtomMatcher =
+ MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID);
+ AtomMatcher stopAtomMatcher =
+ MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID);
+ AtomMatcher atomMatcher =
+ MetricsUtils.simpleAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID);
- // Create AppBreadcrumbReported Start/Stop events.
- doAppBreadcrumbReportedStart(0);
- Thread.sleep(10);
- doAppBreadcrumbReportedStart(1);
- Thread.sleep(10);
- doAppBreadcrumbReportedStart(2);
- Thread.sleep(2000);
- doAppBreadcrumbReportedStop(2);
- Thread.sleep(10);
- doAppBreadcrumbReportedStop(0);
- Thread.sleep(10);
- doAppBreadcrumbReportedStop(1);
- doAppBreadcrumbReportedStart(2);
- Thread.sleep(10);
- doAppBreadcrumbReportedStart(1);
- Thread.sleep(2000);
- doAppBreadcrumbReportedStop(2);
- Thread.sleep(10);
- doAppBreadcrumbReportedStop(1);
+ StatsdConfigProto.StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ builder.addAtomMatcher(startAtomMatcher);
+ builder.addAtomMatcher(stopAtomMatcher);
+ builder.addAtomMatcher(atomMatcher);
- // Wait for the metrics to propagate to statsd.
- Thread.sleep(2000);
+ // Add Predicate's.
+ SimplePredicate simplePredicate = SimplePredicate.newBuilder()
+ .setStart(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID)
+ .setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID)
+ .build();
+ Predicate predicate = Predicate.newBuilder()
+ .setId(MetricsUtils.StringToId("Predicate"))
+ .setSimplePredicate(simplePredicate)
+ .build();
+ builder.addPredicate(predicate);
- StatsLogReport metricReport = getStatsLogReport();
- LogUtil.CLog.d("Got the following gauge metric data: " + metricReport.toString());
- assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.GAUGE_METRIC_ID);
- assertThat(metricReport.hasGaugeMetrics()).isTrue();
- StatsLogReport.GaugeMetricDataWrapper gaugeData = metricReport.getGaugeMetrics();
- gaugeData = backfillGaugeMetricData(gaugeData);
- assertThat(gaugeData.getDataCount()).isEqualTo(1);
+ // Add GaugeMetric.
+ FieldMatcher fieldMatcher = FieldMatcher.newBuilder()
+ .setField(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
+ .build();
+ builder.addGaugeMetric(StatsdConfigProto.GaugeMetric.newBuilder()
+ .setId(MetricsUtils.GAUGE_METRIC_ID)
+ .setWhat(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
+ .setCondition(predicate.getId())
+ .setGaugeFieldsFilter(FieldFilter.newBuilder()
+ .setIncludeAll(false)
+ .setFields(fieldMatcher)
+ .build())
+ .setDimensionsInWhat(FieldMatcher.newBuilder()
+ .setField(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
+ .addChild(FieldMatcher.newBuilder()
+ .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
+ .build())
+ .build())
+ .setBucket(StatsdConfigProto.TimeUnit.CTS)
+ .build());
- int bucketCount = gaugeData.getData(0).getBucketInfoCount();
- GaugeMetricData data = gaugeData.getData(0);
- assertThat(bucketCount).isGreaterThan(2);
- MetricsUtils.assertBucketTimePresent(data.getBucketInfo(0));
- assertThat(data.getBucketInfo(0).getAtomCount()).isEqualTo(1);
- assertThat(data.getBucketInfo(0).getAtom(0).getAppBreadcrumbReported().getLabel())
- .isEqualTo(0);
- assertThat(data.getBucketInfo(0).getAtom(0).getAppBreadcrumbReported().getState())
- .isEqualTo(AppBreadcrumbReported.State.START);
+ // Upload config.
+ ConfigUtils.uploadConfig(getDevice(), builder);
- MetricsUtils.assertBucketTimePresent(data.getBucketInfo(1));
- assertThat(data.getBucketInfo(1).getAtomCount()).isEqualTo(1);
+ // Create AppBreadcrumbReported Start/Stop events.
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 0);
+ RunUtil.getDefault().sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 1);
+ RunUtil.getDefault().sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 2);
+ RunUtil.getDefault().sleep(2000);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 2);
+ RunUtil.getDefault().sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 0);
+ RunUtil.getDefault().sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 1);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 2);
+ RunUtil.getDefault().sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 1);
+ RunUtil.getDefault().sleep(2000);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 2);
+ RunUtil.getDefault().sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 1);
- MetricsUtils.assertBucketTimePresent(data.getBucketInfo(bucketCount-1));
- assertThat(data.getBucketInfo(bucketCount-1).getAtomCount()).isEqualTo(1);
- assertThat(data.getBucketInfo(bucketCount-1).getAtom(0).getAppBreadcrumbReported().getLabel())
- .isEqualTo(2);
- assertThat(data.getBucketInfo(bucketCount-1).getAtom(0).getAppBreadcrumbReported().getState())
- .isEqualTo(AppBreadcrumbReported.State.STOP);
- }
+ // Wait for the metrics to propagate to statsd.
+ RunUtil.getDefault().sleep(2000);
- public void testPulledGaugeMetricWithActivation() throws Exception {
- // Add AtomMatcher's.
- int activationAtomMatcherId = 1;
- int activationAtomMatcherLabel = 1;
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
+ LogUtil.CLog.d("Got the following gauge metric data: " + metricReport.toString());
+ assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.GAUGE_METRIC_ID);
+ assertThat(metricReport.hasGaugeMetrics()).isTrue();
+ StatsLogReport.GaugeMetricDataWrapper gaugeData = metricReport.getGaugeMetrics();
+ gaugeData = backfillGaugeMetricData(gaugeData);
+ assertThat(gaugeData.getDataCount()).isEqualTo(1);
- int systemUptimeMatcherId = 2;
- AtomMatcher activationAtomMatcher =
- MetricsUtils.appBreadcrumbMatcherWithLabel(
- activationAtomMatcherId, activationAtomMatcherLabel);
- AtomMatcher systemUptimeMatcher =
- AtomMatcher.newBuilder()
- .setId(systemUptimeMatcherId)
- .setSimpleAtomMatcher(
- SimpleAtomMatcher.newBuilder().setAtomId(Atom.SYSTEM_UPTIME_FIELD_NUMBER))
- .build();
+ int bucketCount = gaugeData.getData(0).getBucketInfoCount();
+ GaugeMetricData data = gaugeData.getData(0);
+ assertThat(bucketCount).isGreaterThan(2);
+ MetricsUtils.assertBucketTimePresent(data.getBucketInfo(0));
+ assertThat(data.getBucketInfo(0).getAtomCount()).isEqualTo(1);
+ assertThat(data.getBucketInfo(0).getAtom(0).getAppBreadcrumbReported().getLabel())
+ .isEqualTo(0);
+ assertThat(data.getBucketInfo(0).getAtom(0).getAppBreadcrumbReported().getState())
+ .isEqualTo(AppBreadcrumbReported.State.START);
- StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder();
- builder.addAtomMatcher(activationAtomMatcher);
- builder.addAtomMatcher(systemUptimeMatcher);
+ MetricsUtils.assertBucketTimePresent(data.getBucketInfo(1));
+ assertThat(data.getBucketInfo(1).getAtomCount()).isEqualTo(1);
- // Add GaugeMetric.
- builder.addGaugeMetric(
- StatsdConfigProto.GaugeMetric.newBuilder()
- .setId(MetricsUtils.GAUGE_METRIC_ID)
- .setWhat(systemUptimeMatcherId)
- .setGaugeFieldsFilter(
- FieldFilter.newBuilder().setIncludeAll(true).build())
- .setBucket(StatsdConfigProto.TimeUnit.CTS)
- .build());
+ MetricsUtils.assertBucketTimePresent(data.getBucketInfo(bucketCount - 1));
+ assertThat(data.getBucketInfo(bucketCount - 1).getAtomCount()).isEqualTo(1);
+ assertThat(data.getBucketInfo(bucketCount - 1).getAtom(
+ 0).getAppBreadcrumbReported().getLabel())
+ .isEqualTo(2);
+ assertThat(data.getBucketInfo(bucketCount - 1).getAtom(
+ 0).getAppBreadcrumbReported().getState())
+ .isEqualTo(AppBreadcrumbReported.State.STOP);
+ }
- // Add activation.
- builder.addMetricActivation(MetricActivation.newBuilder()
- .setMetricId(MetricsUtils.GAUGE_METRIC_ID)
- .setActivationType(ActivationType.ACTIVATE_IMMEDIATELY)
- .addEventActivation(EventActivation.newBuilder()
- .setAtomMatcherId(activationAtomMatcherId)
- .setTtlSeconds(5)));
+ public void testPulledGaugeMetricWithActivation() throws Exception {
+ // Add AtomMatcher's.
+ int activationAtomMatcherId = 1;
+ int activationAtomMatcherLabel = 1;
- // Upload config.
- uploadConfig(builder);
+ int systemUptimeMatcherId = 2;
+ AtomMatcher activationAtomMatcher = MetricsUtils.appBreadcrumbMatcherWithLabel(
+ activationAtomMatcherId, activationAtomMatcherLabel);
+ AtomMatcher systemUptimeMatcher = AtomMatcher.newBuilder()
+ .setId(systemUptimeMatcherId)
+ .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
+ .setAtomId(Atom.SYSTEM_UPTIME_FIELD_NUMBER))
+ .build();
- // Plenty of time to pull, but we should not keep the data since we are not active.
- Thread.sleep(20_000);
+ StatsdConfigProto.StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ builder.addAtomMatcher(activationAtomMatcher);
+ builder.addAtomMatcher(systemUptimeMatcher);
- StatsLogReport metricReport = getStatsLogReport();
- LogUtil.CLog.d("Got the following gauge metric data: " + metricReport.toString());
- assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.GAUGE_METRIC_ID);
- assertThat(metricReport.hasGaugeMetrics()).isFalse();
- }
+ // Add GaugeMetric.
+ builder.addGaugeMetric(StatsdConfigProto.GaugeMetric.newBuilder()
+ .setId(MetricsUtils.GAUGE_METRIC_ID)
+ .setWhat(systemUptimeMatcherId)
+ .setGaugeFieldsFilter(
+ FieldFilter.newBuilder().setIncludeAll(true).build())
+ .setBucket(StatsdConfigProto.TimeUnit.CTS)
+ .build());
+
+ // Add activation.
+ builder.addMetricActivation(MetricActivation.newBuilder()
+ .setMetricId(MetricsUtils.GAUGE_METRIC_ID)
+ .setActivationType(ActivationType.ACTIVATE_IMMEDIATELY)
+ .addEventActivation(EventActivation.newBuilder()
+ .setAtomMatcherId(activationAtomMatcherId)
+ .setTtlSeconds(5)));
+
+ // Upload config.
+ ConfigUtils.uploadConfig(getDevice(), builder);
+
+ // Plenty of time to pull, but we should not keep the data since we are not active.
+ RunUtil.getDefault().sleep(20_000);
+
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
+ LogUtil.CLog.d("Got the following gauge metric data: " + metricReport.toString());
+ assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.GAUGE_METRIC_ID);
+ assertThat(metricReport.hasGaugeMetrics()).isFalse();
+ }
public void testPulledGaugeMetricWithConditionAndActivation() throws Exception {
final int conditionLabel = 2;
@@ -208,17 +248,16 @@
APP_BREADCRUMB_REPORTED_A_MATCH_START_ID, conditionLabel);
AtomMatcher conditionStopAtomMatcher = MetricsUtils.stopAtomMatcherWithLabel(
APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID, conditionLabel);
- AtomMatcher activationMatcher =
- MetricsUtils.startAtomMatcherWithLabel(
- activationMatcherId, activationMatcherLabel);
- AtomMatcher whatMatcher =
- MetricsUtils.unspecifiedAtomMatcher(whatMatcherId);
+ AtomMatcher activationMatcher = MetricsUtils.startAtomMatcherWithLabel(
+ activationMatcherId, activationMatcherLabel);
+ AtomMatcher whatMatcher = MetricsUtils.unspecifiedAtomMatcher(whatMatcherId);
- StatsdConfig.Builder builder = createConfigBuilder()
- .addAtomMatcher(conditionStartAtomMatcher)
- .addAtomMatcher(conditionStopAtomMatcher)
- .addAtomMatcher(whatMatcher)
- .addAtomMatcher(activationMatcher);
+ StatsdConfig.Builder builder =
+ ConfigUtils.createConfigBuilder(MetricsUtils.DEVICE_SIDE_TEST_PACKAGE)
+ .addAtomMatcher(conditionStartAtomMatcher)
+ .addAtomMatcher(conditionStopAtomMatcher)
+ .addAtomMatcher(whatMatcher)
+ .addAtomMatcher(activationMatcher);
// Add Predicates.
SimplePredicate simplePredicate = SimplePredicate.newBuilder()
@@ -226,95 +265,102 @@
.setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID)
.build();
Predicate predicate = Predicate.newBuilder()
- .setId(MetricsUtils.StringToId("Predicate"))
- .setSimplePredicate(simplePredicate)
- .build();
+ .setId(MetricsUtils.StringToId("Predicate"))
+ .setSimplePredicate(simplePredicate)
+ .build();
builder.addPredicate(predicate);
// Add GaugeMetric.
- builder
- .addGaugeMetric(GaugeMetric.newBuilder()
+ builder.addGaugeMetric(GaugeMetric.newBuilder()
.setId(MetricsUtils.GAUGE_METRIC_ID)
.setWhat(whatMatcher.getId())
.setBucket(TimeUnit.CTS)
.setCondition(predicate.getId())
- .setGaugeFieldsFilter(
- FieldFilter.newBuilder().setIncludeAll(false).setFields(
- FieldMatcher.newBuilder()
- .setField(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
- )
- )
- .setDimensionsInWhat(FieldMatcher.newBuilder().setField(whatMatcherId))
- )
+ .setGaugeFieldsFilter(FieldFilter.newBuilder()
+ .setIncludeAll(false)
+ .setFields(FieldMatcher.newBuilder()
+ .setField(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)))
+ .setDimensionsInWhat(FieldMatcher.newBuilder().setField(whatMatcherId)))
.addMetricActivation(MetricActivation.newBuilder()
.setMetricId(MetricsUtils.GAUGE_METRIC_ID)
.addEventActivation(EventActivation.newBuilder()
.setAtomMatcherId(activationMatcherId)
.setActivationType(ActivationType.ACTIVATE_IMMEDIATELY)
- .setTtlSeconds(ttlSec)
- )
- );
+ .setTtlSeconds(ttlSec)));
- uploadConfig(builder);
+ ConfigUtils.uploadConfig(getDevice(), builder);
// Activate the metric.
- doAppBreadcrumbReportedStart(activationMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), activationMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Set the condition to true.
- doAppBreadcrumbReportedStart(conditionLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), conditionLabel);
+ RunUtil.getDefault().sleep(10);
// This value is collected.
- doAppBreadcrumbReported(10);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 10);
+ RunUtil.getDefault().sleep(10);
// Ignored; value already collected.
- doAppBreadcrumbReported(20);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 20);
+ RunUtil.getDefault().sleep(10);
// Set the condition to false.
- doAppBreadcrumbReportedStop(conditionLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), conditionLabel);
+ RunUtil.getDefault().sleep(10);
// Value not updated because condition is false.
- doAppBreadcrumbReported(30);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 30);
+ RunUtil.getDefault().sleep(10);
// Let the metric deactivate.
- Thread.sleep(ttlSec * 1000);
+ RunUtil.getDefault().sleep(ttlSec * 1000);
// Value not collected.
- doAppBreadcrumbReported(40);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 40);
+ RunUtil.getDefault().sleep(10);
// Condition to true again.
- doAppBreadcrumbReportedStart(conditionLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), conditionLabel);
+ RunUtil.getDefault().sleep(10);
// Value not collected.
- doAppBreadcrumbReported(50);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 50);
+ RunUtil.getDefault().sleep(10);
// Activate the metric.
- doAppBreadcrumbReportedStart(activationMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), activationMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Value collected.
- doAppBreadcrumbReported(60);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 60);
+ RunUtil.getDefault().sleep(10);
// Let the metric deactivate.
- Thread.sleep(ttlSec * 1000);
+ RunUtil.getDefault().sleep(ttlSec * 1000);
// Value not collected.
- doAppBreadcrumbReported(70);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 70);
+ RunUtil.getDefault().sleep(10);
// Wait for the metrics to propagate to statsd.
- Thread.sleep(2000);
+ RunUtil.getDefault().sleep(2000);
- StatsLogReport metricReport = getStatsLogReport();
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
LogUtil.CLog.d("Received the following data: " + metricReport.toString());
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.GAUGE_METRIC_ID);
assertThat(metricReport.hasGaugeMetrics()).isTrue();
@@ -335,4 +381,42 @@
assertThat(bucketInfo.getAtomCount()).isEqualTo(1);
assertThat(bucketInfo.getAtom(0).getAppBreadcrumbReported().getLabel()).isEqualTo(60);
}
+
+ private StatsLogReport.GaugeMetricDataWrapper backfillGaugeMetricData(
+ StatsLogReport.GaugeMetricDataWrapper dataWrapper) {
+ StatsLogReport.GaugeMetricDataWrapper.Builder dataWrapperBuilder = dataWrapper.toBuilder();
+ List<GaugeMetricData> backfilledMetricData = new ArrayList<>();
+ for (GaugeMetricData gaugeMetricData : dataWrapperBuilder.getDataList()) {
+ GaugeMetricData.Builder gaugeMetricDataBuilder = gaugeMetricData.toBuilder();
+ List<GaugeBucketInfo> backfilledBuckets = new ArrayList<>();
+ for (GaugeBucketInfo bucketInfo : gaugeMetricData.getBucketInfoList()) {
+ backfilledBuckets.add(backfillGaugeBucket(bucketInfo.toBuilder()));
+ }
+ gaugeMetricDataBuilder.clearBucketInfo();
+ gaugeMetricDataBuilder.addAllBucketInfo(backfilledBuckets);
+ backfilledMetricData.add(gaugeMetricDataBuilder.build());
+ }
+ dataWrapperBuilder.clearData();
+ dataWrapperBuilder.addAllData(backfilledMetricData);
+ return dataWrapperBuilder.build();
+ }
+
+ private GaugeBucketInfo backfillGaugeBucket(GaugeBucketInfo.Builder bucketInfoBuilder) {
+ if (bucketInfoBuilder.getAtomCount() != 0) {
+ return bucketInfoBuilder.build();
+ }
+ List<Pair<Atom, Long>> atomTimestampData = new ArrayList<>();
+ for (StatsLog.AggregatedAtomInfo atomInfo : bucketInfoBuilder.getAggregatedAtomInfoList()) {
+ for (long timestampNs : atomInfo.getElapsedTimestampNanosList()) {
+ atomTimestampData.add(Pair.create(atomInfo.getAtom(), timestampNs));
+ }
+ }
+ atomTimestampData.sort(Comparator.comparing(o -> o.second));
+ bucketInfoBuilder.clearAggregatedAtomInfo();
+ for (Pair<Atom, Long> atomTimestamp : atomTimestampData) {
+ bucketInfoBuilder.addAtom(atomTimestamp.first);
+ bucketInfoBuilder.addElapsedTimestampNanos(atomTimestamp.second);
+ }
+ return bucketInfoBuilder.build();
+ }
}
diff --git a/tests/src/android/cts/statsd/metric/MetricActivationTests.java b/tests/src/android/cts/statsd/metric/MetricActivationTests.java
index a95cb1b..5c6f2fb 100644
--- a/tests/src/android/cts/statsd/metric/MetricActivationTests.java
+++ b/tests/src/android/cts/statsd/metric/MetricActivationTests.java
@@ -16,32 +16,39 @@
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 android.cts.statsdatom.lib.AtomTestUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
-import com.android.internal.os.StatsdConfigProto;
import com.android.internal.os.StatsdConfigProto.ActivationType;
import com.android.internal.os.StatsdConfigProto.AtomMatcher;
import com.android.internal.os.StatsdConfigProto.EventActivation;
import com.android.internal.os.StatsdConfigProto.EventMetric;
-import com.android.internal.os.StatsdConfigProto.GaugeMetric;
import com.android.internal.os.StatsdConfigProto.MetricActivation;
import com.android.internal.os.StatsdConfigProto.StatsdConfig;
import com.android.os.AtomsProto.AppBreadcrumbReported;
-import com.android.os.AtomsProto.Atom;
import com.android.os.StatsLog.ConfigMetricsReport;
import com.android.os.StatsLog.ConfigMetricsReportList;
import com.android.os.StatsLog.EventMetricData;
import com.android.os.StatsLog.StatsLogReport;
import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.util.RunUtil;
+
+import com.google.protobuf.ExtensionRegistry;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
+import java.util.stream.Collectors;
/**
* Test Statsd Metric activations and deactivations
*/
-public class MetricActivationTests extends DeviceAtomTestCase {
+public class MetricActivationTests extends DeviceTestCase {
private final long metric1Id = 1L;
private final int metric1MatcherId = 1;
@@ -57,6 +64,20 @@
private final int act2MatcherId = 20;
private final int act2CancelMatcherId = -20;
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ RunUtil.getDefault().sleep(1000);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ super.tearDown();
+ }
private StatsdConfig.Builder createConfig(final int act1TtlSecs, final int act2TtlSecs) {
AtomMatcher metric1Matcher =
@@ -65,49 +86,41 @@
MetricsUtils.simpleAtomMatcher(metric2MatcherId, metric2MatcherId);
AtomMatcher metric3Matcher =
MetricsUtils.simpleAtomMatcher(metric3MatcherId, metric3MatcherId);
- AtomMatcher act1Matcher =
- MetricsUtils.simpleAtomMatcher(act1MatcherId, act1MatcherId);
+ AtomMatcher act1Matcher = MetricsUtils.simpleAtomMatcher(act1MatcherId, act1MatcherId);
AtomMatcher act1CancelMatcher =
MetricsUtils.simpleAtomMatcher(act1CancelMatcherId, act1CancelMatcherId);
- AtomMatcher act2Matcher =
- MetricsUtils.simpleAtomMatcher(act2MatcherId, act2MatcherId);
+ AtomMatcher act2Matcher = MetricsUtils.simpleAtomMatcher(act2MatcherId, act2MatcherId);
AtomMatcher act2CancelMatcher =
MetricsUtils.simpleAtomMatcher(act2CancelMatcherId, act2CancelMatcherId);
- EventMetric metric1 = EventMetric.newBuilder()
- .setId(metric1Id)
- .setWhat(metric1MatcherId)
- .build();
+ EventMetric metric1 =
+ EventMetric.newBuilder().setId(metric1Id).setWhat(metric1MatcherId).build();
- EventMetric metric2 = EventMetric.newBuilder()
- .setId(metric2Id)
- .setWhat(metric2MatcherId)
- .build();
+ EventMetric metric2 =
+ EventMetric.newBuilder().setId(metric2Id).setWhat(metric2MatcherId).build();
- EventMetric metric3 = EventMetric.newBuilder()
- .setId(metric3Id)
- .setWhat(metric3MatcherId)
- .build();
+ EventMetric metric3 =
+ EventMetric.newBuilder().setId(metric3Id).setWhat(metric3MatcherId).build();
EventActivation metric1Act1 =
MetricsUtils.createEventActivation(act1TtlSecs, act1MatcherId, act1CancelMatcherId)
- .setActivationType(ActivationType.ACTIVATE_IMMEDIATELY)
- .build();
+ .setActivationType(ActivationType.ACTIVATE_IMMEDIATELY)
+ .build();
EventActivation metric1Act2 =
MetricsUtils.createEventActivation(act2TtlSecs, act2MatcherId, act2CancelMatcherId)
- .setActivationType(ActivationType.ACTIVATE_ON_BOOT)
- .build();
+ .setActivationType(ActivationType.ACTIVATE_ON_BOOT)
+ .build();
EventActivation metric2Act1 =
MetricsUtils.createEventActivation(act1TtlSecs, act1MatcherId, act1CancelMatcherId)
- .setActivationType(ActivationType.ACTIVATE_ON_BOOT)
- .build();
+ .setActivationType(ActivationType.ACTIVATE_ON_BOOT)
+ .build();
EventActivation metric2Act2 =
MetricsUtils.createEventActivation(act2TtlSecs, act2MatcherId, act2CancelMatcherId)
- .setActivationType(ActivationType.ACTIVATE_IMMEDIATELY)
- .build();
+ .setActivationType(ActivationType.ACTIVATE_IMMEDIATELY)
+ .build();
MetricActivation metric1Activation = MetricActivation.newBuilder()
.setMetricId(metric1Id)
@@ -121,7 +134,8 @@
.addEventActivation(metric2Act2)
.build();
- return createConfigBuilder()
+
+ return ConfigUtils.createConfigBuilder(MetricsUtils.DEVICE_SIDE_TEST_PACKAGE)
.addAtomMatcher(metric1Matcher)
.addAtomMatcher(metric2Matcher)
.addAtomMatcher(metric3Matcher)
@@ -138,96 +152,113 @@
/**
* Metric 1:
- * Activation 1:
- * - Ttl: 5 seconds
- * - Type: IMMEDIATE
- * Activation 2:
- * - Ttl: 8 seconds
- * - Type: ON_BOOT
+ * Activation 1:
+ * - Ttl: 5 seconds
+ * - Type: IMMEDIATE
+ * Activation 2:
+ * - Ttl: 8 seconds
+ * - Type: ON_BOOT
*
* Metric 2:
- * Activation 1:
- * - Ttl: 5 seconds
- * - Type: ON_BOOT
- * Activation 2:
- * - Ttl: 8 seconds
- * - Type: IMMEDIATE
+ * Activation 1:
+ * - Ttl: 5 seconds
+ * - Type: ON_BOOT
+ * Activation 2:
+ * - Ttl: 8 seconds
+ * - Type: IMMEDIATE
*
* Metric 3: No activations; always active
**/
public void testCancellation() throws Exception {
final int act1TtlSecs = 5;
final int act2TtlSecs = 8;
- uploadConfig(createConfig(act1TtlSecs, act2TtlSecs));
+ ConfigUtils.uploadConfig(getDevice(), createConfig(act1TtlSecs, act2TtlSecs));
// Ignored, metric not active.
- doAppBreadcrumbReported(metric1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), metric1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// Trigger cancel for already inactive event activation 1.
- doAppBreadcrumbReported(act1CancelMatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), act1CancelMatcherId);
+ RunUtil.getDefault().sleep(10L);
// Trigger event activation 1.
- doAppBreadcrumbReported(act1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), act1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// First logged event.
- doAppBreadcrumbReported(metric1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), metric1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// Second logged event.
- doAppBreadcrumbReported(metric1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), metric1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// Cancel event activation 1.
- doAppBreadcrumbReported(act1CancelMatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), act1CancelMatcherId);
+ RunUtil.getDefault().sleep(10L);
// Ignored, metric not active.
- doAppBreadcrumbReported(metric1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), metric1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// Trigger event activation 1.
- doAppBreadcrumbReported(act1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), act1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// Trigger event activation 2.
- doAppBreadcrumbReported(act2MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), act2MatcherId);
+ RunUtil.getDefault().sleep(10L);
// Third logged event.
- doAppBreadcrumbReported(metric1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), metric1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// Cancel event activation 2.
- doAppBreadcrumbReported(act2CancelMatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), act2CancelMatcherId);
+ RunUtil.getDefault().sleep(10L);
// Fourth logged event.
- doAppBreadcrumbReported(metric1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), metric1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// Expire event activation 1
- Thread.sleep(act1TtlSecs * 1000);
+ RunUtil.getDefault().sleep(act1TtlSecs * 1000);
// Ignored, metric 1 not active. Activation 1 expired and Activation 2 was cancelled.
- doAppBreadcrumbReported(metric1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), metric1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// Trigger event activation 2.
- doAppBreadcrumbReported(act2MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), act2MatcherId);
+ RunUtil.getDefault().sleep(10L);
// Metric 1 log ignored, Activation 1 expired and Activation 2 needs reboot to activate.
- doAppBreadcrumbReported(metric1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), metric1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// First logged event for Metric 3.
- doAppBreadcrumbReported(metric3MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), metric3MatcherId);
+ RunUtil.getDefault().sleep(10L);
- ConfigMetricsReportList reportList = getReportList();
+ ConfigMetricsReportList reportList = ReportUtils.getReportList(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
List<ConfigMetricsReport> reports = getSortedConfigMetricsReports(reportList);
ConfigMetricsReport report = reports.get(0);
verifyMetrics(report, 4, 0, 1);
@@ -235,27 +266,27 @@
/**
* Metric 1:
- * Activation 1:
- * - Ttl: 100 seconds
- * - Type: IMMEDIATE
- * Activation 2:
- * - Ttl: 200 seconds
- * - Type: ON_BOOT
+ * Activation 1:
+ * - Ttl: 100 seconds
+ * - Type: IMMEDIATE
+ * Activation 2:
+ * - Ttl: 200 seconds
+ * - Type: ON_BOOT
*
* Metric 2:
- * Activation 1:
- * - Ttl: 100 seconds
- * - Type: ON_BOOT
- * Activation 2:
- * - Ttl: 200 seconds
- * - Type: IMMEDIATE
+ * Activation 1:
+ * - Ttl: 100 seconds
+ * - Type: ON_BOOT
+ * Activation 2:
+ * - Ttl: 200 seconds
+ * - Type: IMMEDIATE
*
* Metric 3: No activations; always active
**/
public void testRestart() throws Exception {
final int act1TtlSecs = 200;
final int act2TtlSecs = 400;
- uploadConfig(createConfig(act1TtlSecs, act2TtlSecs));
+ ConfigUtils.uploadConfig(getDevice(), createConfig(act1TtlSecs, act2TtlSecs));
// Trigger Metric 1 Activation 1 and Metric 2 Activation 1.
// Time remaining:
@@ -263,8 +294,9 @@
// Metric 1 Activation 2: 0 seconds
// Metric 2 Activation 1: 0 seconds (will activate after boot)
// Metric 2 Activation 2: 0 seconds
- doAppBreadcrumbReported(act1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), act1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// First logged event for Metric 1.
// Metric 2 event ignored, will activate after boot.
@@ -276,7 +308,7 @@
// Metric 1 Activation 2: 0 seconds
// Metric 2 Activation 1: 200 seconds
// Metric 2 Activation 2: 0 seconds
- rebootDeviceAndWaitUntilReady();
+ DeviceUtils.rebootDeviceAndWaitUntilReady(getDevice());
// Second logged event for Metric 1.
// First logged event for Metric 2.
@@ -288,7 +320,7 @@
// Metric 1 Activation 2: 0 seconds
// Metric 2 Activation 1: 0 seconds
// Metric 2 Activation 2: 0 seconds
- Thread.sleep(act1TtlSecs * 1000L);
+ RunUtil.getDefault().sleep(act1TtlSecs * 1000L);
// Metric 1 event ignored, Activation 1 expired.
// Metric 2 event ignored, Activation 1 expired.
@@ -301,8 +333,9 @@
// Metric 1 Activation 2: 0 seconds (will activate after boot)
// Metric 2 Activation 1: 0 seconds
// Metric 2 Activation 2: 400 seconds
- doAppBreadcrumbReported(act2MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), act2MatcherId);
+ RunUtil.getDefault().sleep(10L);
// Metric 1 event ignored, will activate after boot.
// Second logged event for Metric 2.
@@ -315,8 +348,9 @@
// Metric 1 Activation 2: 0 seconds (will activate after boot)
// Metric 2 Activation 1: 0 seconds (will activate after boot)
// Metric 2 Activation 2: 400 seconds
- doAppBreadcrumbReported(act1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), act1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// Third logged event for Metric 1.
// Third logged event for Metric 2.
@@ -328,14 +362,14 @@
// Metric 1 Activation 2: 0 seconds (will activate after boot)
// Metric 2 Activation 1: 0 seconds (will activate after boot)
// Metric 2 Activation 2: 300 seconds
- Thread.sleep(act1TtlSecs * 1000L / 2);
+ RunUtil.getDefault().sleep(act1TtlSecs * 1000L / 2);
// Time remaining:
// Metric 1 Activation 1: 100 seconds
// Metric 1 Activation 2: 400 seconds
// Metric 2 Activation 1: 200 seconds
// Metric 2 Activation 2: 300 seconds
- rebootDeviceAndWaitUntilReady();
+ DeviceUtils.rebootDeviceAndWaitUntilReady(getDevice());
// Fourth logged event for Metric 1.
// Fourth logged event for Metric 2.
@@ -348,7 +382,7 @@
// Metric 1 Activation 2: 300 seconds
// Metric 2 Activation 1: 100 seconds
// Metric 2 Activation 2: 200 seconds
- Thread.sleep(act1TtlSecs * 1000L / 2);
+ RunUtil.getDefault().sleep(act1TtlSecs * 1000L / 2);
// Fifth logged event for Metric 1.
// Fifth logged event for Metric 2.
@@ -361,14 +395,15 @@
// Metric 1 Activation 2: 0 seconds
// Metric 2 Activation 1: 0 seconds
// Metric 2 Activation 2: 0 seconds
- Thread.sleep(act2TtlSecs * 1000L);
+ RunUtil.getDefault().sleep(act2TtlSecs * 1000L);
// Metric 1 event ignored.
// Metric 2 event ignored.
// Eighth logged event for Metric 3.
logAllMetrics();
- ConfigMetricsReportList reportList = getReportList();
+ ConfigMetricsReportList reportList = ReportUtils.getReportList(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
List<ConfigMetricsReport> reports = getSortedConfigMetricsReports(reportList);
assertThat(reports).hasSize(3);
@@ -387,27 +422,27 @@
/**
* Metric 1:
- * Activation 1:
- * - Ttl: 100 seconds
- * - Type: IMMEDIATE
- * Activation 2:
- * - Ttl: 200 seconds
- * - Type: ON_BOOT
+ * Activation 1:
+ * - Ttl: 100 seconds
+ * - Type: IMMEDIATE
+ * Activation 2:
+ * - Ttl: 200 seconds
+ * - Type: ON_BOOT
*
* Metric 2:
- * Activation 1:
- * - Ttl: 100 seconds
- * - Type: ON_BOOT
- * Activation 2:
- * - Ttl: 200 seconds
- * - Type: IMMEDIATE
+ * Activation 1:
+ * - Ttl: 100 seconds
+ * - Type: ON_BOOT
+ * Activation 2:
+ * - Ttl: 200 seconds
+ * - Type: IMMEDIATE
*
* Metric 3: No activations; always active
**/
public void testMultipleActivations() throws Exception {
final int act1TtlSecs = 200;
final int act2TtlSecs = 400;
- uploadConfig(createConfig(act1TtlSecs, act2TtlSecs));
+ ConfigUtils.uploadConfig(getDevice(), createConfig(act1TtlSecs, act2TtlSecs));
// Trigger Metric 1 Activation 1 and Metric 2 Activation 1.
// Time remaining:
@@ -415,8 +450,9 @@
// Metric 1 Activation 2: 0 seconds
// Metric 2 Activation 1: 0 seconds (will activate after boot)
// Metric 2 Activation 2: 0 seconds
- doAppBreadcrumbReported(act1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), act1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// First logged event for Metric 1.
// Metric 2 event ignored, will activate after boot.
@@ -428,7 +464,7 @@
// Metric 1 Activation 2: 0 seconds
// Metric 2 Activation 1: 0 seconds (will activate after boot)
// Metric 2 Activation 2: 0 seconds
- Thread.sleep(act1TtlSecs * 1000L / 2);
+ RunUtil.getDefault().sleep(act1TtlSecs * 1000L / 2);
// Second logged event for Metric 1.
// Metric 2 event ignored, will activate after boot.
@@ -441,8 +477,9 @@
// Metric 1 Activation 2: 0 seconds
// Metric 2 Activation 1: 0 seconds (will activate after boot)
// Metric 2 Activation 2: 0 seconds
- doAppBreadcrumbReported(act1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), act1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// Third logged event for Metric 1.
// Metric 2 event ignored, will activate after boot.
@@ -454,7 +491,7 @@
// Metric 1 Activation 2: 0 seconds
// Metric 2 Activation 1: 200 seconds
// Metric 2 Activation 2: 0 seconds
- rebootDeviceAndWaitUntilReady();
+ DeviceUtils.rebootDeviceAndWaitUntilReady(getDevice());
// Fourth logged event for Metric 1.
// First logged event for Metric 2.
@@ -467,8 +504,9 @@
// Metric 1 Activation 2: 0 seconds
// Metric 2 Activation 1: 200 seconds
// Metric 2 Activation 2: 0 seconds
- doAppBreadcrumbReported(act1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), act1MatcherId);
+ RunUtil.getDefault().sleep(10L);
// Fifth logged event for Metric 1.
// Second logged event for Metric 2.
@@ -481,7 +519,7 @@
// Metric 1 Activation 2: 0 seconds
// Metric 2 Activation 1: 0 seconds
// Metric 2 Activation 2: 0 seconds
- Thread.sleep(act1TtlSecs * 1000L);
+ RunUtil.getDefault().sleep(act1TtlSecs * 1000L);
// Metric 1 event ignored.
// Metric 2 event ignored.
@@ -493,15 +531,16 @@
// Metric 1 Activation 2: 0 seconds
// Metric 2 Activation 1: 0 seconds
// Metric 2 Activation 2: 0 seconds
- rebootDeviceAndWaitUntilReady();
- Thread.sleep(10_000L);
+ DeviceUtils.rebootDeviceAndWaitUntilReady(getDevice());
+ RunUtil.getDefault().sleep(10_000L);
// Metric 1 event ignored.
// Metric 2 event ignored.
// Seventh logged event for Metric 3.
logAllMetrics();
- ConfigMetricsReportList reportList = getReportList();
+ ConfigMetricsReportList reportList = ReportUtils.getReportList(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
List<ConfigMetricsReport> reports = getSortedConfigMetricsReports(reportList);
assertThat(reports).hasSize(3);
@@ -518,35 +557,45 @@
verifyMetrics(report, 0, 0, 1);
}
+ /**
+ * Gets a List of sorted ConfigMetricsReports from ConfigMetricsReportList.
+ */
+ private List<ConfigMetricsReport> getSortedConfigMetricsReports(
+ ConfigMetricsReportList configMetricsReportList) {
+ return configMetricsReportList.getReportsList().stream().sorted(
+ Comparator.comparing(ConfigMetricsReport::getCurrentReportWallClockNanos)).collect(
+ Collectors.toList());
+ }
+
private void logAllMetrics() throws Exception {
- doAppBreadcrumbReported(metric1MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), metric1MatcherId);
+ RunUtil.getDefault().sleep(10L);
- doAppBreadcrumbReported(metric2MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), metric2MatcherId);
+ RunUtil.getDefault().sleep(10L);
- doAppBreadcrumbReported(metric3MatcherId);
- Thread.sleep(10L);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), metric3MatcherId);
+ RunUtil.getDefault().sleep(10L);
}
private void verifyMetrics(ConfigMetricsReport report, int metric1Count, int metric2Count,
int metric3Count) throws Exception {
assertThat(report.getMetricsCount()).isEqualTo(3);
- verifyMetric(
- report.getMetrics(0), // StatsLogReport
+ verifyMetric(report.getMetrics(0), // StatsLogReport
1, // Metric Id
1, // Metric what atom matcher label
metric1Count // Data count
);
- verifyMetric(
- report.getMetrics(1), // StatsLogReport
+ verifyMetric(report.getMetrics(1), // StatsLogReport
2, // Metric Id
2, // Metric what atom matcher label
metric2Count // Data count
);
- verifyMetric(
- report.getMetrics(2), // StatsLogReport
+ verifyMetric(report.getMetrics(2), // StatsLogReport
3, // Metric Id
3, // Metric what atom matcher label
metric3Count // Data count
@@ -562,7 +611,8 @@
StatsLogReport.EventMetricDataWrapper eventData = metricReport.getEventMetrics();
List<EventMetricData> eventMetricDataList = new ArrayList<>();
for (EventMetricData eventMetricData : eventData.getDataList()) {
- eventMetricDataList.addAll(backfillAggregatedAtomsInEventMetric(eventMetricData));
+ eventMetricDataList.addAll(
+ ReportUtils.backfillAggregatedAtomsInEventMetric(eventMetricData));
}
assertThat(eventMetricDataList).hasSize(dataCount);
for (EventMetricData eventMetricData : eventMetricDataList) {
diff --git a/tests/src/android/cts/statsd/metric/MetricsUtils.java b/tests/src/android/cts/statsd/metric/MetricsUtils.java
index 8f559d2..010df49 100644
--- a/tests/src/android/cts/statsd/metric/MetricsUtils.java
+++ b/tests/src/android/cts/statsd/metric/MetricsUtils.java
@@ -17,6 +17,8 @@
import static com.google.common.truth.Truth.assertWithMessage;
+import android.cts.statsd.atom.BufferDebug;
+
import com.android.internal.os.StatsdConfigProto;
import com.android.internal.os.StatsdConfigProto.AtomMatcher;
import com.android.internal.os.StatsdConfigProto.EventActivation;
@@ -24,11 +26,26 @@
import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
import com.android.os.AtomsProto.Atom;
import com.android.os.AtomsProto.AppBreadcrumbReported;
+import com.android.tradefed.device.CollectingByteOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.util.RunUtil;
+
+import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.MessageLite;
+import com.google.protobuf.Parser;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
public class MetricsUtils {
+ public static final String DEVICE_SIDE_TEST_PACKAGE =
+ "com.android.server.cts.device.statsd";
+ public static final String DEVICE_SIDE_TEST_APK = "CtsStatsdApp.apk";
public static final long COUNT_METRIC_ID = 3333;
public static final long DURATION_METRIC_ID = 4444;
public static final long GAUGE_METRIC_ID = 5555;
@@ -38,20 +55,19 @@
public static AtomMatcher.Builder getAtomMatcher(int atomId) {
AtomMatcher.Builder builder = AtomMatcher.newBuilder();
builder.setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
- .setAtomId(atomId));
+ .setAtomId(atomId));
return builder;
}
public static AtomMatcher startAtomMatcher(int id) {
- return AtomMatcher.newBuilder()
- .setId(id)
- .setSimpleAtomMatcher(
- SimpleAtomMatcher.newBuilder()
- .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
- .addFieldValueMatcher(FieldValueMatcher.newBuilder()
- .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
- .setEqInt(AppBreadcrumbReported.State.START.ordinal())))
- .build();
+ return AtomMatcher.newBuilder()
+ .setId(id)
+ .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
+ .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
+ .addFieldValueMatcher(FieldValueMatcher.newBuilder()
+ .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
+ .setEqInt(AppBreadcrumbReported.State.START.getNumber())))
+ .build();
}
public static AtomMatcher startAtomMatcherWithLabel(int id, int label) {
@@ -59,15 +75,14 @@
}
public static AtomMatcher stopAtomMatcher(int id) {
- return AtomMatcher.newBuilder()
- .setId(id)
- .setSimpleAtomMatcher(
- SimpleAtomMatcher.newBuilder()
- .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
- .addFieldValueMatcher(FieldValueMatcher.newBuilder()
- .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
- .setEqInt(AppBreadcrumbReported.State.STOP.ordinal())))
- .build();
+ return AtomMatcher.newBuilder()
+ .setId(id)
+ .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
+ .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
+ .addFieldValueMatcher(FieldValueMatcher.newBuilder()
+ .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
+ .setEqInt(AppBreadcrumbReported.State.STOP.getNumber())))
+ .build();
}
public static AtomMatcher stopAtomMatcherWithLabel(int id, int label) {
@@ -81,16 +96,16 @@
.setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
.addFieldValueMatcher(FieldValueMatcher.newBuilder()
.setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
- .setEqInt(AppBreadcrumbReported.State.UNSPECIFIED.ordinal())))
+ .setEqInt(AppBreadcrumbReported.State.UNSPECIFIED.getNumber())))
.build();
}
public static AtomMatcher simpleAtomMatcher(int id) {
- return AtomMatcher.newBuilder()
- .setId(id)
- .setSimpleAtomMatcher(
- SimpleAtomMatcher.newBuilder().setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER))
- .build();
+ return AtomMatcher.newBuilder()
+ .setId(id)
+ .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
+ .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER))
+ .build();
}
public static AtomMatcher appBreadcrumbMatcherWithLabel(int id, int label) {
@@ -113,7 +128,7 @@
.setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
.addFieldValueMatcher(FieldValueMatcher.newBuilder()
.setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
- .setEqInt(state.ordinal()))
+ .setEqInt(state.getNumber()))
.addFieldValueMatcher(FieldValueMatcher.newBuilder()
.setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER)
.setEqInt(label)))
@@ -121,16 +136,16 @@
}
public static AtomMatcher simpleAtomMatcher(int id, int label) {
- return AtomMatcher.newBuilder()
- .setId(id)
- .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
- .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
- .addFieldValueMatcher(FieldValueMatcher.newBuilder()
- .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER)
- .setEqInt(label)
- )
- )
- .build();
+ return AtomMatcher.newBuilder()
+ .setId(id)
+ .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
+ .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
+ .addFieldValueMatcher(FieldValueMatcher.newBuilder()
+ .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER)
+ .setEqInt(label)
+ )
+ )
+ .build();
}
public static EventActivation.Builder createEventActivation(int ttlSecs, int matcherId,
@@ -142,7 +157,14 @@
}
public static long StringToId(String str) {
- return str.hashCode();
+ return str.hashCode();
+ }
+
+ public static String getCurrentLogcatDate(ITestDevice device) throws Exception {
+ // TODO: Do something more robust than this for getting logcat markers.
+ long timestampMs = device.getDeviceDate();
+ return new SimpleDateFormat("MM-dd HH:mm:ss.SSS")
+ .format(new Date(timestampMs));
}
public static void assertBucketTimePresent(Message bucketInfo) {
@@ -154,11 +176,60 @@
if (bucketNum != null && bucketInfo.hasField(bucketNum)) {
found = true;
} else if (startMillis != null && bucketInfo.hasField(startMillis) &&
- endMillis != null && bucketInfo.hasField(endMillis)) {
+ endMillis != null && bucketInfo.hasField(endMillis)) {
found = true;
}
assertWithMessage(
"Bucket info did not have either bucket num or start and end elapsed millis"
).that(found).isTrue();
}
+
+ public static boolean didIncidentdFireSince(ITestDevice device, String date) throws Exception {
+ final String INCIDENTD_TAG = "incidentd";
+ final String INCIDENTD_STARTED_STRING = "reportIncident";
+ // TODO: Do something more robust than this in case of delayed logging.
+ RunUtil.getDefault().sleep(1000);
+ String log = getLogcatSince(device, date, String.format(
+ "-s %s -e %s", INCIDENTD_TAG, INCIDENTD_STARTED_STRING));
+ return log.contains(INCIDENTD_STARTED_STRING);
+ }
+
+ public static String getLogcatSince(ITestDevice device, String date, String logcatParams)
+ throws Exception {
+ return device.executeShellCommand(String.format(
+ "logcat -v threadtime -t '%s' -d %s", date, logcatParams));
+ }
+
+ /**
+ * Call onto the device with an adb shell command and get the results of
+ * that as a proto of the given type.
+ *
+ * @param parser A protobuf parser object. e.g. MyProto.parser()
+ * @param command The adb shell command to run. e.g. "dumpsys fingerprint --proto"
+ * @throws DeviceNotAvailableException If there was a problem communicating with
+ * the test device.
+ * @throws InvalidProtocolBufferException If there was an error parsing
+ * the proto. Note that a 0 length buffer is not
+ * necessarily an error.
+ */
+ public static <T extends MessageLite> T getDump(ITestDevice device, Parser<T> parser,
+ String command)
+ throws DeviceNotAvailableException, InvalidProtocolBufferException {
+ final CollectingByteOutputReceiver receiver = new CollectingByteOutputReceiver();
+ device.executeShellCommand(command, receiver);
+ if (false) {
+ LogUtil.CLog.d("Command output while parsing " + parser.getClass().getCanonicalName()
+ + " for command: " + command + "\n"
+ + BufferDebug.debugString(receiver.getOutput(), -1));
+ }
+ try {
+ return parser.parseFrom(receiver.getOutput());
+ } catch (Exception ex) {
+ LogUtil.CLog.d(
+ "Error parsing " + parser.getClass().getCanonicalName() + " for command: "
+ + command
+ + BufferDebug.debugString(receiver.getOutput(), 16384));
+ throw ex;
+ }
+ }
}
diff --git a/tests/src/android/cts/statsd/metric/ValueMetricsTests.java b/tests/src/android/cts/statsd/metric/ValueMetricsTests.java
index 3b4ef56..4ac1d5e 100644
--- a/tests/src/android/cts/statsd/metric/ValueMetricsTests.java
+++ b/tests/src/android/cts/statsd/metric/ValueMetricsTests.java
@@ -17,14 +17,14 @@
import static com.google.common.truth.Truth.assertThat;
-import android.cts.statsd.atom.DeviceAtomTestCase;
+import android.cts.statsdatom.lib.AtomTestUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.ReportUtils;
import com.android.internal.os.StatsdConfigProto.ActivationType;
import com.android.internal.os.StatsdConfigProto.AtomMatcher;
import com.android.internal.os.StatsdConfigProto.EventActivation;
-import com.android.internal.os.StatsdConfigProto.FieldFilter;
import com.android.internal.os.StatsdConfigProto.FieldMatcher;
-import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
import com.android.internal.os.StatsdConfigProto.MetricActivation;
import com.android.internal.os.StatsdConfigProto.Predicate;
import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
@@ -41,286 +41,320 @@
import com.android.os.StatsLog.ValueMetricData;
import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.util.RunUtil;
-public class ValueMetricsTests extends DeviceAtomTestCase {
- private static final int APP_BREADCRUMB_REPORTED_A_MATCH_START_ID = 0;
- private static final int APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID = 1;
- private static final int APP_BREADCRUMB_REPORTED_B_MATCH_START_ID = 2;
+import com.google.protobuf.ExtensionRegistry;
- public void testValueMetric() throws Exception {
- // Add AtomMatcher's.
- AtomMatcher startAtomMatcher =
- MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID);
- AtomMatcher stopAtomMatcher =
- MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID);
- AtomMatcher atomMatcher =
- MetricsUtils.simpleAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID);
+public class ValueMetricsTests extends DeviceTestCase {
+ private static final int APP_BREADCRUMB_REPORTED_A_MATCH_START_ID = 0;
+ private static final int APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID = 1;
+ private static final int APP_BREADCRUMB_REPORTED_B_MATCH_START_ID = 2;
- StatsdConfig.Builder builder = createConfigBuilder();
- builder.addAtomMatcher(startAtomMatcher);
- builder.addAtomMatcher(stopAtomMatcher);
- builder.addAtomMatcher(atomMatcher);
-
- // Add ValueMetric.
- builder.addValueMetric(
- ValueMetric.newBuilder()
- .setId(MetricsUtils.VALUE_METRIC_ID)
- .setWhat(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
- .setBucket(TimeUnit.CTS)
- .setValueField(FieldMatcher.newBuilder()
- .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
- .addChild(FieldMatcher.newBuilder().setField(
- AppBreadcrumbReported.LABEL_FIELD_NUMBER)))
- .setDimensionsInWhat(FieldMatcher.newBuilder()
- .setField(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
- .build())
- .build());
-
- // Upload config.
- uploadConfig(builder);
-
- // Create AppBreadcrumbReported Start/Stop events.
- doAppBreadcrumbReportedStart(1);
- Thread.sleep(1000);
- doAppBreadcrumbReportedStop(1);
- doAppBreadcrumbReportedStart(3);
- doAppBreadcrumbReportedStop(3);
-
- // Wait for the metrics to propagate to statsd.
- Thread.sleep(1000);
-
- StatsLogReport metricReport = getStatsLogReport();
- LogUtil.CLog.d("Got the following value metric data: " + metricReport.toString());
- assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
- assertThat(metricReport.hasValueMetrics()).isTrue();
- StatsLogReport.ValueMetricDataWrapper valueData = metricReport.getValueMetrics();
- assertThat(valueData.getDataCount()).isEqualTo(1);
-
- int bucketCount = valueData.getData(0).getBucketInfoCount();
- assertThat(bucketCount).isGreaterThan(1);
- ValueMetricData data = valueData.getData(0);
- int totalValue = 0;
- for (ValueBucketInfo bucketInfo : data.getBucketInfoList()) {
- MetricsUtils.assertBucketTimePresent(bucketInfo);
- assertThat(bucketInfo.getValuesCount()).isEqualTo(1);
- assertThat(bucketInfo.getValues(0).getIndex()).isEqualTo(0);
- totalValue += (int) bucketInfo.getValues(0).getValueLong();
- }
- assertThat(totalValue).isEqualTo(8);
- }
-
- // Test value metric with pulled atoms and across multiple buckets
- public void testPullerAcrossBuckets() throws Exception {
- // Add AtomMatcher's.
- final String predicateTrueName = "APP_BREADCRUMB_REPORTED_START";
- final String predicateFalseName = "APP_BREADCRUMB_REPORTED_STOP";
- final String predicateName = "APP_BREADCRUMB_REPORTED_IS_STOP";
-
- AtomMatcher startAtomMatcher =
- MetricsUtils.startAtomMatcher(predicateTrueName.hashCode());
- AtomMatcher stopAtomMatcher =
- MetricsUtils.stopAtomMatcher(predicateFalseName.hashCode());
-
- StatsdConfig.Builder builder = createConfigBuilder();
- builder.addAtomMatcher(startAtomMatcher);
- builder.addAtomMatcher(stopAtomMatcher);
- builder.addPredicate(Predicate.newBuilder()
- .setId(predicateName.hashCode())
- .setSimplePredicate(SimplePredicate.newBuilder()
- .setStart(predicateTrueName.hashCode())
- .setStop(predicateFalseName.hashCode())
- .setCountNesting(false)
- )
- );
-
- final String atomName = "SYSTEM_ELAPSED_REALTIME";
- SimpleAtomMatcher.Builder sam = SimpleAtomMatcher.newBuilder().setAtomId(Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER);
- builder.addAtomMatcher(AtomMatcher.newBuilder()
- .setId(atomName.hashCode())
- .setSimpleAtomMatcher(sam));
-
- // Add ValueMetric.
- builder.addValueMetric(
- ValueMetric.newBuilder()
- .setId(MetricsUtils.VALUE_METRIC_ID)
- .setWhat(atomName.hashCode())
- .setBucket(TimeUnit.ONE_MINUTE)
- .setValueField(FieldMatcher.newBuilder()
- .setField(Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER)
- .addChild(FieldMatcher.newBuilder().setField(
- SystemElapsedRealtime.TIME_MILLIS_FIELD_NUMBER)))
- .setCondition(predicateName.hashCode())
- .build());
-
- // Upload config.
- uploadConfig(builder);
-
- // Create AppBreadcrumbReported Start/Stop events.
- doAppBreadcrumbReportedStart(1);
- // Wait for 2 min and 1 sec to capture at least 2 buckets
- Thread.sleep(2*60_000 + 10_000);
- doAppBreadcrumbReportedStop(1);
-
- // Wait for the metrics to propagate to statsd.
- Thread.sleep(1_000);
-
- StatsLogReport metricReport = getStatsLogReport();
- LogUtil.CLog.d("Got the following value metric data: " + metricReport.toString());
- assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
- assertThat(metricReport.hasValueMetrics()).isTrue();
- StatsLogReport.ValueMetricDataWrapper valueData = metricReport.getValueMetrics();
- assertThat(valueData.getDataCount()).isEqualTo(1);
-
- int bucketCount = valueData.getData(0).getBucketInfoCount();
- // should have at least 2 buckets
- assertThat(bucketCount).isAtLeast(2);
- ValueMetricData data = valueData.getData(0);
- int totalValue = 0;
- for (ValueBucketInfo bucketInfo : data.getBucketInfoList()) {
- MetricsUtils.assertBucketTimePresent(bucketInfo);
- assertThat(bucketInfo.getValuesCount()).isEqualTo(1);
- assertThat(bucketInfo.getValues(0).getIndex()).isEqualTo(0);
- totalValue += (int) bucketInfo.getValues(0).getValueLong();
- }
- // At most we lose one full min bucket
- assertThat(totalValue).isGreaterThan(130_000 - 60_000);
- }
-
- // Test value metric with pulled atoms and across multiple buckets
- public void testMultipleEventsPerBucket() throws Exception {
- // Add AtomMatcher's.
- final String predicateTrueName = "APP_BREADCRUMB_REPORTED_START";
- final String predicateFalseName = "APP_BREADCRUMB_REPORTED_STOP";
- final String predicateName = "APP_BREADCRUMB_REPORTED_IS_STOP";
-
- AtomMatcher startAtomMatcher =
- MetricsUtils.startAtomMatcher(predicateTrueName.hashCode());
- AtomMatcher stopAtomMatcher =
- MetricsUtils.stopAtomMatcher(predicateFalseName.hashCode());
-
- StatsdConfig.Builder builder = createConfigBuilder();
- builder.addAtomMatcher(startAtomMatcher);
- builder.addAtomMatcher(stopAtomMatcher);
- builder.addPredicate(Predicate.newBuilder()
- .setId(predicateName.hashCode())
- .setSimplePredicate(SimplePredicate.newBuilder()
- .setStart(predicateTrueName.hashCode())
- .setStop(predicateFalseName.hashCode())
- .setCountNesting(false)
- )
- );
-
- final String atomName = "SYSTEM_ELAPSED_REALTIME";
- SimpleAtomMatcher.Builder sam = SimpleAtomMatcher.newBuilder().setAtomId(Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER);
- builder.addAtomMatcher(AtomMatcher.newBuilder()
- .setId(atomName.hashCode())
- .setSimpleAtomMatcher(sam));
-
- // Add ValueMetric.
- builder.addValueMetric(
- ValueMetric.newBuilder()
- .setId(MetricsUtils.VALUE_METRIC_ID)
- .setWhat(atomName.hashCode())
- .setBucket(TimeUnit.ONE_MINUTE)
- .setValueField(FieldMatcher.newBuilder()
- .setField(Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER)
- .addChild(FieldMatcher.newBuilder().setField(
- SystemElapsedRealtime.TIME_MILLIS_FIELD_NUMBER)))
- .setCondition(predicateName.hashCode())
- .build());
-
- // Upload config.
- uploadConfig(builder);
-
- final int NUM_EVENTS = 10;
- final long GAP_INTERVAL = 10_000;
- // Create AppBreadcrumbReported Start/Stop events.
- for (int i = 0; i < NUM_EVENTS; i ++) {
- doAppBreadcrumbReportedStart(1);
- Thread.sleep(GAP_INTERVAL);
- doAppBreadcrumbReportedStop(1);
- Thread.sleep(GAP_INTERVAL);
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ RunUtil.getDefault().sleep(1000);
}
- // Wait for the metrics to propagate to statsd.
- Thread.sleep(1_000);
-
- StatsLogReport metricReport = getStatsLogReport();
- LogUtil.CLog.d("Got the following value metric data: " + metricReport.toString());
- assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
- assertThat(metricReport.hasValueMetrics()).isTrue();
- StatsLogReport.ValueMetricDataWrapper valueData = metricReport.getValueMetrics();
- assertThat(valueData.getDataCount()).isEqualTo(1);
-
- int bucketCount = valueData.getData(0).getBucketInfoCount();
- // should have at least 2 buckets
- assertThat(bucketCount).isAtLeast(2);
- ValueMetricData data = valueData.getData(0);
- int totalValue = 0;
- for (ValueBucketInfo bucketInfo : data.getBucketInfoList()) {
- MetricsUtils.assertBucketTimePresent(bucketInfo);
- assertThat(bucketInfo.getValuesCount()).isEqualTo(1);
- assertThat(bucketInfo.getValues(0).getIndex()).isEqualTo(0);
- totalValue += (int) bucketInfo.getValues(0).getValueLong();
+ @Override
+ protected void tearDown() throws Exception {
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ super.tearDown();
}
- // At most we lose one full min bucket
- assertThat((long) totalValue).isGreaterThan(GAP_INTERVAL * NUM_EVENTS - 60_000);
- }
-
- // Test value metric with pulled atoms and across multiple buckets
- public void testPullerAcrossBucketsWithActivation() throws Exception {
- StatsdConfig.Builder builder = createConfigBuilder();
-
- // Add AtomMatcher's.
- int activationAtomMatcherId = 1;
- int activationAtomMatcherLabel = 1;
- AtomMatcher activationAtomMatcher =
- MetricsUtils.appBreadcrumbMatcherWithLabel(
- activationAtomMatcherId, activationAtomMatcherLabel);
- final String atomName = "SYSTEM_ELAPSED_REALTIME";
- SimpleAtomMatcher.Builder sam = SimpleAtomMatcher.newBuilder()
- .setAtomId(Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER);
- builder.addAtomMatcher(activationAtomMatcher)
- .addAtomMatcher(AtomMatcher.newBuilder()
- .setId(atomName.hashCode())
- .setSimpleAtomMatcher(sam));
-
- // Add ValueMetric.
- builder.addValueMetric(
- ValueMetric.newBuilder()
- .setId(MetricsUtils.VALUE_METRIC_ID)
- .setWhat(atomName.hashCode())
- .setBucket(TimeUnit.ONE_MINUTE)
- .setValueField(FieldMatcher.newBuilder()
- .setField(Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER)
- .addChild(FieldMatcher.newBuilder().setField(
- SystemElapsedRealtime.TIME_MILLIS_FIELD_NUMBER)))
- .build());
- // Add activation.
- builder.addMetricActivation(MetricActivation.newBuilder()
- .setMetricId(MetricsUtils.VALUE_METRIC_ID)
- .setActivationType(ActivationType.ACTIVATE_IMMEDIATELY)
- .addEventActivation(EventActivation.newBuilder()
- .setAtomMatcherId(activationAtomMatcherId)
- .setTtlSeconds(5)));
- // Upload config.
- uploadConfig(builder);
+ public void testValueMetric() throws Exception {
+ // Add AtomMatcher's.
+ AtomMatcher startAtomMatcher =
+ MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID);
+ AtomMatcher stopAtomMatcher =
+ MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID);
+ AtomMatcher atomMatcher =
+ MetricsUtils.simpleAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID);
- // Wait for 1 min and 10 sec to capture at least 1 bucket
- Thread.sleep(60_000 + 10_000);
+ StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ builder.addAtomMatcher(startAtomMatcher);
+ builder.addAtomMatcher(stopAtomMatcher);
+ builder.addAtomMatcher(atomMatcher);
- // Wait for the metrics to propagate to statsd.
- Thread.sleep(1_000);
+ // Add ValueMetric.
+ builder.addValueMetric(ValueMetric.newBuilder()
+ .setId(MetricsUtils.VALUE_METRIC_ID)
+ .setWhat(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
+ .setBucket(TimeUnit.CTS)
+ .setValueField(FieldMatcher.newBuilder()
+ .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
+ .addChild(FieldMatcher.newBuilder().setField(
+ AppBreadcrumbReported.LABEL_FIELD_NUMBER)))
+ .setDimensionsInWhat(FieldMatcher.newBuilder()
+ .setField(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
+ .build())
+ .build());
- StatsLogReport metricReport = getStatsLogReport();
- LogUtil.CLog.d("Got the following value metric data: " + metricReport.toString());
- assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
- assertThat(metricReport.getValueMetrics().getDataList()).isEmpty();
- // Skipped buckets are not added when metric is empty.
- assertThat(metricReport.getValueMetrics().getSkippedList()).isEmpty();
- }
+ // Upload config.
+ ConfigUtils.uploadConfig(getDevice(), builder);
+
+ // Create AppBreadcrumbReported Start/Stop events.
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 1);
+ RunUtil.getDefault().sleep(1000);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 1);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 3);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 3);
+
+ // Wait for the metrics to propagate to statsd.
+ RunUtil.getDefault().sleep(1000);
+
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
+ LogUtil.CLog.d("Got the following value metric data: " + metricReport.toString());
+ assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
+ assertThat(metricReport.hasValueMetrics()).isTrue();
+ StatsLogReport.ValueMetricDataWrapper valueData = metricReport.getValueMetrics();
+ assertThat(valueData.getDataCount()).isEqualTo(1);
+
+ int bucketCount = valueData.getData(0).getBucketInfoCount();
+ assertThat(bucketCount).isGreaterThan(1);
+ ValueMetricData data = valueData.getData(0);
+ int totalValue = 0;
+ for (ValueBucketInfo bucketInfo : data.getBucketInfoList()) {
+ MetricsUtils.assertBucketTimePresent(bucketInfo);
+ assertThat(bucketInfo.getValuesCount()).isEqualTo(1);
+ assertThat(bucketInfo.getValues(0).getIndex()).isEqualTo(0);
+ totalValue += (int) bucketInfo.getValues(0).getValueLong();
+ }
+ assertThat(totalValue).isEqualTo(8);
+ }
+
+ // Test value metric with pulled atoms and across multiple buckets
+ public void testPullerAcrossBuckets() throws Exception {
+ // Add AtomMatcher's.
+ final String predicateTrueName = "APP_BREADCRUMB_REPORTED_START";
+ final String predicateFalseName = "APP_BREADCRUMB_REPORTED_STOP";
+ final String predicateName = "APP_BREADCRUMB_REPORTED_IS_STOP";
+
+ AtomMatcher startAtomMatcher =
+ MetricsUtils.startAtomMatcher(predicateTrueName.hashCode());
+ AtomMatcher stopAtomMatcher =
+ MetricsUtils.stopAtomMatcher(predicateFalseName.hashCode());
+
+ StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ builder.addAtomMatcher(startAtomMatcher);
+ builder.addAtomMatcher(stopAtomMatcher);
+ builder.addPredicate(Predicate.newBuilder()
+ .setId(predicateName.hashCode())
+ .setSimplePredicate(SimplePredicate.newBuilder()
+ .setStart(predicateTrueName.hashCode())
+ .setStop(predicateFalseName.hashCode())
+ .setCountNesting(false)
+ )
+ );
+
+ final String atomName = "SYSTEM_ELAPSED_REALTIME";
+ SimpleAtomMatcher.Builder sam = SimpleAtomMatcher.newBuilder().setAtomId(
+ Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER);
+ builder.addAtomMatcher(AtomMatcher.newBuilder()
+ .setId(atomName.hashCode())
+ .setSimpleAtomMatcher(sam));
+
+ // Add ValueMetric.
+ builder.addValueMetric(ValueMetric.newBuilder()
+ .setId(MetricsUtils.VALUE_METRIC_ID)
+ .setWhat(atomName.hashCode())
+ .setBucket(TimeUnit.ONE_MINUTE)
+ .setValueField(FieldMatcher.newBuilder()
+ .setField(Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER)
+ .addChild(FieldMatcher.newBuilder().setField(
+ SystemElapsedRealtime.TIME_MILLIS_FIELD_NUMBER)))
+ .setCondition(predicateName.hashCode())
+ .build());
+
+ // Upload config.
+ ConfigUtils.uploadConfig(getDevice(), builder);
+
+ // Create AppBreadcrumbReported Start/Stop events.
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 1);
+ // Wait for 2 min and 1 sec to capture at least 2 buckets
+ RunUtil.getDefault().sleep(2 * 60_000 + 10_000);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 1);
+
+ // Wait for the metrics to propagate to statsd.
+ RunUtil.getDefault().sleep(1_000);
+
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
+ LogUtil.CLog.d("Got the following value metric data: " + metricReport.toString());
+ assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
+ assertThat(metricReport.hasValueMetrics()).isTrue();
+ StatsLogReport.ValueMetricDataWrapper valueData = metricReport.getValueMetrics();
+ assertThat(valueData.getDataCount()).isEqualTo(1);
+
+ int bucketCount = valueData.getData(0).getBucketInfoCount();
+ // should have at least 2 buckets
+ assertThat(bucketCount).isAtLeast(2);
+ ValueMetricData data = valueData.getData(0);
+ int totalValue = 0;
+ for (ValueBucketInfo bucketInfo : data.getBucketInfoList()) {
+ MetricsUtils.assertBucketTimePresent(bucketInfo);
+ assertThat(bucketInfo.getValuesCount()).isEqualTo(1);
+ assertThat(bucketInfo.getValues(0).getIndex()).isEqualTo(0);
+ totalValue += (int) bucketInfo.getValues(0).getValueLong();
+ }
+ // At most we lose one full min bucket
+ assertThat(totalValue).isGreaterThan(130_000 - 60_000);
+ }
+
+ // Test value metric with pulled atoms and across multiple buckets
+ public void testMultipleEventsPerBucket() throws Exception {
+ // Add AtomMatcher's.
+ final String predicateTrueName = "APP_BREADCRUMB_REPORTED_START";
+ final String predicateFalseName = "APP_BREADCRUMB_REPORTED_STOP";
+ final String predicateName = "APP_BREADCRUMB_REPORTED_IS_STOP";
+
+ AtomMatcher startAtomMatcher =
+ MetricsUtils.startAtomMatcher(predicateTrueName.hashCode());
+ AtomMatcher stopAtomMatcher =
+ MetricsUtils.stopAtomMatcher(predicateFalseName.hashCode());
+
+ StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ builder.addAtomMatcher(startAtomMatcher);
+ builder.addAtomMatcher(stopAtomMatcher);
+ builder.addPredicate(Predicate.newBuilder()
+ .setId(predicateName.hashCode())
+ .setSimplePredicate(SimplePredicate.newBuilder()
+ .setStart(predicateTrueName.hashCode())
+ .setStop(predicateFalseName.hashCode())
+ .setCountNesting(false)
+ )
+ );
+
+ final String atomName = "SYSTEM_ELAPSED_REALTIME";
+ SimpleAtomMatcher.Builder sam = SimpleAtomMatcher.newBuilder().setAtomId(
+ Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER);
+ builder.addAtomMatcher(AtomMatcher.newBuilder()
+ .setId(atomName.hashCode())
+ .setSimpleAtomMatcher(sam));
+
+ // Add ValueMetric.
+ builder.addValueMetric(ValueMetric.newBuilder()
+ .setId(MetricsUtils.VALUE_METRIC_ID)
+ .setWhat(atomName.hashCode())
+ .setBucket(TimeUnit.ONE_MINUTE)
+ .setValueField(FieldMatcher.newBuilder()
+ .setField(Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER)
+ .addChild(FieldMatcher.newBuilder().setField(
+ SystemElapsedRealtime.TIME_MILLIS_FIELD_NUMBER)))
+ .setCondition(predicateName.hashCode())
+ .build());
+
+ // Upload config.
+ ConfigUtils.uploadConfig(getDevice(), builder);
+
+ final int NUM_EVENTS = 10;
+ final long GAP_INTERVAL = 10_000;
+ // Create AppBreadcrumbReported Start/Stop events.
+ for (int i = 0; i < NUM_EVENTS; i++) {
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), 1);
+ RunUtil.getDefault().sleep(GAP_INTERVAL);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), 1);
+ RunUtil.getDefault().sleep(GAP_INTERVAL);
+ }
+
+ // Wait for the metrics to propagate to statsd.
+ RunUtil.getDefault().sleep(1_000);
+
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
+ LogUtil.CLog.d("Got the following value metric data: " + metricReport.toString());
+ assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
+ assertThat(metricReport.hasValueMetrics()).isTrue();
+ StatsLogReport.ValueMetricDataWrapper valueData = metricReport.getValueMetrics();
+ assertThat(valueData.getDataCount()).isEqualTo(1);
+
+ int bucketCount = valueData.getData(0).getBucketInfoCount();
+ // should have at least 2 buckets
+ assertThat(bucketCount).isAtLeast(2);
+ ValueMetricData data = valueData.getData(0);
+ int totalValue = 0;
+ for (ValueBucketInfo bucketInfo : data.getBucketInfoList()) {
+ MetricsUtils.assertBucketTimePresent(bucketInfo);
+ assertThat(bucketInfo.getValuesCount()).isEqualTo(1);
+ assertThat(bucketInfo.getValues(0).getIndex()).isEqualTo(0);
+ totalValue += (int) bucketInfo.getValues(0).getValueLong();
+ }
+ // At most we lose one full min bucket
+ assertThat((long) totalValue).isGreaterThan(GAP_INTERVAL * NUM_EVENTS - 60_000);
+ }
+
+ // Test value metric with pulled atoms and across multiple buckets
+ public void testPullerAcrossBucketsWithActivation() throws Exception {
+ StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+
+ // Add AtomMatcher's.
+ int activationAtomMatcherId = 1;
+ int activationAtomMatcherLabel = 1;
+ AtomMatcher activationAtomMatcher =
+ MetricsUtils.appBreadcrumbMatcherWithLabel(
+ activationAtomMatcherId, activationAtomMatcherLabel);
+ final String atomName = "SYSTEM_ELAPSED_REALTIME";
+ SimpleAtomMatcher.Builder sam = SimpleAtomMatcher.newBuilder()
+ .setAtomId(Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER);
+ builder.addAtomMatcher(activationAtomMatcher)
+ .addAtomMatcher(AtomMatcher.newBuilder()
+ .setId(atomName.hashCode())
+ .setSimpleAtomMatcher(sam));
+
+ // Add ValueMetric.
+ builder.addValueMetric(ValueMetric.newBuilder()
+ .setId(MetricsUtils.VALUE_METRIC_ID)
+ .setWhat(atomName.hashCode())
+ .setBucket(TimeUnit.ONE_MINUTE)
+ .setValueField(FieldMatcher.newBuilder()
+ .setField(Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER)
+ .addChild(FieldMatcher.newBuilder().setField(
+ SystemElapsedRealtime.TIME_MILLIS_FIELD_NUMBER)))
+ .build());
+ // Add activation.
+ builder.addMetricActivation(MetricActivation.newBuilder()
+ .setMetricId(MetricsUtils.VALUE_METRIC_ID)
+ .setActivationType(ActivationType.ACTIVATE_IMMEDIATELY)
+ .addEventActivation(EventActivation.newBuilder()
+ .setAtomMatcherId(activationAtomMatcherId)
+ .setTtlSeconds(5)));
+
+
+ // Upload config.
+ ConfigUtils.uploadConfig(getDevice(), builder);
+
+ // Wait for 1 min and 10 sec to capture at least 1 bucket
+ RunUtil.getDefault().sleep(60_000 + 10_000);
+
+ // Wait for the metrics to propagate to statsd.
+ RunUtil.getDefault().sleep(1_000);
+
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
+ LogUtil.CLog.d("Got the following value metric data: " + metricReport.toString());
+ assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
+ assertThat(metricReport.getValueMetrics().getDataList()).isEmpty();
+ // Skipped buckets are not added when metric is empty.
+ assertThat(metricReport.getValueMetrics().getSkippedList()).isEmpty();
+ }
public void testValueMetricWithConditionAndActivation() throws Exception {
final int conditionLabel = 2;
@@ -340,7 +374,8 @@
AtomMatcher whatMatcher =
MetricsUtils.unspecifiedAtomMatcher(whatMatcherId);
- StatsdConfig.Builder builder = createConfigBuilder()
+ StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE)
.addAtomMatcher(conditionStartAtomMatcher)
.addAtomMatcher(conditionStopAtomMatcher)
.addAtomMatcher(whatMatcher)
@@ -352,14 +387,13 @@
.setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID)
.build();
Predicate predicate = Predicate.newBuilder()
- .setId(MetricsUtils.StringToId("Predicate"))
- .setSimplePredicate(simplePredicate)
- .build();
+ .setId(MetricsUtils.StringToId("Predicate"))
+ .setSimplePredicate(simplePredicate)
+ .build();
builder.addPredicate(predicate);
// Add ValueMetric.
- builder
- .addValueMetric(ValueMetric.newBuilder()
+ builder.addValueMetric(ValueMetric.newBuilder()
.setId(MetricsUtils.VALUE_METRIC_ID)
.setWhat(whatMatcher.getId())
.setBucket(TimeUnit.ONE_MINUTE)
@@ -380,66 +414,79 @@
)
);
- uploadConfig(builder);
+ ConfigUtils.uploadConfig(getDevice(), builder);
// Activate the metric.
- doAppBreadcrumbReportedStart(activationMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), activationMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Set the condition to true.
- doAppBreadcrumbReportedStart(conditionLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), conditionLabel);
+ RunUtil.getDefault().sleep(10);
// Skipped due to unknown condition at start of bucket.
- doAppBreadcrumbReported(10);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 10);
+ RunUtil.getDefault().sleep(10);
// Skipped due to unknown condition at start of bucket.
- doAppBreadcrumbReported(200);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 200);
+ RunUtil.getDefault().sleep(10);
// Set the condition to false.
- doAppBreadcrumbReportedStop(conditionLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.STOP.getNumber(), conditionLabel);
+ RunUtil.getDefault().sleep(10);
// Log an event that should not be counted because condition is false.
- doAppBreadcrumbReported(3_000);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 3_000);
+ RunUtil.getDefault().sleep(10);
// Let the metric deactivate.
- Thread.sleep(ttlSec * 1000);
+ RunUtil.getDefault().sleep(ttlSec * 1000);
// Log an event that should not be counted.
- doAppBreadcrumbReported(40_000);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 40_000);
+ RunUtil.getDefault().sleep(10);
// Condition to true again.
- doAppBreadcrumbReportedStart(conditionLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), conditionLabel);
+ RunUtil.getDefault().sleep(10);
// Event should not be counted, metric is still not active.
- doAppBreadcrumbReported(500_000);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 500_000);
+ RunUtil.getDefault().sleep(10);
// Activate the metric.
- doAppBreadcrumbReportedStart(activationMatcherLabel);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.START.getNumber(), activationMatcherLabel);
+ RunUtil.getDefault().sleep(10);
// Log an event that should be counted.
- doAppBreadcrumbReported(6_000_000);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 6_000_000);
+ RunUtil.getDefault().sleep(10);
// Let the metric deactivate.
- Thread.sleep(ttlSec * 1000);
+ RunUtil.getDefault().sleep(ttlSec * 1000);
// Log an event that should not be counted.
- doAppBreadcrumbReported(70_000_000);
- Thread.sleep(10);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 70_000_000);
+ RunUtil.getDefault().sleep(10);
// Wait for the metrics to propagate to statsd.
- Thread.sleep(2000);
+ RunUtil.getDefault().sleep(2000);
- StatsLogReport metricReport = getStatsLogReport();
+ StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
LogUtil.CLog.d("Received the following data: " + metricReport.toString());
assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
assertThat(metricReport.hasValueMetrics()).isTrue();
diff --git a/tests/src/android/cts/statsd/restricted/ReadRestrictedStatsPermissionTest.java b/tests/src/android/cts/statsd/restricted/ReadRestrictedStatsPermissionTest.java
index 5191f39..8e563b9 100644
--- a/tests/src/android/cts/statsd/restricted/ReadRestrictedStatsPermissionTest.java
+++ b/tests/src/android/cts/statsd/restricted/ReadRestrictedStatsPermissionTest.java
@@ -1,14 +1,44 @@
package android.cts.statsd.restricted;
-import android.cts.statsd.atom.DeviceAtomTestCase;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.cts.statsd.metric.MetricsUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.RunUtil;
/**
* Tests Suite for restricted stats permissions.
*/
-public class ReadRestrictedStatsPermissionTest extends DeviceAtomTestCase {
+public class ReadRestrictedStatsPermissionTest extends DeviceTestCase implements IBuildReceiver {
+
+ private IBuildInfo mCtsBuild;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ assertThat(mCtsBuild).isNotNull();
+ DeviceUtils.installTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_APK,
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, mCtsBuild);
+ RunUtil.getDefault().sleep(1000);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ DeviceUtils.uninstallTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ super.tearDown();
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
+ }
public void testReadRestrictedStatsPermission() throws Exception {
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE,
+ DeviceUtils.runDeviceTests(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE,
".RestrictedPermissionTests", "testReadRestrictedStatsPermission");
}
}
diff --git a/tests/src/android/cts/statsd/subscriber/ShellSubscriberTest.java b/tests/src/android/cts/statsd/subscriber/ShellSubscriberTest.java
index d3c142b..a79b2b0 100644
--- a/tests/src/android/cts/statsd/subscriber/ShellSubscriberTest.java
+++ b/tests/src/android/cts/statsd/subscriber/ShellSubscriberTest.java
@@ -16,12 +16,11 @@
package android.cts.statsd.subscriber;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
import com.android.compatibility.common.util.CpuFeatures;
import com.android.internal.os.StatsdConfigProto;
+import com.android.os.AtomsProto;
import com.android.os.AtomsProto.Atom;
-import com.android.os.AtomsProto.SystemUptime;
import com.android.os.ShellConfig;
import com.android.os.statsd.ShellDataProto;
import com.android.tradefed.device.CollectingByteOutputReceiver;
@@ -29,6 +28,8 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil;
import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.util.RunUtil;
+
import com.google.common.io.Files;
import com.google.protobuf.InvalidProtocolBufferException;
@@ -37,18 +38,20 @@
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
-import android.cts.statsd.atom.AtomTestCase;
+
+import android.cts.statsdatom.lib.AtomTestUtils;
/**
* Statsd shell data subscription test.
*/
-public class ShellSubscriberTest extends AtomTestCase {
+public class ShellSubscriberTest extends DeviceTestCase {
private int sizetBytes;
public class ShellSubscriptionThread extends Thread {
String cmd;
CollectingByteOutputReceiver receiver;
int maxTimeoutForCommandSec;
+
public ShellSubscriptionThread(
String cmd,
CollectingByteOutputReceiver receiver,
@@ -57,7 +60,8 @@
this.receiver = receiver;
this.maxTimeoutForCommandSec = maxTimeoutForCommandSec;
}
- public void run () {
+
+ public void run() {
try {
getDevice().executeShellCommand(cmd, receiver, maxTimeoutForCommandSec,
/*maxTimeToOutputShellResponse=*/maxTimeoutForCommandSec, TimeUnit.SECONDS,
@@ -124,27 +128,28 @@
String cmd = "cat " + remotePath + " | cmd stats data-subscribe " + timeout;
String firstSubCmd =
- "cat " + remotePath + " | cmd stats data-subscribe " + firstSubTimeout;
+ "cat " + remotePath + " | cmd stats data-subscribe " + firstSubTimeout;
for (int i = 0; i < maxSubs; i++) {
// Run data-subscribe on a thread
receivers[i] = new CollectingByteOutputReceiver();
if (i == 0) {
shellThreads[i] =
- new ShellSubscriptionThread(firstSubCmd, receivers[i], firstSubTimeout);
+ new ShellSubscriptionThread(firstSubCmd, receivers[i], firstSubTimeout);
} else {
shellThreads[i] =
- new ShellSubscriptionThread(cmd, receivers[i], timeout);
+ new ShellSubscriptionThread(cmd, receivers[i], timeout);
}
shellThreads[i].start();
LogUtil.CLog.d("Starting new shell subscription.");
}
// Sleep 2 seconds to make sure all subscription clients are initialized before
// first pushed event
- Thread.sleep(2000);
+ RunUtil.getDefault().sleep(2000);
// Pushed event. arbitrary label = 1
- doAppBreadcrumbReported(1);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AtomsProto.AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 1);
// Make sure the last 19 threads die before moving to the next step.
// First subscription is still active due to its longer timeout that is used keep
@@ -163,26 +168,27 @@
// Run data-subscribe on a thread
receivers[i] = new CollectingByteOutputReceiver();
shellThreads[i] =
- new ShellSubscriptionThread(cmd, receivers[i], timeout);
+ new ShellSubscriptionThread(cmd, receivers[i], timeout);
shellThreads[i].start();
LogUtil.CLog.d("Starting new shell subscription.");
}
// Sleep 2 seconds to make sure all subscription clients are initialized before
// pushed event
- Thread.sleep(2000);
+ RunUtil.getDefault().sleep(2000);
// ShellSubscriber only allows 20 subscriptions at a time. This is the 21st which will
// be ignored
receivers[maxSubs] = new CollectingByteOutputReceiver();
shellThreads[maxSubs] =
- new ShellSubscriptionThread(cmd, receivers[maxSubs], timeout);
+ new ShellSubscriptionThread(cmd, receivers[maxSubs], timeout);
shellThreads[maxSubs].start();
// Sleep 1 seconds to ensure that the 21st subscription is rejected
- Thread.sleep(1000);
+ RunUtil.getDefault().sleep(1000);
// Pushed event. arbitrary label = 1
- doAppBreadcrumbReported(1);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AtomsProto.AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 1);
// Make sure all the threads die before moving to the next step
for (int i = 0; i <= maxSubs; i++) {
@@ -219,7 +225,7 @@
private ShellConfig.ShellSubscription createConfig() {
return ShellConfig.ShellSubscription.newBuilder()
.addPushed((StatsdConfigProto.SimpleAtomMatcher.newBuilder()
- .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER))
+ .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER))
.build()).build();
}
@@ -260,15 +266,16 @@
String cmd = "cat " + remotePath + " | cmd stats data-subscribe " + timeout;
// Run data-subscribe on a thread
ShellSubscriptionThread shellThread =
- new ShellSubscriptionThread(cmd, receiver, timeout);
+ new ShellSubscriptionThread(cmd, receiver, timeout);
shellThread.start();
LogUtil.CLog.d("Starting new shell subscription.");
// Sleep a second to make sure subscription is initiated
- Thread.sleep(1000);
+ RunUtil.getDefault().sleep(1000);
// Pushed event. arbitrary label = 1
- doAppBreadcrumbReported(1);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AtomsProto.AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 1);
// Wait for thread to die before returning
shellThread.join();
// Remove config from device if not already deleted
@@ -319,7 +326,7 @@
assertThat(data.getAtom(0).hasAppBreadcrumbReported()).isTrue();
assertThat(data.getAtom(0).getAppBreadcrumbReported().getLabel()).isEqualTo(1);
assertThat(data.getAtom(0).getAppBreadcrumbReported().getState().getNumber())
- .isEqualTo(1);
+ .isEqualTo(1);
atomCount++;
startIndex += sizetBytes + dataLength;
}
diff --git a/tests/src/android/cts/statsd/uidmap/UidMapTests.java b/tests/src/android/cts/statsd/uidmap/UidMapTests.java
index 4ceefa7..595a987 100644
--- a/tests/src/android/cts/statsd/uidmap/UidMapTests.java
+++ b/tests/src/android/cts/statsd/uidmap/UidMapTests.java
@@ -17,7 +17,12 @@
import static com.google.common.truth.Truth.assertThat;
-import android.cts.statsd.atom.DeviceAtomTestCase;
+import android.cts.statsd.metric.MetricsUtils;
+import android.cts.statsdatom.lib.AtomTestUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
+
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.internal.os.StatsdConfigProto;
import com.android.os.AtomsProto;
@@ -25,18 +30,54 @@
import com.android.os.StatsLog.ConfigMetricsReport;
import com.android.os.StatsLog.UidMapping;
import com.android.os.StatsLog.UidMapping.PackageInfoSnapshot;
+import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.RunUtil;
-import java.util.List;
+import com.google.protobuf.ExtensionRegistry;
-public class UidMapTests extends DeviceAtomTestCase {
+public class UidMapTests extends DeviceTestCase implements IBuildReceiver {
+
+ private static final long DEVICE_SIDE_TEST_PKG_HASH =
+ Long.parseUnsignedLong("15694052924544098582");
+
+ private IBuildInfo mCtsBuild;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ assertThat(mCtsBuild).isNotNull();
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ DeviceUtils.installTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_APK,
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, mCtsBuild);
+ RunUtil.getDefault().sleep(1000);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ DeviceUtils.uninstallTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ super.tearDown();
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
+ }
// Tests that every report has at least one snapshot.
public void testUidSnapshotIncluded() throws Exception {
// There should be at least the test app installed during the test setup.
- createAndUploadConfig(AtomsProto.Atom.UID_PROCESS_STATE_CHANGED_FIELD_NUMBER);
+ ConfigUtils.uploadConfigForPushedAtom(getDevice(),
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE,
+ AtomsProto.Atom.UID_PROCESS_STATE_CHANGED_FIELD_NUMBER);
- ConfigMetricsReportList reports = getReportList();
+ ConfigMetricsReportList reports = ReportUtils.getReportList(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
assertThat(reports.getReportsCount()).isGreaterThan(0);
for (ConfigMetricsReport report : reports.getReportsList()) {
@@ -64,21 +105,24 @@
// Tests that delta event included during app installation.
public void testChangeFromInstallation() throws Exception {
- getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE);
- createAndUploadConfig(AtomsProto.Atom.UID_PROCESS_STATE_CHANGED_FIELD_NUMBER);
+ getDevice().uninstallPackage(MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ ConfigUtils.uploadConfigForPushedAtom(getDevice(),
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE,
+ AtomsProto.Atom.UID_PROCESS_STATE_CHANGED_FIELD_NUMBER);
// Install the package after the config is sent to statsd. The uid map is not guaranteed to
// be updated if there's no config in statsd.
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
final String result = getDevice().installPackage(
- buildHelper.getTestFile(DEVICE_SIDE_TEST_APK), false, true);
+ buildHelper.getTestFile(MetricsUtils.DEVICE_SIDE_TEST_APK), false, true);
- Thread.sleep(WAIT_TIME_LONG);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
- ConfigMetricsReportList reports = getReportList();
+ ConfigMetricsReportList reports = ReportUtils.getReportList(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
assertThat(reports.getReportsCount()).isGreaterThan(0);
boolean found = false;
- int uid = getUid();
+ int uid = DeviceUtils.getAppUid(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
for (ConfigMetricsReport report : reports.getReportsList()) {
LogUtil.CLog.d("Got the following report: \n" + report.toString());
if (hasMatchingChange(report.getUidMap(), uid, false)) {
@@ -91,18 +135,23 @@
// We check that a re-installation gives a change event (similar to an app upgrade).
public void testChangeFromReinstall() throws Exception {
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
- getDevice().installPackage(buildHelper.getTestFile(DEVICE_SIDE_TEST_APK), false, true);
- createAndUploadConfig(AtomsProto.Atom.UID_PROCESS_STATE_CHANGED_FIELD_NUMBER);
+ getDevice().installPackage(buildHelper.getTestFile(MetricsUtils.DEVICE_SIDE_TEST_APK),
+ false, true);
+ ConfigUtils.uploadConfigForPushedAtom(getDevice(),
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE,
+ AtomsProto.Atom.UID_PROCESS_STATE_CHANGED_FIELD_NUMBER);
// Now enable re-installation.
- getDevice().installPackage(buildHelper.getTestFile(DEVICE_SIDE_TEST_APK), true, true);
+ getDevice().installPackage(buildHelper.getTestFile(MetricsUtils.DEVICE_SIDE_TEST_APK), true,
+ true);
- Thread.sleep(WAIT_TIME_LONG);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
- ConfigMetricsReportList reports = getReportList();
+ ConfigMetricsReportList reports = ReportUtils.getReportList(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
assertThat(reports.getReportsCount()).isGreaterThan(0);
boolean found = false;
- int uid = getUid();
+ int uid = DeviceUtils.getAppUid(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
for (ConfigMetricsReport report : reports.getReportsList()) {
LogUtil.CLog.d("Got the following report: \n" + report.toString());
if (hasMatchingChange(report.getUidMap(), uid, false)) {
@@ -114,14 +163,19 @@
public void testChangeFromUninstall() throws Exception {
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
- getDevice().installPackage(buildHelper.getTestFile(DEVICE_SIDE_TEST_APK), true, true);
- createAndUploadConfig(AtomsProto.Atom.UID_PROCESS_STATE_CHANGED_FIELD_NUMBER);
- int uid = getUid();
- getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE);
+ getDevice().installPackage(buildHelper.getTestFile(MetricsUtils.DEVICE_SIDE_TEST_APK), true,
+ true);
- Thread.sleep(WAIT_TIME_LONG);
+ ConfigUtils.uploadConfigForPushedAtom(getDevice(),
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE,
+ AtomsProto.Atom.UID_PROCESS_STATE_CHANGED_FIELD_NUMBER);
+ int uid = DeviceUtils.getAppUid(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ getDevice().uninstallPackage(MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
- ConfigMetricsReportList reports = getReportList();
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
+
+ ConfigMetricsReportList reports = ReportUtils.getReportList(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
assertThat(reports.getReportsCount()).isGreaterThan(0);
boolean found = false;
diff --git a/tests/src/android/cts/statsd/validation/DirectoryValidationTest.java b/tests/src/android/cts/statsd/validation/DirectoryValidationTest.java
index 37ded0b..4fa5e2a 100644
--- a/tests/src/android/cts/statsd/validation/DirectoryValidationTest.java
+++ b/tests/src/android/cts/statsd/validation/DirectoryValidationTest.java
@@ -1,34 +1,64 @@
package android.cts.statsd.validation;
-import android.cts.statsd.atom.DeviceAtomTestCase;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.cts.statsd.metric.MetricsUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.RunUtil;
/**
* Tests Suite for directories used by Statsd.
*/
-public class DirectoryValidationTest extends DeviceAtomTestCase {
+public class DirectoryValidationTest extends DeviceTestCase implements IBuildReceiver {
+
+ private IBuildInfo mCtsBuild;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ assertThat(mCtsBuild).isNotNull();
+ DeviceUtils.installTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_APK,
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, mCtsBuild);
+ RunUtil.getDefault().sleep(1000);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ DeviceUtils.uninstallTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ super.tearDown();
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
+ }
public void testStatsActiveMetricDirectoryExists() throws Exception {
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE,
+ DeviceUtils.runDeviceTests(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE,
".DirectoryTests", "testStatsActiveMetricDirectoryExists");
}
public void testStatsDataDirectoryExists() throws Exception {
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE,
+ DeviceUtils.runDeviceTests(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE,
".DirectoryTests", "testStatsDataDirectoryExists");
}
public void testStatsMetadataDirectoryExists() throws Exception {
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE,
+ DeviceUtils.runDeviceTests(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE,
".DirectoryTests", "testStatsMetadataDirectoryExists");
}
public void testStatsServiceDirectoryExists() throws Exception {
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE,
+ DeviceUtils.runDeviceTests(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE,
".DirectoryTests", "testStatsServiceDirectoryExists");
}
public void testTrainInfoDirectoryExists() throws Exception {
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE,
+ DeviceUtils.runDeviceTests(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE,
".DirectoryTests", "testTrainInfoDirectoryExists");
}
}
diff --git a/tests/src/android/cts/statsd/validation/ProcStatsValidationTests.java b/tests/src/android/cts/statsd/validation/ProcStatsValidationTests.java
index 1ca4c5c..6b61497 100644
--- a/tests/src/android/cts/statsd/validation/ProcStatsValidationTests.java
+++ b/tests/src/android/cts/statsd/validation/ProcStatsValidationTests.java
@@ -18,20 +18,22 @@
import static com.google.common.truth.Truth.assertThat;
import android.cts.statsd.atom.ProcStateTestCase;
-import android.service.procstats.ProcessState;
+import android.cts.statsd.metric.MetricsUtils;
+import android.cts.statsdatom.lib.AtomTestUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
import android.service.procstats.AggregatedProcessState;
import com.android.internal.os.StatsdConfigProto.StatsdConfig;
+import com.android.os.AtomsProto;
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 com.android.tradefed.util.RunUtil;
import java.util.List;
@@ -42,54 +44,61 @@
private static final String TAG = "Statsd.ProcStatsValidationTests";
+ private static final String sBackgroundServiceName = "StatsdCtsBackgroundService";
+
private static final int EXTRA_WAIT_TIME_MS = 1_000; // as buffer when proc state changing.
+ private static final String DUMP_PROCSTATS_CMD = "dumpsys procstats";
+
private void toggleScreenAndSleep(final long duration) throws Exception {
final long half = duration >> 1;
- Thread.sleep(half);
- turnScreenOff();
- Thread.sleep(half);
- turnScreenOn();
+ RunUtil.getDefault().sleep(half);
+ DeviceUtils.turnScreenOff(getDevice());
+ RunUtil.getDefault().sleep(half);
+ DeviceUtils.turnScreenOn(getDevice());
}
public void testProcessStateByPulling() throws Exception {
startProcStatsTesting();
clearProcStats();
- Thread.sleep(WAIT_TIME_SHORT);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT);
// foreground service
executeForegroundService();
- Thread.sleep(SLEEP_OF_FOREGROUND_SERVICE + EXTRA_WAIT_TIME_MS);
+ RunUtil.getDefault().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);
+ DeviceUtils.executeBackgroundService(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE,
+ sBackgroundServiceName, ACTION_BACKGROUND_SLEEP);
+ RunUtil.getDefault().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);
+ RunUtil.getDefault().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);
+ DeviceUtils.executeBackgroundService(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE,
+ sBackgroundServiceName, ACTION_END_IMMEDIATELY);
final int cacheTime = 2_000; // process should be in cached state for up to this long
- Thread.sleep(cacheTime);
+ RunUtil.getDefault().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);
+ RunUtil.getDefault().sleep(EXTRA_WAIT_TIME_MS + 5_000);
- Thread.sleep(60_000);
- uninstallPackage();
+ RunUtil.getDefault().sleep(60_000);
+ DeviceUtils.uninstallTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
stopProcStatsTesting();
commitProcStatsToDisk();
- Thread.sleep(WAIT_TIME_SHORT);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT);
final String fileName = "PROCSTATSQ_PULL.pbtxt";
- StatsdConfig config = createValidationUtil().getConfig(fileName);
+ StatsdConfig config = ValidationTestUtil.getConfig(fileName, mCtsBuild);
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);
+ ConfigUtils.uploadConfig(getDevice(), config.toBuilder());
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT);
+ AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
+ AtomsProto.AppBreadcrumbReported.State.START.getNumber(), 1);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT + 5_000);
- List<Atom> statsdData = getGaugeMetricDataList();
+ List<Atom> statsdData = ReportUtils.getGaugeMetricAtoms(getDevice());
List<android.service.procstats.ProcessStatsProto> processStatsProtoList
= getAllProcStatsProtoForStatsd();
@@ -101,7 +110,8 @@
String statsdPkgName = "com.android.server.cts.device.statsd";
long rssAvgStatsd = 0;
for (Atom d : statsdData) {
- for (ProcessStatsProto proc : d.getProcStats().getProcStatsSection().getProcessStatsList()) {
+ for (ProcessStatsProto proc :
+ d.getProcStats().getProcStatsSection().getProcessStatsList()) {
if (proc.getProcess().equals(statsdPkgName)) {
LogUtil.CLog.d("Got proto from statsd:");
LogUtil.CLog.d(proc.toString());
@@ -116,7 +126,7 @@
}
long rssAvgProcstats = 0;
- for (android.service.procstats.ProcessStatsProto process: processStatsProtoList) {
+ 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());
@@ -139,111 +149,112 @@
* 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);
+ startProcStatsTesting();
+ clearProcStats();
+ RunUtil.getDefault().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);
+ // foreground service
+ executeForegroundService();
+ RunUtil.getDefault().sleep(SLEEP_OF_FOREGROUND_SERVICE + EXTRA_WAIT_TIME_MS);
+ // background
+ executeBackgroundService(ACTION_BACKGROUND_SLEEP);
+ RunUtil.getDefault().sleep(SLEEP_OF_ACTION_BACKGROUND_SLEEP + EXTRA_WAIT_TIME_MS);
+ // top
+ executeForegroundActivity(ACTION_SLEEP_WHILE_TOP);
+ RunUtil.getDefault().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
+ RunUtil.getDefault().sleep(cacheTime);
+ // foreground
+ // overlay should take 2 sec to appear. So this makes it 4 sec in TOP
+ executeForegroundActivity(ACTION_SHOW_APPLICATION_OVERLAY);
+ RunUtil.getDefault().sleep(EXTRA_WAIT_TIME_MS + 5_000);
- Thread.sleep(60_000);
- uninstallPackage();
- stopProcStatsTesting();
- commitProcStatsToDisk();
- Thread.sleep(WAIT_TIME_SHORT);
+ RunUtil.getDefault().sleep(60_000);
+ uninstallPackage();
+ stopProcStatsTesting();
+ commitProcStatsToDisk();
+ RunUtil.getDefault().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);
+ 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);
+ RunUtil.getDefault().sleep(WAIT_TIME_SHORT);
+ setAppBreadcrumbPredicate();
+ RunUtil.getDefault().sleep(WAIT_TIME_SHORT);
- List<Atom> statsdData = getGaugeMetricDataList();
- assertThat(statsdData).isNotEmpty();
- assertThat(
- statsdData.get(0).getProcStatsPkgProc().getProcStatsSection()
- .getProcessStatsList()
- ).isNotEmpty();
+ 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("======================");
+ // 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);
- }
- }
+ 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);
+ LogUtil.CLog.d("avg rss from statsd is " + rssAvgStatsd);
- List<ProcessStatsPackageProto> processStatsPackageProtoList = getAllProcStatsProto();
+ 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);
+ 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);
- */
+ LogUtil.CLog.d("avg pss from procstats is " + pssAvgProcstats);
+ assertThat(rssAvgStatsd).isEqualTo(rssAvgProcstats);
+ */
}
private boolean isPssProfilingDisabled() throws Exception {
@@ -254,4 +265,45 @@
final String dumpsys = device.executeShellCommand("dumpsys activity settings");
return (dumpsys.contains(stringToCompare));
}
+
+ protected void clearProcStats() throws Exception {
+ getDevice().executeShellCommand("dumpsys procstats --clear");
+ }
+
+ private void startProcStatsTesting() throws Exception {
+ getDevice().executeShellCommand("dumpsys procstats --start-testing");
+ }
+
+ private void stopProcStatsTesting() throws Exception {
+ getDevice().executeShellCommand("dumpsys procstats --stop-testing");
+ }
+
+ private void commitProcStatsToDisk() throws Exception {
+ getDevice().executeShellCommand("dumpsys procstats --commit");
+ }
+
+ /*
+ * Get all processes' procstats statsd data in proto
+ */
+ protected List<android.service.procstats.ProcessStatsProto> getAllProcStatsProtoForStatsd()
+ throws Exception {
+ try {
+ android.service.procstats.ProcessStatsSectionProto sectionProto = MetricsUtils.getDump(
+ getDevice(),
+ android.service.procstats.ProcessStatsSectionProto.parser(),
+ String.join(" ", DUMP_PROCSTATS_CMD,
+ "--statsd"));
+ List<android.service.procstats.ProcessStatsProto> processStatsProtoList
+ = sectionProto.getProcessStatsList();
+ LogUtil.CLog.d("Got procstats:\n ");
+ for (android.service.procstats.ProcessStatsProto processStatsProto
+ : processStatsProtoList) {
+ LogUtil.CLog.d(processStatsProto.toString());
+ }
+ return processStatsProtoList;
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ LogUtil.CLog.e("Failed to dump procstats proto");
+ throw (e);
+ }
+ }
}
diff --git a/tests/src/android/cts/statsd/validation/StatsFrameworkInitializerTest.java b/tests/src/android/cts/statsd/validation/StatsFrameworkInitializerTest.java
index 0ea332e..2a67748 100644
--- a/tests/src/android/cts/statsd/validation/StatsFrameworkInitializerTest.java
+++ b/tests/src/android/cts/statsd/validation/StatsFrameworkInitializerTest.java
@@ -16,13 +16,43 @@
package android.cts.statsd.validation;
-import android.cts.statsd.atom.DeviceAtomTestCase;
+import static com.google.common.truth.Truth.assertThat;
-public class StatsFrameworkInitializerTest extends DeviceAtomTestCase {
+import android.cts.statsd.metric.MetricsUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.RunUtil;
+
+public class StatsFrameworkInitializerTest extends DeviceTestCase implements IBuildReceiver {
+
+ private IBuildInfo mCtsBuild;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ assertThat(mCtsBuild).isNotNull();
+ DeviceUtils.installTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_APK,
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, mCtsBuild);
+ RunUtil.getDefault().sleep(1000);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ DeviceUtils.uninstallTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ super.tearDown();
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
+ }
public void testStatsFrameworkInitializer_failsWhenCalledOutsideOfSystemServiceRegistry()
throws Exception {
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE,
+ DeviceUtils.runDeviceTests(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE,
".StatsFrameworkInitializerTests", "testRegisterServiceWrappers_expectFail");
}
diff --git a/tests/src/android/cts/statsd/validation/ValidationTestUtil.java b/tests/src/android/cts/statsd/validation/ValidationTestUtil.java
index d3e5bad..cb3a41e 100644
--- a/tests/src/android/cts/statsd/validation/ValidationTestUtil.java
+++ b/tests/src/android/cts/statsd/validation/ValidationTestUtil.java
@@ -15,11 +15,10 @@
*/
package android.cts.statsd.validation;
-import android.cts.statsd.atom.BaseTestCase;
-
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.internal.os.StatsdConfigProto.StatsdConfig;
+import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.log.LogUtil;
-import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.util.FileUtil;
import com.google.protobuf.TextFormat;
@@ -28,14 +27,14 @@
import java.io.File;
import java.io.IOException;
-public class ValidationTestUtil extends BaseTestCase {
+public class ValidationTestUtil {
private static final String TAG = "Statsd.ValidationTestUtil";
- public StatsdConfig getConfig(String fileName) throws IOException {
+ public static StatsdConfig getConfig(String fileName, IBuildInfo ctsBuild) throws IOException {
try {
// TODO: Ideally, we should use real metrics that are also pushed to the fleet.
- File configFile = getBuildHelper().getTestFile(fileName);
+ File configFile = getBuildHelper(ctsBuild).getTestFile(fileName);
String configStr = FileUtil.readStringFromFile(configFile);
StatsdConfig.Builder builder = StatsdConfig.newBuilder();
TextFormat.merge(configStr, builder);
@@ -47,4 +46,8 @@
}
return null;
}
+
+ private static CompatibilityBuildHelper getBuildHelper(IBuildInfo ctsBuild) {
+ return new CompatibilityBuildHelper(ctsBuild);
+ }
}
diff --git a/tests/src/android/cts/statsd/validation/ValidationTests.java b/tests/src/android/cts/statsd/validation/ValidationTests.java
index 3add66d..a3f0109 100644
--- a/tests/src/android/cts/statsd/validation/ValidationTests.java
+++ b/tests/src/android/cts/statsd/validation/ValidationTests.java
@@ -18,7 +18,11 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-import android.cts.statsd.atom.DeviceAtomTestCase;
+import android.cts.statsd.metric.MetricsUtils;
+import android.cts.statsdatom.lib.AtomTestUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
import android.os.BatteryPluggedStateEnum;
import android.os.BatteryStatsProto;
import android.os.UidProto;
@@ -47,9 +51,14 @@
import com.android.os.StatsLog.DurationMetricData;
import com.android.os.StatsLog.EventMetricData;
import com.android.os.StatsLog.StatsLogReport;
+import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.RunUtil;
import com.google.common.collect.Range;
+import com.google.protobuf.ExtensionRegistry;
import java.util.Arrays;
import java.util.HashMap;
@@ -60,36 +69,53 @@
/**
* Side-by-side comparison between statsd and batterystats.
*/
-public class ValidationTests extends DeviceAtomTestCase {
+public class ValidationTests extends DeviceTestCase implements IBuildReceiver {
+
+ private IBuildInfo mCtsBuild;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ assertThat(mCtsBuild).isNotNull();
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ DeviceUtils.installTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_APK,
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, mCtsBuild);
+ RunUtil.getDefault().sleep(1000);
+ DeviceUtils.turnBatteryStatsAutoResetOff(
+ getDevice()); // Turn off Battery Stats auto resetting
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ DeviceUtils.uninstallTestApp(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
+ DeviceUtils.resetBatteryStatus(getDevice());
+ DeviceUtils.turnScreenOn(getDevice());
+ DeviceUtils.turnBatteryStatsAutoResetOn(getDevice());
+ super.tearDown();
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
+ }
private static final String TAG = "Statsd.ValidationTests";
private static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
private static final boolean ENABLE_LOAD_TEST = false;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- turnBatteryStatsAutoResetOff(); // Turn off Battery Stats auto resetting
- }
-
- @Override
- protected void tearDown() throws Exception {
- resetBatteryStatus(); // Undo any unplugDevice().
- turnScreenOn(); // Reset screen to on state
- turnBatteryStatsAutoResetOn(); // Turn Battery Stats auto resetting back on
- super.tearDown();
- }
-
public void testPartialWakelock() throws Exception {
- if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return;
+ if (!DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return;
resetBatteryStats();
- unplugDevice();
- flushBatteryStatsHandlers();
+ DeviceUtils.unplugDevice(getDevice());
+ DeviceUtils.flushBatteryStatsHandlers(getDevice());
// AoD needs to be turned off because the screen should go into an off state. But, if AoD is
// on and the device doesn't support STATE_DOZE, the screen sadly goes back to STATE_ON.
- String aodState = getAodState();
- setAodState("0");
- turnScreenOff();
+ String aodState = DeviceUtils.getAodState(getDevice());
+ DeviceUtils.setAodState(getDevice(), "0");
+ DeviceUtils.turnScreenOff(getDevice());
final int atomTag = Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER;
Set<Integer> wakelockOn = new HashSet<>(Arrays.asList(
@@ -105,15 +131,17 @@
// Add state sets to the list in order.
List<Set<Integer>> stateSet = Arrays.asList(wakelockOn, wakelockOff);
- createAndUploadConfig(atomTag, true); // True: uses attribution.
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWakelockState");
+ ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(),
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, atomTag, true); // True: uses attribution.
+ DeviceUtils.runDeviceTests(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, ".AtomTests",
+ "testWakelockState");
// Sorted list of events in order in which they occurred.
- List<EventMetricData> data = getEventMetricDataList();
+ List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
//=================== verify that statsd is correct ===============//
// Assert that the events happened in the expected order.
- assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
+ AtomTestUtils.assertStatesOccurred(stateSet, data,
atom -> atom.getWakelockStateChanged().getState().getNumber());
for (EventMetricData event : data) {
@@ -126,28 +154,30 @@
@RestrictedBuildTest
public void testPartialWakelockDuration() throws Exception {
- if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return;
+ if (!DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return;
// getUid() needs shell command via ADB. turnScreenOff() sometimes let system go to suspend.
// ADB disconnection causes failure of getUid(). Move up here before turnScreenOff().
- final int EXPECTED_UID = getUid();
+ final int EXPECTED_UID = DeviceUtils.getAppUid(getDevice(),
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
- turnScreenOn(); // To ensure that the ScreenOff later gets logged.
+ DeviceUtils.turnScreenOn(getDevice()); // To ensure that the ScreenOff later gets logged.
// AoD needs to be turned off because the screen should go into an off state. But, if AoD is
// on and the device doesn't support STATE_DOZE, the screen sadly goes back to STATE_ON.
- String aodState = getAodState();
- setAodState("0");
+ String aodState = DeviceUtils.getAodState(getDevice());
+ DeviceUtils.setAodState(getDevice(), "0");
uploadWakelockDurationBatteryStatsConfig(TimeUnit.CTS);
- Thread.sleep(WAIT_TIME_SHORT);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT);
resetBatteryStats();
- unplugDevice();
- turnScreenOff();
- flushBatteryStatsHandlers();
+ DeviceUtils.unplugDevice(getDevice());
+ DeviceUtils.turnScreenOff(getDevice());
+ DeviceUtils.flushBatteryStatsHandlers(getDevice());
- Thread.sleep(WAIT_TIME_SHORT);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT);
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWakelockState");
- Thread.sleep(WAIT_TIME_LONG); // Make sure the one second bucket has ended.
+ DeviceUtils.runDeviceTests(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, ".AtomTests",
+ "testWakelockState");
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); // Make sure the one second bucket has ended.
final String EXPECTED_TAG = "StatsdPartialWakelock";
@@ -169,33 +199,35 @@
EXPECTED_UID, EXPECTED_TAG
).that(statsdDurationMs).isIn(Range.closed((long) MIN_DURATION, (long) MAX_DURATION));
- setAodState(aodState); // restores AOD to initial state.
+ DeviceUtils.setAodState(getDevice(), aodState); // restores AOD to initial state.
}
public void testPartialWakelockLoad() throws Exception {
if (!ENABLE_LOAD_TEST) return;
- turnScreenOn(); // To ensure that the ScreenOff later gets logged.
+ DeviceUtils.turnScreenOn(getDevice()); // To ensure that the ScreenOff later gets logged.
uploadWakelockDurationBatteryStatsConfig(TimeUnit.CTS);
- Thread.sleep(WAIT_TIME_SHORT);
+ RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT);
resetBatteryStats();
- unplugDevice();
- turnScreenOff();
+ DeviceUtils.unplugDevice(getDevice());
+ DeviceUtils.turnScreenOff(getDevice());
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWakelockLoad");
+ DeviceUtils.runDeviceTests(getDevice(), MetricsUtils.DEVICE_SIDE_TEST_PACKAGE, ".AtomTests",
+ "testWakelockLoad");
// Give time for stuck wakelocks to increase duration.
- Thread.sleep(10_000);
+ RunUtil.getDefault().sleep(10_000);
final String EXPECTED_TAG = "StatsdPartialWakelock";
- final int EXPECTED_UID = getUid();
+ final int EXPECTED_UID = DeviceUtils.getAppUid(getDevice(),
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
final int NUM_THREADS = 16;
final int NUM_COUNT_PER_THREAD = 1000;
final int MAX_DURATION_MS = 15_000;
final int MIN_DURATION_MS = 1_000;
- BatteryStatsProto batterystatsProto = getBatteryStatsProto();
- HashMap<Integer, HashMap<Long, Long>> statsdWakelockData = getStatsdWakelockData();
+// BatteryStatsProto batterystatsProto = getBatteryStatsProto();
+// HashMap<Integer, HashMap<Long, Long>> statsdWakelockData = getStatsdWakelockData();
// TODO: this fails because we only have the hashes of the wakelock tags in statsd.
// If we want to run this test, we need to fix this.
@@ -256,7 +288,8 @@
// TODO: Refactor these into some utils class.
public HashMap<Integer, HashMap<Long, Long>> getStatsdWakelockData() throws Exception {
- StatsLogReport report = getStatsLogReport();
+ StatsLogReport report = ReportUtils.getStatsLogReport(getDevice(),
+ ExtensionRegistry.getEmptyRegistry());
CLog.d("Received the following stats log report: \n" + report.toString());
// Stores total duration of each wakelock across buckets.
@@ -607,13 +640,14 @@
.addPredicate(screenIsOffId)
.addPredicate(deviceIsUnpluggedId));
- StatsdConfig.Builder builder = createConfigBuilder();
+ StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
+ MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
builder.addDurationMetric(DurationMetric.newBuilder()
- .setId(metricId)
- .setWhat(partialWakelockIsOnId)
- .setCondition(screenOffBatteryOnId)
- .setDimensionsInWhat(dimensions)
- .setBucket(bucketsize))
+ .setId(metricId)
+ .setWhat(partialWakelockIsOnId)
+ .setCondition(screenOffBatteryOnId)
+ .setDimensionsInWhat(dimensions)
+ .setBucket(bucketsize))
.addAtomMatcher(wakelockAcquire)
.addAtomMatcher(wakelockChangeAcquire)
.addAtomMatcher(wakelockRelease)
@@ -639,6 +673,10 @@
.addPredicate(screenIsOff)
.addPredicate(screenOffBatteryOn);
- uploadConfig(builder);
+ ConfigUtils.uploadConfig(getDevice(), builder);
+ }
+
+ private void resetBatteryStats() throws Exception {
+ getDevice().executeShellCommand("dumpsys batterystats --reset");
}
}