// 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 "StatsLogProcessor.h" #include "config/ConfigKey.h" #include "frameworks/base/cmds/statsd/src/stats_log.pb.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "guardrail/StatsdStats.h" #include "logd/LogEvent.h" #include "packages/UidMap.h" #include "statslog.h" #include #include #include "tests/statsd_test_util.h" #include using namespace android; using namespace testing; namespace android { namespace os { namespace statsd { using android::util::ProtoOutputStream; #ifdef __ANDROID__ /** * Mock MetricsManager (ByteSize() is called). */ class MockMetricsManager : public MetricsManager { public: MockMetricsManager() : MetricsManager(ConfigKey(1, 12345), StatsdConfig(), 1000, 1000, new UidMap(), new StatsPullerManager(), new AlarmMonitor(10, [](const sp&, int64_t) {}, [](const sp&) {}), new AlarmMonitor(10, [](const sp&, int64_t) {}, [](const sp&) {})) { } MOCK_METHOD0(byteSize, size_t()); MOCK_METHOD1(dropData, void(const int64_t dropTimeNs)); }; TEST(StatsLogProcessorTest, TestRateLimitByteSize) { sp m = new UidMap(); sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp periodicAlarmMonitor; // Construct the processor with a dummy sendBroadcast function that does nothing. StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, 0, [](const ConfigKey& key) { return true; }, [](const int&, const vector&) {return true;}); MockMetricsManager mockMetricsManager; ConfigKey key(100, 12345); // Expect only the first flush to trigger a check for byte size since the last two are // rate-limited. EXPECT_CALL(mockMetricsManager, byteSize()).Times(1); p.flushIfNecessaryLocked(99, key, mockMetricsManager); p.flushIfNecessaryLocked(100, key, mockMetricsManager); p.flushIfNecessaryLocked(101, key, mockMetricsManager); } TEST(StatsLogProcessorTest, TestRateLimitBroadcast) { sp m = new UidMap(); sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp subscriberAlarmMonitor; int broadcastCount = 0; StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, [&broadcastCount](const ConfigKey& key) { broadcastCount++; return true; }, [](const int&, const vector&) {return true;}); MockMetricsManager mockMetricsManager; ConfigKey key(100, 12345); EXPECT_CALL(mockMetricsManager, byteSize()) .Times(1) .WillRepeatedly(Return(int(StatsdStats::kMaxMetricsBytesPerConfig * .95))); // Expect only one broadcast despite always returning a size that should trigger broadcast. p.flushIfNecessaryLocked(1, key, mockMetricsManager); EXPECT_EQ(1, broadcastCount); // b/73089712 // This next call to flush should not trigger a broadcast. // p.mLastByteSizeTimes.clear(); // Force another check for byte size. // p.flushIfNecessaryLocked(2, key, mockMetricsManager); // EXPECT_EQ(1, broadcastCount); } TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge) { sp m = new UidMap(); sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp subscriberAlarmMonitor; int broadcastCount = 0; StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, [&broadcastCount](const ConfigKey& key) { broadcastCount++; return true; }, [](const int&, const vector&) {return true;}); MockMetricsManager mockMetricsManager; ConfigKey key(100, 12345); EXPECT_CALL(mockMetricsManager, byteSize()) .Times(1) .WillRepeatedly(Return(int(StatsdStats::kMaxMetricsBytesPerConfig * 1.2))); EXPECT_CALL(mockMetricsManager, dropData(_)).Times(1); // Expect to call the onDumpReport and skip the broadcast. p.flushIfNecessaryLocked(1, key, mockMetricsManager); EXPECT_EQ(0, broadcastCount); } StatsdConfig MakeConfig(bool includeMetric) { StatsdConfig config; config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. if (includeMetric) { auto appCrashMatcher = CreateProcessCrashAtomMatcher(); *config.add_atom_matcher() = appCrashMatcher; auto countMetric = config.add_count_metric(); countMetric->set_id(StringToId("AppCrashes")); countMetric->set_what(appCrashMatcher.id()); countMetric->set_bucket(FIVE_MINUTES); } return config; } TEST(StatsLogProcessorTest, TestUidMapHasSnapshot) { // Setup simple config key corresponding to empty config. sp m = new UidMap(); sp pullerManager = new StatsPullerManager(); m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")}, {String16("p1"), String16("p2")}, {String16(""), String16("")}); sp anomalyAlarmMonitor; sp subscriberAlarmMonitor; int broadcastCount = 0; StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, [&broadcastCount](const ConfigKey& key) { broadcastCount++; return true; }, [](const int&, const vector&) {return true;}); ConfigKey key(3, 4); StatsdConfig config = MakeConfig(true); p.OnConfigUpdated(0, key, config); // Expect to get no metrics, but snapshot specified above in uidmap. vector bytes; p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes); ConfigMetricsReportList output; output.ParseFromArray(bytes.data(), bytes.size()); EXPECT_TRUE(output.reports_size() > 0); auto uidmap = output.reports(0).uid_map(); EXPECT_TRUE(uidmap.snapshots_size() > 0); EXPECT_EQ(2, uidmap.snapshots(0).package_info_size()); } TEST(StatsLogProcessorTest, TestEmptyConfigHasNoUidMap) { // Setup simple config key corresponding to empty config. sp m = new UidMap(); sp pullerManager = new StatsPullerManager(); m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")}, {String16("p1"), String16("p2")}, {String16(""), String16("")}); sp anomalyAlarmMonitor; sp subscriberAlarmMonitor; int broadcastCount = 0; StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, [&broadcastCount](const ConfigKey& key) { broadcastCount++; return true; }, [](const int&, const vector&) {return true;}); ConfigKey key(3, 4); StatsdConfig config = MakeConfig(false); p.OnConfigUpdated(0, key, config); // Expect to get no metrics, but snapshot specified above in uidmap. vector bytes; p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes); ConfigMetricsReportList output; output.ParseFromArray(bytes.data(), bytes.size()); EXPECT_TRUE(output.reports_size() > 0); EXPECT_FALSE(output.reports(0).has_uid_map()); } TEST(StatsLogProcessorTest, TestReportIncludesSubConfig) { // Setup simple config key corresponding to empty config. sp m = new UidMap(); sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp subscriberAlarmMonitor; int broadcastCount = 0; StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, [&broadcastCount](const ConfigKey& key) { broadcastCount++; return true; }, [](const int&, const vector&) {return true;}); ConfigKey key(3, 4); StatsdConfig config; auto annotation = config.add_annotation(); annotation->set_field_int64(1); annotation->set_field_int32(2); config.add_allowed_log_source("AID_ROOT"); p.OnConfigUpdated(1, key, config); // Expect to get no metrics, but snapshot specified above in uidmap. vector bytes; p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes); ConfigMetricsReportList output; output.ParseFromArray(bytes.data(), bytes.size()); EXPECT_TRUE(output.reports_size() > 0); auto report = output.reports(0); EXPECT_EQ(1, report.annotation_size()); EXPECT_EQ(1, report.annotation(0).field_int64()); EXPECT_EQ(2, report.annotation(0).field_int32()); } TEST(StatsLogProcessorTest, TestOnDumpReportEraseData) { // Setup a simple config. StatsdConfig config; config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher(); *config.add_atom_matcher() = wakelockAcquireMatcher; auto countMetric = config.add_count_metric(); countMetric->set_id(123456); countMetric->set_what(wakelockAcquireMatcher.id()); countMetric->set_bucket(FIVE_MINUTES); ConfigKey cfgKey; sp processor = CreateStatsLogProcessor(1, 1, config, cfgKey); std::vector attributions1 = {CreateAttribution(111, "App1")}; auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 2); processor->OnLogEvent(event.get()); vector bytes; ConfigMetricsReportList output; // Dump report WITHOUT erasing data. processor->onDumpReport(cfgKey, 3, true, false /* Do NOT erase data. */, ADB_DUMP, FAST, &bytes); output.ParseFromArray(bytes.data(), bytes.size()); EXPECT_EQ(output.reports_size(), 1); EXPECT_EQ(output.reports(0).metrics_size(), 1); EXPECT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1); // Dump report WITH erasing data. There should be data since we didn't previously erase it. processor->onDumpReport(cfgKey, 4, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes); output.ParseFromArray(bytes.data(), bytes.size()); EXPECT_EQ(output.reports_size(), 1); EXPECT_EQ(output.reports(0).metrics_size(), 1); EXPECT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1); // Dump report again. There should be no data since we erased it. processor->onDumpReport(cfgKey, 5, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes); output.ParseFromArray(bytes.data(), bytes.size()); // We don't care whether statsd has a report, as long as it has no count metrics in it. bool noData = output.reports_size() == 0 || output.reports(0).metrics_size() == 0 || output.reports(0).metrics(0).count_metrics().data_size() == 0; EXPECT_TRUE(noData); } TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) { int uid = 1111; // Setup a simple config, no activation StatsdConfig config1; int64_t cfgId1 = 12341; config1.set_id(cfgId1); config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher(); *config1.add_atom_matcher() = wakelockAcquireMatcher; long metricId1 = 1234561; long metricId2 = 1234562; auto countMetric1 = config1.add_count_metric(); countMetric1->set_id(metricId1); countMetric1->set_what(wakelockAcquireMatcher.id()); countMetric1->set_bucket(FIVE_MINUTES); auto countMetric2 = config1.add_count_metric(); countMetric2->set_id(metricId2); countMetric2->set_what(wakelockAcquireMatcher.id()); countMetric2->set_bucket(FIVE_MINUTES); ConfigKey cfgKey1(uid, cfgId1); // Add another config, with two metrics, one with activation StatsdConfig config2; int64_t cfgId2 = 12342; config2.set_id(cfgId2); config2.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. *config2.add_atom_matcher() = wakelockAcquireMatcher; long metricId3 = 1234561; long metricId4 = 1234562; auto countMetric3 = config2.add_count_metric(); countMetric3->set_id(metricId3); countMetric3->set_what(wakelockAcquireMatcher.id()); countMetric3->set_bucket(FIVE_MINUTES); auto countMetric4 = config2.add_count_metric(); countMetric4->set_id(metricId4); countMetric4->set_what(wakelockAcquireMatcher.id()); countMetric4->set_bucket(FIVE_MINUTES); auto metric3Activation = config2.add_metric_activation(); metric3Activation->set_metric_id(metricId3); auto metric3ActivationTrigger = metric3Activation->add_event_activation(); metric3ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id()); metric3ActivationTrigger->set_ttl_seconds(100); ConfigKey cfgKey2(uid, cfgId2); // Add another config, with two metrics, both with activations StatsdConfig config3; int64_t cfgId3 = 12343; config3.set_id(cfgId3); config3.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. *config3.add_atom_matcher() = wakelockAcquireMatcher; long metricId5 = 1234565; long metricId6 = 1234566; auto countMetric5 = config3.add_count_metric(); countMetric5->set_id(metricId5); countMetric5->set_what(wakelockAcquireMatcher.id()); countMetric5->set_bucket(FIVE_MINUTES); auto countMetric6 = config3.add_count_metric(); countMetric6->set_id(metricId6); countMetric6->set_what(wakelockAcquireMatcher.id()); countMetric6->set_bucket(FIVE_MINUTES); auto metric5Activation = config3.add_metric_activation(); metric5Activation->set_metric_id(metricId5); auto metric5ActivationTrigger = metric5Activation->add_event_activation(); metric5ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id()); metric5ActivationTrigger->set_ttl_seconds(100); auto metric6Activation = config3.add_metric_activation(); metric6Activation->set_metric_id(metricId6); auto metric6ActivationTrigger = metric6Activation->add_event_activation(); metric6ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id()); metric6ActivationTrigger->set_ttl_seconds(200); ConfigKey cfgKey3(uid, cfgId3); sp m = new UidMap(); sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp subscriberAlarmMonitor; vector activeConfigsBroadcast; long timeBase1 = 1; int broadcastCount = 0; StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, timeBase1, [](const ConfigKey& key) { return true; }, [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid, const vector& activeConfigs) { broadcastCount++; EXPECT_EQ(broadcastUid, uid); activeConfigsBroadcast.clear(); activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(), activeConfigs.end()); return true; }); processor.OnConfigUpdated(1, cfgKey1, config1); processor.OnConfigUpdated(2, cfgKey2, config2); processor.OnConfigUpdated(3, cfgKey3, config3); EXPECT_EQ(3, processor.mMetricsManagers.size()); // Expect the first config and both metrics in it to be active. auto it = processor.mMetricsManagers.find(cfgKey1); EXPECT_TRUE(it != processor.mMetricsManagers.end()); auto& metricsManager1 = it->second; EXPECT_TRUE(metricsManager1->isActive()); auto metricIt = metricsManager1->mAllMetricProducers.begin(); for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId1) { break; } } EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end()); auto& metricProducer1 = *metricIt; EXPECT_TRUE(metricProducer1->isActive()); metricIt = metricsManager1->mAllMetricProducers.begin(); for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId2) { break; } } EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end()); auto& metricProducer2 = *metricIt; EXPECT_TRUE(metricProducer2->isActive()); // Expect config 2 to be active. Metric 3 shouldn't be active, metric 4 should be active. it = processor.mMetricsManagers.find(cfgKey2); EXPECT_TRUE(it != processor.mMetricsManagers.end()); auto& metricsManager2 = it->second; EXPECT_TRUE(metricsManager2->isActive()); metricIt = metricsManager2->mAllMetricProducers.begin(); for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId3) { break; } } EXPECT_TRUE(metricIt != metricsManager2->mAllMetricProducers.end()); auto& metricProducer3 = *metricIt; EXPECT_FALSE(metricProducer3->isActive()); metricIt = metricsManager2->mAllMetricProducers.begin(); for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId4) { break; } } EXPECT_TRUE(metricIt != metricsManager2->mAllMetricProducers.end()); auto& metricProducer4 = *metricIt; EXPECT_TRUE(metricProducer4->isActive()); // Expect the third config and both metrics in it to be inactive. it = processor.mMetricsManagers.find(cfgKey3); EXPECT_TRUE(it != processor.mMetricsManagers.end()); auto& metricsManager3 = it->second; EXPECT_FALSE(metricsManager3->isActive()); metricIt = metricsManager3->mAllMetricProducers.begin(); for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId5) { break; } } EXPECT_TRUE(metricIt != metricsManager3->mAllMetricProducers.end()); auto& metricProducer5 = *metricIt; EXPECT_FALSE(metricProducer5->isActive()); metricIt = metricsManager3->mAllMetricProducers.begin(); for (; metricIt != metricsManager3->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId6) { break; } } EXPECT_TRUE(metricIt != metricsManager3->mAllMetricProducers.end()); auto& metricProducer6 = *metricIt; EXPECT_FALSE(metricProducer6->isActive()); // No broadcast for active configs should have happened yet. EXPECT_EQ(broadcastCount, 0); // Activate all 3 metrics that were not active. std::vector attributions1 = {CreateAttribution(111, "App1")}; auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1); processor.OnLogEvent(event.get()); // Assert that all 3 configs are active. EXPECT_TRUE(metricsManager1->isActive()); EXPECT_TRUE(metricsManager2->isActive()); EXPECT_TRUE(metricsManager3->isActive()); // A broadcast should have happened, and all 3 configs should be active in the broadcast. EXPECT_EQ(broadcastCount, 1); EXPECT_EQ(activeConfigsBroadcast.size(), 3); EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId1) != activeConfigsBroadcast.end()); EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId2) != activeConfigsBroadcast.end()); EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId3) != activeConfigsBroadcast.end()); // When we shut down, metrics 3 & 5 have 100ns remaining, metric 6 has 100s + 100ns. int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC; EXPECT_TRUE(metricProducer3->isActive()); int64_t ttl3 = metricProducer3->getRemainingTtlNs(shutDownTime); EXPECT_EQ(100, ttl3); EXPECT_TRUE(metricProducer5->isActive()); int64_t ttl5 = metricProducer5->getRemainingTtlNs(shutDownTime); EXPECT_EQ(100, ttl5); EXPECT_TRUE(metricProducer6->isActive()); int64_t ttl6 = metricProducer6->getRemainingTtlNs(shutDownTime); EXPECT_EQ(100 + 100 * NS_PER_SEC, ttl6); processor.WriteMetricsActivationToDisk(shutDownTime); // Create a second StatsLogProcessor and push the same 3 configs. long timeBase2 = 1000; sp processor2 = CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1); processor2->OnConfigUpdated(timeBase2, cfgKey2, config2); processor2->OnConfigUpdated(timeBase2, cfgKey3, config3); EXPECT_EQ(3, processor2->mMetricsManagers.size()); // First config and both metrics are active. it = processor2->mMetricsManagers.find(cfgKey1); EXPECT_TRUE(it != processor2->mMetricsManagers.end()); auto& metricsManager1001 = it->second; EXPECT_TRUE(metricsManager1001->isActive()); metricIt = metricsManager1001->mAllMetricProducers.begin(); for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId1) { break; } } EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end()); auto& metricProducer1001 = *metricIt; EXPECT_TRUE(metricProducer1001->isActive()); metricIt = metricsManager1001->mAllMetricProducers.begin(); for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId2) { break; } } EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end()); auto& metricProducer1002 = *metricIt; EXPECT_TRUE(metricProducer1002->isActive()); // Second config is active. Metric 3 is inactive, metric 4 is active. it = processor2->mMetricsManagers.find(cfgKey2); EXPECT_TRUE(it != processor2->mMetricsManagers.end()); auto& metricsManager1002 = it->second; EXPECT_TRUE(metricsManager1002->isActive()); metricIt = metricsManager1002->mAllMetricProducers.begin(); for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId3) { break; } } EXPECT_TRUE(metricIt != metricsManager1002->mAllMetricProducers.end()); auto& metricProducer1003 = *metricIt; EXPECT_FALSE(metricProducer1003->isActive()); metricIt = metricsManager1002->mAllMetricProducers.begin(); for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId4) { break; } } EXPECT_TRUE(metricIt != metricsManager1002->mAllMetricProducers.end()); auto& metricProducer1004 = *metricIt; EXPECT_TRUE(metricProducer1004->isActive()); // Config 3 is inactive. both metrics are inactive. it = processor2->mMetricsManagers.find(cfgKey3); EXPECT_TRUE(it != processor2->mMetricsManagers.end()); auto& metricsManager1003 = it->second; EXPECT_FALSE(metricsManager1003->isActive()); EXPECT_EQ(2, metricsManager1003->mAllMetricProducers.size()); metricIt = metricsManager1003->mAllMetricProducers.begin(); for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId5) { break; } } EXPECT_TRUE(metricIt != metricsManager1003->mAllMetricProducers.end()); auto& metricProducer1005 = *metricIt; EXPECT_FALSE(metricProducer1005->isActive()); metricIt = metricsManager1003->mAllMetricProducers.begin(); for (; metricIt != metricsManager1003->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId6) { break; } } EXPECT_TRUE(metricIt != metricsManager1003->mAllMetricProducers.end()); auto& metricProducer1006 = *metricIt; EXPECT_FALSE(metricProducer1006->isActive()); // Assert that all 3 metrics with activation are inactive and that the ttls were properly set. EXPECT_FALSE(metricProducer1003->isActive()); const auto& activation1003 = metricProducer1003->mEventActivationMap.begin()->second; EXPECT_EQ(100 * NS_PER_SEC, activation1003.ttl_ns); EXPECT_EQ(0, activation1003.activation_ns); EXPECT_FALSE(metricProducer1005->isActive()); const auto& activation1005 = metricProducer1005->mEventActivationMap.begin()->second; EXPECT_EQ(100 * NS_PER_SEC, activation1005.ttl_ns); EXPECT_EQ(0, activation1005.activation_ns); EXPECT_FALSE(metricProducer1006->isActive()); const auto& activation1006 = metricProducer1006->mEventActivationMap.begin()->second; EXPECT_EQ(200 * NS_PER_SEC, activation1006.ttl_ns); EXPECT_EQ(0, activation1006.activation_ns); processor2->LoadMetricsActivationFromDisk(); // After loading activations from disk, assert that all 3 metrics are active. EXPECT_TRUE(metricProducer1003->isActive()); EXPECT_EQ(timeBase2 + ttl3 - activation1003.ttl_ns, activation1003.activation_ns); EXPECT_TRUE(metricProducer1005->isActive()); EXPECT_EQ(timeBase2 + ttl5 - activation1005.ttl_ns, activation1005.activation_ns); EXPECT_TRUE(metricProducer1006->isActive()); EXPECT_EQ(timeBase2 + ttl6 - activation1006.ttl_ns, activation1003.activation_ns); // Make sure no more broadcasts have happened. EXPECT_EQ(broadcastCount, 1); } TEST(StatsLogProcessorTest, TestActivationOnBoot) { int uid = 1111; // Setup a simple config, no activation StatsdConfig config1; config1.set_id(12341); config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher(); *config1.add_atom_matcher() = wakelockAcquireMatcher; long metricId1 = 1234561; long metricId2 = 1234562; auto countMetric1 = config1.add_count_metric(); countMetric1->set_id(metricId1); countMetric1->set_what(wakelockAcquireMatcher.id()); countMetric1->set_bucket(FIVE_MINUTES); auto countMetric2 = config1.add_count_metric(); countMetric2->set_id(metricId2); countMetric2->set_what(wakelockAcquireMatcher.id()); countMetric2->set_bucket(FIVE_MINUTES); auto metric1Activation = config1.add_metric_activation(); metric1Activation->set_metric_id(metricId1); metric1Activation->set_activation_type(MetricActivation::ACTIVATE_ON_BOOT); auto metric1ActivationTrigger = metric1Activation->add_event_activation(); metric1ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id()); metric1ActivationTrigger->set_ttl_seconds(100); ConfigKey cfgKey1(uid, 12341); long timeBase1 = 1; sp processor = CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1); EXPECT_EQ(1, processor->mMetricsManagers.size()); auto it = processor->mMetricsManagers.find(cfgKey1); EXPECT_TRUE(it != processor->mMetricsManagers.end()); auto& metricsManager1 = it->second; EXPECT_TRUE(metricsManager1->isActive()); auto metricIt = metricsManager1->mAllMetricProducers.begin(); for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId1) { break; } } EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end()); auto& metricProducer1 = *metricIt; EXPECT_FALSE(metricProducer1->isActive()); metricIt = metricsManager1->mAllMetricProducers.begin(); for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId2) { break; } } EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end()); auto& metricProducer2 = *metricIt; EXPECT_TRUE(metricProducer2->isActive()); const auto& activation1 = metricProducer1->mEventActivationMap.begin()->second; EXPECT_EQ(100 * NS_PER_SEC, activation1.ttl_ns); EXPECT_EQ(0, activation1.activation_ns); EXPECT_EQ(kNotActive, activation1.state); std::vector attributions1 = {CreateAttribution(111, "App1")}; auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1); processor->OnLogEvent(event.get()); EXPECT_FALSE(metricProducer1->isActive()); EXPECT_EQ(0, activation1.activation_ns); EXPECT_EQ(kActiveOnBoot, activation1.state); int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC; processor->WriteMetricsActivationToDisk(shutDownTime); EXPECT_TRUE(metricProducer1->isActive()); int64_t ttl1 = metricProducer1->getRemainingTtlNs(shutDownTime); EXPECT_EQ(100 * NS_PER_SEC, ttl1); long timeBase2 = 1000; sp processor2 = CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1); EXPECT_EQ(1, processor2->mMetricsManagers.size()); it = processor2->mMetricsManagers.find(cfgKey1); EXPECT_TRUE(it != processor2->mMetricsManagers.end()); auto& metricsManager1001 = it->second; EXPECT_TRUE(metricsManager1001->isActive()); metricIt = metricsManager1001->mAllMetricProducers.begin(); for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId1) { break; } } EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end()); auto& metricProducer1001 = *metricIt; EXPECT_FALSE(metricProducer1001->isActive()); metricIt = metricsManager1001->mAllMetricProducers.begin(); for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) { if ((*metricIt)->getMetricId() == metricId2) { break; } } EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end()); auto& metricProducer1002 = *metricIt; EXPECT_TRUE(metricProducer1002->isActive()); const auto& activation1001 = metricProducer1001->mEventActivationMap.begin()->second; EXPECT_EQ(100 * NS_PER_SEC, activation1001.ttl_ns); EXPECT_EQ(0, activation1001.activation_ns); EXPECT_EQ(kNotActive, activation1001.state); processor2->LoadMetricsActivationFromDisk(); EXPECT_TRUE(metricProducer1001->isActive()); EXPECT_EQ(timeBase2 + ttl1 - activation1001.ttl_ns, activation1001.activation_ns); } #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } // namespace statsd } // namespace os } // namespace android