diff options
-rw-r--r-- | cmds/statsd/Android.mk | 3 | ||||
-rw-r--r-- | cmds/statsd/src/StatsLogProcessor.h | 5 | ||||
-rw-r--r-- | cmds/statsd/src/metrics/MetricsManager.h | 1 | ||||
-rw-r--r-- | cmds/statsd/tests/e2e/Attribution_e2e_test.cpp | 181 | ||||
-rw-r--r-- | cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp | 3 | ||||
-rw-r--r-- | cmds/statsd/tests/statsd_test_util.cpp | 48 | ||||
-rw-r--r-- | cmds/statsd/tests/statsd_test_util.h | 15 |
7 files changed, 255 insertions, 1 deletions
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index 735efe391eb1..ffe652f72256 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -185,7 +185,8 @@ LOCAL_SRC_FILES := \ tests/metrics/metrics_test_helper.cpp \ tests/statsd_test_util.cpp \ tests/e2e/WakelockDuration_e2e_test.cpp \ - tests/e2e/MetricConditionLink_e2e_test.cpp + tests/e2e/MetricConditionLink_e2e_test.cpp \ + tests/e2e/Attribution_e2e_test.cpp LOCAL_STATIC_LIBRARIES := \ $(statsd_common_static_libraries) \ diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index b527e2790a0c..adc9161f043f 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -56,6 +56,10 @@ public: /* Flushes data to disk. Data on memory will be gone after written to disk. */ void WriteDataToDisk(); + inline sp<UidMap> getUidMap() { + return mUidMap; + } + private: mutable mutex mMetricsMutex; @@ -87,6 +91,7 @@ private: FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge); FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions); FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks); + FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice); }; diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index a03047f3aff2..08b0981bb14f 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -140,6 +140,7 @@ private: FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions); FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks); + FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice); }; } // namespace statsd diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp new file mode 100644 index 000000000000..e28dd3117c06 --- /dev/null +++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp @@ -0,0 +1,181 @@ +// 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. + +#include <gtest/gtest.h> + +#include "src/StatsLogProcessor.h" +#include "src/stats_log_util.h" +#include "tests/statsd_test_util.h" + +#include <vector> + +namespace android { +namespace os { +namespace statsd { + +#ifdef __ANDROID__ + +namespace { + +StatsdConfig CreateStatsdConfig() { + StatsdConfig config; + auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher(); + auto attributionNodeMatcher = + wakelockAcquireMatcher.mutable_simple_atom_matcher()->add_field_value_matcher(); + attributionNodeMatcher->set_field(1); + attributionNodeMatcher->set_position(Position::ANY); + auto uidMatcher = attributionNodeMatcher->mutable_matches_tuple()->add_field_value_matcher(); + uidMatcher->set_field(1); // uid field. + uidMatcher->set_eq_string("com.android.gmscore"); + + *config.add_atom_matcher() = wakelockAcquireMatcher; + + auto countMetric = config.add_count_metric(); + countMetric->set_id(123456); + countMetric->set_what(wakelockAcquireMatcher.id()); + *countMetric->mutable_dimensions() = + CreateAttributionUidAndTagDimensions( + android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST}); + countMetric->set_bucket(ONE_MINUTE); + return config; +} + +} // namespace + +TEST(AttributionE2eTest, TestAttributionMatchAndSlice) { + auto config = CreateStatsdConfig(); + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + + // Here it assumes that GMS core has two uids. + processor->getUidMap()->updateApp( + android::String16("com.android.gmscore"), 222 /* uid */, 1 /* version code*/); + processor->getUidMap()->updateApp( + android::String16("com.android.gmscore"), 444 /* uid */, 1 /* version code*/); + processor->getUidMap()->updateApp( + android::String16("app1"), 111 /* uid */, 2 /* version code*/); + processor->getUidMap()->updateApp( + android::String16("APP3"), 333 /* uid */, 2 /* version code*/); + + // GMS core node is in the middle. + std::vector<AttributionNode> attributions1 = + {CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"), + CreateAttribution(333, "App3")}; + + // GMS core node is the last one. + std::vector<AttributionNode> attributions2 = + {CreateAttribution(111, "App1"), CreateAttribution(333, "App3"), + CreateAttribution(222, "GMSCoreModule1")}; + + // GMS core node is the first one. + std::vector<AttributionNode> attributions3 = + {CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(333, "App3")}; + + // Single GMS core node. + std::vector<AttributionNode> attributions4 = + {CreateAttribution(222, "GMSCoreModule1")}; + + // GMS core has another uid. + std::vector<AttributionNode> attributions5 = + {CreateAttribution(111, "App1"), CreateAttribution(444, "GMSCoreModule2"), + CreateAttribution(333, "App3")}; + + // Multiple GMS core nodes. + std::vector<AttributionNode> attributions6 = + {CreateAttribution(444, "GMSCoreModule2"), CreateAttribution(222, "GMSCoreModule1")}; + + // No GMS core nodes. + std::vector<AttributionNode> attributions7 = + {CreateAttribution(111, "App1"), CreateAttribution(333, "App3")}; + std::vector<AttributionNode> attributions8 = {CreateAttribution(111, "App1")}; + + + std::vector<std::unique_ptr<LogEvent>> events; + // Events 1~4 are in the 1st bucket. + events.push_back(CreateAcquireWakelockEvent( + attributions1, "wl1", bucketStartTimeNs + 2)); + events.push_back(CreateAcquireWakelockEvent( + attributions2, "wl1", bucketStartTimeNs + 200)); + events.push_back(CreateAcquireWakelockEvent( + attributions3, "wl1", bucketStartTimeNs + bucketSizeNs - 1)); + events.push_back(CreateAcquireWakelockEvent( + attributions4, "wl1", bucketStartTimeNs + bucketSizeNs)); + + // Events 5~8 are in the 3rd bucket. + events.push_back(CreateAcquireWakelockEvent( + attributions5, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1)); + events.push_back(CreateAcquireWakelockEvent( + attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100)); + events.push_back(CreateAcquireWakelockEvent( + attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 1)); + events.push_back(CreateAcquireWakelockEvent( + attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs)); + + sortLogEventsByTimestamp(&events); + + for (const auto& event : events) { + processor->OnLogEvent(*event); + } + ConfigMetricsReportList reports; + processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs + 1, &reports); + EXPECT_EQ(reports.reports_size(), 1); + EXPECT_EQ(reports.reports(0).metrics_size(), 1); + StatsLogReport::CountMetricDataWrapper countMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(countMetrics.data_size(), 3); + + auto data = countMetrics.data(0); + ValidateAttributionUidAndTagDimension( + data.dimension(), android::util::WAKELOCK_STATE_CHANGED, 111, "App1"); + EXPECT_EQ(data.bucket_info_size(), 2); + EXPECT_EQ(data.bucket_info(0).count(), 2); + EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs); + EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs); + EXPECT_EQ(data.bucket_info(1).count(), 1); + EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs); + EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs); + + data = countMetrics.data(1); + ValidateAttributionUidAndTagDimension( + data.dimension(), android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1"); + EXPECT_EQ(data.bucket_info_size(), 2); + EXPECT_EQ(data.bucket_info(0).count(), 1); + EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs); + EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs); + EXPECT_EQ(data.bucket_info(1).count(), 1); + EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs); + EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs); + + data = countMetrics.data(2); + ValidateAttributionUidAndTagDimension( + data.dimension(), android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2"); + EXPECT_EQ(data.bucket_info_size(), 1); + EXPECT_EQ(data.bucket_info(0).count(), 1); + EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs); + EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs); +} + +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif + +} // namespace statsd +} // namespace os +} // namespace android
\ No newline at end of file diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp index cbcc36b78785..a81bbb9db435 100644 --- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp @@ -25,6 +25,7 @@ namespace os { namespace statsd { #ifdef __ANDROID__ +namespace { StatsdConfig CreateStatsdConfig() { StatsdConfig config; @@ -92,6 +93,8 @@ StatsdConfig CreateStatsdConfig() { dimensionCondition->add_child()->set_field(1); // uid field. return config; } +} // namespace + TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks) { auto config = CreateStatsdConfig(); diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index 939dc1f7c66c..f9ac6d6d787f 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -319,6 +319,54 @@ void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events) { int64_t StringToId(const string& str) { return static_cast<int64_t>(std::hash<std::string>()(str)); } + +void ValidateAttributionUidDimension(const DimensionsValue& value, int atomId, int uid) { + EXPECT_EQ(value.field(), atomId); + EXPECT_EQ(value.value_tuple().dimensions_value_size(), 1); + // Attribution field. + EXPECT_EQ(value.value_tuple().dimensions_value(0).field(), 1); + // Uid only. + EXPECT_EQ(value.value_tuple().dimensions_value(0) + .value_tuple().dimensions_value_size(), 1); + EXPECT_EQ(value.value_tuple().dimensions_value(0) + .value_tuple().dimensions_value(0).field(), 1); + EXPECT_EQ(value.value_tuple().dimensions_value(0) + .value_tuple().dimensions_value(0).value_int(), uid); +} + +void ValidateUidDimension(const DimensionsValue& value, int atomId, int uid) { + EXPECT_EQ(value.field(), atomId); + EXPECT_EQ(value.value_tuple().dimensions_value_size(), 1); + // Attribution field. + EXPECT_EQ(value.value_tuple().dimensions_value(0).field(), 1); + // Uid only. + EXPECT_EQ(value.value_tuple().dimensions_value(0) + .value_tuple().dimensions_value_size(), 1); + EXPECT_EQ(value.value_tuple().dimensions_value(0) + .value_tuple().dimensions_value(0).field(), 1); + EXPECT_EQ(value.value_tuple().dimensions_value(0) + .value_tuple().dimensions_value(0).value_int(), uid); +} + +void ValidateAttributionUidAndTagDimension( + const DimensionsValue& value, int atomId, int uid, const std::string& tag) { + EXPECT_EQ(value.field(), atomId); + EXPECT_EQ(value.value_tuple().dimensions_value_size(), 1); + // Attribution field. + EXPECT_EQ(value.value_tuple().dimensions_value(0).field(), 1); + // Uid only. + EXPECT_EQ(value.value_tuple().dimensions_value(0) + .value_tuple().dimensions_value_size(), 2); + EXPECT_EQ(value.value_tuple().dimensions_value(0) + .value_tuple().dimensions_value(0).field(), 1); + EXPECT_EQ(value.value_tuple().dimensions_value(0) + .value_tuple().dimensions_value(0).value_int(), uid); + EXPECT_EQ(value.value_tuple().dimensions_value(0) + .value_tuple().dimensions_value(1).field(), 2); + EXPECT_EQ(value.value_tuple().dimensions_value(0) + .value_tuple().dimensions_value(1).value_str(), tag); +} + } // namespace statsd } // namespace os } // namespace android
\ No newline at end of file diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h index 5e19da032e07..f1ce358d0652 100644 --- a/cmds/statsd/tests/statsd_test_util.h +++ b/cmds/statsd/tests/statsd_test_util.h @@ -123,6 +123,21 @@ void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events); int64_t StringToId(const string& str); +void ValidateAttributionUidDimension(const DimensionsValue& value, int atomId, int uid); +void ValidateAttributionUidAndTagDimension( + const DimensionsValue& value, int atomId, int uid, const std::string& tag); + +template <typename T> +void sortMetricDataByDimensionsValue(const T& metricData, T* sortedMetricData) { + std::map<HashableDimensionKey, int> dimensionIndexMap; + for (int i = 0; i < metricData.data_size(); ++i) { + dimensionIndexMap.insert(std::make_pair(metricData.data(i).dimension(), i)); + } + for (const auto& itr : dimensionIndexMap) { + *sortedMetricData->add_data() = metricData.data(itr.second); + } +} + } // namespace statsd } // namespace os } // namespace android
\ No newline at end of file |