condition_util.cpp revision 7ba8fc357e44ee3bb8e614c202852a1c46a9d4a8
1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Log.h"
18
19#include "condition_util.h"
20
21#include <log/event_tag_map.h>
22#include <log/log_event_list.h>
23#include <log/logprint.h>
24#include <utils/Errors.h>
25#include <unordered_map>
26#include "../matchers/matcher_util.h"
27#include "ConditionTracker.h"
28#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
29#include "stats_util.h"
30#include "dimension.h"
31
32namespace android {
33namespace os {
34namespace statsd {
35
36using std::set;
37using std::string;
38using std::unordered_map;
39using std::vector;
40
41
42ConditionState evaluateCombinationCondition(const std::vector<int>& children,
43                                            const LogicalOperation& operation,
44                                            const std::vector<ConditionState>& conditionCache) {
45    ConditionState newCondition;
46
47    bool hasUnknown = false;
48    bool hasFalse = false;
49    bool hasTrue = false;
50
51    for (auto childIndex : children) {
52        ConditionState childState = conditionCache[childIndex];
53        if (childState == ConditionState::kUnknown) {
54            hasUnknown = true;
55            break;
56        }
57        if (childState == ConditionState::kFalse) {
58            hasFalse = true;
59        }
60        if (childState == ConditionState::kTrue) {
61            hasTrue = true;
62        }
63    }
64
65    // If any child condition is in unknown state, the condition is unknown too.
66    if (hasUnknown) {
67        return ConditionState::kUnknown;
68    }
69
70    switch (operation) {
71        case LogicalOperation::AND: {
72            newCondition = hasFalse ? ConditionState::kFalse : ConditionState::kTrue;
73            break;
74        }
75        case LogicalOperation::OR: {
76            newCondition = hasTrue ? ConditionState::kTrue : ConditionState::kFalse;
77            break;
78        }
79        case LogicalOperation::NOT:
80            newCondition = (conditionCache[children[0]] == ConditionState::kFalse)
81                                   ? ConditionState::kTrue
82                                   : ConditionState::kFalse;
83            break;
84        case LogicalOperation::NAND:
85            newCondition = hasFalse ? ConditionState::kTrue : ConditionState::kFalse;
86            break;
87        case LogicalOperation::NOR:
88            newCondition = hasTrue ? ConditionState::kFalse : ConditionState::kTrue;
89            break;
90        case LogicalOperation::LOGICAL_OPERATION_UNSPECIFIED:
91            newCondition = ConditionState::kFalse;
92            break;
93    }
94    return newCondition;
95}
96
97ConditionState operator|(ConditionState l, ConditionState r) {
98    return l >= r ? l : r;
99}
100
101void OrConditionState(const std::vector<ConditionState>& ref, vector<ConditionState> * ored) {
102    if (ref.size() != ored->size()) {
103        return;
104    }
105    for (size_t i = 0; i < ored->size(); ++i) {
106        ored->at(i) = ored->at(i) | ref.at(i);
107    }
108}
109
110void OrBooleanVector(const std::vector<bool>& ref, vector<bool> * ored) {
111    if (ref.size() != ored->size()) {
112        return;
113    }
114    for (size_t i = 0; i < ored->size(); ++i) {
115        ored->at(i) = ored->at(i) | ref.at(i);
116    }
117}
118
119void getFieldsFromFieldMatcher(const FieldMatcher& matcher, Field* rootField, Field* leafField,
120                               std::vector<Field> *allFields) {
121    if (matcher.child_size() == 0) {
122        allFields->push_back(*rootField);
123        return;
124    }
125    for (int i = 0; i < matcher.child_size(); ++i) {
126        Field* newLeafField = leafField->add_child();
127        newLeafField->set_field(matcher.child(i).field());
128        getFieldsFromFieldMatcher(matcher.child(i), rootField, newLeafField, allFields);
129    }
130}
131
132void getFieldsFromFieldMatcher(const FieldMatcher& matcher, std::vector<Field> *allFields) {
133    if (!matcher.has_field()) {
134        return;
135    }
136    Field rootField;
137    rootField.set_field(matcher.field());
138    getFieldsFromFieldMatcher(matcher, &rootField, &rootField, allFields);
139}
140
141void flattenValueLeaves(const DimensionsValue& value,
142                        std::vector<const DimensionsValue*> *allLaves) {
143    switch (value.value_case()) {
144        case DimensionsValue::ValueCase::kValueStr:
145        case DimensionsValue::ValueCase::kValueInt:
146        case DimensionsValue::ValueCase::kValueLong:
147        case DimensionsValue::ValueCase::kValueBool:
148        case DimensionsValue::ValueCase::kValueFloat:
149        case DimensionsValue::ValueCase::VALUE_NOT_SET:
150            allLaves->push_back(&value);
151            break;
152        case DimensionsValue::ValueCase::kValueTuple:
153            for (int i = 0; i < value.value_tuple().dimensions_value_size(); ++i) {
154                flattenValueLeaves(value.value_tuple().dimensions_value(i), allLaves);
155            }
156            break;
157    }
158}
159
160void getDimensionKeysForCondition(
161    const LogEvent& event, const MetricConditionLink& link,
162    std::vector<HashableDimensionKey> *hashableDimensionKeys) {
163    std::vector<Field> whatFields;
164    getFieldsFromFieldMatcher(link.fields_in_what(), &whatFields);
165    std::vector<Field> conditionFields;
166    getFieldsFromFieldMatcher(link.fields_in_condition(), &conditionFields);
167
168    // TODO(yanglu): here we could simplify the logic to get the leaf value node in what and
169    // directly construct the full condition value tree.
170    std::vector<DimensionsValue> whatValues;
171    getDimensionKeys(event, link.fields_in_what(), &whatValues);
172
173    for (size_t i = 0; i < whatValues.size(); ++i) {
174        std::vector<const DimensionsValue*> whatLeaves;
175        flattenValueLeaves(whatValues[i], &whatLeaves);
176        if (whatLeaves.size() != whatFields.size() ||
177            whatLeaves.size() != conditionFields.size()) {
178            ALOGE("Dimensions between what and condition not equal.");
179            return;
180        }
181        FieldValueMap conditionValueMap;
182        for (size_t j = 0; j < whatLeaves.size(); ++j) {
183            DimensionsValue* conditionValue = &conditionValueMap[conditionFields[j]];
184            *conditionValue = *whatLeaves[i];
185            if (!setFieldInLeafValueProto(conditionFields[j], conditionValue)) {
186                ALOGE("Not able to reset the field for condition leaf value.");
187                return;
188            }
189        }
190        std::vector<DimensionsValue> conditionValueTrees;
191        findDimensionsValues(conditionValueMap, link.fields_in_condition(), &conditionValueTrees);
192        if (conditionValueTrees.size() != 1) {
193            ALOGE("Not able to find unambiguous field value in condition atom.");
194            continue;
195        }
196        hashableDimensionKeys->push_back(HashableDimensionKey(conditionValueTrees[0]));
197    }
198}
199
200}  // namespace statsd
201}  // namespace os
202}  // namespace android
203