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/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
new file mode 100644
index 0000000..6188383
--- /dev/null
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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 "CombinationConditionTracker"
+#define DEBUG true  // STOPSHIP if true
+#define VLOG(...) \
+    if (DEBUG) ALOGD(__VA_ARGS__);
+
+#include "CombinationConditionTracker.h"
+#include <cutils/log.h>
+#include <log/logprint.h>
+using std::string;
+using std::unique_ptr;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+CombinationConditionTracker::CombinationConditionTracker(const string& name, const int index)
+    : ConditionTracker(name, index) {
+    VLOG("creating CombinationConditionTracker %s", mName.c_str());
+}
+
+CombinationConditionTracker::~CombinationConditionTracker() {
+    VLOG("~CombinationConditionTracker() %s", mName.c_str());
+}
+
+bool CombinationConditionTracker::init(const vector<Condition>& allConditionConfig,
+                                       const vector<sp<ConditionTracker>>& allConditionTrackers,
+                                       const unordered_map<string, int>& conditionNameIndexMap,
+                                       vector<bool>& stack) {
+    VLOG("Combiniation condition init() %s", mName.c_str());
+    if (mInitialized) {
+        return true;
+    }
+
+    // mark this node as visited in the recursion stack.
+    stack[mIndex] = true;
+
+    Condition_Combination combinationCondition = allConditionConfig[mIndex].combination();
+
+    if (!combinationCondition.has_operation()) {
+        return false;
+    }
+    mLogicalOperation = combinationCondition.operation();
+
+    if (mLogicalOperation == LogicalOperation::NOT && combinationCondition.condition_size() != 1) {
+        return false;
+    }
+
+    for (string child : combinationCondition.condition()) {
+        auto it = conditionNameIndexMap.find(child);
+
+        if (it == conditionNameIndexMap.end()) {
+            ALOGW("Condition %s not found in the config", child.c_str());
+            return false;
+        }
+
+        int childIndex = it->second;
+        const auto& childTracker = allConditionTrackers[childIndex];
+        // if the child is a visited node in the recursion -> circle detected.
+        if (stack[childIndex]) {
+            ALOGW("Circle detected!!!");
+            return false;
+        }
+
+        bool initChildSucceeded = childTracker->init(allConditionConfig, allConditionTrackers,
+                                                     conditionNameIndexMap, stack);
+
+        if (!initChildSucceeded) {
+            ALOGW("Child initialization failed %s ", child.c_str());
+            return false;
+        } else {
+            ALOGW("Child initialization success %s ", child.c_str());
+        }
+
+        mChildren.push_back(childIndex);
+
+        mTrackerIndex.insert(childTracker->getLogTrackerIndex().begin(),
+                             childTracker->getLogTrackerIndex().end());
+    }
+
+    // unmark this node in the recursion stack.
+    stack[mIndex] = false;
+
+    mInitialized = true;
+
+    return true;
+}
+
+bool CombinationConditionTracker::evaluateCondition(
+        const LogEventWrapper& event, const std::vector<MatchingState>& eventMatcherValues,
+        const std::vector<sp<ConditionTracker>>& mAllConditions,
+        std::vector<ConditionState>& conditionCache, std::vector<bool>& changedCache) {
+    // value is up to date.
+    if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
+        return false;
+    }
+
+    for (const int childIndex : mChildren) {
+        if (conditionCache[childIndex] == ConditionState::kNotEvaluated) {
+            const sp<ConditionTracker>& child = mAllConditions[childIndex];
+            child->evaluateCondition(event, eventMatcherValues, mAllConditions, conditionCache,
+                                     changedCache);
+        }
+    }
+
+    ConditionState newCondition =
+            evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
+
+    bool changed = (mConditionState != newCondition);
+    mConditionState = newCondition;
+
+    conditionCache[mIndex] = mConditionState;
+
+    changedCache[mIndex] = changed;
+    return changed;
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
new file mode 100644
index 0000000..38780e7
--- /dev/null
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -0,0 +1,57 @@
+/*
+ * 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 COMBINATION_CONDITION_TRACKER_H
+#define COMBINATION_CONDITION_TRACKER_H
+
+#include "ConditionTracker.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class CombinationConditionTracker : public virtual ConditionTracker {
+public:
+    CombinationConditionTracker(const std::string& name, const int index);
+
+    ~CombinationConditionTracker();
+
+    bool init(const std::vector<Condition>& allConditionConfig,
+              const std::vector<sp<ConditionTracker>>& allConditionTrackers,
+              const std::unordered_map<std::string, int>& conditionNameIndexMap,
+              std::vector<bool>& stack) override;
+
+    bool evaluateCondition(const LogEventWrapper& event,
+                           const std::vector<MatchingState>& eventMatcherValues,
+                           const std::vector<sp<ConditionTracker>>& mAllConditions,
+                           std::vector<ConditionState>& conditionCache,
+                           std::vector<bool>& changedCache) override;
+
+private:
+    LogicalOperation mLogicalOperation;
+    // Store index of the children Conditions.
+    // We don't store string name of the Children, because we want to get rid of the hash map to
+    // map the name to object. We don't want to store smart pointers to children, because it
+    // increases the risk of circular dependency and memory leak.
+    std::vector<int> mChildren;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
+#endif  // COMBINATION_CONDITION_TRACKER_H
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
new file mode 100644
index 0000000..2da8fa0
--- /dev/null
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -0,0 +1,105 @@
+/*
+ * 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 <cutils/log.h>
+#include <log/logprint.h>
+#include <utils/RefBase.h>
+#include <unordered_map>
+#include "../matchers/LogMatchingTracker.h"
+#include "../matchers/matcher_util.h"
+#include "condition_util.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class ConditionTracker : public virtual RefBase {
+public:
+    ConditionTracker(const std::string& name, const int index)
+        : mName(name),
+          mIndex(index),
+          mInitialized(false),
+          mConditionState(ConditionState::kUnknown),
+          mTrackerIndex(){};
+
+    virtual ~ConditionTracker(){};
+
+    // Initialize this ConditionTracker. This initialization is done recursively (DFS). It can also
+    // be done in the constructor, but we do it separately because (1) easy to return a bool to
+    // indicate whether the initialization is successful. (2) makes unit test easier.
+    // allConditionConfig: the list of all Condition config from statsd_config.
+    // allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
+    //                       need to call init() on children conditions)
+    // conditionNameIndexMap: the mapping from condition name to its index.
+    // stack: a bit map to keep track which nodes have been visited on the stack in the recursion.
+    virtual bool init(const std::vector<Condition>& allConditionConfig,
+                      const std::vector<sp<ConditionTracker>>& allConditionTrackers,
+                      const std::unordered_map<std::string, int>& conditionNameIndexMap,
+                      std::vector<bool>& stack) = 0;
+
+    // evaluate current condition given the new event.
+    // return true if the condition state changed, false if the condition state is not changed.
+    // event: the new log event
+    // eventMatcherValues: the results of the LogMatcherTrackers. LogMatcherTrackers always process
+    //                     event before ConditionTrackers, because ConditionTracker depends on
+    //                     LogMatchingTrackers.
+    // mAllConditions: the list of all ConditionTracker
+    // conditionCache: the cached results of the ConditionTrackers for this new event.
+    // changedCache: the bit map to record whether the condition has changed.
+    virtual bool evaluateCondition(const LogEventWrapper& event,
+                                   const std::vector<MatchingState>& eventMatcherValues,
+                                   const std::vector<sp<ConditionTracker>>& mAllConditions,
+                                   std::vector<ConditionState>& conditionCache,
+                                   std::vector<bool>& changedCache) = 0;
+
+    // Return the current condition state.
+    virtual ConditionState isConditionMet() {
+        ALOGW("Condition %s value %d", mName.c_str(), mConditionState);
+        return mConditionState;
+    };
+
+    // return the list of LogMatchingTracker index that this ConditionTracker uses.
+    virtual const std::set<int>& getLogTrackerIndex() const {
+        return mTrackerIndex;
+    }
+
+protected:
+    // We don't really need the string name, but having a name here makes log messages
+    // easy to debug.
+    const std::string mName;
+
+    // the index of this condition in the manager's condition list.
+    const int mIndex;
+
+    // if it's properly initialized.
+    bool mInitialized;
+
+    // current condition state.
+    ConditionState mConditionState;
+
+    // the list of LogMatchingTracker index that this ConditionTracker uses.
+    std::set<int> mTrackerIndex;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
+#endif  // CONDITION_TRACKER_H
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
new file mode 100644
index 0000000..14ec72e
--- /dev/null
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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 "Stats_SimpleConditionTracker"
+#define DEBUG true  // STOPSHIP if true
+#define VLOG(...) \
+    if (DEBUG) ALOGD(__VA_ARGS__);
+
+#include "SimpleConditionTracker.h"
+#include <cutils/log.h>
+#include <log/logprint.h>
+
+using std::string;
+using std::unique_ptr;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+SimpleConditionTracker::SimpleConditionTracker(
+        const string& name, const int index, const SimpleCondition& simpleCondition,
+        const unordered_map<string, int>& trackerNameIndexMap)
+    : ConditionTracker(name, index) {
+    VLOG("creating SimpleConditionTracker %s", mName.c_str());
+    mCountNesting = simpleCondition.count_nesting();
+
+    if (simpleCondition.has_start()) {
+        auto pair = trackerNameIndexMap.find(simpleCondition.start());
+        if (pair == trackerNameIndexMap.end()) {
+            ALOGW("Start matcher %s not found in the config", simpleCondition.start().c_str());
+            return;
+        }
+        mStartLogMatcherIndex = pair->second;
+        mTrackerIndex.insert(mStartLogMatcherIndex);
+    } else {
+        mStartLogMatcherIndex = -1;
+    }
+
+    if (simpleCondition.has_stop()) {
+        auto pair = trackerNameIndexMap.find(simpleCondition.stop());
+        if (pair == trackerNameIndexMap.end()) {
+            ALOGW("Stop matcher %s not found in the config", simpleCondition.stop().c_str());
+            return;
+        }
+        mStopLogMatcherIndex = pair->second;
+        mTrackerIndex.insert(mStartLogMatcherIndex);
+    } else {
+        mStopLogMatcherIndex = -1;
+    }
+
+    if (simpleCondition.has_stop_all()) {
+        auto pair = trackerNameIndexMap.find(simpleCondition.stop_all());
+        if (pair == trackerNameIndexMap.end()) {
+            ALOGW("Stop matcher %s not found in the config", simpleCondition.stop().c_str());
+            return;
+        }
+        mStopAllLogMatcherIndex = pair->second;
+        mTrackerIndex.insert(mStopAllLogMatcherIndex);
+    } else {
+        mStopAllLogMatcherIndex = -1;
+    }
+
+    mInitialized = true;
+}
+
+SimpleConditionTracker::~SimpleConditionTracker() {
+    VLOG("~SimpleConditionTracker()");
+}
+
+bool SimpleConditionTracker::init(const vector<Condition>& allConditionConfig,
+                                  const vector<sp<ConditionTracker>>& allConditionTrackers,
+                                  const unordered_map<string, int>& conditionNameIndexMap,
+                                  vector<bool>& stack) {
+    // SimpleConditionTracker does not have dependency on other conditions, thus we just return
+    // if the initialization was successful.
+    return mInitialized;
+}
+
+bool SimpleConditionTracker::evaluateCondition(const LogEventWrapper& event,
+                                               const vector<MatchingState>& eventMatcherValues,
+                                               const vector<sp<ConditionTracker>>& mAllConditions,
+                                               vector<ConditionState>& conditionCache,
+                                               vector<bool>& changedCache) {
+    if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
+        // it has been evaluated.
+        VLOG("Yes, already evaluated, %s %d", mName.c_str(), mConditionState);
+        return false;
+    }
+
+    // Ignore nesting, because we know we cannot trust ourselves on tracking nesting conditions.
+    ConditionState newCondition = mConditionState;
+    // Note: The order to evaluate the following start, stop, stop_all matters.
+    // The priority of overwrite is stop_all > stop > start.
+    if (mStartLogMatcherIndex >= 0 &&
+        eventMatcherValues[mStartLogMatcherIndex] == MatchingState::kMatched) {
+        newCondition = ConditionState::kTrue;
+    }
+
+    if (mStopLogMatcherIndex >= 0 &&
+        eventMatcherValues[mStopLogMatcherIndex] == MatchingState::kMatched) {
+        newCondition = ConditionState::kFalse;
+    }
+
+    if (mStopAllLogMatcherIndex >= 0 &&
+        eventMatcherValues[mStopAllLogMatcherIndex] == MatchingState::kMatched) {
+        newCondition = ConditionState::kFalse;
+    }
+
+    bool changed = (mConditionState != newCondition);
+    mConditionState = newCondition;
+    conditionCache[mIndex] = mConditionState;
+    changedCache[mIndex] = changed;
+    return changed;
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
new file mode 100644
index 0000000..41e1707
--- /dev/null
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -0,0 +1,64 @@
+/*
+ * 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 SIMPLE_CONDITION_TRACKER_H
+#define SIMPLE_CONDITION_TRACKER_H
+
+#include "ConditionTracker.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class SimpleConditionTracker : public virtual ConditionTracker {
+public:
+    SimpleConditionTracker(const std::string& name, const int index,
+                           const SimpleCondition& simpleCondition,
+                           const std::unordered_map<std::string, int>& trackerNameIndexMap);
+
+    ~SimpleConditionTracker();
+
+    bool init(const std::vector<Condition>& allConditionConfig,
+              const std::vector<sp<ConditionTracker>>& allConditionTrackers,
+              const std::unordered_map<std::string, int>& conditionNameIndexMap,
+              std::vector<bool>& stack) override;
+
+    bool evaluateCondition(const LogEventWrapper& event,
+                           const std::vector<MatchingState>& eventMatcherValues,
+                           const std::vector<sp<ConditionTracker>>& mAllConditions,
+                           std::vector<ConditionState>& conditionCache,
+                           std::vector<bool>& changedCache) override;
+
+private:
+    // The index of the LogEventMatcher which defines the start.
+    int mStartLogMatcherIndex;
+
+    // The index of the LogEventMatcher which defines the end.
+    int mStopLogMatcherIndex;
+
+    // if the start end needs to be nested.
+    bool mCountNesting;
+
+    // The index of the LogEventMatcher which defines the stop all.
+    int mStopAllLogMatcherIndex;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
+#endif  // SIMPLE_CONDITION_TRACKER_H
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
new file mode 100644
index 0000000..cb07d15
--- /dev/null
+++ b/cmds/statsd/src/condition/condition_util.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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_util.h"
+
+#include <cutils/log.h>
+#include <log/event_tag_map.h>
+#include <log/log_event_list.h>
+#include <log/logprint.h>
+#include <utils/Errors.h>
+#include <unordered_map>
+#include "ConditionTracker.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "stats_util.h"
+
+using std::set;
+using std::string;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+ConditionState evaluateCombinationCondition(const std::vector<int>& children,
+                                            const LogicalOperation& operation,
+                                            const std::vector<ConditionState>& conditionCache) {
+    ConditionState newCondition;
+
+    bool hasUnknown = false;
+    bool hasFalse = false;
+    bool hasTrue = false;
+
+    for (auto childIndex : children) {
+        ConditionState childState = conditionCache[childIndex];
+        if (childState == ConditionState::kUnknown) {
+            hasUnknown = true;
+            break;
+        }
+        if (childState == ConditionState::kFalse) {
+            hasFalse = true;
+        }
+        if (childState == ConditionState::kTrue) {
+            hasTrue = true;
+        }
+    }
+
+    // If any child condition is in unknown state, the condition is unknown too.
+    if (hasUnknown) {
+        return ConditionState::kUnknown;
+    }
+
+    switch (operation) {
+        case LogicalOperation::AND: {
+            newCondition = hasFalse ? ConditionState::kFalse : ConditionState::kTrue;
+            break;
+        }
+        case LogicalOperation::OR: {
+            newCondition = hasTrue ? ConditionState::kTrue : ConditionState::kFalse;
+            break;
+        }
+        case LogicalOperation::NOT:
+            newCondition = (conditionCache[children[0]] == ConditionState::kFalse)
+                                   ? ConditionState::kTrue
+                                   : ConditionState::kFalse;
+            break;
+        case LogicalOperation::NAND:
+            newCondition = hasFalse ? ConditionState::kTrue : ConditionState::kFalse;
+            break;
+        case LogicalOperation::NOR:
+            newCondition = hasTrue ? ConditionState::kFalse : ConditionState::kTrue;
+            break;
+    }
+    return newCondition;
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/condition/condition_util.h b/cmds/statsd/src/condition/condition_util.h
new file mode 100644
index 0000000..a4fcea3
--- /dev/null
+++ b/cmds/statsd/src/condition/condition_util.h
@@ -0,0 +1,41 @@
+/*
+ * 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_UTIL_H
+#define CONDITION_UTIL_H
+
+#include <vector>
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+enum ConditionState {
+    kNotEvaluated = -2,
+    kUnknown = -1,
+    kFalse = 0,
+    kTrue = 1,
+};
+
+ConditionState evaluateCombinationCondition(const std::vector<int>& children,
+                                            const LogicalOperation& operation,
+                                            const std::vector<ConditionState>& conditionCache);
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+#endif  // CONDITION_UTIL_H