| // Copyright (C) 2019 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 <vector> |
| |
| #include "flags/FlagProvider.h" |
| #include "src/StatsLogProcessor.h" |
| #include "src/state/StateTracker.h" |
| #include "src/stats_log_util.h" |
| #include "tests/statsd_test_util.h" |
| |
| namespace android { |
| namespace os { |
| namespace statsd { |
| |
| #ifdef __ANDROID__ |
| |
| // Setup for test fixture. |
| class EventMetricE2eTest : public ::testing::Test { |
| void SetUp() override { |
| FlagProvider::getInstance().overrideFuncs(&isAtLeastSFuncTrue); |
| } |
| |
| void TearDown() override { |
| FlagProvider::getInstance().resetOverrides(); |
| } |
| |
| public: |
| void doTestRepeatedFieldsAndEmptyArrays(); |
| void doTestMatchRepeatedFieldPositionFirst(); |
| }; |
| |
| TEST_F(EventMetricE2eTest, TestEventMetricDataAggregated) { |
| StatsdConfig config; |
| |
| AtomMatcher wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher(); |
| *config.add_atom_matcher() = wakelockAcquireMatcher; |
| |
| EventMetric wakelockEventMetric = |
| createEventMetric("EventWakelockStateChanged", wakelockAcquireMatcher.id(), nullopt); |
| *config.add_event_metric() = wakelockEventMetric; |
| |
| ConfigKey key(123, 987); |
| uint64_t bucketStartTimeNs = 10000000000; // 0:10 |
| sp<StatsLogProcessor> processor = |
| CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key); |
| |
| // Initialize log events before update. |
| std::vector<std::unique_ptr<LogEvent>> events; |
| |
| int app1Uid = 123; |
| vector<int> attributionUids = {app1Uid}; |
| std::vector<string> attributionTags = {"App1"}; |
| |
| events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, |
| attributionUids, attributionTags, "wl1")); |
| events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 20 * NS_PER_SEC, |
| attributionUids, attributionTags, "wl1")); |
| events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 30 * NS_PER_SEC, |
| attributionUids, attributionTags, "wl2")); |
| |
| // Send log events to StatsLogProcessor. |
| for (auto& event : events) { |
| processor->OnLogEvent(event.get()); |
| } |
| |
| uint64_t dumpTimeNs = bucketStartTimeNs + 100 * NS_PER_SEC; |
| ConfigMetricsReportList reports; |
| vector<uint8_t> buffer; |
| processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer); |
| EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); |
| backfillStringInReport(&reports); |
| backfillStartEndTimestamp(&reports); |
| backfillAggregatedAtoms(&reports); |
| 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); |
| auto data = wakelockEventMetricReport.event_metrics().data(0); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 10 * NS_PER_SEC); |
| EXPECT_EQ(data.atom().wakelock_state_changed().tag(), "wl1"); |
| data = wakelockEventMetricReport.event_metrics().data(1); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 20 * NS_PER_SEC); |
| EXPECT_EQ(data.atom().wakelock_state_changed().tag(), "wl1"); |
| data = wakelockEventMetricReport.event_metrics().data(2); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 30 * NS_PER_SEC); |
| EXPECT_EQ(data.atom().wakelock_state_changed().tag(), "wl2"); |
| } |
| |
| TEST_F_GUARDED(EventMetricE2eTest, TestRepeatedFieldsAndEmptyArrays, __ANDROID_API_T__) { |
| StatsdConfig config; |
| |
| AtomMatcher testAtomReportedAtomMatcher = |
| CreateSimpleAtomMatcher("TestAtomReportedMatcher", util::TEST_ATOM_REPORTED); |
| *config.add_atom_matcher() = testAtomReportedAtomMatcher; |
| |
| EventMetric testAtomReportedEventMetric = |
| createEventMetric("EventTestAtomReported", testAtomReportedAtomMatcher.id(), nullopt); |
| *config.add_event_metric() = testAtomReportedEventMetric; |
| |
| ConfigKey key(123, 987); |
| uint64_t bucketStartTimeNs = 10000000000; // 0:10 |
| sp<StatsLogProcessor> processor = |
| CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key); |
| |
| // Initialize log events before update. |
| std::vector<std::unique_ptr<LogEvent>> events; |
| |
| vector<int> intArray = {3, 6}; |
| vector<int64_t> longArray = {1000L, 10002L}; |
| vector<float> floatArray = {0.3f, 0.09f}; |
| vector<string> stringArray = {"str1", "str2"}; |
| int boolArrayLength = 2; |
| bool boolArray[boolArrayLength]; |
| boolArray[0] = 1; |
| boolArray[1] = 0; |
| vector<uint8_t> boolArrayVector = {1, 0}; |
| vector<int> enumArray = {TestAtomReported::ON, TestAtomReported::OFF}; |
| |
| events.push_back(CreateTestAtomReportedEventVariableRepeatedFields( |
| bucketStartTimeNs + 10 * NS_PER_SEC, intArray, longArray, floatArray, stringArray, |
| boolArray, boolArrayLength, enumArray)); |
| events.push_back(CreateTestAtomReportedEventVariableRepeatedFields( |
| bucketStartTimeNs + 20 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, {})); |
| events.push_back(CreateTestAtomReportedEventVariableRepeatedFields( |
| bucketStartTimeNs + 30 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArray)); |
| |
| // Send log events to StatsLogProcessor. |
| for (auto& event : events) { |
| processor->OnLogEvent(event.get()); |
| } |
| |
| uint64_t dumpTimeNs = bucketStartTimeNs + 100 * NS_PER_SEC; |
| ConfigMetricsReportList reports; |
| vector<uint8_t> buffer; |
| processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer); |
| EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); |
| backfillStringInReport(&reports); |
| backfillStartEndTimestamp(&reports); |
| backfillAggregatedAtoms(&reports); |
| ASSERT_EQ(reports.reports_size(), 1); |
| |
| ConfigMetricsReport report = reports.reports(0); |
| ASSERT_EQ(report.metrics_size(), 1); |
| StatsLogReport testAtomEventMetricReport = report.metrics(0); |
| EXPECT_EQ(testAtomEventMetricReport.metric_id(), testAtomReportedEventMetric.id()); |
| EXPECT_TRUE(testAtomEventMetricReport.has_event_metrics()); |
| ASSERT_EQ(testAtomEventMetricReport.event_metrics().data_size(), 3); |
| |
| EventMetricData data = testAtomEventMetricReport.event_metrics().data(0); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 10 * NS_PER_SEC); |
| TestAtomReported atom = data.atom().test_atom_reported(); |
| EXPECT_THAT(atom.repeated_int_field(), ElementsAreArray(intArray)); |
| EXPECT_THAT(atom.repeated_long_field(), ElementsAreArray(longArray)); |
| EXPECT_THAT(atom.repeated_float_field(), ElementsAreArray(floatArray)); |
| EXPECT_THAT(atom.repeated_string_field(), ElementsAreArray(stringArray)); |
| EXPECT_THAT(atom.repeated_boolean_field(), ElementsAreArray(boolArrayVector)); |
| EXPECT_THAT(atom.repeated_enum_field(), ElementsAreArray(enumArray)); |
| |
| data = testAtomEventMetricReport.event_metrics().data(1); |
| atom = data.atom().test_atom_reported(); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 20 * NS_PER_SEC); |
| EXPECT_EQ(atom.repeated_int_field_size(), 0); |
| EXPECT_EQ(atom.repeated_long_field_size(), 0); |
| EXPECT_EQ(atom.repeated_float_field_size(), 0); |
| EXPECT_EQ(atom.repeated_string_field_size(), 0); |
| EXPECT_EQ(atom.repeated_boolean_field_size(), 0); |
| EXPECT_EQ(atom.repeated_enum_field_size(), 0); |
| |
| data = testAtomEventMetricReport.event_metrics().data(2); |
| atom = data.atom().test_atom_reported(); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 30 * NS_PER_SEC); |
| EXPECT_EQ(atom.repeated_int_field_size(), 0); |
| EXPECT_EQ(atom.repeated_long_field_size(), 0); |
| EXPECT_EQ(atom.repeated_float_field_size(), 0); |
| EXPECT_EQ(atom.repeated_string_field_size(), 0); |
| EXPECT_EQ(atom.repeated_boolean_field_size(), 0); |
| EXPECT_THAT(atom.repeated_enum_field(), ElementsAreArray(enumArray)); |
| } |
| |
| TEST_F_GUARDED(EventMetricE2eTest, TestMatchRepeatedFieldPositionFirst, __ANDROID_API_T__) { |
| StatsdConfig config; |
| |
| AtomMatcher testAtomReportedStateFirstOnAtomMatcher = |
| CreateTestAtomRepeatedStateFirstOnAtomMatcher(); |
| *config.add_atom_matcher() = testAtomReportedStateFirstOnAtomMatcher; |
| |
| EventMetric testAtomReportedEventMetric = createEventMetric( |
| "EventTestAtomReported", testAtomReportedStateFirstOnAtomMatcher.id(), nullopt); |
| *config.add_event_metric() = testAtomReportedEventMetric; |
| |
| ConfigKey key(123, 987); |
| uint64_t bucketStartTimeNs = 10000000000; // 0:10 |
| sp<StatsLogProcessor> processor = |
| CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key); |
| |
| // Initialize log events before update. |
| std::vector<std::unique_ptr<LogEvent>> events; |
| |
| vector<int> enumArrayNoMatch = {TestAtomReported::OFF, TestAtomReported::ON}; |
| vector<int> enumArrayMatch = {TestAtomReported::ON, TestAtomReported::OFF}; |
| |
| events.push_back(CreateTestAtomReportedEventVariableRepeatedFields( |
| bucketStartTimeNs + 10 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayNoMatch)); |
| events.push_back(CreateTestAtomReportedEventVariableRepeatedFields( |
| bucketStartTimeNs + 20 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayMatch)); |
| // No matching is done on an empty array. |
| events.push_back(CreateTestAtomReportedEventVariableRepeatedFields( |
| bucketStartTimeNs + 30 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, {})); |
| |
| // Send log events to StatsLogProcessor. |
| for (auto& event : events) { |
| processor->OnLogEvent(event.get()); |
| } |
| |
| uint64_t dumpTimeNs = bucketStartTimeNs + 100 * NS_PER_SEC; |
| ConfigMetricsReportList reports; |
| vector<uint8_t> buffer; |
| processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer); |
| EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); |
| backfillStringInReport(&reports); |
| backfillStartEndTimestamp(&reports); |
| backfillAggregatedAtoms(&reports); |
| ASSERT_EQ(reports.reports_size(), 1); |
| |
| ConfigMetricsReport report = reports.reports(0); |
| ASSERT_EQ(report.metrics_size(), 1); |
| StatsLogReport testAtomEventMetricReport = report.metrics(0); |
| EXPECT_EQ(testAtomEventMetricReport.metric_id(), testAtomReportedEventMetric.id()); |
| EXPECT_TRUE(testAtomEventMetricReport.has_event_metrics()); |
| ASSERT_EQ(testAtomEventMetricReport.event_metrics().data_size(), 1); |
| |
| EventMetricData data = testAtomEventMetricReport.event_metrics().data(0); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 20 * NS_PER_SEC); |
| TestAtomReported atom = data.atom().test_atom_reported(); |
| ASSERT_EQ(atom.repeated_int_field_size(), 0); |
| ASSERT_EQ(atom.repeated_long_field_size(), 0); |
| ASSERT_EQ(atom.repeated_float_field_size(), 0); |
| ASSERT_EQ(atom.repeated_string_field_size(), 0); |
| ASSERT_EQ(atom.repeated_boolean_field_size(), 0); |
| EXPECT_THAT(atom.repeated_enum_field(), ElementsAreArray(enumArrayMatch)); |
| } |
| |
| TEST_F(EventMetricE2eTest, TestDumpReportIncrementsReportNumber) { |
| StatsdConfig config; |
| |
| AtomMatcher testAtomReportedStateFirstOnAtomMatcher = |
| CreateTestAtomRepeatedStateFirstOnAtomMatcher(); |
| *config.add_atom_matcher() = testAtomReportedStateFirstOnAtomMatcher; |
| |
| EventMetric testAtomReportedEventMetric = createEventMetric( |
| "EventTestAtomReported", testAtomReportedStateFirstOnAtomMatcher.id(), nullopt); |
| *config.add_event_metric() = testAtomReportedEventMetric; |
| |
| ConfigKey key(123, 987); |
| uint64_t configUpdateTime = 10000000000; // 0:10 |
| sp<StatsLogProcessor> processor = |
| CreateStatsLogProcessor(configUpdateTime, configUpdateTime, config, key); |
| |
| uint64_t dumpTimeNs = configUpdateTime + 100 * NS_PER_SEC; |
| ConfigMetricsReportList reports; |
| vector<uint8_t> buffer; |
| processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer); |
| EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); |
| ASSERT_EQ(reports.reports_size(), 1); |
| |
| EXPECT_EQ(reports.report_number(), 1); |
| EXPECT_EQ(reports.statsd_stats_id(), StatsdStats::getInstance().getStatsdStatsId()); |
| |
| buffer.clear(); |
| processor->onDumpReport(key, dumpTimeNs + 100, true, true, ADB_DUMP, FAST, &buffer); |
| EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); |
| ASSERT_EQ(reports.reports_size(), 1); |
| |
| EXPECT_EQ(reports.report_number(), 2); |
| EXPECT_EQ(reports.statsd_stats_id(), StatsdStats::getInstance().getStatsdStatsId()); |
| } |
| |
| TEST_F(EventMetricE2eTest, TestEventMetricSampling) { |
| // Set srand seed to make rand deterministic for testing. |
| srand(0); |
| |
| StatsdConfig config; |
| |
| AtomMatcher batterySaverOnMatcher = CreateBatterySaverModeStartAtomMatcher(); |
| *config.add_atom_matcher() = batterySaverOnMatcher; |
| |
| EventMetric batterySaverOnEventMetric = |
| createEventMetric("EventBatterySaverOn", batterySaverOnMatcher.id(), nullopt); |
| batterySaverOnEventMetric.set_sampling_percentage(50); |
| *config.add_event_metric() = batterySaverOnEventMetric; |
| |
| ConfigKey key(123, 987); |
| uint64_t bucketStartTimeNs = 10000000000; // 0:10 |
| sp<StatsLogProcessor> processor = |
| CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key); |
| |
| // Initialize log events before update. |
| std::vector<std::unique_ptr<LogEvent>> events; |
| |
| for (int i = 0; i < 100; i++) { |
| events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + (10 + 10 * i) * NS_PER_SEC)); |
| } |
| |
| // Send log events to StatsLogProcessor. |
| for (auto& event : events) { |
| processor->OnLogEvent(event.get()); |
| } |
| |
| uint64_t dumpTimeNs = bucketStartTimeNs + 2000 * NS_PER_SEC; |
| ConfigMetricsReportList reports; |
| vector<uint8_t> buffer; |
| processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer); |
| EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); |
| backfillStringInReport(&reports); |
| backfillStartEndTimestamp(&reports); |
| backfillAggregatedAtoms(&reports); |
| ASSERT_EQ(reports.reports_size(), 1); |
| |
| ConfigMetricsReport report = reports.reports(0); |
| ASSERT_EQ(report.metrics_size(), 1); |
| StatsLogReport metricReport = report.metrics(0); |
| EXPECT_EQ(metricReport.metric_id(), batterySaverOnEventMetric.id()); |
| EXPECT_TRUE(metricReport.has_event_metrics()); |
| ASSERT_EQ(metricReport.event_metrics().data_size(), 46); |
| } |
| |
| /** |
| * Test an event metric that has one slice_by_state with no primary fields. |
| * |
| * Once the EventMetricProducer is initialized, it has one atom id in |
| * mSlicedStateAtoms and no entries in mStateGroupMap. |
| |
| * One StateTracker tracks the state atom, and it has one listener which is the |
| * EventMetricProducer that was initialized. |
| */ |
| TEST_F(EventMetricE2eTest, TestSlicedState) { |
| // Initialize config. |
| StatsdConfig config; |
| |
| auto syncStartMatcher = CreateSyncStartAtomMatcher(); |
| *config.add_atom_matcher() = syncStartMatcher; |
| |
| auto state = CreateScreenState(); |
| *config.add_state() = state; |
| |
| // Create event metric that slices by screen state. |
| EventMetric syncStateEventMetric = |
| createEventMetric("SyncStartReported", syncStartMatcher.id(), nullopt, {state.id()}); |
| *config.add_event_metric() = syncStateEventMetric; |
| |
| // Initialize StatsLogProcessor. |
| const uint64_t bucketStartTimeNs = 10000000000; // 0:10 |
| ConfigKey key(123, 987); |
| auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key); |
| |
| // Check that EventMetricProducer was initialized correctly. |
| ASSERT_EQ(processor->mMetricsManagers.size(), 1u); |
| sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; |
| EXPECT_TRUE(metricsManager->isConfigValid()); |
| ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1); |
| sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; |
| ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1); |
| EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID); |
| ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0); |
| |
| // Check that StateTrackers were initialized correctly. |
| EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); |
| EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID)); |
| |
| // Initialize log events. |
| std::vector<int> attributionUids1 = {123}; |
| std::vector<string> attributionTags1 = {"App1"}; |
| |
| std::vector<std::unique_ptr<LogEvent>> events; |
| events.push_back(CreateScreenStateChangedEvent( |
| bucketStartTimeNs + 50 * NS_PER_SEC, |
| android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 1:00 |
| events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 75 * NS_PER_SEC, attributionUids1, |
| attributionTags1, "sync_name")); // 1:25 |
| events.push_back(CreateScreenStateChangedEvent( |
| bucketStartTimeNs + 200 * NS_PER_SEC, |
| android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 3:30 |
| events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 250 * NS_PER_SEC, attributionUids1, |
| attributionTags1, "sync_name")); // 4:20 |
| |
| // Send log events to StatsLogProcessor. |
| for (auto& event : events) { |
| processor->OnLogEvent(event.get()); |
| } |
| |
| // Check dump report. |
| uint64_t dumpTimeNs = bucketStartTimeNs + 2000 * NS_PER_SEC; |
| ConfigMetricsReportList reports; |
| vector<uint8_t> buffer; |
| processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer); |
| EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); |
| backfillStringInReport(&reports); |
| backfillStartEndTimestamp(&reports); |
| backfillAggregatedAtoms(&reports); |
| ASSERT_EQ(reports.reports_size(), 1); |
| |
| ConfigMetricsReport report = reports.reports(0); |
| ASSERT_EQ(report.metrics_size(), 1); |
| StatsLogReport metricReport = report.metrics(0); |
| EXPECT_EQ(metricReport.metric_id(), syncStateEventMetric.id()); |
| EXPECT_TRUE(metricReport.has_event_metrics()); |
| ASSERT_EQ(metricReport.event_metrics().data_size(), 2); |
| |
| // For each EventMetricData, check StateValue info is correct |
| EventMetricData data = metricReport.event_metrics().data(0); |
| |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 75 * NS_PER_SEC); |
| ASSERT_EQ(1, data.slice_by_state_size()); |
| EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(0).has_value()); |
| EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value()); |
| |
| data = metricReport.event_metrics().data(1); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 250 * NS_PER_SEC); |
| ASSERT_EQ(1, data.slice_by_state_size()); |
| EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(0).has_value()); |
| EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value()); |
| } |
| |
| /** |
| * Test an event metric that has one slice_by_state with a mapping and no |
| * primary fields. |
| * |
| * Once the EventMetricProducer is initialized, it has one atom id in |
| * mSlicedStateAtoms and has one entry per state value in mStateGroupMap. |
| * |
| * One StateTracker tracks the state atom, and it has one listener which is the |
| * EventMetricProducer that was initialized. |
| */ |
| TEST_F(EventMetricE2eTest, TestSlicedStateWithMap) { |
| // Initialize config. |
| StatsdConfig config; |
| |
| auto syncStartMatcher = CreateSyncStartAtomMatcher(); |
| *config.add_atom_matcher() = syncStartMatcher; |
| |
| int64_t screenOnId = 4444; |
| int64_t screenOffId = 9876; |
| auto state = CreateScreenStateWithOnOffMap(screenOnId, screenOffId); |
| *config.add_state() = state; |
| |
| // Create event metric that slices by screen state with on/off map. |
| EventMetric syncStateEventMetric = |
| createEventMetric("SyncStartReported", syncStartMatcher.id(), nullopt, {state.id()}); |
| *config.add_event_metric() = syncStateEventMetric; |
| |
| // Initialize StatsLogProcessor. |
| const uint64_t bucketStartTimeNs = 10000000000; // 0:10 |
| ConfigKey key(123, 987); |
| auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key); |
| |
| /* |
| | 1 2 3 4(minutes) |
| |-----------------------|- |
| x x x x (syncStartEvents) |
| -------------------------SCREEN_OFF events |
| | (ScreenStateOffEvent = 1) |
| | (ScreenStateDozeEvent = 3) |
| -------------------------SCREEN_ON events |
| | (ScreenStateOnEvent = 2) |
| | (ScreenStateVrEvent = 5) |
| |
| Based on the diagram above, a Sync Start Event querying for Screen State would return: |
| - Event 0: StateTracker::kStateUnknown |
| - Event 1: Off |
| - Event 2: Off |
| - Event 3: On |
| */ |
| // Initialize log events |
| std::vector<int> attributionUids1 = {123}; |
| std::vector<string> attributionTags1 = {"App1"}; |
| |
| std::vector<std::unique_ptr<LogEvent>> events; |
| events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 20 * NS_PER_SEC, attributionUids1, |
| attributionTags1, "sync_name")); // 0:30 |
| // Event 0 Occurred |
| events.push_back(CreateScreenStateChangedEvent( |
| bucketStartTimeNs + 30 * NS_PER_SEC, |
| android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 0:40 |
| events.push_back(CreateScreenStateChangedEvent( |
| bucketStartTimeNs + 50 * NS_PER_SEC, |
| android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 1:00 |
| events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 60 * NS_PER_SEC, attributionUids1, |
| attributionTags1, "sync_name")); // 1:10 |
| // Event 1 Occurred |
| events.push_back(CreateScreenStateChangedEvent( |
| bucketStartTimeNs + 90 * NS_PER_SEC, |
| android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 1:40 |
| events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 120 * NS_PER_SEC, attributionUids1, |
| attributionTags1, "sync_name")); // 2:10 |
| // Event 2 Occurred |
| events.push_back(CreateScreenStateChangedEvent( |
| bucketStartTimeNs + 180 * NS_PER_SEC, |
| android::view::DisplayStateEnum::DISPLAY_STATE_VR)); // 3:10 |
| events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 200 * NS_PER_SEC, attributionUids1, |
| attributionTags1, "sync_name")); // 3:30 |
| // Event 3 Occurred |
| |
| // Send log events to StatsLogProcessor. |
| for (auto& event : events) { |
| processor->OnLogEvent(event.get()); |
| } |
| |
| // Check dump report. |
| uint64_t dumpTimeNs = bucketStartTimeNs + 2000 * NS_PER_SEC; |
| vector<uint8_t> buffer; |
| ConfigMetricsReportList reports; |
| processor->onDumpReport(key, dumpTimeNs, false, true, ADB_DUMP, FAST, &buffer); |
| ASSERT_GT(buffer.size(), 0); |
| EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); |
| backfillStringInReport(&reports); |
| backfillStartEndTimestamp(&reports); |
| backfillAggregatedAtoms(&reports); |
| ASSERT_EQ(reports.reports_size(), 1); |
| |
| ConfigMetricsReport report = reports.reports(0); |
| ASSERT_EQ(report.metrics_size(), 1); |
| StatsLogReport metricReport = report.metrics(0); |
| EXPECT_EQ(metricReport.metric_id(), syncStateEventMetric.id()); |
| EXPECT_TRUE(metricReport.has_event_metrics()); |
| ASSERT_EQ(metricReport.event_metrics().data_size(), 4); |
| |
| // For each EventMetricData, check StateValue info is correct |
| EventMetricData data = metricReport.event_metrics().data(0); |
| |
| // StateTracker::kStateUnknown |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 20 * NS_PER_SEC); |
| ASSERT_EQ(1, data.slice_by_state_size()); |
| EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(0).has_value()); |
| EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value()); |
| |
| // Off |
| data = metricReport.event_metrics().data(1); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 60 * NS_PER_SEC); |
| ASSERT_EQ(1, data.slice_by_state_size()); |
| EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(0).has_group_id()); |
| EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id()); |
| |
| // Off |
| data = metricReport.event_metrics().data(2); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 120 * NS_PER_SEC); |
| ASSERT_EQ(1, data.slice_by_state_size()); |
| EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(0).has_group_id()); |
| EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id()); |
| |
| // On |
| data = metricReport.event_metrics().data(3); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 200 * NS_PER_SEC); |
| ASSERT_EQ(1, data.slice_by_state_size()); |
| EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(0).has_group_id()); |
| EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id()); |
| } |
| |
| /** |
| * Test an event metric that has one slice_by_state with a primary field. |
| |
| * Once the EventMetricProducer is initialized, it should have one |
| * MetricStateLink stored. State querying using a non-empty primary key |
| * should also work as intended. |
| */ |
| TEST_F(EventMetricE2eTest, TestSlicedStateWithPrimaryFields) { |
| // Initialize config. |
| StatsdConfig config; |
| |
| auto appCrashMatcher = CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED); |
| *config.add_atom_matcher() = appCrashMatcher; |
| |
| auto state = CreateUidProcessState(); |
| *config.add_state() = state; |
| |
| // Create event metric that slices by uid process state. |
| EventMetric appCrashEventMetric = |
| createEventMetric("AppCrashReported", appCrashMatcher.id(), nullopt, {state.id()}); |
| MetricStateLink* stateLink = appCrashEventMetric.add_state_link(); |
| stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID); |
| auto fieldsInWhat = stateLink->mutable_fields_in_what(); |
| *fieldsInWhat = CreateDimensions(util::APP_CRASH_OCCURRED, {1 /*uid*/}); |
| auto fieldsInState = stateLink->mutable_fields_in_state(); |
| *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/}); |
| *config.add_event_metric() = appCrashEventMetric; |
| |
| // Initialize StatsLogProcessor. |
| const uint64_t bucketStartTimeNs = 10000000000; // 0:10 |
| ConfigKey key(123, 987); |
| auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key); |
| |
| /* |
| NOTE: "1" or "2" represents the uid associated with the state/app crash event |
| | 1 2 3 |
| |--------------|- |
| 1 1 2 1(AppCrashEvents) |
| ----------------PROCESS STATE events |
| 2 (TopEvent = 1002) |
| 1 (ImportantForegroundEvent = 1005) |
| |
| Based on the diagram above, an AppCrashEvent querying for process state value would return: |
| - Event 0: StateTracker::kStateUnknown |
| - Event 1: Important Foreground |
| - Event 2: Top |
| - Event 3: Important Foreground |
| */ |
| // Initialize log events |
| std::vector<std::unique_ptr<LogEvent>> events; |
| events.push_back( |
| CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /*uid*/)); // 0:30 |
| // Event 0 Occurred |
| events.push_back(CreateUidProcessStateChangedEvent( |
| bucketStartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/, |
| android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 0:40 |
| events.push_back( |
| CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, 1 /*uid*/)); // 1:10 |
| // Event 1 Occurred |
| events.push_back(CreateUidProcessStateChangedEvent( |
| bucketStartTimeNs + 90 * NS_PER_SEC, 2 /*uid*/, |
| android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 1:40 |
| events.push_back( |
| CreateAppCrashOccurredEvent(bucketStartTimeNs + 160 * NS_PER_SEC, 2 /*uid*/)); // 2:50 |
| // Event 2 Occurred |
| events.push_back( |
| CreateAppCrashOccurredEvent(bucketStartTimeNs + 180 * NS_PER_SEC, 1 /*uid*/)); // 3:10 |
| // Event 3 Occurred |
| |
| // Send log events to StatsLogProcessor. |
| for (auto& event : events) { |
| processor->OnLogEvent(event.get()); |
| } |
| |
| // Check dump report. |
| uint64_t dumpTimeNs = bucketStartTimeNs + 2000 * NS_PER_SEC; |
| vector<uint8_t> buffer; |
| ConfigMetricsReportList reports; |
| processor->onDumpReport(key, dumpTimeNs, false, true, ADB_DUMP, FAST, &buffer); |
| ASSERT_GT(buffer.size(), 0); |
| EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); |
| backfillStringInReport(&reports); |
| backfillStartEndTimestamp(&reports); |
| backfillAggregatedAtoms(&reports); |
| ASSERT_EQ(reports.reports_size(), 1); |
| |
| ConfigMetricsReport report = reports.reports(0); |
| ASSERT_EQ(report.metrics_size(), 1); |
| StatsLogReport metricReport = report.metrics(0); |
| EXPECT_EQ(metricReport.metric_id(), appCrashEventMetric.id()); |
| EXPECT_TRUE(metricReport.has_event_metrics()); |
| ASSERT_EQ(metricReport.event_metrics().data_size(), 4); |
| |
| // For each EventMetricData, check StateValue info is correct |
| EventMetricData data = metricReport.event_metrics().data(0); |
| |
| // StateTracker::kStateUnknown |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 20 * NS_PER_SEC); |
| ASSERT_EQ(1, data.slice_by_state_size()); |
| EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(0).has_value()); |
| EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value()); |
| |
| // Important Foreground |
| data = metricReport.event_metrics().data(1); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 60 * NS_PER_SEC); |
| ASSERT_EQ(1, data.slice_by_state_size()); |
| EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(0).has_value()); |
| EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value()); |
| |
| // Top |
| data = metricReport.event_metrics().data(2); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 160 * NS_PER_SEC); |
| ASSERT_EQ(1, data.slice_by_state_size()); |
| EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(0).has_value()); |
| EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value()); |
| |
| // Important Foreground |
| data = metricReport.event_metrics().data(3); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 180 * NS_PER_SEC); |
| ASSERT_EQ(1, data.slice_by_state_size()); |
| EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(0).has_value()); |
| EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value()); |
| } |
| |
| TEST_F(EventMetricE2eTest, TestMultipleSlicedStates) { |
| // Initialize config. |
| StatsdConfig config; |
| |
| auto appCrashMatcher = CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED); |
| *config.add_atom_matcher() = appCrashMatcher; |
| |
| int64_t screenOnId = 4444; |
| int64_t screenOffId = 9876; |
| auto state1 = CreateScreenStateWithOnOffMap(screenOnId, screenOffId); |
| *config.add_state() = state1; |
| auto state2 = CreateUidProcessState(); |
| *config.add_state() = state2; |
| |
| // Create event metric that slices by screen state with on/off map and |
| // slices by uid process state. |
| EventMetric appCrashEventMetric = createEventMetric("AppCrashReported", appCrashMatcher.id(), |
| nullopt, {state1.id(), state2.id()}); |
| MetricStateLink* stateLink = appCrashEventMetric.add_state_link(); |
| stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID); |
| auto fieldsInWhat = stateLink->mutable_fields_in_what(); |
| *fieldsInWhat = CreateDimensions(util::APP_CRASH_OCCURRED, {1 /*uid*/}); |
| auto fieldsInState = stateLink->mutable_fields_in_state(); |
| *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/}); |
| *config.add_event_metric() = appCrashEventMetric; |
| |
| // Initialize StatsLogProcessor. |
| const uint64_t bucketStartTimeNs = 10000000000; // 0:10 |
| ConfigKey key(123, 987); |
| auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key); |
| |
| /* |
| | 1 2 3 (minutes) |
| |----------------- |
| 1 1 1 1 (AppCrashEvents) |
| -----------------SCREEN_OFF events |
| | (ScreenOffEvent = 1) |
| | (ScreenDozeEvent = 3) |
| -----------------SCREEN_ON events |
| | (ScreenOnEvent = 2) |
| -----------------PROCESS STATE events |
| 1 (TopEvent = 1002) |
| 1 1 (ImportantForegroundEvent = 1005) |
| |
| Based on the diagram above, Screen State / Process State pairs for each |
| AppCrashEvent are: |
| - 0: StateTracker::kStateUnknown / Important Foreground |
| - 1: Off / Important Foreground |
| - 2: Off / Top |
| - 3: On / Important Foreground |
| */ |
| |
| // Initialize log events |
| std::vector<std::unique_ptr<LogEvent>> events; |
| events.push_back(CreateUidProcessStateChangedEvent( |
| bucketStartTimeNs + 5 * NS_PER_SEC, 1 /*uid*/, |
| android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 0:15 |
| events.push_back( |
| CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /*uid*/)); // 0:30 |
| // Event 0 Occurred |
| events.push_back(CreateScreenStateChangedEvent( |
| bucketStartTimeNs + 30 * NS_PER_SEC, |
| android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 0:40 |
| events.push_back( |
| CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, 1 /*uid*/)); // 1:10 |
| // Event 1 Occurred |
| events.push_back(CreateUidProcessStateChangedEvent( |
| bucketStartTimeNs + 90 * NS_PER_SEC, 1 /*uid*/, |
| android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 1:40 |
| events.push_back(CreateScreenStateChangedEvent( |
| bucketStartTimeNs + 90 * NS_PER_SEC, |
| android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 1:40 |
| events.push_back( |
| CreateAppCrashOccurredEvent(bucketStartTimeNs + 120 * NS_PER_SEC, 1 /*uid*/)); // 2:10 |
| // Event 2 Occurred |
| events.push_back(CreateUidProcessStateChangedEvent( |
| bucketStartTimeNs + 150 * NS_PER_SEC, 1 /*uid*/, |
| android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 2:40 |
| events.push_back(CreateScreenStateChangedEvent( |
| bucketStartTimeNs + 160 * NS_PER_SEC, |
| android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 2:50 |
| events.push_back( |
| CreateAppCrashOccurredEvent(bucketStartTimeNs + 200 * NS_PER_SEC, 1 /*uid*/)); // 3:30 |
| // Event 3 Occurred |
| |
| // Send log events to StatsLogProcessor. |
| for (auto& event : events) { |
| processor->OnLogEvent(event.get()); |
| } |
| |
| // Check dump report. |
| uint64_t dumpTimeNs = bucketStartTimeNs + 2000 * NS_PER_SEC; |
| vector<uint8_t> buffer; |
| ConfigMetricsReportList reports; |
| processor->onDumpReport(key, dumpTimeNs, false, true, ADB_DUMP, FAST, &buffer); |
| ASSERT_GT(buffer.size(), 0); |
| EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); |
| backfillStringInReport(&reports); |
| backfillStartEndTimestamp(&reports); |
| backfillAggregatedAtoms(&reports); |
| ASSERT_EQ(reports.reports_size(), 1); |
| |
| ConfigMetricsReport report = reports.reports(0); |
| ASSERT_EQ(report.metrics_size(), 1); |
| StatsLogReport metricReport = report.metrics(0); |
| EXPECT_EQ(metricReport.metric_id(), appCrashEventMetric.id()); |
| EXPECT_TRUE(metricReport.has_event_metrics()); |
| ASSERT_EQ(metricReport.event_metrics().data_size(), 4); |
| |
| // For each EventMetricData, check StateValue info is correct |
| EventMetricData data = metricReport.event_metrics().data(0); |
| |
| // Screen State: StateTracker::kStateUnknown |
| // Process State: Important Foreground |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 20 * NS_PER_SEC); |
| ASSERT_EQ(2, data.slice_by_state_size()); |
| EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(0).has_value()); |
| EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value()); |
| EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(1).has_value()); |
| EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); |
| |
| // Screen State: Off |
| // Process State: Important Foreground |
| data = metricReport.event_metrics().data(1); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 60 * NS_PER_SEC); |
| ASSERT_EQ(2, data.slice_by_state_size()); |
| EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(0).has_group_id()); |
| EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id()); |
| EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(1).has_value()); |
| EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); |
| |
| // Screen State: Off |
| // Process State: Top |
| data = metricReport.event_metrics().data(2); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 120 * NS_PER_SEC); |
| ASSERT_EQ(2, data.slice_by_state_size()); |
| EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(0).has_group_id()); |
| EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id()); |
| EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(1).has_value()); |
| EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value()); |
| |
| // Screen State: On |
| // Process State: Important Foreground |
| data = metricReport.event_metrics().data(3); |
| EXPECT_EQ(data.elapsed_timestamp_nanos(), bucketStartTimeNs + 200 * NS_PER_SEC); |
| ASSERT_EQ(2, data.slice_by_state_size()); |
| EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(0).has_group_id()); |
| EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id()); |
| EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); |
| EXPECT_TRUE(data.slice_by_state(1).has_value()); |
| EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); |
| } |
| |
| TEST_F(EventMetricE2eTest, TestEventMetricFieldsFilter) { |
| StatsdConfig config; |
| |
| AtomMatcher testAtomReportedAtomMatcher = |
| CreateSimpleAtomMatcher("TestAtomReportedMatcher", util::TEST_ATOM_REPORTED); |
| *config.add_atom_matcher() = testAtomReportedAtomMatcher; |
| |
| EventMetric metric = |
| createEventMetric("EventTestAtomReported", testAtomReportedAtomMatcher.id(), nullopt); |
| metric.mutable_fields_filter()->mutable_fields()->set_field(util::TEST_ATOM_REPORTED); |
| metric.mutable_fields_filter()->mutable_fields()->add_child()->set_field(2); // int_field |
| *config.add_event_metric() = metric; |
| |
| ConfigKey key(123, 987); |
| uint64_t bucketStartTimeNs = 10000000000; // 0:10 |
| sp<StatsLogProcessor> processor = |
| CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key); |
| |
| // Initialize log events before update. |
| std::vector<std::unique_ptr<LogEvent>> events; |
| |
| vector<int> enumArrayNoMatch = {TestAtomReported::OFF, TestAtomReported::ON}; |
| vector<int> enumArrayMatch = {TestAtomReported::ON, TestAtomReported::OFF}; |
| |
| events.push_back(CreateTestAtomReportedEventWithPrimitives( |
| bucketStartTimeNs + 10 * NS_PER_SEC, 1 /* intField */, 1l /* longField */, |
| 1.0f /* floatField */, "string_field1", false /* boolField */, |
| TestAtomReported::OFF /* enumField */)); |
| events.push_back(CreateTestAtomReportedEventWithPrimitives( |
| bucketStartTimeNs + 20 * NS_PER_SEC, 2 /* intField */, 2l /* longField */, |
| 2.0f /* floatField */, "string_field2", true /* boolField */, |
| TestAtomReported::ON /* enumField */)); |
| events.push_back(CreateTestAtomReportedEventWithPrimitives( |
| bucketStartTimeNs + 30 * NS_PER_SEC, 3 /* intField */, 3l /* longField */, |
| 3.0f /* floatField */, "string_field3", false /* boolField */, |
| TestAtomReported::ON /* enumField */)); |
| |
| // Send log events to StatsLogProcessor. |
| for (auto& event : events) { |
| processor->OnLogEvent(event.get()); |
| } |
| |
| uint64_t dumpTimeNs = bucketStartTimeNs + 100 * NS_PER_SEC; |
| ConfigMetricsReportList reports; |
| vector<uint8_t> buffer; |
| processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer); |
| EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); |
| backfillStringInReport(&reports); |
| backfillStartEndTimestamp(&reports); |
| backfillAggregatedAtoms(&reports); |
| ASSERT_EQ(reports.reports_size(), 1); |
| |
| ConfigMetricsReport report = reports.reports(0); |
| ASSERT_EQ(report.metrics_size(), 1); |
| StatsLogReport testAtomEventMetricReport = report.metrics(0); |
| EXPECT_EQ(testAtomEventMetricReport.metric_id(), metric.id()); |
| EXPECT_TRUE(testAtomEventMetricReport.has_event_metrics()); |
| ASSERT_EQ(testAtomEventMetricReport.event_metrics().data_size(), 3); |
| |
| TestAtomReported atom = |
| testAtomEventMetricReport.event_metrics().data(0).atom().test_atom_reported(); |
| EXPECT_EQ(atom.int_field(), 1); |
| EXPECT_FALSE(atom.has_long_field()); |
| EXPECT_FALSE(atom.has_float_field()); |
| EXPECT_FALSE(atom.has_string_field()); |
| EXPECT_FALSE(atom.has_boolean_field()); |
| EXPECT_FALSE(atom.has_state()); |
| |
| atom = testAtomEventMetricReport.event_metrics().data(1).atom().test_atom_reported(); |
| EXPECT_EQ(atom.int_field(), 2); |
| EXPECT_FALSE(atom.has_long_field()); |
| EXPECT_FALSE(atom.has_float_field()); |
| EXPECT_FALSE(atom.has_string_field()); |
| EXPECT_FALSE(atom.has_boolean_field()); |
| EXPECT_FALSE(atom.has_state()); |
| |
| atom = testAtomEventMetricReport.event_metrics().data(2).atom().test_atom_reported(); |
| EXPECT_EQ(atom.int_field(), 3); |
| EXPECT_FALSE(atom.has_long_field()); |
| EXPECT_FALSE(atom.has_float_field()); |
| EXPECT_FALSE(atom.has_string_field()); |
| EXPECT_FALSE(atom.has_boolean_field()); |
| EXPECT_FALSE(atom.has_state()); |
| } |
| |
| #else |
| GTEST_LOG_(INFO) << "This test does nothing.\n"; |
| #endif |
| |
| } // namespace statsd |
| } // namespace os |
| } // namespace android |