Files
frameworks_base/cmds/statsd/tests/StatsLogProcessor_test.cpp
Tej Singh 756541526a Mark bucket as condition_unknown properly
Previously, if the condition was unknown for the entire bucket, the
bucket would be annotated with a NO_DATA rather than being dropped
because CONDITION_UNKNOWN. This updates all the buckets to be dropped
due to CONDITION_UNKNOWN. Note that this will make the condition unknown
problem appear worse, when in reality it is making our bucket drop
reasons more correct and should not have any impact on the true
CONDITION_UNKNOWN.

Also fix an issue where a test was failing due to a previous test
leaving data persisted to disk. This fix is a hack for now, and should
be properly fixed later.

Bug: 158897179
Test: atest statsd_test
Change-Id: Ic703600d37aa1873ec67cb1a279dcf349d48fc9f
2020-06-13 03:50:59 -07:00

1887 lines
82 KiB
C++

// 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 <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdio.h>
#include "StatsService.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_statsdtest.h"
#include "storage/StorageManager.h"
#include "tests/statsd_test_util.h"
using namespace android;
using namespace testing;
using ::ndk::SharedRefBase;
using std::shared_ptr;
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 shared_ptr<IStatsCompanionService>&, int64_t) {},
[](const shared_ptr<IStatsCompanionService>&) {}),
new AlarmMonitor(10,
[](const shared_ptr<IStatsCompanionService>&, int64_t) {},
[](const shared_ptr<IStatsCompanionService>&) {})) {
}
MOCK_METHOD0(byteSize, size_t());
MOCK_METHOD1(dropData, void(const int64_t dropTimeNs));
};
TEST(StatsLogProcessorTest, TestRateLimitByteSize) {
sp<UidMap> m = new UidMap();
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> 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<int64_t>&) {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(key, mockMetricsManager);
p.flushIfNecessaryLocked(key, mockMetricsManager);
p.flushIfNecessaryLocked(key, mockMetricsManager);
}
TEST(StatsLogProcessorTest, TestRateLimitBroadcast) {
sp<UidMap> m = new UidMap();
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> subscriberAlarmMonitor;
int broadcastCount = 0;
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
},
[](const int&, const vector<int64_t>&) {return true;});
MockMetricsManager mockMetricsManager;
ConfigKey key(100, 12345);
EXPECT_CALL(mockMetricsManager, byteSize())
.Times(1)
.WillRepeatedly(::testing::Return(int(
StatsdStats::kMaxMetricsBytesPerConfig * .95)));
// Expect only one broadcast despite always returning a size that should trigger broadcast.
p.flushIfNecessaryLocked(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<UidMap> m = new UidMap();
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> subscriberAlarmMonitor;
int broadcastCount = 0;
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
},
[](const int&, const vector<int64_t>&) {return true;});
MockMetricsManager mockMetricsManager;
ConfigKey key(100, 12345);
EXPECT_CALL(mockMetricsManager, byteSize())
.Times(1)
.WillRepeatedly(::testing::Return(int(StatsdStats::kMaxMetricsBytesPerConfig * 1.2)));
EXPECT_CALL(mockMetricsManager, dropData(_)).Times(1);
// Expect to call the onDumpReport and skip the broadcast.
p.flushIfNecessaryLocked(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<UidMap> m = new UidMap();
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")},
{String16("p1"), String16("p2")}, {String16(""), String16("")});
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> subscriberAlarmMonitor;
int broadcastCount = 0;
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
},
[](const int&, const vector<int64_t>&) {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<uint8_t> 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);
ASSERT_EQ(2, uidmap.snapshots(0).package_info_size());
}
TEST(StatsLogProcessorTest, TestEmptyConfigHasNoUidMap) {
// Setup simple config key corresponding to empty config.
sp<UidMap> m = new UidMap();
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")},
{String16("p1"), String16("p2")}, {String16(""), String16("")});
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> subscriberAlarmMonitor;
int broadcastCount = 0;
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
},
[](const int&, const vector<int64_t>&) {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<uint8_t> 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<UidMap> m = new UidMap();
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> subscriberAlarmMonitor;
int broadcastCount = 0;
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
},
[](const int&, const vector<int64_t>&) {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<uint8_t> 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);
ASSERT_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<StatsLogProcessor> processor = CreateStatsLogProcessor(1, 1, config, cfgKey);
std::vector<int> attributionUids = {111};
std::vector<string> attributionTags = {"App1"};
std::unique_ptr<LogEvent> event =
CreateAcquireWakelockEvent(2 /*timestamp*/, attributionUids, attributionTags, "wl1");
processor->OnLogEvent(event.get());
vector<uint8_t> 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());
ASSERT_EQ(output.reports_size(), 1);
ASSERT_EQ(output.reports(0).metrics_size(), 1);
ASSERT_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());
ASSERT_EQ(output.reports_size(), 1);
ASSERT_EQ(output.reports(0).metrics_size(), 1);
ASSERT_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, TestPullUidProviderSetOnConfigUpdate) {
// Setup simple config key corresponding to empty config.
sp<UidMap> m = new UidMap();
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> subscriberAlarmMonitor;
StatsLogProcessor p(
m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
[](const ConfigKey& key) { return true; },
[](const int&, const vector<int64_t>&) { return true; });
ConfigKey key(3, 4);
StatsdConfig config = MakeConfig(false);
p.OnConfigUpdated(0, key, config);
EXPECT_NE(pullerManager->mPullUidProviders.find(key), pullerManager->mPullUidProviders.end());
config.add_default_pull_packages("AID_STATSD");
p.OnConfigUpdated(5, key, config);
EXPECT_NE(pullerManager->mPullUidProviders.find(key), pullerManager->mPullUidProviders.end());
p.OnConfigRemoved(key);
EXPECT_EQ(pullerManager->mPullUidProviders.find(key), pullerManager->mPullUidProviders.end());
}
TEST(StatsLogProcessorTest, InvalidConfigRemoved) {
// Setup simple config key corresponding to empty config.
StatsdStats::getInstance().reset();
sp<UidMap> m = new UidMap();
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")},
{String16("p1"), String16("p2")}, {String16(""), String16("")});
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> subscriberAlarmMonitor;
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
[](const ConfigKey& key) { return true; },
[](const int&, const vector<int64_t>&) {return true;});
ConfigKey key(3, 4);
StatsdConfig config = MakeConfig(true);
p.OnConfigUpdated(0, key, config);
EXPECT_EQ(1, p.mMetricsManagers.size());
EXPECT_NE(p.mMetricsManagers.find(key), p.mMetricsManagers.end());
// Cannot assert the size of mConfigStats since it is static and does not get cleared on reset.
EXPECT_NE(StatsdStats::getInstance().mConfigStats.end(),
StatsdStats::getInstance().mConfigStats.find(key));
EXPECT_EQ(0, StatsdStats::getInstance().mIceBox.size());
StatsdConfig invalidConfig = MakeConfig(true);
invalidConfig.clear_allowed_log_source();
p.OnConfigUpdated(0, key, invalidConfig);
EXPECT_EQ(0, p.mMetricsManagers.size());
// The current configs should not contain the invalid config.
EXPECT_EQ(StatsdStats::getInstance().mConfigStats.end(),
StatsdStats::getInstance().mConfigStats.find(key));
// Both "config" and "invalidConfig" should be in the icebox.
EXPECT_EQ(2, StatsdStats::getInstance().mIceBox.size());
}
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);
metric3Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
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);
metric5Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
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);
metric6Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
auto metric6ActivationTrigger = metric6Activation->add_event_activation();
metric6ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
metric6ActivationTrigger->set_ttl_seconds(200);
ConfigKey cfgKey3(uid, cfgId3);
sp<UidMap> m = new UidMap();
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> subscriberAlarmMonitor;
vector<int64_t> 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<int64_t>& 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);
ASSERT_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<int> attributionUids = {111};
std::vector<string> attributionTags = {"App1"};
std::unique_ptr<LogEvent> event =
CreateAcquireWakelockEvent(timeBase1 + 100, attributionUids, attributionTags, "wl1");
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);
ASSERT_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;
processor.SaveActiveConfigsToDisk(shutDownTime);
const int64_t ttl3 = event->GetElapsedTimestampNs() +
metric3ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
const int64_t ttl5 = event->GetElapsedTimestampNs() +
metric5ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
const int64_t ttl6 = event->GetElapsedTimestampNs() +
metric6ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
// Create a second StatsLogProcessor and push the same 3 configs.
long timeBase2 = 1000;
sp<StatsLogProcessor> processor2 =
CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
processor2->OnConfigUpdated(timeBase2, cfgKey2, config2);
processor2->OnConfigUpdated(timeBase2, cfgKey3, config3);
ASSERT_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());
ASSERT_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->start_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->start_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->start_ns);
processor2->LoadActiveConfigsFromDisk();
// After loading activations from disk, assert that all 3 metrics are active.
EXPECT_TRUE(metricProducer1003->isActive());
EXPECT_EQ(timeBase2 + ttl3 - activation1003->ttl_ns, activation1003->start_ns);
EXPECT_TRUE(metricProducer1005->isActive());
EXPECT_EQ(timeBase2 + ttl5 - activation1005->ttl_ns, activation1005->start_ns);
EXPECT_TRUE(metricProducer1006->isActive());
EXPECT_EQ(timeBase2 + ttl6 - activation1006->ttl_ns, activation1003->start_ns);
// Make sure no more broadcasts have happened.
EXPECT_EQ(broadcastCount, 1);
}
TEST(StatsLogProcessorTest, TestActivationOnBoot) {
int uid = 1111;
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(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<StatsLogProcessor> processor =
CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
ASSERT_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->start_ns);
EXPECT_EQ(kNotActive, activation1->state);
std::vector<int> attributionUids = {111};
std::vector<string> attributionTags = {"App1"};
std::unique_ptr<LogEvent> event =
CreateAcquireWakelockEvent(timeBase1 + 100, attributionUids, attributionTags, "wl1");
processor->OnLogEvent(event.get());
EXPECT_FALSE(metricProducer1->isActive());
EXPECT_EQ(0, activation1->start_ns);
EXPECT_EQ(kActiveOnBoot, activation1->state);
int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
processor->SaveActiveConfigsToDisk(shutDownTime);
EXPECT_FALSE(metricProducer1->isActive());
const int64_t ttl1 = metric1ActivationTrigger->ttl_seconds() * NS_PER_SEC;
long timeBase2 = 1000;
sp<StatsLogProcessor> processor2 =
CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
ASSERT_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->start_ns);
EXPECT_EQ(kNotActive, activation1001->state);
processor2->LoadActiveConfigsFromDisk();
EXPECT_TRUE(metricProducer1001->isActive());
EXPECT_EQ(timeBase2 + ttl1 - activation1001->ttl_ns, activation1001->start_ns);
EXPECT_EQ(kActive, activation1001->state);
}
TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) {
int uid = 1111;
// Create config with 2 metrics:
// Metric 1: Activate on boot with 2 activations
// Metric 2: Always active
StatsdConfig config1;
config1.set_id(12341);
config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
*config1.add_atom_matcher() = wakelockAcquireMatcher;
*config1.add_atom_matcher() = screenOnMatcher;
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(ACTIVATE_ON_BOOT);
auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
metric1ActivationTrigger1->set_ttl_seconds(100);
auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
metric1ActivationTrigger2->set_ttl_seconds(200);
ConfigKey cfgKey1(uid, 12341);
long timeBase1 = 1;
sp<StatsLogProcessor> processor =
CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
ASSERT_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());
int i = 0;
for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
if (metricsManager1->mAllAtomMatchers[i]->getId() ==
metric1ActivationTrigger1->atom_matcher_id()) {
break;
}
}
const auto& activation1 = metricProducer1->mEventActivationMap.at(i);
EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
EXPECT_EQ(0, activation1->start_ns);
EXPECT_EQ(kNotActive, activation1->state);
i = 0;
for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
if (metricsManager1->mAllAtomMatchers[i]->getId() ==
metric1ActivationTrigger2->atom_matcher_id()) {
break;
}
}
const auto& activation2 = metricProducer1->mEventActivationMap.at(i);
EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns);
EXPECT_EQ(0, activation2->start_ns);
EXPECT_EQ(kNotActive, activation2->state);
// }}}------------------------------------------------------------------------------
// Trigger Activation 1 for Metric 1
std::vector<int> attributionUids = {111};
std::vector<string> attributionTags = {"App1"};
std::unique_ptr<LogEvent> event =
CreateAcquireWakelockEvent(timeBase1 + 100, attributionUids, attributionTags, "wl1");
processor->OnLogEvent(event.get());
// Metric 1 is not active; Activation 1 set to kActiveOnBoot
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
EXPECT_FALSE(metricProducer1->isActive());
EXPECT_EQ(0, activation1->start_ns);
EXPECT_EQ(kActiveOnBoot, activation1->state);
EXPECT_EQ(0, activation2->start_ns);
EXPECT_EQ(kNotActive, activation2->state);
EXPECT_TRUE(metricProducer2->isActive());
// }}}-----------------------------------------------------------------------------
// Simulate shutdown by saving state to disk
int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
processor->SaveActiveConfigsToDisk(shutDownTime);
EXPECT_FALSE(metricProducer1->isActive());
int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
// Simulate device restarted state by creating new instance of StatsLogProcessor with the
// same config.
long timeBase2 = 1000;
sp<StatsLogProcessor> processor2 =
CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
ASSERT_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());
i = 0;
for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
metric1ActivationTrigger1->atom_matcher_id()) {
break;
}
}
const auto& activation1001_1 = metricProducer1001->mEventActivationMap.at(i);
EXPECT_EQ(100 * NS_PER_SEC, activation1001_1->ttl_ns);
EXPECT_EQ(0, activation1001_1->start_ns);
EXPECT_EQ(kNotActive, activation1001_1->state);
i = 0;
for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
metric1ActivationTrigger2->atom_matcher_id()) {
break;
}
}
const auto& activation1001_2 = metricProducer1001->mEventActivationMap.at(i);
EXPECT_EQ(200 * NS_PER_SEC, activation1001_2->ttl_ns);
EXPECT_EQ(0, activation1001_2->start_ns);
EXPECT_EQ(kNotActive, activation1001_2->state);
// }}}-----------------------------------------------------------------------------------
// Load saved state from disk.
processor2->LoadActiveConfigsFromDisk();
// Metric 1 active; Activation 1 is active, Activation 2 is not active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
EXPECT_TRUE(metricProducer1001->isActive());
EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
EXPECT_EQ(kActive, activation1001_1->state);
EXPECT_EQ(0, activation1001_2->start_ns);
EXPECT_EQ(kNotActive, activation1001_2->state);
EXPECT_TRUE(metricProducer1002->isActive());
// }}}--------------------------------------------------------------------------------
// Trigger Activation 2 for Metric 1.
auto screenOnEvent =
CreateScreenStateChangedEvent(timeBase2 + 200, android::view::DISPLAY_STATE_ON);
processor2->OnLogEvent(screenOnEvent.get());
// Metric 1 active; Activation 1 is active, Activation 2 is set to kActiveOnBoot
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
EXPECT_TRUE(metricProducer1001->isActive());
EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
EXPECT_EQ(kActive, activation1001_1->state);
EXPECT_EQ(0, activation1001_2->start_ns);
EXPECT_EQ(kActiveOnBoot, activation1001_2->state);
EXPECT_TRUE(metricProducer1002->isActive());
// }}}---------------------------------------------------------------------------
// Simulate shutdown by saving state to disk
shutDownTime = timeBase2 + 50 * NS_PER_SEC;
processor2->SaveActiveConfigsToDisk(shutDownTime);
EXPECT_TRUE(metricProducer1001->isActive());
EXPECT_TRUE(metricProducer1002->isActive());
ttl1 = timeBase2 + metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC - shutDownTime;
int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC;
// Simulate device restarted state by creating new instance of StatsLogProcessor with the
// same config.
long timeBase3 = timeBase2 + 120 * NS_PER_SEC;
sp<StatsLogProcessor> processor3 =
CreateStatsLogProcessor(timeBase3, timeBase3, config1, cfgKey1);
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
ASSERT_EQ(1, processor3->mMetricsManagers.size());
it = processor3->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor3->mMetricsManagers.end());
auto& metricsManagerTimeBase3 = it->second;
EXPECT_TRUE(metricsManagerTimeBase3->isActive());
metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
if ((*metricIt)->getMetricId() == metricId1) {
break;
}
}
EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
auto& metricProducerTimeBase3_1 = *metricIt;
EXPECT_FALSE(metricProducerTimeBase3_1->isActive());
metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
if ((*metricIt)->getMetricId() == metricId2) {
break;
}
}
EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
auto& metricProducerTimeBase3_2 = *metricIt;
EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
i = 0;
for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
metric1ActivationTrigger1->atom_matcher_id()) {
break;
}
}
const auto& activationTimeBase3_1 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase3_1->ttl_ns);
EXPECT_EQ(0, activationTimeBase3_1->start_ns);
EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
i = 0;
for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
metric1ActivationTrigger2->atom_matcher_id()) {
break;
}
}
const auto& activationTimeBase3_2 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase3_2->ttl_ns);
EXPECT_EQ(0, activationTimeBase3_2->start_ns);
EXPECT_EQ(kNotActive, activationTimeBase3_2->state);
EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
// }}}----------------------------------------------------------------------------------
// Load saved state from disk.
processor3->LoadActiveConfigsFromDisk();
// Metric 1 active: Activation 1 is active, Activation 2 is active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
EXPECT_EQ(timeBase3 + ttl1 - activationTimeBase3_1->ttl_ns, activationTimeBase3_1->start_ns);
EXPECT_EQ(kActive, activationTimeBase3_1->state);
EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
EXPECT_EQ(kActive, activationTimeBase3_2->state);
EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
// }}}-------------------------------------------------------------------------------
// Trigger Activation 2 for Metric 1 again.
screenOnEvent = CreateScreenStateChangedEvent(timeBase3 + 100 * NS_PER_SEC,
android::view::DISPLAY_STATE_ON);
processor3->OnLogEvent(screenOnEvent.get());
// Metric 1 active; Activation 1 is not active, Activation 2 is set to active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
EXPECT_EQ(kActive, activationTimeBase3_2->state);
EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
// }}}---------------------------------------------------------------------------
// Simulate shutdown by saving state to disk.
shutDownTime = timeBase3 + 500 * NS_PER_SEC;
processor3->SaveActiveConfigsToDisk(shutDownTime);
EXPECT_TRUE(metricProducer1001->isActive());
EXPECT_TRUE(metricProducer1002->isActive());
ttl1 = timeBase3 + ttl1 - shutDownTime;
ttl2 = timeBase3 + metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC - shutDownTime;
// Simulate device restarted state by creating new instance of StatsLogProcessor with the
// same config.
long timeBase4 = timeBase3 + 600 * NS_PER_SEC;
sp<StatsLogProcessor> processor4 =
CreateStatsLogProcessor(timeBase4, timeBase4, config1, cfgKey1);
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
ASSERT_EQ(1, processor4->mMetricsManagers.size());
it = processor4->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor4->mMetricsManagers.end());
auto& metricsManagerTimeBase4 = it->second;
EXPECT_TRUE(metricsManagerTimeBase4->isActive());
metricIt = metricsManagerTimeBase4->mAllMetricProducers.begin();
for (; metricIt != metricsManagerTimeBase4->mAllMetricProducers.end(); metricIt++) {
if ((*metricIt)->getMetricId() == metricId1) {
break;
}
}
EXPECT_TRUE(metricIt != metricsManagerTimeBase4->mAllMetricProducers.end());
auto& metricProducerTimeBase4_1 = *metricIt;
EXPECT_FALSE(metricProducerTimeBase4_1->isActive());
metricIt = metricsManagerTimeBase4->mAllMetricProducers.begin();
for (; metricIt != metricsManagerTimeBase4->mAllMetricProducers.end(); metricIt++) {
if ((*metricIt)->getMetricId() == metricId2) {
break;
}
}
EXPECT_TRUE(metricIt != metricsManagerTimeBase4->mAllMetricProducers.end());
auto& metricProducerTimeBase4_2 = *metricIt;
EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
i = 0;
for (; i < metricsManagerTimeBase4->mAllAtomMatchers.size(); i++) {
if (metricsManagerTimeBase4->mAllAtomMatchers[i]->getId() ==
metric1ActivationTrigger1->atom_matcher_id()) {
break;
}
}
const auto& activationTimeBase4_1 = metricProducerTimeBase4_1->mEventActivationMap.at(i);
EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase4_1->ttl_ns);
EXPECT_EQ(0, activationTimeBase4_1->start_ns);
EXPECT_EQ(kNotActive, activationTimeBase4_1->state);
i = 0;
for (; i < metricsManagerTimeBase4->mAllAtomMatchers.size(); i++) {
if (metricsManagerTimeBase4->mAllAtomMatchers[i]->getId() ==
metric1ActivationTrigger2->atom_matcher_id()) {
break;
}
}
const auto& activationTimeBase4_2 = metricProducerTimeBase4_1->mEventActivationMap.at(i);
EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase4_2->ttl_ns);
EXPECT_EQ(0, activationTimeBase4_2->start_ns);
EXPECT_EQ(kNotActive, activationTimeBase4_2->state);
EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
// }}}----------------------------------------------------------------------------------
// Load saved state from disk.
processor4->LoadActiveConfigsFromDisk();
// Metric 1 active: Activation 1 is not active, Activation 2 is not active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
EXPECT_FALSE(metricProducerTimeBase4_1->isActive());
EXPECT_EQ(kNotActive, activationTimeBase4_1->state);
EXPECT_EQ(kNotActive, activationTimeBase4_2->state);
EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
// }}}-------------------------------------------------------------------------------
}
TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActivationTypes) {
int uid = 1111;
// Create config with 2 metrics:
// Metric 1: Activate on boot with 2 activations
// Metric 2: Always active
StatsdConfig config1;
config1.set_id(12341);
config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
*config1.add_atom_matcher() = wakelockAcquireMatcher;
*config1.add_atom_matcher() = screenOnMatcher;
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(ACTIVATE_ON_BOOT);
auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
metric1ActivationTrigger1->set_ttl_seconds(100);
auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
metric1ActivationTrigger2->set_ttl_seconds(200);
metric1ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
ConfigKey cfgKey1(uid, 12341);
long timeBase1 = 1;
sp<StatsLogProcessor> processor1 =
CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
ASSERT_EQ(1, processor1->mMetricsManagers.size());
auto it = processor1->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor1->mMetricsManagers.end());
auto& metricsManager1 = it->second;
EXPECT_TRUE(metricsManager1->isActive());
ASSERT_EQ(metricsManager1->mAllMetricProducers.size(), 2);
// We assume that the index of a MetricProducer within the mAllMetricProducers
// array follows the order in which metrics are added to the config.
auto& metricProducer1_1 = metricsManager1->mAllMetricProducers[0];
EXPECT_EQ(metricProducer1_1->getMetricId(), metricId1);
EXPECT_FALSE(metricProducer1_1->isActive()); // inactive due to associated MetricActivation
auto& metricProducer1_2 = metricsManager1->mAllMetricProducers[1];
EXPECT_EQ(metricProducer1_2->getMetricId(), metricId2);
EXPECT_TRUE(metricProducer1_2->isActive());
ASSERT_EQ(metricProducer1_1->mEventActivationMap.size(), 2);
// The key in mEventActivationMap is the index of the associated atom matcher. We assume
// that matchers are indexed in the order that they are added to the config.
const auto& activation1_1_1 = metricProducer1_1->mEventActivationMap.at(0);
EXPECT_EQ(100 * NS_PER_SEC, activation1_1_1->ttl_ns);
EXPECT_EQ(0, activation1_1_1->start_ns);
EXPECT_EQ(kNotActive, activation1_1_1->state);
EXPECT_EQ(ACTIVATE_ON_BOOT, activation1_1_1->activationType);
const auto& activation1_1_2 = metricProducer1_1->mEventActivationMap.at(1);
EXPECT_EQ(200 * NS_PER_SEC, activation1_1_2->ttl_ns);
EXPECT_EQ(0, activation1_1_2->start_ns);
EXPECT_EQ(kNotActive, activation1_1_2->state);
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1_1_2->activationType);
// }}}------------------------------------------------------------------------------
// Trigger Activation 1 for Metric 1
std::vector<int> attributionUids = {111};
std::vector<string> attributionTags = {"App1"};
std::unique_ptr<LogEvent> event =
CreateAcquireWakelockEvent(timeBase1 + 100, attributionUids, attributionTags, "wl1");
processor1->OnLogEvent(event.get());
// Metric 1 is not active; Activation 1 set to kActiveOnBoot
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
EXPECT_FALSE(metricProducer1_1->isActive());
EXPECT_EQ(0, activation1_1_1->start_ns);
EXPECT_EQ(kActiveOnBoot, activation1_1_1->state);
EXPECT_EQ(0, activation1_1_2->start_ns);
EXPECT_EQ(kNotActive, activation1_1_2->state);
EXPECT_TRUE(metricProducer1_2->isActive());
// }}}-----------------------------------------------------------------------------
// Simulate shutdown by saving state to disk
int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
processor1->SaveActiveConfigsToDisk(shutDownTime);
EXPECT_FALSE(metricProducer1_1->isActive());
// Simulate device restarted state by creating new instance of StatsLogProcessor with the
// same config.
long timeBase2 = 1000;
sp<StatsLogProcessor> processor2 =
CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
ASSERT_EQ(1, processor2->mMetricsManagers.size());
it = processor2->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
auto& metricsManager2 = it->second;
EXPECT_TRUE(metricsManager2->isActive());
ASSERT_EQ(metricsManager2->mAllMetricProducers.size(), 2);
// We assume that the index of a MetricProducer within the mAllMetricProducers
// array follows the order in which metrics are added to the config.
auto& metricProducer2_1 = metricsManager2->mAllMetricProducers[0];
EXPECT_EQ(metricProducer2_1->getMetricId(), metricId1);
EXPECT_FALSE(metricProducer2_1->isActive());
auto& metricProducer2_2 = metricsManager2->mAllMetricProducers[1];
EXPECT_EQ(metricProducer2_2->getMetricId(), metricId2);
EXPECT_TRUE(metricProducer2_2->isActive());
ASSERT_EQ(metricProducer2_1->mEventActivationMap.size(), 2);
// The key in mEventActivationMap is the index of the associated atom matcher. We assume
// that matchers are indexed in the order that they are added to the config.
const auto& activation2_1_1 = metricProducer2_1->mEventActivationMap.at(0);
EXPECT_EQ(100 * NS_PER_SEC, activation2_1_1->ttl_ns);
EXPECT_EQ(0, activation2_1_1->start_ns);
EXPECT_EQ(kNotActive, activation2_1_1->state);
EXPECT_EQ(ACTIVATE_ON_BOOT, activation2_1_1->activationType);
const auto& activation2_1_2 = metricProducer2_1->mEventActivationMap.at(1);
EXPECT_EQ(200 * NS_PER_SEC, activation2_1_2->ttl_ns);
EXPECT_EQ(0, activation2_1_2->start_ns);
EXPECT_EQ(kNotActive, activation2_1_2->state);
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2_1_2->activationType);
// }}}-----------------------------------------------------------------------------------
// Load saved state from disk.
processor2->LoadActiveConfigsFromDisk();
// Metric 1 active; Activation 1 is active, Activation 2 is not active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
EXPECT_TRUE(metricProducer2_1->isActive());
int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns);
EXPECT_EQ(kActive, activation2_1_1->state);
EXPECT_EQ(0, activation2_1_2->start_ns);
EXPECT_EQ(kNotActive, activation2_1_2->state);
EXPECT_TRUE(metricProducer2_2->isActive());
// }}}--------------------------------------------------------------------------------
// Trigger Activation 2 for Metric 1.
auto screenOnEvent =
CreateScreenStateChangedEvent(timeBase2 + 200, android::view::DISPLAY_STATE_ON);
processor2->OnLogEvent(screenOnEvent.get());
// Metric 1 active; Activation 1 is active, Activation 2 is active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
EXPECT_TRUE(metricProducer2_1->isActive());
EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns);
EXPECT_EQ(kActive, activation2_1_1->state);
EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation2_1_2->start_ns);
EXPECT_EQ(kActive, activation2_1_2->state);
EXPECT_TRUE(metricProducer2_2->isActive());
// }}}---------------------------------------------------------------------------
// Simulate shutdown by saving state to disk
shutDownTime = timeBase2 + 50 * NS_PER_SEC;
processor2->SaveActiveConfigsToDisk(shutDownTime);
EXPECT_TRUE(metricProducer2_1->isActive());
EXPECT_TRUE(metricProducer2_2->isActive());
ttl1 -= shutDownTime - timeBase2;
int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC -
(shutDownTime - screenOnEvent->GetElapsedTimestampNs());
// Simulate device restarted state by creating new instance of StatsLogProcessor with the
// same config.
long timeBase3 = timeBase2 + 120 * NS_PER_SEC;
sp<StatsLogProcessor> processor3 =
CreateStatsLogProcessor(timeBase3, timeBase3, config1, cfgKey1);
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
ASSERT_EQ(1, processor3->mMetricsManagers.size());
it = processor3->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor3->mMetricsManagers.end());
auto& metricsManager3 = it->second;
EXPECT_TRUE(metricsManager3->isActive());
ASSERT_EQ(metricsManager3->mAllMetricProducers.size(), 2);
// We assume that the index of a MetricProducer within the mAllMetricProducers
// array follows the order in which metrics are added to the config.
auto& metricProducer3_1 = metricsManager3->mAllMetricProducers[0];
EXPECT_EQ(metricProducer3_1->getMetricId(), metricId1);
EXPECT_FALSE(metricProducer3_1->isActive());
auto& metricProducer3_2 = metricsManager3->mAllMetricProducers[1];
EXPECT_EQ(metricProducer3_2->getMetricId(), metricId2);
EXPECT_TRUE(metricProducer3_2->isActive());
ASSERT_EQ(metricProducer3_1->mEventActivationMap.size(), 2);
// The key in mEventActivationMap is the index of the associated atom matcher. We assume
// that matchers are indexed in the order that they are added to the config.
const auto& activation3_1_1 = metricProducer3_1->mEventActivationMap.at(0);
EXPECT_EQ(100 * NS_PER_SEC, activation3_1_1->ttl_ns);
EXPECT_EQ(0, activation3_1_1->start_ns);
EXPECT_EQ(kNotActive, activation3_1_1->state);
EXPECT_EQ(ACTIVATE_ON_BOOT, activation3_1_1->activationType);
const auto& activation3_1_2 = metricProducer3_1->mEventActivationMap.at(1);
EXPECT_EQ(200 * NS_PER_SEC, activation3_1_2->ttl_ns);
EXPECT_EQ(0, activation3_1_2->start_ns);
EXPECT_EQ(kNotActive, activation3_1_2->state);
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation3_1_2->activationType);
// }}}----------------------------------------------------------------------------------
// Load saved state from disk.
processor3->LoadActiveConfigsFromDisk();
// Metric 1 active: Activation 1 is active, Activation 2 is active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
EXPECT_TRUE(metricProducer3_1->isActive());
EXPECT_EQ(timeBase3 + ttl1 - activation3_1_1->ttl_ns, activation3_1_1->start_ns);
EXPECT_EQ(kActive, activation3_1_1->state);
EXPECT_EQ(timeBase3 + ttl2 - activation3_1_2->ttl_ns, activation3_1_2->start_ns);
EXPECT_EQ(kActive, activation3_1_2->state);
EXPECT_TRUE(metricProducer3_2->isActive());
// }}}-------------------------------------------------------------------------------
// Trigger Activation 2 for Metric 1 again.
screenOnEvent = CreateScreenStateChangedEvent(timeBase3 + 100 * NS_PER_SEC,
android::view::DISPLAY_STATE_ON);
processor3->OnLogEvent(screenOnEvent.get());
// Metric 1 active; Activation 1 is inactive (above screenOnEvent causes ttl1 to expire),
// Activation 2 is set to active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
EXPECT_TRUE(metricProducer3_1->isActive());
EXPECT_EQ(kNotActive, activation3_1_1->state);
EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation3_1_2->start_ns);
EXPECT_EQ(kActive, activation3_1_2->state);
EXPECT_TRUE(metricProducer3_2->isActive());
// }}}---------------------------------------------------------------------------
}
TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) {
int uid = 9876;
long configId = 12341;
// Create config with 3 metrics:
// Metric 1: Activate on 2 activations, 1 on boot, 1 immediate.
// Metric 2: Activate on 2 activations, 1 on boot, 1 immediate.
// Metric 3: Always active
StatsdConfig config1;
config1.set_id(configId);
config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
auto jobStartMatcher = CreateStartScheduledJobAtomMatcher();
auto jobFinishMatcher = CreateFinishScheduledJobAtomMatcher();
*config1.add_atom_matcher() = wakelockAcquireMatcher;
*config1.add_atom_matcher() = screenOnMatcher;
*config1.add_atom_matcher() = jobStartMatcher;
*config1.add_atom_matcher() = jobFinishMatcher;
long metricId1 = 1234561;
long metricId2 = 1234562;
long metricId3 = 1234563;
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 countMetric3 = config1.add_count_metric();
countMetric3->set_id(metricId3);
countMetric3->set_what(wakelockAcquireMatcher.id());
countMetric3->set_bucket(FIVE_MINUTES);
// Metric 1 activates on boot for wakelock acquire, immediately for screen on.
auto metric1Activation = config1.add_metric_activation();
metric1Activation->set_metric_id(metricId1);
auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
metric1ActivationTrigger1->set_ttl_seconds(100);
metric1ActivationTrigger1->set_activation_type(ACTIVATE_ON_BOOT);
auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
metric1ActivationTrigger2->set_ttl_seconds(200);
metric1ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
// Metric 2 activates on boot for scheduled job start, immediately for scheduled job finish.
auto metric2Activation = config1.add_metric_activation();
metric2Activation->set_metric_id(metricId2);
auto metric2ActivationTrigger1 = metric2Activation->add_event_activation();
metric2ActivationTrigger1->set_atom_matcher_id(jobStartMatcher.id());
metric2ActivationTrigger1->set_ttl_seconds(100);
metric2ActivationTrigger1->set_activation_type(ACTIVATE_ON_BOOT);
auto metric2ActivationTrigger2 = metric2Activation->add_event_activation();
metric2ActivationTrigger2->set_atom_matcher_id(jobFinishMatcher.id());
metric2ActivationTrigger2->set_ttl_seconds(200);
metric2ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
// Send the config.
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
string serialized = config1.SerializeAsString();
service->addConfigurationChecked(uid, configId, {serialized.begin(), serialized.end()});
// Make sure the config is stored on disk. Otherwise, we will not reset on system server death.
StatsdConfig tmpConfig;
ConfigKey cfgKey1(uid, configId);
EXPECT_TRUE(StorageManager::readConfigFromDisk(cfgKey1, &tmpConfig));
// Metric 1 is not active.
// Metric 2 is not active.
// Metric 3 is active.
// {{{---------------------------------------------------------------------------
sp<StatsLogProcessor> processor = service->mProcessor;
ASSERT_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());
ASSERT_EQ(3, metricsManager1->mAllMetricProducers.size());
auto& metricProducer1 = metricsManager1->mAllMetricProducers[0];
EXPECT_EQ(metricId1, metricProducer1->getMetricId());
EXPECT_FALSE(metricProducer1->isActive());
auto& metricProducer2 = metricsManager1->mAllMetricProducers[1];
EXPECT_EQ(metricId2, metricProducer2->getMetricId());
EXPECT_FALSE(metricProducer2->isActive());
auto& metricProducer3 = metricsManager1->mAllMetricProducers[2];
EXPECT_EQ(metricId3, metricProducer3->getMetricId());
EXPECT_TRUE(metricProducer3->isActive());
// Check event activations.
ASSERT_EQ(metricsManager1->mAllAtomMatchers.size(), 4);
EXPECT_EQ(metricsManager1->mAllAtomMatchers[0]->getId(),
metric1ActivationTrigger1->atom_matcher_id());
const auto& activation1 = metricProducer1->mEventActivationMap.at(0);
EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
EXPECT_EQ(0, activation1->start_ns);
EXPECT_EQ(kNotActive, activation1->state);
EXPECT_EQ(ACTIVATE_ON_BOOT, activation1->activationType);
EXPECT_EQ(metricsManager1->mAllAtomMatchers[1]->getId(),
metric1ActivationTrigger2->atom_matcher_id());
const auto& activation2 = metricProducer1->mEventActivationMap.at(1);
EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns);
EXPECT_EQ(0, activation2->start_ns);
EXPECT_EQ(kNotActive, activation2->state);
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2->activationType);
EXPECT_EQ(metricsManager1->mAllAtomMatchers[2]->getId(),
metric2ActivationTrigger1->atom_matcher_id());
const auto& activation3 = metricProducer2->mEventActivationMap.at(2);
EXPECT_EQ(100 * NS_PER_SEC, activation3->ttl_ns);
EXPECT_EQ(0, activation3->start_ns);
EXPECT_EQ(kNotActive, activation3->state);
EXPECT_EQ(ACTIVATE_ON_BOOT, activation3->activationType);
EXPECT_EQ(metricsManager1->mAllAtomMatchers[3]->getId(),
metric2ActivationTrigger2->atom_matcher_id());
const auto& activation4 = metricProducer2->mEventActivationMap.at(3);
EXPECT_EQ(200 * NS_PER_SEC, activation4->ttl_ns);
EXPECT_EQ(0, activation4->start_ns);
EXPECT_EQ(kNotActive, activation4->state);
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation4->activationType);
// }}}------------------------------------------------------------------------------
// Trigger Activation 1 for Metric 1. Should activate on boot.
// Trigger Activation 4 for Metric 2. Should activate immediately.
int64_t configAddedTimeNs = metricsManager1->mLastReportTimeNs;
std::vector<int> attributionUids = {111};
std::vector<string> attributionTags = {"App1"};
std::unique_ptr<LogEvent> event1 = CreateAcquireWakelockEvent(
1 + configAddedTimeNs, attributionUids, attributionTags, "wl1");
processor->OnLogEvent(event1.get());
std::unique_ptr<LogEvent> event2 = CreateFinishScheduledJobEvent(
2 + configAddedTimeNs, attributionUids, attributionTags, "finish1");
processor->OnLogEvent(event2.get());
// Metric 1 is not active; Activation 1 set to kActiveOnBoot
// Metric 2 is active. Activation 4 set to kActive
// Metric 3 is active.
// {{{---------------------------------------------------------------------------
EXPECT_FALSE(metricProducer1->isActive());
EXPECT_EQ(0, activation1->start_ns);
EXPECT_EQ(kActiveOnBoot, activation1->state);
EXPECT_EQ(0, activation2->start_ns);
EXPECT_EQ(kNotActive, activation2->state);
EXPECT_TRUE(metricProducer2->isActive());
EXPECT_EQ(0, activation3->start_ns);
EXPECT_EQ(kNotActive, activation3->state);
EXPECT_EQ(2 + configAddedTimeNs, activation4->start_ns);
EXPECT_EQ(kActive, activation4->state);
EXPECT_TRUE(metricProducer3->isActive());
// }}}-----------------------------------------------------------------------------
// Can't fake time with StatsService.
// Lets get a time close to the system server death time and make sure it's sane.
int64_t approximateSystemServerDeath = getElapsedRealtimeNs();
EXPECT_TRUE(approximateSystemServerDeath > 2 + configAddedTimeNs);
EXPECT_TRUE(approximateSystemServerDeath < NS_PER_SEC + configAddedTimeNs);
// System server dies.
service->statsCompanionServiceDiedImpl();
// We should have a new metrics manager. Lets get it and ensure activation status is restored.
// {{{---------------------------------------------------------------------------
ASSERT_EQ(1, processor->mMetricsManagers.size());
it = processor->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor->mMetricsManagers.end());
auto& metricsManager2 = it->second;
EXPECT_TRUE(metricsManager2->isActive());
ASSERT_EQ(3, metricsManager2->mAllMetricProducers.size());
auto& metricProducer1001 = metricsManager2->mAllMetricProducers[0];
EXPECT_EQ(metricId1, metricProducer1001->getMetricId());
EXPECT_FALSE(metricProducer1001->isActive());
auto& metricProducer1002 = metricsManager2->mAllMetricProducers[1];
EXPECT_EQ(metricId2, metricProducer1002->getMetricId());
EXPECT_TRUE(metricProducer1002->isActive());
auto& metricProducer1003 = metricsManager2->mAllMetricProducers[2];
EXPECT_EQ(metricId3, metricProducer1003->getMetricId());
EXPECT_TRUE(metricProducer1003->isActive());
// Check event activations.
// Activation 1 is kActiveOnBoot.
// Activation 2 and 3 are not active.
// Activation 4 is active.
ASSERT_EQ(metricsManager2->mAllAtomMatchers.size(), 4);
EXPECT_EQ(metricsManager2->mAllAtomMatchers[0]->getId(),
metric1ActivationTrigger1->atom_matcher_id());
const auto& activation1001 = metricProducer1001->mEventActivationMap.at(0);
EXPECT_EQ(100 * NS_PER_SEC, activation1001->ttl_ns);
EXPECT_EQ(0, activation1001->start_ns);
EXPECT_EQ(kActiveOnBoot, activation1001->state);
EXPECT_EQ(ACTIVATE_ON_BOOT, activation1001->activationType);
EXPECT_EQ(metricsManager2->mAllAtomMatchers[1]->getId(),
metric1ActivationTrigger2->atom_matcher_id());
const auto& activation1002 = metricProducer1001->mEventActivationMap.at(1);
EXPECT_EQ(200 * NS_PER_SEC, activation1002->ttl_ns);
EXPECT_EQ(0, activation1002->start_ns);
EXPECT_EQ(kNotActive, activation1002->state);
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1002->activationType);
EXPECT_EQ(metricsManager2->mAllAtomMatchers[2]->getId(),
metric2ActivationTrigger1->atom_matcher_id());
const auto& activation1003 = metricProducer1002->mEventActivationMap.at(2);
EXPECT_EQ(100 * NS_PER_SEC, activation1003->ttl_ns);
EXPECT_EQ(0, activation1003->start_ns);
EXPECT_EQ(kNotActive, activation1003->state);
EXPECT_EQ(ACTIVATE_ON_BOOT, activation1003->activationType);
EXPECT_EQ(metricsManager2->mAllAtomMatchers[3]->getId(),
metric2ActivationTrigger2->atom_matcher_id());
const auto& activation1004 = metricProducer1002->mEventActivationMap.at(3);
EXPECT_EQ(200 * NS_PER_SEC, activation1004->ttl_ns);
EXPECT_EQ(2 + configAddedTimeNs, activation1004->start_ns);
EXPECT_EQ(kActive, activation1004->state);
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1004->activationType);
// }}}------------------------------------------------------------------------------
// Clear the data stored on disk as a result of the system server death.
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey1, configAddedTimeNs + NS_PER_SEC, false, true, ADB_DUMP, FAST,
&buffer);
}
TEST(StatsLogProcessorTest_mapIsolatedUidToHostUid, LogHostUid) {
int hostUid = 20;
int isolatedUid = 30;
uint64_t eventTimeNs = 12355;
int atomId = 89;
int field1 = 90;
int field2 = 28;
sp<MockUidMap> mockUidMap = makeMockUidMapForOneHost(hostUid, {isolatedUid});
ConfigKey cfgKey;
StatsdConfig config = MakeConfig(false);
sp<StatsLogProcessor> processor =
CreateStatsLogProcessor(1, 1, config, cfgKey, nullptr, 0, mockUidMap);
shared_ptr<LogEvent> logEvent = makeUidLogEvent(atomId, eventTimeNs, hostUid, field1, field2);
processor->OnLogEvent(logEvent.get());
const vector<FieldValue>* actualFieldValues = &logEvent->getValues();
ASSERT_EQ(3, actualFieldValues->size());
EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
EXPECT_EQ(field1, actualFieldValues->at(1).mValue.int_value);
EXPECT_EQ(field2, actualFieldValues->at(2).mValue.int_value);
}
TEST(StatsLogProcessorTest_mapIsolatedUidToHostUid, LogIsolatedUid) {
int hostUid = 20;
int isolatedUid = 30;
uint64_t eventTimeNs = 12355;
int atomId = 89;
int field1 = 90;
int field2 = 28;
sp<MockUidMap> mockUidMap = makeMockUidMapForOneHost(hostUid, {isolatedUid});
ConfigKey cfgKey;
StatsdConfig config = MakeConfig(false);
sp<StatsLogProcessor> processor =
CreateStatsLogProcessor(1, 1, config, cfgKey, nullptr, 0, mockUidMap);
shared_ptr<LogEvent> logEvent =
makeUidLogEvent(atomId, eventTimeNs, isolatedUid, field1, field2);
processor->OnLogEvent(logEvent.get());
const vector<FieldValue>* actualFieldValues = &logEvent->getValues();
ASSERT_EQ(3, actualFieldValues->size());
EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
EXPECT_EQ(field1, actualFieldValues->at(1).mValue.int_value);
EXPECT_EQ(field2, actualFieldValues->at(2).mValue.int_value);
}
TEST(StatsLogProcessorTest_mapIsolatedUidToHostUid, LogHostUidAttributionChain) {
int hostUid = 20;
int isolatedUid = 30;
uint64_t eventTimeNs = 12355;
int atomId = 89;
int field1 = 90;
int field2 = 28;
sp<MockUidMap> mockUidMap = makeMockUidMapForOneHost(hostUid, {isolatedUid});
ConfigKey cfgKey;
StatsdConfig config = MakeConfig(false);
sp<StatsLogProcessor> processor =
CreateStatsLogProcessor(1, 1, config, cfgKey, nullptr, 0, mockUidMap);
shared_ptr<LogEvent> logEvent = makeAttributionLogEvent(atomId, eventTimeNs, {hostUid, 200},
{"tag1", "tag2"}, field1, field2);
processor->OnLogEvent(logEvent.get());
const vector<FieldValue>* actualFieldValues = &logEvent->getValues();
ASSERT_EQ(6, actualFieldValues->size());
EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
EXPECT_EQ("tag1", actualFieldValues->at(1).mValue.str_value);
EXPECT_EQ(200, actualFieldValues->at(2).mValue.int_value);
EXPECT_EQ("tag2", actualFieldValues->at(3).mValue.str_value);
EXPECT_EQ(field1, actualFieldValues->at(4).mValue.int_value);
EXPECT_EQ(field2, actualFieldValues->at(5).mValue.int_value);
}
TEST(StatsLogProcessorTest_mapIsolatedUidToHostUid, LogIsolatedUidAttributionChain) {
int hostUid = 20;
int isolatedUid = 30;
uint64_t eventTimeNs = 12355;
int atomId = 89;
int field1 = 90;
int field2 = 28;
sp<MockUidMap> mockUidMap = makeMockUidMapForOneHost(hostUid, {isolatedUid});
ConfigKey cfgKey;
StatsdConfig config = MakeConfig(false);
sp<StatsLogProcessor> processor =
CreateStatsLogProcessor(1, 1, config, cfgKey, nullptr, 0, mockUidMap);
shared_ptr<LogEvent> logEvent = makeAttributionLogEvent(atomId, eventTimeNs, {isolatedUid, 200},
{"tag1", "tag2"}, field1, field2);
processor->OnLogEvent(logEvent.get());
const vector<FieldValue>* actualFieldValues = &logEvent->getValues();
ASSERT_EQ(6, actualFieldValues->size());
EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
EXPECT_EQ("tag1", actualFieldValues->at(1).mValue.str_value);
EXPECT_EQ(200, actualFieldValues->at(2).mValue.int_value);
EXPECT_EQ("tag2", actualFieldValues->at(3).mValue.str_value);
EXPECT_EQ(field1, actualFieldValues->at(4).mValue.int_value);
EXPECT_EQ(field2, actualFieldValues->at(5).mValue.int_value);
}
TEST(StatsLogProcessorTest, TestDumpReportWithoutErasingDataDoesNotUpdateTimestamp) {
int hostUid = 20;
int isolatedUid = 30;
sp<MockUidMap> mockUidMap = makeMockUidMapForOneHost(hostUid, {isolatedUid});
ConfigKey key(3, 4);
// TODO: All tests should not persist state on disk. This removes any reports that were present.
ProtoOutputStream proto;
StorageManager::appendConfigMetricsReport(key, &proto, /*erase data=*/true, /*isAdb=*/false);
StatsdConfig config = MakeConfig(false);
sp<StatsLogProcessor> processor =
CreateStatsLogProcessor(1, 1, config, key, nullptr, 0, mockUidMap);
vector<uint8_t> bytes;
int64_t dumpTime1Ns = 1 * NS_PER_SEC;
processor->onDumpReport(key, dumpTime1Ns, false /* include_current_bucket */,
true /* erase_data */, ADB_DUMP, FAST, &bytes);
ConfigMetricsReportList output;
output.ParseFromArray(bytes.data(), bytes.size());
EXPECT_EQ(output.reports_size(), 1);
EXPECT_EQ(output.reports(0).current_report_elapsed_nanos(), dumpTime1Ns);
int64_t dumpTime2Ns = 5 * NS_PER_SEC;
processor->onDumpReport(key, dumpTime2Ns, false /* include_current_bucket */,
false /* erase_data */, ADB_DUMP, FAST, &bytes);
// Check that the dump report without clearing data is successful.
output.ParseFromArray(bytes.data(), bytes.size());
EXPECT_EQ(output.reports_size(), 1);
EXPECT_EQ(output.reports(0).current_report_elapsed_nanos(), dumpTime2Ns);
EXPECT_EQ(output.reports(0).last_report_elapsed_nanos(), dumpTime1Ns);
int64_t dumpTime3Ns = 10 * NS_PER_SEC;
processor->onDumpReport(key, dumpTime3Ns, false /* include_current_bucket */,
true /* erase_data */, ADB_DUMP, FAST, &bytes);
// Check that the previous dump report that didn't clear data did not overwrite the first dump's
// timestamps.
output.ParseFromArray(bytes.data(), bytes.size());
EXPECT_EQ(output.reports_size(), 1);
EXPECT_EQ(output.reports(0).current_report_elapsed_nanos(), dumpTime3Ns);
EXPECT_EQ(output.reports(0).last_report_elapsed_nanos(), dumpTime1Ns);
}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
} // namespace statsd
} // namespace os
} // namespace android