1/ Support nested message and repeated fields in statsd.
2/ Filter gauge fields by FieldMatcher.
3/ Wire up wakelock attribution chain.
4/ e2e test: wakelock duration metric with aggregated predicate dimensions.
5/ e2e test: count metric with multiple metric condition links for 2 predicates and 1 non-sliced predicate.

Test: statsd unit test passed.

Change-Id: I89db31cb068184a54e0a892fad710966d3127bc9
diff --git a/cmds/statsd/src/dimension.cpp b/cmds/statsd/src/dimension.cpp
new file mode 100644
index 0000000..886a33bf
--- /dev/null
+++ b/cmds/statsd/src/dimension.cpp
@@ -0,0 +1,356 @@
+/*
+ * 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 "Log.h"
+
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "dimension.h"
+#include "field_util.h"
+
+
+namespace android {
+namespace os {
+namespace statsd {
+
+const DimensionsValue* getSingleLeafValue(const DimensionsValue* value) {
+    if (value->value_case() == DimensionsValue::ValueCase::kValueTuple) {
+        return getSingleLeafValue(&value->value_tuple().dimensions_value(0));
+    } else {
+        return value;
+    }
+}
+
+DimensionsValue getSingleLeafValue(const DimensionsValue& value) {
+    const DimensionsValue* leafValue = getSingleLeafValue(&value);
+    return *leafValue;
+}
+
+void appendLeafNodeToParent(const Field& field,
+                            const DimensionsValue& value,
+                            DimensionsValue* parentValue) {
+    if (field.child_size() <= 0) {
+        *parentValue = value;
+        parentValue->set_field(field.field());
+        return;
+    }
+    parentValue->set_field(field.field());
+    int idx = -1;
+    for (int i = 0; i < parentValue->mutable_value_tuple()->dimensions_value_size(); ++i) {
+        if (parentValue->mutable_value_tuple()->dimensions_value(i).field() ==
+                field.child(0).field()) {
+            idx = i;
+        }
+    }
+    if (idx < 0) {
+        parentValue->mutable_value_tuple()->add_dimensions_value();
+        idx = parentValue->mutable_value_tuple()->dimensions_value_size() - 1;
+    }
+    appendLeafNodeToParent(
+        field.child(0), value,
+        parentValue->mutable_value_tuple()->mutable_dimensions_value(idx));
+}
+
+void addNodeToRootDimensionsValues(const Field& field,
+                                   const DimensionsValue& node,
+                                   std::vector<DimensionsValue>* rootValues) {
+    if (rootValues == nullptr) {
+        return;
+    }
+    if (rootValues->empty()) {
+        DimensionsValue rootValue;
+        appendLeafNodeToParent(field, node, &rootValue);
+        rootValues->push_back(rootValue);
+    } else {
+        for (size_t i = 0; i < rootValues->size(); ++i) {
+            appendLeafNodeToParent(field, node, &rootValues->at(i));
+        }
+    }
+}
+
+namespace {
+
+void findDimensionsValues(
+       const FieldValueMap& fieldValueMap,
+       const FieldMatcher& matcher,
+       const Field& field,
+       std::vector<DimensionsValue>* rootDimensionsValues);
+
+void findNonRepeatedDimensionsValues(
+       const FieldValueMap& fieldValueMap,
+       const FieldMatcher& matcher,
+       const Field& field,
+       std::vector<DimensionsValue>* rootValues) {
+    if (matcher.child_size() > 0) {
+        for (const auto& childMatcher : matcher.child()) {
+          Field childField = field;
+          appendLeaf(&childField, childMatcher.field());
+          findDimensionsValues(fieldValueMap, childMatcher, childField, rootValues);
+        }
+    } else {
+        auto ret = fieldValueMap.equal_range(field);
+        int found = 0;
+        for (auto it = ret.first; it != ret.second; ++it) {
+            found++;
+        }
+        // Not found.
+        if (found <= 0) {
+            return;
+        }
+        if (found > 1) {
+            ALOGE("Found multiple values for optional field.");
+            return;
+        }
+        addNodeToRootDimensionsValues(field, ret.first->second, rootValues);
+    }
+}
+
+void findRepeatedDimensionsValues(const FieldValueMap& fieldValueMap,
+                                  const FieldMatcher& matcher,
+                                  const Field& field,
+                                  std::vector<DimensionsValue>* rootValues) {
+    if (matcher.position() == Position::FIRST) {
+        Field first_field = field;
+        setPositionForLeaf(&first_field, 0);
+        findNonRepeatedDimensionsValues(fieldValueMap, matcher, first_field, rootValues);
+    } else {
+        auto itLower = fieldValueMap.lower_bound(field);
+        if (itLower == fieldValueMap.end()) {
+            return;
+        }
+        Field next_field = field;
+        getNextField(&next_field);
+        auto itUpper = fieldValueMap.lower_bound(next_field);
+
+        switch (matcher.position()) {
+             case Position::LAST:
+                 {
+                     itUpper--;
+                     if (itUpper != fieldValueMap.end()) {
+                         Field last_field = field;
+                         int last_index = getPositionByReferenceField(field, itUpper->first);
+                         if (last_index < 0) {
+                            return;
+                         }
+                         setPositionForLeaf(&last_field, last_index);
+                         findNonRepeatedDimensionsValues(
+                            fieldValueMap, matcher, last_field, rootValues);
+                     }
+                 }
+                 break;
+             case Position::ANY:
+                 {
+                    std::set<int> indexes;
+                    for (auto it = itLower; it != itUpper; ++it) {
+                        int index = getPositionByReferenceField(field, it->first);
+                        if (index >= 0) {
+                            indexes.insert(index);
+                        }
+                    }
+                    if (!indexes.empty()) {
+                        Field any_field = field;
+                        std::vector<DimensionsValue> allValues;
+                        for (const int index : indexes) {
+                             setPositionForLeaf(&any_field, index);
+                             std::vector<DimensionsValue> newValues = *rootValues;
+                             findNonRepeatedDimensionsValues(
+                                fieldValueMap, matcher, any_field, &newValues);
+                             allValues.insert(allValues.end(), newValues.begin(), newValues.end());
+                        }
+                        rootValues->clear();
+                        rootValues->insert(rootValues->end(), allValues.begin(), allValues.end());
+                    }
+                 }
+                 break;
+             default:
+                break;
+         }
+    }
+}
+
+void findDimensionsValues(
+       const FieldValueMap& fieldValueMap,
+       const FieldMatcher& matcher,
+       const Field& field,
+       std::vector<DimensionsValue>* rootDimensionsValues) {
+    if (!matcher.has_position()) {
+        findNonRepeatedDimensionsValues(fieldValueMap, matcher, field, rootDimensionsValues);
+    } else {
+        findRepeatedDimensionsValues(fieldValueMap, matcher, field, rootDimensionsValues);
+    }
+}
+
+} // namespace
+
+void findDimensionsValues(
+       const FieldValueMap& fieldValueMap,
+       const FieldMatcher& matcher,
+       std::vector<DimensionsValue>* rootDimensionsValues) {
+    findDimensionsValues(fieldValueMap, matcher,
+                    buildSimpleAtomField(matcher.field()), rootDimensionsValues);
+}
+
+FieldMatcher buildSimpleAtomFieldMatcher(const int tagId) {
+    FieldMatcher matcher;
+    matcher.set_field(tagId);
+    return matcher;
+}
+
+FieldMatcher buildSimpleAtomFieldMatcher(const int tagId, const int atomFieldNum) {
+    FieldMatcher matcher;
+    matcher.set_field(tagId);
+    matcher.add_child()->set_field(atomFieldNum);
+    return matcher;
+}
+
+constexpr int ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO = 1;
+constexpr int UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO = 1;
+constexpr int TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO = 2;
+
+void buildAttributionUidFieldMatcher(const int tagId, const Position position,
+                                     FieldMatcher *matcher) {
+    matcher->set_field(tagId);
+    matcher->add_child()->set_field(ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO);
+    FieldMatcher* child = matcher->mutable_child(0)->add_child();
+    child->set_field(UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+}
+
+void buildAttributionTagFieldMatcher(const int tagId, const Position position,
+                                     FieldMatcher *matcher) {
+    matcher->set_field(tagId);
+    FieldMatcher* child = matcher->add_child();
+    child->set_field(ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO);
+    child->set_position(position);
+    child = child->add_child();
+    child->set_field(TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+}
+
+void buildAttributionFieldMatcher(const int tagId, const Position position,
+                                  FieldMatcher *matcher) {
+    matcher->set_field(tagId);
+    FieldMatcher* child = matcher->add_child();
+    child->set_field(ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO);
+    child->set_position(position);
+    child = child->add_child();
+    child->set_field(UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+    child->set_field(TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+}
+
+void DimensionsValueToString(const DimensionsValue& value, std::string *flattened) {
+    *flattened += std::to_string(value.field());
+    *flattened += ":";
+    switch (value.value_case()) {
+        case DimensionsValue::ValueCase::kValueStr:
+            *flattened += value.value_str();
+            break;
+        case DimensionsValue::ValueCase::kValueInt:
+            *flattened += std::to_string(value.value_int());
+            break;
+        case DimensionsValue::ValueCase::kValueLong:
+            *flattened += std::to_string(value.value_long());
+            break;
+        case DimensionsValue::ValueCase::kValueBool:
+            *flattened += std::to_string(value.value_bool());
+            break;
+        case DimensionsValue::ValueCase::kValueFloat:
+            *flattened += std::to_string(value.value_float());
+            break;
+        case DimensionsValue::ValueCase::kValueTuple:
+            {
+                *flattened += "{";
+                for (int i = 0; i < value.value_tuple().dimensions_value_size(); ++i) {
+                    DimensionsValueToString(value.value_tuple().dimensions_value(i), flattened);
+                    *flattened += "|";
+                }
+                *flattened += "}";
+            }
+            break;
+        case DimensionsValue::ValueCase::VALUE_NOT_SET:
+            break;
+    }
+}
+
+void getDimensionsValueLeafNodes(
+    const DimensionsValue& value, std::vector<DimensionsValue> *leafNodes) {
+    switch (value.value_case()) {
+        case DimensionsValue::ValueCase::kValueStr:
+        case DimensionsValue::ValueCase::kValueInt:
+        case DimensionsValue::ValueCase::kValueLong:
+        case DimensionsValue::ValueCase::kValueBool:
+        case DimensionsValue::ValueCase::kValueFloat:
+            leafNodes->push_back(value);
+            break;
+        case DimensionsValue::ValueCase::kValueTuple:
+            for (int i = 0; i < value.value_tuple().dimensions_value_size(); ++i) {
+                getDimensionsValueLeafNodes(value.value_tuple().dimensions_value(i), leafNodes);
+            }
+            break;
+        case DimensionsValue::ValueCase::VALUE_NOT_SET:
+            break;
+        default:
+            break;
+    }
+}
+
+std::string DimensionsValueToString(const DimensionsValue& value) {
+    std::string flatten;
+    DimensionsValueToString(value, &flatten);
+    return flatten;
+}
+
+bool IsSubDimension(const DimensionsValue& dimension, const DimensionsValue& sub) {
+    if (dimension.field() != sub.field()) {
+        return false;
+    }
+    if (dimension.value_case() != sub.value_case()) {
+        return false;
+    }
+    switch (dimension.value_case()) {
+        case DimensionsValue::ValueCase::kValueStr:
+            return dimension.value_str() == sub.value_str();
+        case DimensionsValue::ValueCase::kValueInt:
+            return dimension.value_int() == sub.value_int();
+        case DimensionsValue::ValueCase::kValueLong:
+            return dimension.value_long() == sub.value_long();
+        case DimensionsValue::ValueCase::kValueBool:
+            return dimension.value_bool() == sub.value_bool();
+        case DimensionsValue::ValueCase::kValueFloat:
+            return dimension.value_float() == sub.value_float();
+        case DimensionsValue::ValueCase::kValueTuple: {
+            if (dimension.value_tuple().dimensions_value_size() < sub.value_tuple().dimensions_value_size()) {
+                return false;
+            }
+            bool allSub = true;
+            for (int i = 0; i < sub.value_tuple().dimensions_value_size(); ++i) {
+                bool isSub = false;
+                for (int j = 0; !isSub && j < dimension.value_tuple().dimensions_value_size(); ++j) {
+                    isSub |= IsSubDimension(dimension.value_tuple().dimensions_value(j),
+                                            sub.value_tuple().dimensions_value(i));
+                }
+                allSub &= isSub;
+            }
+            return allSub;
+        }
+        break;
+        case DimensionsValue::ValueCase::VALUE_NOT_SET:
+            return false;
+        default:
+            return false;
+    }
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android