Save EventActivations to disk

Also:
- rename time_to_live to ttl
- rename activation_ns to start_ns

Bug: 129719662
Fixes: 129719662
Test: statsd_test

Change-Id: I4069f85d0c1f5bd0885a9588d8a9157d94b2c587
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index a9f5208e..ec02b12 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -68,12 +68,8 @@
 const int FIELD_ID_DUMP_REPORT_REASON = 8;
 const int FIELD_ID_STRINGS = 9;
 
-const int FIELD_ID_ACTIVE_CONFIG_LIST = 1;
-const int FIELD_ID_CONFIG_ID = 1;
-const int FIELD_ID_CONFIG_UID = 2;
-const int FIELD_ID_ACTIVE_METRIC = 3;
-const int FIELD_ID_METRIC_ID = 1;
-const int FIELD_ID_TIME_TO_LIVE_NANOS = 2;
+// for ActiveConfigList
+const int FIELD_ID_ACTIVE_CONFIG_LIST_CONFIG = 1;
 
 #define NS_PER_HOUR 3600 * NS_PER_SEC
 
@@ -523,7 +519,7 @@
     std::lock_guard<std::mutex> lock(mMetricsMutex);
     auto it = mMetricsManagers.find(key);
     if (it != mMetricsManagers.end()) {
-        WriteDataToDiskLocked(key, getElapsedRealtimeNs(), CONFIG_REMOVED, 
+        WriteDataToDiskLocked(key, getElapsedRealtimeNs(), CONFIG_REMOVED,
                               NO_TIME_CONSTRAINTS);
         mMetricsManagers.erase(it);
         mUidMap->OnConfigRemoved(key);
@@ -613,7 +609,7 @@
     mOnDiskDataConfigs.insert(key);
 }
 
-void StatsLogProcessor::WriteMetricsActivationToDisk(int64_t currentTimeNs) {
+void StatsLogProcessor::SaveActiveConfigsToDisk(int64_t currentTimeNs) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
 
     const int64_t timeNs = getElapsedRealtimeNs();
@@ -629,28 +625,12 @@
     mLastActiveMetricsWriteNs = timeNs;
 
     ProtoOutputStream proto;
-
     for (const auto& pair : mMetricsManagers) {
-        uint64_t activeConfigListToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                                     FIELD_ID_ACTIVE_CONFIG_LIST);
-        proto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_ID, (long long)pair.first.GetId());
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_UID, pair.first.GetUid());
-
-        vector<MetricProducer*> activeMetrics;
-        pair.second->prepForShutDown(currentTimeNs);
-        pair.second->getActiveMetrics(activeMetrics);
-        for (MetricProducer* metric : activeMetrics) {
-            if (metric->isActive()) {
-                uint64_t metricToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                                   FIELD_ID_ACTIVE_METRIC);
-                proto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_ID,
-                            (long long)metric->getMetricId());
-                proto.write(FIELD_TYPE_INT64 | FIELD_ID_TIME_TO_LIVE_NANOS,
-                            (long long)metric->getRemainingTtlNs(currentTimeNs));
-                proto.end(metricToken);
-            }
-        }
-        proto.end(activeConfigListToken);
+        const sp<MetricsManager>& metricsManager = pair.second;
+        uint64_t configToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+                                                     FIELD_ID_ACTIVE_CONFIG_LIST_CONFIG);
+        metricsManager->writeActiveConfigToProtoOutputStream(currentTimeNs, &proto);
+        proto.end(configToken);
     }
 
     string file_name = StringPrintf("%s/active_metrics", STATS_ACTIVE_METRIC_DIR);
@@ -664,30 +644,45 @@
     proto.flush(fd.get());
 }
 
-void StatsLogProcessor::LoadMetricsActivationFromDisk() {
+void StatsLogProcessor::LoadActiveConfigsFromDisk() {
+    std::lock_guard<std::mutex> lock(mMetricsMutex);
+
     string file_name = StringPrintf("%s/active_metrics", STATS_ACTIVE_METRIC_DIR);
     int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
-    if (fd != -1) {
-        string content;
-        if (android::base::ReadFdToString(fd, &content)) {
-            ActiveConfigList activeConfigList;
-            if (activeConfigList.ParseFromString(content)) {
-                for (int i = 0; i < activeConfigList.active_config_size(); i++) {
-                    const auto& config = activeConfigList.active_config(i);
-                    ConfigKey key(config.uid(), config.config_id());
-                    auto it = mMetricsManagers.find(key);
-                    if (it == mMetricsManagers.end()) {
-                        ALOGE("No config found for config %s", key.ToString().c_str());
-                        continue;
-                    }
-                    VLOG("Setting active config %s", key.ToString().c_str());
-                    it->second->setActiveMetrics(config, mTimeBaseNs);
-                }
-            }
-            VLOG("Successfully loaded %d active configs.", activeConfigList.active_config_size());
-        }
-        close(fd);
+    if (-1 == fd) {
+        VLOG("Attempt to read %s but failed", file_name.c_str());
+        StorageManager::deleteFile(file_name.c_str());
+        return;
     }
+    string content;
+    if (!android::base::ReadFdToString(fd, &content)) {
+        ALOGE("Attempt to read %s but failed", file_name.c_str());
+        close(fd);
+        StorageManager::deleteFile(file_name.c_str());
+        return;
+    }
+
+    close(fd);
+
+    ActiveConfigList activeConfigList;
+    if (!activeConfigList.ParseFromString(content)) {
+        ALOGE("Attempt to read %s but failed; failed to load active configs", file_name.c_str());
+        StorageManager::deleteFile(file_name.c_str());
+        return;
+    }
+    for (int i = 0; i < activeConfigList.config_size(); i++) {
+        const auto& config = activeConfigList.config(i);
+        ConfigKey key(config.uid(), config.id());
+        auto it = mMetricsManagers.find(key);
+        if (it == mMetricsManagers.end()) {
+            ALOGE("No config found for config %s", key.ToString().c_str());
+            continue;
+        }
+        VLOG("Setting active config %s", key.ToString().c_str());
+        it->second->loadActiveConfig(config, mTimeBaseNs);
+    }
+    VLOG("Successfully loaded %d active configs.", activeConfigList.config_size());
+
     StorageManager::deleteFile(file_name.c_str());
 }
 
@@ -709,7 +704,7 @@
     }
 }
 
-void StatsLogProcessor::WriteDataToDisk(const DumpReportReason dumpReportReason, 
+void StatsLogProcessor::WriteDataToDisk(const DumpReportReason dumpReportReason,
                                         const DumpLatency dumpLatency) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
     WriteDataToDiskLocked(dumpReportReason, dumpLatency);
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 6178a4b..2c8382d 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -89,11 +89,11 @@
     void WriteDataToDisk(const DumpReportReason dumpReportReason,
                          const DumpLatency dumpLatency);
 
-    /* Persist metric activation status onto disk. */
-    void WriteMetricsActivationToDisk(int64_t currentTimeNs);
+    /* Persist configs containing metrics with active activations to disk. */
+    void SaveActiveConfigsToDisk(int64_t currentTimeNs);
 
-    /* Load metric activation status from disk. */
-    void LoadMetricsActivationFromDisk();
+    /* Load configs containing metrics with active activations from disk. */
+    void LoadActiveConfigsFromDisk();
 
     // Reset all configs.
     void resetConfigs();
@@ -221,6 +221,7 @@
     FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
     FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
     FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
+    FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations);
 
     FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1);
     FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 4c97c34..662be05 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -986,7 +986,7 @@
     ENFORCE_UID(AID_SYSTEM);
     VLOG("StatsService::informDeviceShutdown");
     mProcessor->WriteDataToDisk(DEVICE_SHUTDOWN, FAST);
-    mProcessor->WriteMetricsActivationToDisk(getElapsedRealtimeNs());
+    mProcessor->SaveActiveConfigsToDisk(getElapsedRealtimeNs());
     return Status::ok();
 }
 
@@ -1021,14 +1021,14 @@
 
 void StatsService::Startup() {
     mConfigManager->Startup();
-    mProcessor->LoadMetricsActivationFromDisk();
+    mProcessor->LoadActiveConfigsFromDisk();
 }
 
 void StatsService::Terminate() {
     ALOGI("StatsService::Terminating");
     if (mProcessor != nullptr) {
         mProcessor->WriteDataToDisk(TERMINATION_SIGNAL_RECEIVED, FAST);
-        mProcessor->WriteMetricsActivationToDisk(getElapsedRealtimeNs());
+        mProcessor->SaveActiveConfigsToDisk(getElapsedRealtimeNs());
     }
 }
 
diff --git a/cmds/statsd/src/active_config_list.proto b/cmds/statsd/src/active_config_list.proto
index 0e9ee03..5ce396d 100644
--- a/cmds/statsd/src/active_config_list.proto
+++ b/cmds/statsd/src/active_config_list.proto
@@ -21,23 +21,26 @@
 option java_multiple_files = true;
 option java_outer_classname = "ActiveConfigProto";
 
+message ActiveEventActivation {
+    optional int32 atom_matcher_index = 1;
+
+    // TIme left in activation. When this proto is loaded after device boot,
+    // the activation should be set to active for this duration.
+    optional int64 remaining_ttl_nanos = 2;
+}
+
 message ActiveMetric {
-    // metric id
-    optional int64 metric_id = 1;
-    // Remaining time to live in nano seconds. -1 for infinity.
-    optional int64 time_to_live_nanos = 2;
+    optional int64 id = 1;
+    repeated ActiveEventActivation activation = 2;
 }
 
 message ActiveConfig {
-    // config id
-    optional int64 config_id = 1;
-    // config uid
+    optional int64 id = 1;
     optional int32 uid = 2;
-    // metrics
-    repeated ActiveMetric active_metric = 3;
+    repeated ActiveMetric metric = 3;
 }
 
 // all configs and their metrics on device.
 message ActiveConfigList {
-    repeated ActiveConfig active_config = 1;
-}
\ No newline at end of file
+    repeated ActiveConfig config = 1;
+}
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index e22b853..2e682de 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -18,12 +18,26 @@
 #include "Log.h"
 #include "MetricProducer.h"
 
+using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_MESSAGE;
+using android::util::ProtoOutputStream;
+
 namespace android {
 namespace os {
 namespace statsd {
 
 using std::map;
 
+// for ActiveMetric
+const int FIELD_ID_ACTIVE_METRIC_ID = 1;
+const int FIELD_ID_ACTIVE_METRIC_ACTIVATION = 2;
+
+// for ActiveEventActivation
+const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX = 1;
+const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS = 2;
+
 void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) {
     if (!mIsActive) {
         return;
@@ -74,7 +88,7 @@
     bool isActive = mEventActivationMap.empty();
     for (auto& it : mEventActivationMap) {
         if (it.second->state == ActivationState::kActive &&
-            elapsedTimestampNs > it.second->ttl_ns + it.second->activation_ns) {
+            elapsedTimestampNs > it.second->ttl_ns + it.second->start_ns) {
             it.second->state = ActivationState::kNotActive;
         }
         if (it.second->state == ActivationState::kActive) {
@@ -122,7 +136,7 @@
         it->second->state = ActivationState::kActiveOnBoot;
         return;
     }
-    it->second->activation_ns = elapsedTimestampNs;
+    it->second->start_ns = elapsedTimestampNs;
     it->second->state = ActivationState::kActive;
     mIsActive = true;
 }
@@ -135,46 +149,55 @@
     it->second->state = ActivationState::kNotActive;
 }
 
-void MetricProducer::setActiveLocked(int64_t currentTimeNs, int64_t remainingTtlNs) {
+void MetricProducer::loadActiveMetricLocked(const ActiveMetric& activeMetric,
+                                            int64_t currentTimeNs) {
     if (mEventActivationMap.size() == 0) {
         return;
     }
-    for (auto& pair : mEventActivationMap) {
-        auto& activation = pair.second;
-        if (activation->ttl_ns >= remainingTtlNs) {
-            activation->activation_ns = currentTimeNs + remainingTtlNs - activation->ttl_ns;
-            activation->state = kActive;
-            mIsActive = true;
-            VLOG("setting new activation->time to %lld, %lld, %lld",
-                 (long long)activation->activation_ns, (long long)currentTimeNs,
-                 (long long)remainingTtlNs);
-            return;
+    for (int i = 0; i < activeMetric.activation_size(); i++) {
+        const auto& activeEventActivation = activeMetric.activation(i);
+        auto it = mEventActivationMap.find(activeEventActivation.atom_matcher_index());
+        if (it == mEventActivationMap.end()) {
+            ALOGE("Saved event activation not found");
+            continue;
         }
+        auto& activation = it->second;
+        // We don't want to change the ttl for future activations, so we set the start_ns
+        // such that start_ns + ttl_ns == currentTimeNs + remaining_ttl_nanos
+        activation->start_ns =
+            currentTimeNs + activeEventActivation.remaining_ttl_nanos() - activation->ttl_ns;
+        activation->state = ActivationState::kActive;
+        mIsActive = true;
     }
-    ALOGE("Required ttl is longer than all possible activations.");
 }
 
-int64_t MetricProducer::getRemainingTtlNsLocked(int64_t currentTimeNs) const {
-    int64_t maxTtl = 0;
-    for (const auto& activation : mEventActivationMap) {
-        if (activation.second->state == kActive) {
-            maxTtl = std::max(maxTtl, activation.second->ttl_ns + activation.second->activation_ns -
-                                              currentTimeNs);
-        }
-    }
-    return maxTtl;
-}
+void MetricProducer::writeActiveMetricToProtoOutputStream(
+        int64_t currentTimeNs, ProtoOutputStream* proto) {
+    proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_METRIC_ID, (long long)mMetricId);
+    for (auto& it : mEventActivationMap) {
+        const int atom_matcher_index = it.first;
+        const std::shared_ptr<Activation>& activation = it.second;
 
-void MetricProducer::prepActiveForBootIfNecessaryLocked(int64_t currentTimeNs) {
-    if (mActivationType != MetricActivation::ACTIVATE_ON_BOOT) {
-        return;
-    }
-    for (auto& activation : mEventActivationMap) {
-        if (activation.second->state == kActiveOnBoot) {
-            activation.second->state = kActive;
-            activation.second->activation_ns = currentTimeNs;
-            mIsActive = true;
+        if (ActivationState::kNotActive == activation->state ||
+                (ActivationState::kActive == activation->state &&
+                 activation->start_ns + activation->ttl_ns < currentTimeNs)) {
+            continue;
         }
+
+        const uint64_t activationToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+                FIELD_ID_ACTIVE_METRIC_ACTIVATION);
+        proto->write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX,
+                atom_matcher_index);
+        if (ActivationState::kActive == activation->state) {
+            const int64_t remainingTtlNs =
+                    activation->start_ns + activation->ttl_ns - currentTimeNs;
+            proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
+                    (long long)remainingTtlNs);
+        } else if (ActivationState::kActiveOnBoot == activation->state) {
+            proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
+                    (long long)activation->ttl_ns);
+        }
+        proto->end(activationToken);
     }
 }
 
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 750566d..aa04938 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -19,6 +19,7 @@
 
 #include <shared_mutex>
 
+#include <frameworks/base/cmds/statsd/src/active_config_list.pb.h>
 #include "HashableDimensionKey.h"
 #include "anomaly/AnomalyTracker.h"
 #include "condition/ConditionWizard.h"
@@ -198,15 +199,9 @@
         return mMetricId;
     }
 
-    int64_t getRemainingTtlNs(int64_t currentTimeNs) const {
+    void loadActiveMetric(const ActiveMetric& activeMetric, int64_t currentTimeNs) {
         std::lock_guard<std::mutex> lock(mMutex);
-        return getRemainingTtlNsLocked(currentTimeNs);
-    }
-
-    // Set metric to active for ttlNs.
-    void setActive(int64_t currentTimeNs, int64_t remainingTtlNs) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        setActiveLocked(currentTimeNs, remainingTtlNs);
+        loadActiveMetricLocked(activeMetric, currentTimeNs);
     }
 
     // Let MetricProducer drop in-memory data to save memory.
@@ -238,11 +233,6 @@
         return isActiveLocked();
     }
 
-    void prepActiveForBootIfNecessary(int64_t currentTimeNs) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        prepActiveForBootIfNecessaryLocked(currentTimeNs);
-    }
-
     void addActivation(int activationTrackerIndex, int64_t ttl_seconds,
                        int deactivationTrackerIndex = -1);
 
@@ -257,6 +247,8 @@
 
     void flushIfExpire(int64_t elapsedTimestampNs);
 
+    void writeActiveMetricToProtoOutputStream(
+            int64_t currentTimeNs, ProtoOutputStream* proto);
 protected:
     virtual void onConditionChangedLocked(const bool condition, const int64_t eventTime) = 0;
     virtual void onSlicedConditionMayChangeLocked(bool overallCondition,
@@ -282,9 +274,7 @@
 
     void prepActiveForBootIfNecessaryLocked(int64_t currentTimeNs);
 
-    int64_t getRemainingTtlNsLocked(int64_t currentTimeNs) const;
-
-    void setActiveLocked(int64_t currentTimeNs, int64_t remainingTtlNs);
+    void loadActiveMetricLocked(const ActiveMetric& activeMetric, int64_t currentTimeNs);
 
     virtual void prepareFistBucketLocked() {};
     /**
@@ -396,10 +386,10 @@
     mutable std::mutex mMutex;
 
     struct Activation {
-        Activation() : ttl_ns(0), activation_ns(0), state(ActivationState::kNotActive)  {}
+        Activation() : ttl_ns(0), start_ns(0), state(ActivationState::kNotActive)  {}
 
         int64_t ttl_ns;
-        int64_t activation_ns;
+        int64_t start_ns;
         ActivationState state;
     };
     // When the metric producer has multiple activations, these activations are ORed to determine
@@ -420,6 +410,7 @@
 
     FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
     FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
+    FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 6a55289..947f377 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -54,6 +54,11 @@
 const int FIELD_ID_ANNOTATIONS_INT64 = 1;
 const int FIELD_ID_ANNOTATIONS_INT32 = 2;
 
+// for ActiveConfig
+const int FIELD_ID_ACTIVE_CONFIG_ID = 1;
+const int FIELD_ID_ACTIVE_CONFIG_UID = 2;
+const int FIELD_ID_ACTIVE_CONFIG_METRIC = 3;
+
 MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
                                const int64_t timeBaseNs, const int64_t currentTimeNs,
                                const sp<UidMap>& uidMap,
@@ -503,25 +508,41 @@
     return totalSize;
 }
 
-void MetricsManager::setActiveMetrics(ActiveConfig config, int64_t currentTimeNs) {
-    if (config.active_metric_size() == 0) {
+void MetricsManager::loadActiveConfig(const ActiveConfig& config, int64_t currentTimeNs) {
+    if (config.metric_size() == 0) {
         ALOGW("No active metric for config %s", mConfigKey.ToString().c_str());
         return;
     }
 
-    for (int i = 0; i < config.active_metric_size(); i++) {
-        for (int metric : mMetricIndexesWithActivation) {
-            if (mAllMetricProducers[metric]->getMetricId() == config.active_metric(i).metric_id()) {
-                VLOG("Setting active metric: %lld",
-                     (long long)mAllMetricProducers[metric]->getMetricId());
-                mAllMetricProducers[metric]->setActive(
-                        currentTimeNs, config.active_metric(i).time_to_live_nanos());
-                mIsActive = true;
+    for (int i = 0; i < config.metric_size(); i++) {
+        const auto& activeMetric = config.metric(i);
+        for (int metricIndex : mMetricIndexesWithActivation) {
+            const auto& metric = mAllMetricProducers[metricIndex];
+            if (metric->getMetricId() == activeMetric.id()) {
+                VLOG("Setting active metric: %lld", (long long)metric->getMetricId());
+                metric->loadActiveMetric(activeMetric, currentTimeNs);
+                mIsActive |= metric->isActive();
             }
         }
     }
 }
 
+void MetricsManager::writeActiveConfigToProtoOutputStream(
+        int64_t currentTimeNs, ProtoOutputStream* proto) {
+    proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_CONFIG_ID, (long long)mConfigKey.GetId());
+    proto->write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVE_CONFIG_UID, mConfigKey.GetUid());
+    for (int metricIndex : mMetricIndexesWithActivation) {
+        const auto& metric = mAllMetricProducers[metricIndex];
+        const uint64_t metricToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+                FIELD_ID_ACTIVE_CONFIG_METRIC);
+        metric->writeActiveMetricToProtoOutputStream(currentTimeNs, proto);
+        proto->end(metricToken);
+    }
+}
+
+
+
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index d05bb8b..e1a8175 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -16,7 +16,6 @@
 
 #pragma once
 
-#include <frameworks/base/cmds/statsd/src/active_config_list.pb.h>
 #include "anomaly/AlarmMonitor.h"
 #include "anomaly/AlarmTracker.h"
 #include "anomaly/AnomalyTracker.h"
@@ -139,21 +138,10 @@
         return mIsActive;
     }
 
-    inline void getActiveMetrics(std::vector<MetricProducer*>& metrics) const {
-        for (const auto& metric : mAllMetricProducers) {
-            if (metric->isActive()) {
-                metrics.push_back(metric.get());
-            }
-        }
-    }
+    void loadActiveConfig(const ActiveConfig& config, int64_t currentTimeNs);
 
-    inline void prepForShutDown(int64_t currentTimeNs) {
-        for (const auto& metric : mAllMetricProducers) {
-            metric->prepActiveForBootIfNecessary(currentTimeNs);
-        }
-    }
-
-    void setActiveMetrics(ActiveConfig config, int64_t currentTimeNs);
+    void writeActiveConfigToProtoOutputStream(
+            int64_t currentTimeNs, ProtoOutputStream* proto);
 
 private:
     // For test only.
@@ -299,6 +287,7 @@
 
     FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
     FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
+    FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations);
 };
 
 }  // namespace statsd