// 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 <android-base/stringprintf.h>
#include <android-modules-utils/sdk_level.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdio.h>

#include "StatsService.h"
#include "config/ConfigKey.h"
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "packages/UidMap.h"
#include "src/stats_log.pb.h"
#include "src/statsd_config.pb.h"
#include "state/StateManager.h"
#include "statslog_statsdtest.h"
#include "storage/StorageManager.h"
#include "tests/statsd_test_util.h"
#include "utils/DbUtils.h"

using namespace android;
using namespace testing;
using ::ndk::SharedRefBase;
using std::shared_ptr;

namespace android {
namespace os {
namespace statsd {

using android::base::StringPrintf;
using android::modules::sdklevel::IsAtLeastU;
using android::util::ProtoOutputStream;

using ::testing::Expectation;

#ifdef __ANDROID__
#define STATS_DATA_DIR "/data/misc/stats-data"

/**
 * Mock MetricsManager (ByteSize() is called).
 */
class MockMetricsManager : public MetricsManager {
public:
    MockMetricsManager(ConfigKey configKey = ConfigKey(1, 12345))
        : MetricsManager(configKey, 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));

    MOCK_METHOD(void, onLogEvent, (const LogEvent& event), (override));

    MOCK_METHOD(void, onDumpReport,
                (const int64_t dumpTimeNs, const int64_t wallClockNs,
                 const bool include_current_partial_bucket, const bool erase_data,
                 const DumpLatency dumpLatency, std::set<string>* str_set,
                 android::util::ProtoOutputStream* protoOutput),
                (override));
};

TEST(StatsLogProcessorTest, TestRateLimitByteSize) {
    sp<UidMap> m = new UidMap();
    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
    sp<AlarmMonitor> anomalyAlarmMonitor;
    sp<AlarmMonitor> periodicAlarmMonitor;
    // Construct the processor with a no-op 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; },
            [](const ConfigKey&, const string&, const vector<int64_t>&) {}, nullptr);

    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; },
            [](const ConfigKey&, const string&, const vector<int64_t>&) {}, nullptr);

    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; },
            [](const ConfigKey&, const string&, const vector<int64_t>&) {}, nullptr);

    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;
}

StatsdConfig makeRestrictedConfig(bool includeMetric = false) {
    StatsdConfig config;
    config.add_allowed_log_source("AID_ROOT");
    config.set_restricted_metrics_delegate_package_name("delegate");

    if (includeMetric) {
        auto appCrashMatcher = CreateProcessCrashAtomMatcher();
        *config.add_atom_matcher() = appCrashMatcher;
        auto eventMetric = config.add_event_metric();
        eventMetric->set_id(StringToId("EventAppCrashes"));
        eventMetric->set_what(appCrashMatcher.id());
    }
    return config;
}

class MockRestrictedMetricsManager : public MetricsManager {
public:
    MockRestrictedMetricsManager(ConfigKey configKey = ConfigKey(1, 12345))
        : MetricsManager(configKey, makeRestrictedConfig(), 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_METHOD(void, onLogEvent, (const LogEvent& event), (override));
    MOCK_METHOD(void, onDumpReport,
                (const int64_t dumpTimeNs, const int64_t wallClockNs,
                 const bool include_current_partial_bucket, const bool erase_data,
                 const DumpLatency dumpLatency, std::set<string>* str_set,
                 android::util::ProtoOutputStream* protoOutput),
                (override));
    MOCK_METHOD(size_t, byteSize, (), (override));
    MOCK_METHOD(void, flushRestrictedData, (), (override));
};

TEST(StatsLogProcessorTest, TestUidMapHasSnapshot) {
    ConfigKey key(3, 4);
    StatsdConfig config = MakeConfig(true);

    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("")},
                 /* certificateHash */ {{}, {}});
    sp<AlarmMonitor> anomalyAlarmMonitor;
    sp<AlarmMonitor> subscriberAlarmMonitor;
    int broadcastCount = 0;
    std::shared_ptr<MockLogEventFilter> mockLogEventFilter = std::make_shared<MockLogEventFilter>();
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(StatsLogProcessor::getDefaultAtomIdSet(), _))
            .Times(1);
    StatsLogProcessor p(
            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
            [&broadcastCount](const ConfigKey& key) {
                broadcastCount++;
                return true;
            },
            [](const int&, const vector<int64_t>&) { return true; },
            [](const ConfigKey&, const string&, const vector<int64_t>&) {}, mockLogEventFilter);

    const LogEventFilter::AtomIdSet atomIdsList = CreateAtomIdSetFromConfig(config);
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(atomIdsList, &p)).Times(1);

    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.
    ConfigKey key(3, 4);
    StatsdConfig config = MakeConfig(false);

    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("")},
                 /* certificateHash */ {{}, {}});
    sp<AlarmMonitor> anomalyAlarmMonitor;
    sp<AlarmMonitor> subscriberAlarmMonitor;
    int broadcastCount = 0;
    std::shared_ptr<MockLogEventFilter> mockLogEventFilter = std::make_shared<MockLogEventFilter>();
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(StatsLogProcessor::getDefaultAtomIdSet(), _))
            .Times(1);
    StatsLogProcessor p(
            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
            [&broadcastCount](const ConfigKey& key) {
                broadcastCount++;
                return true;
            },
            [](const int&, const vector<int64_t>&) { return true; },
            [](const ConfigKey&, const string&, const vector<int64_t>&) {}, mockLogEventFilter);

    const LogEventFilter::AtomIdSet atomIdsList = CreateAtomIdSetFromConfig(config);
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(atomIdsList, &p)).Times(1);

    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.
    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");

    sp<UidMap> m = new UidMap();
    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
    sp<AlarmMonitor> anomalyAlarmMonitor;
    sp<AlarmMonitor> subscriberAlarmMonitor;
    int broadcastCount = 0;
    std::shared_ptr<MockLogEventFilter> mockLogEventFilter = std::make_shared<MockLogEventFilter>();
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(StatsLogProcessor::getDefaultAtomIdSet(), _))
            .Times(1);
    StatsLogProcessor p(
            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
            [&broadcastCount](const ConfigKey& key) {
                broadcastCount++;
                return true;
            },
            [](const int&, const vector<int64_t>&) { return true; },
            [](const ConfigKey&, const string&, const vector<int64_t>&) {}, mockLogEventFilter);

    const LogEventFilter::AtomIdSet atomIdsList = CreateAtomIdSetFromConfig(config);
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(atomIdsList, &p)).Times(1);

    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.
    ConfigKey key(3, 4);
    StatsdConfig config = MakeConfig(false);

    sp<UidMap> m = new UidMap();
    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
    sp<AlarmMonitor> anomalyAlarmMonitor;
    sp<AlarmMonitor> subscriberAlarmMonitor;
    std::shared_ptr<MockLogEventFilter> mockLogEventFilter = std::make_shared<MockLogEventFilter>();
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(StatsLogProcessor::getDefaultAtomIdSet(), _))
            .Times(1);
    StatsLogProcessor p(
            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
            [](const ConfigKey& key) { return true; },
            [](const int&, const vector<int64_t>&) { return true; },
            [](const ConfigKey&, const string&, const vector<int64_t>&) {}, mockLogEventFilter);

    const LogEventFilter::AtomIdSet atomIdsList = CreateAtomIdSetFromConfig(config);
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(atomIdsList, &p)).Times(3);

    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) {
    ConfigKey key(3, 4);
    StatsdConfig config = MakeConfig(true);

    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("")},
                 /* certificateHash */ {{}, {}});
    sp<AlarmMonitor> anomalyAlarmMonitor;
    sp<AlarmMonitor> subscriberAlarmMonitor;
    std::shared_ptr<MockLogEventFilter> mockLogEventFilter = std::make_shared<MockLogEventFilter>();
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(StatsLogProcessor::getDefaultAtomIdSet(), _))
            .Times(1);
    StatsLogProcessor p(
            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
            [](const ConfigKey& key) { return true; },
            [](const int&, const vector<int64_t>&) { return true; },
            [](const ConfigKey&, const string&, const vector<int64_t>&) {}, mockLogEventFilter);

    EXPECT_CALL(*mockLogEventFilter, setAtomIds(CreateAtomIdSetDefault(), &p)).Times(1);
    // atom used by matcher defined in MakeConfig() API
    Expectation exp =
            EXPECT_CALL(*mockLogEventFilter, setAtomIds(CreateAtomIdSetFromConfig(config), &p))
                    .Times(1);
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(CreateAtomIdSetDefault(), &p)).Times(1).After(exp);

    // Remove the config mConfigStats so that the Icebox starts at 0 configs.
    p.OnConfigRemoved(key);
    StatsdStats::getInstance().reset();
    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());
    string suffix = StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId());
    StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, suffix.c_str());
}

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;
    std::shared_ptr<MockLogEventFilter> mockLogEventFilter = std::make_shared<MockLogEventFilter>();
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(StatsLogProcessor::getDefaultAtomIdSet(), _))
            .Times(1);
    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;
            },
            [](const ConfigKey&, const string&, const vector<int64_t>&) {}, mockLogEventFilter);

    // config1,config2,config3 use the same atom
    const LogEventFilter::AtomIdSet atomIdsList = CreateAtomIdSetFromConfig(config1);
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(atomIdsList, &processor)).Times(3);

    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->mAllAtomMatchingTrackers.size(); i++) {
        if (metricsManager1->mAllAtomMatchingTrackers[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->mAllAtomMatchingTrackers.size(); i++) {
        if (metricsManager1->mAllAtomMatchingTrackers[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->mAllAtomMatchingTrackers.size(); i++) {
        if (metricsManager1001->mAllAtomMatchingTrackers[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->mAllAtomMatchingTrackers.size(); i++) {
        if (metricsManager1001->mAllAtomMatchingTrackers[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->mAllAtomMatchingTrackers.size(); i++) {
        if (metricsManagerTimeBase3->mAllAtomMatchingTrackers[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->mAllAtomMatchingTrackers.size(); i++) {
        if (metricsManagerTimeBase3->mAllAtomMatchingTrackers[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->mAllAtomMatchingTrackers.size(); i++) {
        if (metricsManagerTimeBase4->mAllAtomMatchingTrackers[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->mAllAtomMatchingTrackers.size(); i++) {
        if (metricsManagerTimeBase4->mAllAtomMatchingTrackers[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.
    const sp<UidMap> uidMap = new UidMap();
    const shared_ptr<StatsService> service =
            SharedRefBase::make<StatsService>(uidMap, /* queue */ 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->mAllAtomMatchingTrackers.size(), 4);
    EXPECT_EQ(metricsManager1->mAllAtomMatchingTrackers[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->mAllAtomMatchingTrackers[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->mAllAtomMatchingTrackers[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->mAllAtomMatchingTrackers[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->mAllAtomMatchingTrackers.size(), 4);
    EXPECT_EQ(metricsManager2->mAllAtomMatchingTrackers[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->mAllAtomMatchingTrackers[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->mAllAtomMatchingTrackers[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->mAllAtomMatchingTrackers[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);

    service->removeConfiguration(configId, uid);
    service->mProcessor->onDumpReport(cfgKey1, getElapsedRealtimeNs(),
                                      false /* include_current_bucket*/, true /* erase_data */,
                                      ADB_DUMP, NO_TIME_CONSTRAINTS, nullptr);
}

TEST(StatsLogProcessorTest, LogEventFilterOnSetPrintLogs) {
    sp<UidMap> m = new UidMap();
    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
    sp<AlarmMonitor> anomalyAlarmMonitor;
    sp<AlarmMonitor> periodicAlarmMonitor;

    std::shared_ptr<MockLogEventFilter> mockLogEventFilter = std::make_shared<MockLogEventFilter>();
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(StatsLogProcessor::getDefaultAtomIdSet(), _))
            .Times(1);
    StatsLogProcessor p(
            m, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, 0,
            [](const ConfigKey& key) { return true; },
            [](const int&, const vector<int64_t>&) { return true; },
            [](const ConfigKey&, const string&, const vector<int64_t>&) {}, mockLogEventFilter);

    Expectation filterSetFalse =
            EXPECT_CALL(*mockLogEventFilter, setFilteringEnabled(false)).Times(1);
    EXPECT_CALL(*mockLogEventFilter, setFilteringEnabled(true)).Times(1).After(filterSetFalse);

    p.setPrintLogs(true);
    p.setPrintLogs(false);
}

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 = makeMockUidMapForHosts({{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 = makeMockUidMapForHosts({{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, LogThreeIsolatedUids) {
    int hostUid = 20;
    int isolatedUid = 30;
    int hostUid2 = 200;
    int isolatedUid2 = 300;
    int hostUid3 = 2000;
    int isolatedUid3 = 3000;
    uint64_t eventTimeNs = 12355;
    int atomId = 89;
    int field1 = 90;
    int field2 = 28;
    sp<MockUidMap> mockUidMap = makeMockUidMapForHosts(
            {{hostUid, {isolatedUid}}, {hostUid2, {isolatedUid2}}, {hostUid3, {isolatedUid3}}});
    ConfigKey cfgKey;
    StatsdConfig config = MakeConfig(false);
    sp<StatsLogProcessor> processor =
            CreateStatsLogProcessor(1, 1, config, cfgKey, nullptr, 0, mockUidMap);

    shared_ptr<LogEvent> logEvent = makeExtraUidsLogEvent(atomId, eventTimeNs, isolatedUid, field1,
                                                          field2, {isolatedUid2, isolatedUid3});

    processor->OnLogEvent(logEvent.get());

    const vector<FieldValue>* actualFieldValues = &logEvent->getValues();
    ASSERT_EQ(5, 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);
    EXPECT_EQ(hostUid2, actualFieldValues->at(3).mValue.int_value);
    EXPECT_EQ(hostUid3, actualFieldValues->at(4).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 = makeMockUidMapForHosts({{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 = makeMockUidMapForHosts({{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 cases for repeated uid fields:
 * - empty field
 * - single host uid
 * - single isolated uid
 * - multiple host uids
 * - multiple isolated uids
 * - multiple host and isolated uids
 */
TEST(StatsLogProcessorTest_mapIsolatedUidToHostUid, LogRepeatedUidField) {
    int hostUid1 = 21;
    int hostUid2 = 22;
    int isolatedUid1 = 31;
    int isolatedUid2 = 32;
    uint64_t eventTimeNs = 12355;
    int atomId = 89;
    int field1 = 90;
    int field2 = 28;
    sp<MockUidMap> mockUidMap =
            makeMockUidMapForHosts({{hostUid1, {isolatedUid1}}, {hostUid2, {isolatedUid2}}});

    ConfigKey cfgKey;
    StatsdConfig config = MakeConfig(false);
    sp<StatsLogProcessor> processor =
            CreateStatsLogProcessor(1, 1, config, cfgKey, nullptr, 0, mockUidMap);

    // Empty repeated uid field.
    shared_ptr<LogEvent> logEvent = makeRepeatedUidLogEvent(atomId, eventTimeNs, {});
    processor->OnLogEvent(logEvent.get());

    const vector<FieldValue>* actualFieldValues = &logEvent->getValues();
    ASSERT_EQ(0, actualFieldValues->size());

    // Single host uid.
    logEvent = makeRepeatedUidLogEvent(atomId, eventTimeNs, {hostUid1});
    processor->OnLogEvent(logEvent.get());

    actualFieldValues = &logEvent->getValues();
    ASSERT_EQ(1, actualFieldValues->size());
    EXPECT_EQ(hostUid1, actualFieldValues->at(0).mValue.int_value);

    // Single isolated uid.
    logEvent = makeRepeatedUidLogEvent(atomId, eventTimeNs, {isolatedUid1});
    processor->OnLogEvent(logEvent.get());

    actualFieldValues = &logEvent->getValues();
    ASSERT_EQ(1, actualFieldValues->size());
    EXPECT_EQ(hostUid1, actualFieldValues->at(0).mValue.int_value);

    // Multiple host uids.
    logEvent = makeRepeatedUidLogEvent(atomId, eventTimeNs, {hostUid1, hostUid2});
    processor->OnLogEvent(logEvent.get());

    actualFieldValues = &logEvent->getValues();
    ASSERT_EQ(2, actualFieldValues->size());
    EXPECT_EQ(hostUid1, actualFieldValues->at(0).mValue.int_value);
    EXPECT_EQ(hostUid2, actualFieldValues->at(1).mValue.int_value);

    // Multiple isolated uids.
    logEvent = makeRepeatedUidLogEvent(atomId, eventTimeNs, {isolatedUid1, isolatedUid2});
    processor->OnLogEvent(logEvent.get());

    actualFieldValues = &logEvent->getValues();
    ASSERT_EQ(2, actualFieldValues->size());
    EXPECT_EQ(hostUid1, actualFieldValues->at(0).mValue.int_value);
    EXPECT_EQ(hostUid2, actualFieldValues->at(1).mValue.int_value);

    // Multiple host and isolated uids.
    logEvent = makeRepeatedUidLogEvent(atomId, eventTimeNs,
                                       {isolatedUid1, hostUid2, isolatedUid2, hostUid1});
    processor->OnLogEvent(logEvent.get());

    actualFieldValues = &logEvent->getValues();
    ASSERT_EQ(4, actualFieldValues->size());
    EXPECT_EQ(hostUid1, actualFieldValues->at(0).mValue.int_value);
    EXPECT_EQ(hostUid2, actualFieldValues->at(1).mValue.int_value);
    EXPECT_EQ(hostUid2, actualFieldValues->at(2).mValue.int_value);
    EXPECT_EQ(hostUid1, actualFieldValues->at(3).mValue.int_value);
}

TEST(StatsLogProcessorTest, TestDumpReportWithoutErasingDataDoesNotUpdateTimestamp) {
    int hostUid = 20;
    int isolatedUid = 30;
    sp<MockUidMap> mockUidMap = makeMockUidMapForHosts({{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);
}

class StatsLogProcessorTestRestricted : public Test {
protected:
    const ConfigKey mConfigKey = ConfigKey(1, 12345);
    void SetUp() override {
        if (!IsAtLeastU()) {
            GTEST_SKIP();
        }
    }
    void TearDown() override {
        if (!IsAtLeastU()) {
            GTEST_SKIP();
        }
        FlagProvider::getInstance().resetOverrides();
        StorageManager::deleteAllFiles(STATS_DATA_DIR);
        dbutils::deleteDb(mConfigKey);
    }
};

TEST_F(StatsLogProcessorTestRestricted, TestInconsistentRestrictedMetricsConfigUpdate) {
    ConfigKey key(3, 4);
    StatsdConfig config = makeRestrictedConfig(true);
    config.set_restricted_metrics_delegate_package_name("rm_package");

    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("")},
                 /* certificateHash */ {{}, {}});
    sp<AlarmMonitor> anomalyAlarmMonitor;
    sp<AlarmMonitor> subscriberAlarmMonitor;
    std::shared_ptr<MockLogEventFilter> mockLogEventFilter = std::make_shared<MockLogEventFilter>();
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(StatsLogProcessor::getDefaultAtomIdSet(), _))
            .Times(1);
    StatsLogProcessor p(
            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
            [](const ConfigKey& key) { return true; },
            [](const int&, const vector<int64_t>&) { return true; },
            [](const ConfigKey&, const string&, const vector<int64_t>&) {}, mockLogEventFilter);

    // new newConfig will be the same as config
    const LogEventFilter::AtomIdSet atomIdsList = CreateAtomIdSetFromConfig(config);
    EXPECT_CALL(*mockLogEventFilter, setAtomIds(atomIdsList, &p)).Times(2);

    p.OnConfigUpdated(0, key, config);

    EXPECT_EQ(1, p.mMetricsManagers.size());
    EXPECT_NE(p.mMetricsManagers.find(key), p.mMetricsManagers.end());
    sp<MetricsManager> oldMetricsManager = p.mMetricsManagers.find(key)->second;

    StatsdConfig newConfig = makeRestrictedConfig(true);
    newConfig.clear_restricted_metrics_delegate_package_name();
    p.OnConfigUpdated(/*timestampNs=*/0, key, newConfig);

    ASSERT_NE(p.mMetricsManagers.find(key)->second, oldMetricsManager);
}

TEST_F(StatsLogProcessorTestRestricted, TestRestrictedLogEventNotPassed) {
    sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
            /*timeBaseNs=*/1, /*currentTimeNs=*/1, StatsdConfig(), mConfigKey);
    ConfigKey key(3, 4);
    sp<MockMetricsManager> metricsManager = new MockMetricsManager(mConfigKey);
    EXPECT_CALL(*metricsManager, onLogEvent).Times(0);

    processor->mMetricsManagers[mConfigKey] = metricsManager;
    EXPECT_FALSE(processor->mMetricsManagers[mConfigKey]->hasRestrictedMetricsDelegate());

    unique_ptr<LogEvent> event = CreateRestrictedLogEvent(123);
    EXPECT_TRUE(event->isValid());
    EXPECT_TRUE(event->isRestricted());
    processor->OnLogEvent(event.get());
}

TEST_F(StatsLogProcessorTestRestricted, TestRestrictedLogEventPassed) {
    sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
            /*timeBaseNs=*/1, /*currentTimeNs=*/1, StatsdConfig(), mConfigKey);
    sp<MockRestrictedMetricsManager> metricsManager = new MockRestrictedMetricsManager(mConfigKey);
    EXPECT_CALL(*metricsManager, onLogEvent).Times(1);

    processor->mMetricsManagers[mConfigKey] = metricsManager;
    EXPECT_TRUE(processor->mMetricsManagers[mConfigKey]->hasRestrictedMetricsDelegate());

    unique_ptr<LogEvent> event = CreateRestrictedLogEvent(123);
    EXPECT_TRUE(event->isValid());
    EXPECT_TRUE(event->isRestricted());
    processor->OnLogEvent(event.get());
}

TEST_F(StatsLogProcessorTestRestricted, RestrictedMetricsManagerOnDumpReportNotCalled) {
    sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
            /*timeBaseNs=*/1, /*currentTimeNs=*/1, makeRestrictedConfig(/*includeMetric=*/true),
            mConfigKey);
    sp<MockRestrictedMetricsManager> metricsManager = new MockRestrictedMetricsManager(mConfigKey);
    EXPECT_CALL(*metricsManager, onDumpReport).Times(0);

    processor->mMetricsManagers[mConfigKey] = metricsManager;
    EXPECT_TRUE(processor->mMetricsManagers[mConfigKey]->hasRestrictedMetricsDelegate());

    vector<uint8_t> buffer;
    processor->onConfigMetricsReportLocked(mConfigKey, /*dumpTimeStampNs=*/1, /*wallClockNs=*/0,
                                           /*include_current_partial_bucket=*/true,
                                           /*erase_data=*/true, GET_DATA_CALLED, FAST,
                                           /*dataSavedToDisk=*/true, &buffer);
}

TEST_F(StatsLogProcessorTestRestricted, RestrictedMetricFlushIfReachMemoryLimit) {
    sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
            /*timeBaseNs=*/1, /*currentTimeNs=*/1, makeRestrictedConfig(/*includeMetric=*/true),
            mConfigKey);
    sp<MockRestrictedMetricsManager> metricsManager = new MockRestrictedMetricsManager(mConfigKey);
    EXPECT_CALL(*metricsManager, flushRestrictedData).Times(1);
    EXPECT_CALL(*metricsManager, byteSize)
            .Times(1)
            .WillOnce(Return(StatsdStats::kBytesPerRestrictedConfigTriggerFlush + 1));

    processor->mMetricsManagers[mConfigKey] = metricsManager;
    EXPECT_TRUE(processor->mMetricsManagers[mConfigKey]->hasRestrictedMetricsDelegate());

    processor->flushIfNecessaryLocked(mConfigKey, *metricsManager);
}

TEST_F(StatsLogProcessorTestRestricted, RestrictedMetricNotFlushIfNotReachMemoryLimit) {
    sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
            /*timeBaseNs=*/1, /*currentTimeNs=*/1, makeRestrictedConfig(/*includeMetric=*/true),
            mConfigKey);
    sp<MockRestrictedMetricsManager> metricsManager = new MockRestrictedMetricsManager(mConfigKey);
    EXPECT_CALL(*metricsManager, flushRestrictedData).Times(0);
    EXPECT_CALL(*metricsManager, byteSize)
            .Times(1)
            .WillOnce(Return(StatsdStats::kBytesPerRestrictedConfigTriggerFlush - 1));

    processor->mMetricsManagers[mConfigKey] = metricsManager;
    EXPECT_TRUE(processor->mMetricsManagers[mConfigKey]->hasRestrictedMetricsDelegate());

    processor->flushIfNecessaryLocked(mConfigKey, *metricsManager);
}

TEST_F(StatsLogProcessorTestRestricted, NonRestrictedMetricsManagerOnDumpReportCalled) {
    sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
            /*timeBaseNs=*/1, /*currentTimeNs=*/1, MakeConfig(/*includeMetric=*/true), mConfigKey);
    sp<MockMetricsManager> metricsManager = new MockMetricsManager(mConfigKey);
    EXPECT_CALL(*metricsManager, onDumpReport).Times(1);

    processor->mMetricsManagers[mConfigKey] = metricsManager;
    EXPECT_FALSE(processor->mMetricsManagers[mConfigKey]->hasRestrictedMetricsDelegate());

    vector<uint8_t> buffer;
    processor->onConfigMetricsReportLocked(mConfigKey, /*dumpTimeStampNs=*/1, /*wallClockNs=*/0,
                                           /*include_current_partial_bucket=*/true,
                                           /*erase_data=*/true, GET_DATA_CALLED, FAST,
                                           /*dataSavedToDisk=*/true, &buffer);
}

TEST_F(StatsLogProcessorTestRestricted, RestrictedMetricOnDumpReportEmpty) {
    sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
            /*timeBaseNs=*/1, /*currentTimeNs=*/1, makeRestrictedConfig(/*includeMetric=*/true),
            mConfigKey);
    ProtoOutputStream proto;
    processor->onDumpReport(mConfigKey, /*dumpTimeStampNs=*/1, /*wallClockNs=*/2,
                            /*include_current_partial_bucket=*/true, /*erase_data=*/true,
                            DEVICE_SHUTDOWN, FAST, &proto);
    ASSERT_EQ(proto.size(), 0);
}

TEST_F(StatsLogProcessorTestRestricted, NonRestrictedMetricOnDumpReportNotEmpty) {
    sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
            /*timeBaseNs=*/1, /*currentTimeNs=*/1, MakeConfig(/*includeMetric=*/true), mConfigKey);

    ProtoOutputStream proto;
    processor->onDumpReport(mConfigKey, /*dumpTimeStampNs=*/1, /*wallClockNs=*/2,
                            /*include_current_partial_bucket=*/true, /*erase_data=*/true,
                            DEVICE_SHUTDOWN, FAST, &proto);
    ASSERT_NE(proto.size(), 0);
}

TEST_F(StatsLogProcessorTestRestricted, RestrictedMetricNotWriteToDisk) {
    sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
            /*timeBaseNs=*/1, /*currentTimeNs=*/1, makeRestrictedConfig(/*includeMetric=*/true),
            mConfigKey);

    processor->WriteDataToDiskLocked(mConfigKey, /*timestampNs=*/0, /*wallClockNs=*/0,
                                     CONFIG_UPDATED, FAST);

    ASSERT_FALSE(StorageManager::hasConfigMetricsReport(mConfigKey));
}

TEST_F(StatsLogProcessorTestRestricted, NonRestrictedMetricWriteToDisk) {
    sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
            /*timeBaseNs=*/1, /*currentTimeNs=*/1, MakeConfig(true), mConfigKey);

    processor->WriteDataToDiskLocked(mConfigKey, /*timestampNs=*/0, /*wallClockNs=*/0,
                                     CONFIG_UPDATED, FAST);

    ASSERT_TRUE(StorageManager::hasConfigMetricsReport(mConfigKey));
}

#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif

}  // namespace statsd
}  // namespace os
}  // namespace android