More complete implementation for condition and log matchers in statsd.

+ also synced proto from google3 to fix the LogEntryMatcher proto

+ MetricsManager represents StatsdConfig, it's responsible for initializing and managing all
LogEntryMatcher, Condition, and Metrics. Start review from here.

+ Added more complete StatsdConfig initialization, including building the map for:
    LogEntryMatcher -> Metrics
    LogEntryMatcher -> Condition
    Condition       -> Metrics.

    All the maps use index(int). The extra amount of memory for storing mappings help us
    quickly process log events.

  The StatsdConfig initialization process detects malformed config
  - Circle dependency
  - Missing definition
  etc.

 And once we detect ANY error, statsd will reject the config. And the resources related to this
 config will be released.

Test: Added unit tests
Change-Id: I2c4aefdbf3e2aa1701eacbb2fb5e653819ec1fbb
diff --git a/cmds/statsd/src/metrics/ConditionTracker.cpp b/cmds/statsd/src/metrics/ConditionTracker.cpp
deleted file mode 100644
index 684ffdb..0000000
--- a/cmds/statsd/src/metrics/ConditionTracker.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "ConditionTracker"
-#define DEBUG true  // STOPSHIP if true
-#define VLOG(...) \
-    if (DEBUG) ALOGD(__VA_ARGS__);
-
-#include "ConditionTracker.h"
-#include <cutils/log.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-ConditionTracker::ConditionTracker() : mIsConditionMet(true) {
-    VLOG("ConditionTracker()");
-}
-
-ConditionTracker::ConditionTracker(const Condition& condition)
-    : mCondition(condition), mIsConditionMet(true) {
-    VLOG("ConditionTracker()");
-}
-
-ConditionTracker::~ConditionTracker() {
-    VLOG("~ConditionTracker()");
-}
-
-void ConditionTracker::evaluateCondition(const LogEventWrapper& event) {
-    // modify condition.
-    VLOG("evaluateCondition");
-}
-
-bool ConditionTracker::isConditionMet() const {
-    VLOG("isConditionMet() %d", mIsConditionMet);
-    return mIsConditionMet;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/metrics/ConditionTracker.h b/cmds/statsd/src/metrics/ConditionTracker.h
deleted file mode 100644
index b94d5ab..0000000
--- a/cmds/statsd/src/metrics/ConditionTracker.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef CONDITION_TRACKER_H
-#define CONDITION_TRACKER_H
-
-#include <utils/RefBase.h>
-#include "../matchers/LogEntryMatcherManager.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class ConditionTracker : public RefBase {
-public:
-    ConditionTracker();
-
-    ConditionTracker(const Condition& condition);
-
-    ~ConditionTracker();
-
-    void evaluateCondition(const LogEventWrapper& event);
-
-    bool isConditionMet() const;
-
-private:
-    // this is the definition of the Condition.
-    Condition mCondition;
-
-    bool mIsConditionMet;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // CONDITION_TRACKER_H
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 635777f..e98999e 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -21,7 +21,6 @@
 
 #include "CountMetricProducer.h"
 #include "CountAnomalyTracker.h"
-#include "parse_util.h"
 
 #include <cutils/log.h>
 #include <limits.h>
@@ -33,15 +32,14 @@
 namespace os {
 namespace statsd {
 
-CountMetricProducer::CountMetricProducer(const CountMetric& metric,
-                                         const sp<ConditionTracker> condition)
+CountMetricProducer::CountMetricProducer(const CountMetric& metric, const bool hasCondition)
     : mMetric(metric),
-      mConditionTracker(condition),
-      mStartTime(std::time(nullptr)),
+      mStartTime(time(nullptr)),
       mCounter(0),
       mCurrentBucketStartTime(mStartTime),
       // TODO: read mAnomalyTracker parameters from config file.
-      mAnomalyTracker(6, 10) {
+      mAnomalyTracker(6, 10),
+      mCondition(hasCondition ? ConditionState::kUnknown : ConditionState::kTrue) {
     // TODO: evaluate initial conditions. and set mConditionMet.
     if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
         mBucketSize_sec = metric.bucket().bucket_size_millis() / 1000;
@@ -52,10 +50,6 @@
     VLOG("created. bucket size %lu start_time: %lu", mBucketSize_sec, mStartTime);
 }
 
-CountMetricProducer::CountMetricProducer(const CountMetric& metric)
-    : CountMetricProducer(metric, new ConditionTracker()) {
-}
-
 CountMetricProducer::~CountMetricProducer() {
     VLOG("~CountMetricProducer() called");
 }
@@ -63,13 +57,17 @@
 void CountMetricProducer::finish() {
     // TODO: write the StatsLogReport to dropbox using
     // DropboxWriter.
-    onDumpReport();
 }
 
 void CountMetricProducer::onDumpReport() {
     VLOG("dump report now...");
 }
 
+void CountMetricProducer::onConditionChanged(const bool conditionMet) {
+    VLOG("onConditionChanged");
+    mCondition = conditionMet;
+}
+
 void CountMetricProducer::onMatchedLogEvent(const LogEventWrapper& event) {
     time_t eventTime = event.timestamp_ns / 1000000000;
 
@@ -78,22 +76,24 @@
         return;
     }
 
-    if (mConditionTracker->isConditionMet()) {
+    if (mCondition == ConditionState::kTrue) {
         flushCounterIfNeeded(eventTime);
         mCounter++;
         mAnomalyTracker.checkAnomaly(mCounter);
+        VLOG("metric %lld count %d", mMetric.metric_id(), mCounter);
     }
 }
 
-// When a new matched event comes in, we check if it falls into the current bucket. And flush the
-// counter to the StatsLogReport and adjust the bucket if needed.
+// When a new matched event comes in, we check if it falls into the current
+// bucket. And flush the counter to the StatsLogReport and adjust the bucket if
+// needed.
 void CountMetricProducer::flushCounterIfNeeded(const time_t& eventTime) {
     if (mCurrentBucketStartTime + mBucketSize_sec > eventTime) {
         return;
     }
 
     // TODO: add a KeyValuePair to StatsLogReport.
-    ALOGD("CountMetric: dump counter %d", mCounter);
+    ALOGD("%lld:  dump counter %d", mMetric.metric_id(), mCounter);
 
     // adjust the bucket start time
     time_t numBucketsForward = (eventTime - mCurrentBucketStartTime)
@@ -106,7 +106,7 @@
     mAnomalyTracker.addPastBucket(mCounter, numBucketsForward);
     mCounter = 0;
 
-    VLOG("new bucket start time: %lu", mCurrentBucketStartTime);
+    VLOG("%lld: new bucket start time: %lu", mMetric.metric_id(), mCurrentBucketStartTime);
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 7502320..0729e2c 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -17,13 +17,11 @@
 #ifndef COUNT_METRIC_PRODUCER_H
 #define COUNT_METRIC_PRODUCER_H
 
-#include <mutex>
-#include <thread>
 #include <unordered_map>
-#include "../matchers/LogEntryMatcherManager.h"
+
 #include "CountAnomalyTracker.h"
-#include "ConditionTracker.h"
-#include "DropboxWriter.h"
+#include "../condition/ConditionTracker.h"
+#include "../matchers/matcher_util.h"
 #include "MetricProducer.h"
 #include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
@@ -34,14 +32,14 @@
 
 class CountMetricProducer : public MetricProducer {
 public:
-    CountMetricProducer(const CountMetric& countMetric, const sp<ConditionTracker> condition);
-
-    CountMetricProducer(const CountMetric& countMetric);
+    CountMetricProducer(const CountMetric& countMetric, const bool hasCondition);
 
     virtual ~CountMetricProducer();
 
     void onMatchedLogEvent(const LogEventWrapper& event) override;
 
+    void onConditionChanged(const bool conditionMet) override;
+
     void finish() override;
 
     void onDumpReport() override;
@@ -49,8 +47,6 @@
 private:
     const CountMetric mMetric;
 
-    const sp<ConditionTracker> mConditionTracker;
-
     const time_t mStartTime;
     // TODO: Add dimensions.
     // Counter value for the current bucket.
@@ -62,6 +58,8 @@
 
     CountAnomalyTracker mAnomalyTracker;
 
+    bool mCondition;
+
     void flushCounterIfNeeded(const time_t& newEventTime);
 };
 
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 44a778b..7d3d661 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -18,7 +18,8 @@
 #define METRIC_PRODUCER_H
 
 #include <log/logprint.h>
-#include "../matchers/LogEntryMatcherManager.h"
+#include <utils/RefBase.h>
+#include "../matchers/matcher_util.h"
 
 namespace android {
 namespace os {
@@ -26,13 +27,15 @@
 
 // A MetricProducer is responsible for compute one single metrics, creating stats log report, and
 // writing the report to dropbox.
-class MetricProducer {
+class MetricProducer : public virtual RefBase {
 public:
     virtual ~MetricProducer(){};
 
-    // Consume the stats log if it's interesting to this metric.
+    // Consume the parsed stats log entry that already matched the "what" of the metric.
     virtual void onMatchedLogEvent(const LogEventWrapper& event) = 0;
 
+    virtual void onConditionChanged(const bool condition) = 0;
+
     // This is called when the metric collecting is done, e.g., when there is a new configuration
     // coming. MetricProducer should do the clean up, and dump existing data to dropbox.
     virtual void finish() = 0;
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index cb74206..1e65f58 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -21,13 +21,17 @@
 #include "MetricsManager.h"
 #include <cutils/log.h>
 #include <log/logprint.h>
+#include "../condition/CombinationConditionTracker.h"
+#include "../condition/SimpleConditionTracker.h"
+#include "../matchers/CombinationLogMatchingTracker.h"
+#include "../matchers/SimpleLogMatchingTracker.h"
 #include "CountMetricProducer.h"
-#include "parse_util.h"
+#include "metrics_manager_util.h"
+#include "stats_util.h"
 
 using std::make_unique;
 using std::set;
 using std::string;
-using std::unique_ptr;
 using std::unordered_map;
 using std::vector;
 
@@ -35,93 +39,90 @@
 namespace os {
 namespace statsd {
 
-MetricsManager::MetricsManager(const StatsdConfig& config) : mConfig(config), mLogMatchers() {
-    std::unordered_map<string, LogEntryMatcher> matcherMap;
-    std::unordered_map<string, sp<ConditionTracker>> conditionMap;
-
-    for (int i = 0; i < config.log_entry_matcher_size(); i++) {
-        const LogEntryMatcher& logMatcher = config.log_entry_matcher(i);
-        mMatchers.push_back(logMatcher);
-
-        matcherMap[config.log_entry_matcher(i).name()] = logMatcher;
-
-        mLogMatchers[logMatcher.name()] = vector<unique_ptr<MetricProducer>>();
-        // Collect all the tag ids that are interesting
-        set<int> tagIds = LogEntryMatcherManager::getTagIdsFromMatcher(logMatcher);
-
-        mTagIds.insert(tagIds.begin(), tagIds.end());
-    }
-
-    for (int i = 0; i < config.condition_size(); i++) {
-        const Condition& condition = config.condition(i);
-        conditionMap[condition.name()] = new ConditionTracker(condition);
-    }
-
-    // Build MetricProducers for each metric defined in config.
-    // (1) build CountMetricProducer
-    for (int i = 0; i < config.count_metric_size(); i++) {
-        const CountMetric& metric = config.count_metric(i);
-        auto it = mLogMatchers.find(metric.what());
-        if (it == mLogMatchers.end()) {
-            ALOGW("cannot find the LogEntryMatcher %s in config", metric.what().c_str());
-            continue;
-        }
-
-        if (metric.has_condition()) {
-            auto condition_it = conditionMap.find(metric.condition());
-            if (condition_it == conditionMap.end()) {
-                ALOGW("cannot find the Condition %s in the config", metric.condition().c_str());
-                continue;
-            }
-            it->second.push_back(make_unique<CountMetricProducer>(metric, condition_it->second));
-        } else {
-            it->second.push_back(make_unique<CountMetricProducer>(metric));
-        }
-    }
-
-    // TODO: build other types of metrics too.
+MetricsManager::MetricsManager(const StatsdConfig& config) {
+    mConfigValid = initStatsdConfig(config, mTagIds, mAllLogEntryMatchers, mAllConditionTrackers,
+                                    mAllMetricProducers, mConditionToMetricMap, mTrackerToMetricMap,
+                                    mTrackerToConditionMap);
 }
 
 MetricsManager::~MetricsManager() {
     VLOG("~MetricManager()");
 }
 
+bool MetricsManager::isConfigValid() const {
+    return mConfigValid;
+}
+
 void MetricsManager::finish() {
-    for (auto const& entryPair : mLogMatchers) {
-        for (auto const& metric : entryPair.second) {
-            metric->finish();
-        }
+    for (auto& metricProducer : mAllMetricProducers) {
+        metricProducer->finish();
     }
 }
 
 // Consume the stats log if it's interesting to this metric.
 void MetricsManager::onLogEvent(const log_msg& logMsg) {
+    if (!mConfigValid) {
+        return;
+    }
+
     int tagId = getTagId(logMsg);
     if (mTagIds.find(tagId) == mTagIds.end()) {
         // not interesting...
         return;
     }
-    // Since at least one of the metrics is interested in this event, we parse it now.
-    LogEventWrapper event = LogEntryMatcherManager::parseLogEvent(logMsg);
 
-    // Evaluate the conditions. Order matters, this should happen
-    // before sending the event to metrics
-    for (auto& condition : mConditionTracker) {
-        condition->evaluateCondition(event);
+    // Since at least one of the metrics is interested in this event, we parse it now.
+    LogEventWrapper event = parseLogEvent(logMsg);
+    vector<MatchingState> matcherCache(mAllLogEntryMatchers.size(), MatchingState::kNotComputed);
+
+    for (auto& matcher : mAllLogEntryMatchers) {
+        matcher->onLogEvent(event, mAllLogEntryMatchers, matcherCache);
     }
 
-    // Now find out which LogMatcher matches this event, and let relevant metrics know.
-    for (auto matcher : mMatchers) {
-        if (LogEntryMatcherManager::matches(matcher, event)) {
-            auto it = mLogMatchers.find(matcher.name());
-            if (it != mLogMatchers.end()) {
-                for (auto const& it2 : it->second) {
-                    // Only metrics that matches this event get notified.
-                    it2->onMatchedLogEvent(event);
+    // A bitmap to see which ConditionTracker needs to be re-evaluated.
+    vector<bool> conditionToBeEvaluated(mAllConditionTrackers.size(), false);
+
+    for (const auto& pair : mTrackerToConditionMap) {
+        if (matcherCache[pair.first] == MatchingState::kMatched) {
+            const auto& conditionList = pair.second;
+            for (const int conditionIndex : conditionList) {
+                conditionToBeEvaluated[conditionIndex] = true;
+            }
+        }
+    }
+
+    vector<ConditionState> conditionCache(mAllConditionTrackers.size(),
+                                          ConditionState::kNotEvaluated);
+    // A bitmap to track if a condition has changed value.
+    vector<bool> changedCache(mAllConditionTrackers.size(), false);
+    for (size_t i = 0; i < mAllConditionTrackers.size(); i++) {
+        if (conditionToBeEvaluated[i] == false) {
+            continue;
+        }
+
+        sp<ConditionTracker>& condition = mAllConditionTrackers[i];
+        condition->evaluateCondition(event, matcherCache, mAllConditionTrackers, conditionCache,
+                                     changedCache);
+        if (changedCache[i]) {
+            auto pair = mConditionToMetricMap.find(i);
+            if (pair != mConditionToMetricMap.end()) {
+                auto& metricList = pair->second;
+                for (auto metricIndex : metricList) {
+                    mAllMetricProducers[metricIndex]->onConditionChanged(conditionCache[i]);
                 }
-            } else {
-                // TODO: we should remove any redundant matchers that the config provides.
-                ALOGW("Matcher not used by any metrics.");
+            }
+        }
+    }
+
+    // For matched LogEntryMatchers, tell relevant metrics that a matched event has come.
+    for (size_t i = 0; i < mAllLogEntryMatchers.size(); i++) {
+        if (matcherCache[i] == MatchingState::kMatched) {
+            auto pair = mTrackerToMetricMap.find(i);
+            if (pair != mTrackerToMetricMap.end()) {
+                auto& metricList = pair->second;
+                for (const int metricIndex : metricList) {
+                    mAllMetricProducers[metricIndex]->onMatchedLogEvent(event);
+                }
             }
         }
     }
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 77d7535..70c34db 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -20,8 +20,8 @@
 #include <cutils/log.h>
 #include <log/logprint.h>
 #include <unordered_map>
-#include "../matchers/LogEntryMatcherManager.h"
-#include "ConditionTracker.h"
+#include "../condition/ConditionTracker.h"
+#include "../matchers/LogMatchingTracker.h"
 #include "MetricProducer.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
@@ -36,25 +36,58 @@
 
     ~MetricsManager();
 
-    // Consume the stats log if it's interesting to this metric.
+    // Return whether the configuration is valid.
+    bool isConfigValid() const;
+
     void onLogEvent(const log_msg& logMsg);
 
+    // Called when everything should wrap up. We are about to finish (e.g., new config comes).
     void finish();
 
 private:
-    const StatsdConfig mConfig;
-
     // All event tags that are interesting to my metrics.
     std::set<int> mTagIds;
 
-    // The matchers that my metrics share.
-    std::vector<LogEntryMatcher> mMatchers;
+    // We only store the sp of LogMatchingTracker, MetricProducer, and ConditionTracker in
+    // MetricManager. There are relationship between them, and the relationship are denoted by index
+    // instead of poiters. The reasons for this are: (1) the relationship between them are
+    // complicated, store index instead of pointers reduce the risk of A holds B's sp, and B holds
+    // A's sp. (2) When we evaluate matcher results, or condition results, we can quickly get the
+    // related results from a cache using the index.
+    // TODO: using unique_ptr may be more appriopreate?
 
-    // The conditions that my metrics share.
-    std::vector<sp<ConditionTracker>> mConditionTracker;
+    // Hold all the log entry matchers from the config.
+    std::vector<sp<LogMatchingTracker>> mAllLogEntryMatchers;
 
-    // the map from LogEntryMatcher names to the metrics that use this matcher.
-    std::unordered_map<std::string, std::vector<std::unique_ptr<MetricProducer>>> mLogMatchers;
+    // Hold all the conditions from the config.
+    std::vector<sp<ConditionTracker>> mAllConditionTrackers;
+
+    // Hold all metrics from the config.
+    std::vector<sp<MetricProducer>> mAllMetricProducers;
+
+    // To make the log processing more efficient, we want to do as much filtering as possible
+    // before we go into individual trackers and conditions to match.
+
+    // 1st filter: check if the event tag id is in mTagIds.
+    // 2nd filter: if it is, we parse the event because there is at least one member is interested.
+    //             then pass to all LogMatchingTrackers (itself also filter events by ids).
+    // 3nd filter: for LogMatchingTrackers that matched this event, we pass this event to the
+    //             ConditionTrackers and MetricProducers that use this matcher.
+    // 4th filter: for ConditionTrackers that changed value due to this event, we pass
+    //             new conditions to  metrics that use this condition.
+
+    // The following map is initialized from the statsd_config.
+
+    // maps from the index of the LogMatchingTracker to index of MetricProducer.
+    std::unordered_map<int, std::vector<int>> mTrackerToMetricMap;
+
+    // maps from LogMatchingTracker to ConditionTracker
+    std::unordered_map<int, std::vector<int>> mTrackerToConditionMap;
+
+    // maps from ConditionTracker to MetricProducer
+    std::unordered_map<int, std::vector<int>> mConditionToMetricMap;
+
+    bool mConfigValid;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
new file mode 100644
index 0000000..6fdd228
--- /dev/null
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -0,0 +1,200 @@
+/*
+ * 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 "../condition/CombinationConditionTracker.h"
+#include "../condition/SimpleConditionTracker.h"
+#include "../matchers/CombinationLogMatchingTracker.h"
+#include "../matchers/SimpleLogMatchingTracker.h"
+#include "CountMetricProducer.h"
+#include "stats_util.h"
+
+using std::set;
+using std::string;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+bool initLogTrackers(const StatsdConfig& config, unordered_map<string, int>& logTrackerMap,
+                     vector<sp<LogMatchingTracker>>& allLogEntryMatchers, set<int>& allTagIds) {
+    vector<LogEntryMatcher> matcherConfigs;
+
+    for (int i = 0; i < config.log_entry_matcher_size(); i++) {
+        const LogEntryMatcher& logMatcher = config.log_entry_matcher(i);
+
+        int index = allLogEntryMatchers.size();
+        switch (logMatcher.contents_case()) {
+            case LogEntryMatcher::ContentsCase::kSimpleLogEntryMatcher:
+                allLogEntryMatchers.push_back(new SimpleLogMatchingTracker(
+                        logMatcher.name(), index, logMatcher.simple_log_entry_matcher()));
+                break;
+            case LogEntryMatcher::ContentsCase::kCombination:
+                allLogEntryMatchers.push_back(
+                        new CombinationLogMatchingTracker(logMatcher.name(), index));
+                break;
+            default:
+                ALOGE("Matcher %s malformed", logMatcher.name().c_str());
+                return false;
+                // continue;
+        }
+        if (logTrackerMap.find(logMatcher.name()) != logTrackerMap.end()) {
+            ALOGE("Duplicate LogEntryMatcher found!");
+            return false;
+        }
+        logTrackerMap[logMatcher.name()] = index;
+        matcherConfigs.push_back(logMatcher);
+    }
+
+    vector<bool> stackTracker2(allLogEntryMatchers.size(), false);
+    for (auto& matcher : allLogEntryMatchers) {
+        if (!matcher->init(matcherConfigs, allLogEntryMatchers, logTrackerMap, stackTracker2)) {
+            return false;
+        }
+        // Collect all the tag ids that are interesting. TagIds exist in leaf nodes only.
+        const set<int>& tagIds = matcher->getTagIds();
+        allTagIds.insert(tagIds.begin(), tagIds.end());
+    }
+    return true;
+}
+
+bool initConditions(const StatsdConfig& config, const unordered_map<string, int>& logTrackerMap,
+                    unordered_map<string, int>& conditionTrackerMap,
+                    vector<sp<ConditionTracker>>& allConditionTrackers,
+                    unordered_map<int, std::vector<int>>& trackerToConditionMap) {
+    vector<Condition> conditionConfigs;
+
+    for (int i = 0; i < config.condition_size(); i++) {
+        const Condition& condition = config.condition(i);
+        int index = allConditionTrackers.size();
+        switch (condition.contents_case()) {
+            case Condition::ContentsCase::kSimpleCondition: {
+                allConditionTrackers.push_back(new SimpleConditionTracker(
+                        condition.name(), index, condition.simple_condition(), logTrackerMap));
+                break;
+            }
+            case Condition::ContentsCase::kCombination: {
+                allConditionTrackers.push_back(
+                        new CombinationConditionTracker(condition.name(), index));
+                break;
+            }
+            default:
+                ALOGE("Condition %s malformed", condition.name().c_str());
+                return false;
+        }
+        if (conditionTrackerMap.find(condition.name()) != conditionTrackerMap.end()) {
+            ALOGE("Duplicate Condition found!");
+            return false;
+        }
+        conditionTrackerMap[condition.name()] = index;
+        conditionConfigs.push_back(condition);
+    }
+
+    vector<bool> stackTracker(allConditionTrackers.size(), false);
+    for (size_t i = 0; i < allConditionTrackers.size(); i++) {
+        auto& conditionTracker = allConditionTrackers[i];
+        if (!conditionTracker->init(conditionConfigs, allConditionTrackers, conditionTrackerMap,
+                                    stackTracker)) {
+            return false;
+        }
+        for (const int trackerIndex : conditionTracker->getLogTrackerIndex()) {
+            auto& conditionList = trackerToConditionMap[trackerIndex];
+            conditionList.push_back(i);
+        }
+    }
+    return true;
+}
+
+bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& logTrackerMap,
+                 const unordered_map<string, int>& conditionTrackerMap,
+                 vector<sp<MetricProducer>>& allMetricProducers,
+                 unordered_map<int, std::vector<int>>& conditionToMetricMap,
+                 unordered_map<int, std::vector<int>>& trackerToMetricMap) {
+    // Build MetricProducers for each metric defined in config.
+    // (1) build CountMetricProducer
+    for (int i = 0; i < config.count_metric_size(); i++) {
+        const CountMetric& metric = config.count_metric(i);
+        if (!metric.has_what()) {
+            ALOGW("cannot find what in CountMetric %lld", metric.metric_id());
+            return false;
+        }
+
+        auto logTrackerIt = logTrackerMap.find(metric.what());
+        if (logTrackerIt == logTrackerMap.end()) {
+            ALOGW("cannot find the LogEntryMatcher %s in config", metric.what().c_str());
+            return false;
+        }
+
+        sp<MetricProducer> countProducer;
+        int metricIndex = allMetricProducers.size();
+        if (metric.has_condition()) {
+            auto condition_it = conditionTrackerMap.find(metric.condition());
+            if (condition_it == conditionTrackerMap.end()) {
+                ALOGW("cannot find the Condition %s in the config", metric.condition().c_str());
+                return false;
+            }
+            countProducer = new CountMetricProducer(metric, true /*has condition*/);
+            // will create new vector if not exist before.
+            auto& metricList = conditionToMetricMap[condition_it->second];
+            metricList.push_back(metricIndex);
+        } else {
+            countProducer = new CountMetricProducer(metric, false /*no condition*/);
+        }
+
+        int logTrackerIndex = logTrackerIt->second;
+        auto& metric_list = trackerToMetricMap[logTrackerIndex];
+        metric_list.push_back(metricIndex);
+        allMetricProducers.push_back(countProducer);
+    }
+
+    // TODO: build other types of metrics too.
+
+    return true;
+}
+
+bool initStatsdConfig(const StatsdConfig& config, set<int>& allTagIds,
+                      vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
+                      vector<sp<ConditionTracker>>& allConditionTrackers,
+                      vector<sp<MetricProducer>>& allMetricProducers,
+                      unordered_map<int, std::vector<int>>& conditionToMetricMap,
+                      unordered_map<int, std::vector<int>>& trackerToMetricMap,
+                      unordered_map<int, std::vector<int>>& trackerToConditionMap) {
+    unordered_map<string, int> logTrackerMap;
+    unordered_map<string, int> conditionTrackerMap;
+
+    if (!initLogTrackers(config, logTrackerMap, allLogEntryMatchers, allTagIds)) {
+        ALOGE("initLogMatchingTrackers failed");
+        return false;
+    }
+
+    if (!initConditions(config, logTrackerMap, conditionTrackerMap, allConditionTrackers,
+                        trackerToConditionMap)) {
+        ALOGE("initConditionTrackers failed");
+        return false;
+    }
+
+    if (!initMetrics(config, logTrackerMap, conditionTrackerMap, allMetricProducers,
+                     conditionToMetricMap, trackerToMetricMap)) {
+        ALOGE("initMetricProducers failed");
+        return false;
+    }
+    return true;
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
new file mode 100644
index 0000000..5f1f295
--- /dev/null
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+#ifndef METRIC_UTIL_H
+#define METRIC_UTIL_H
+#include <memory>
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+#include "../condition/ConditionTracker.h"
+#include "../matchers/LogMatchingTracker.h"
+#include "CountMetricProducer.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// Helper functions for MetricsManager to initialize from StatsdConfig.
+// *Note*: only initStatsdConfig() should be called from outside.
+// All other functions are intermediate
+// steps, created to make unit tests easier. And most of the parameters in these
+// functions are temporary objects in the initialization phase.
+
+// Initialize the LogMatchingTrackers.
+// input:
+// [config]: the input StatsdConfig
+// output:
+// [logTrackerMap]: this map should contain matcher name to index mapping
+// [allLogEntryMatchers]: should store the sp to all the LogMatchingTracker
+// [allTagIds]: contains the set of all interesting tag ids to this config.
+bool initLogTrackers(const StatsdConfig& config,
+                     std::unordered_map<std::string, int>& logTrackerMap,
+                     std::vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
+                     std::set<int>& allTagIds);
+
+// Initialize ConditionTrackers
+// input:
+// [config]: the input config
+// [logTrackerMap]: LogMatchingTracker name to index mapping from previous step.
+// output:
+// [conditionTrackerMap]: this map should contain condition name to index mapping
+// [allConditionTrackers]: stores the sp to all the ConditionTrackers
+// [trackerToConditionMap]: contain the mapping from index of
+//                        log tracker to condition trackers that use the log tracker
+bool initConditions(const StatsdConfig& config,
+                    const std::unordered_map<std::string, int>& logTrackerMap,
+                    std::unordered_map<std::string, int>& conditionTrackerMap,
+                    std::vector<sp<ConditionTracker>>& allConditionTrackers,
+                    std::unordered_map<int, std::vector<int>>& trackerToConditionMap);
+
+// Initialize MetricProducers.
+// input:
+// [config]: the input config
+// [logTrackerMap]: LogMatchingTracker name to index mapping from previous step.
+// [conditionTrackerMap]: condition name to index mapping
+// output:
+// [allMetricProducers]: contains the list of sp to the MetricProducers created.
+// [conditionToMetricMap]: contains the mapping from condition tracker index to
+//                          the list of MetricProducer index
+// [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index.
+bool initMetrics(const StatsdConfig& config,
+                 const std::unordered_map<std::string, int>& logTrackerMap,
+                 const std::unordered_map<std::string, int>& conditionTrackerMap,
+                 std::vector<sp<MetricProducer>>& allMetricProducers,
+                 std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
+                 std::unordered_map<int, std::vector<int>>& trackerToMetricMap);
+
+// Initialize MetricManager from StatsdConfig.
+// Parameters are the members of MetricsManager. See MetricsManager for declaration.
+bool initStatsdConfig(const StatsdConfig& config, std::set<int>& allTagIds,
+                      std::vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
+                      std::vector<sp<ConditionTracker>>& allConditionTrackers,
+                      std::vector<sp<MetricProducer>>& allMetricProducers,
+                      std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
+                      std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
+                      std::unordered_map<int, std::vector<int>>& trackerToConditionMap);
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+#endif  // METRIC_UTIL_H