condition_util.cpp revision 9369446f0b04945d6674550728ae81196d6fb5c2
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.has_position()) {
122        leafField->set_position_index(0);
123    }
124    if (matcher.child_size() == 0) {
125        allFields->push_back(*rootField);
126        return;
127    }
128    for (int i = 0; i < matcher.child_size(); ++i) {
129        Field* newLeafField = leafField->add_child();
130        newLeafField->set_field(matcher.child(i).field());
131        getFieldsFromFieldMatcher(matcher.child(i), rootField, newLeafField, allFields);
132    }
133}
134
135void getFieldsFromFieldMatcher(const FieldMatcher& matcher, std::vector<Field> *allFields) {
136    if (!matcher.has_field()) {
137        return;
138    }
139    Field rootField;
140    rootField.set_field(matcher.field());
141    getFieldsFromFieldMatcher(matcher, &rootField, &rootField, allFields);
142}
143
144void flattenValueLeaves(const DimensionsValue& value,
145                        std::vector<const DimensionsValue*> *allLaves) {
146    switch (value.value_case()) {
147        case DimensionsValue::ValueCase::kValueStr:
148        case DimensionsValue::ValueCase::kValueInt:
149        case DimensionsValue::ValueCase::kValueLong:
150        case DimensionsValue::ValueCase::kValueBool:
151        case DimensionsValue::ValueCase::kValueFloat:
152        case DimensionsValue::ValueCase::VALUE_NOT_SET:
153            allLaves->push_back(&value);
154            break;
155        case DimensionsValue::ValueCase::kValueTuple:
156            for (int i = 0; i < value.value_tuple().dimensions_value_size(); ++i) {
157                flattenValueLeaves(value.value_tuple().dimensions_value(i), allLaves);
158            }
159            break;
160    }
161}
162
163void getDimensionKeysForCondition(
164    const LogEvent& event, const MetricConditionLink& link,
165    std::vector<HashableDimensionKey> *hashableDimensionKeys) {
166    std::vector<Field> whatFields;
167    getFieldsFromFieldMatcher(link.fields_in_what(), &whatFields);
168    std::vector<Field> conditionFields;
169    getFieldsFromFieldMatcher(link.fields_in_condition(), &conditionFields);
170
171    // TODO(yanglu): here we could simplify the logic to get the leaf value node in what and
172    // directly construct the full condition value tree.
173    std::vector<DimensionsValue> whatValues;
174    getDimensionKeys(event, link.fields_in_what(), &whatValues);
175
176    for (size_t i = 0; i < whatValues.size(); ++i) {
177        std::vector<const DimensionsValue*> whatLeaves;
178        flattenValueLeaves(whatValues[i], &whatLeaves);
179        if (whatLeaves.size() != whatFields.size() ||
180            whatLeaves.size() != conditionFields.size()) {
181            ALOGE("Dimensions between what and condition not equal.");
182            return;
183        }
184        FieldValueMap conditionValueMap;
185        for (size_t j = 0; j < whatLeaves.size(); ++j) {
186            DimensionsValue* conditionValue = &conditionValueMap[conditionFields[j]];
187            *conditionValue = *whatLeaves[i];
188            if (!setFieldInLeafValueProto(conditionFields[j], conditionValue)) {
189                ALOGE("Not able to reset the field for condition leaf value.");
190                return;
191            }
192        }
193        std::vector<DimensionsValue> conditionValueTrees;
194        findDimensionsValues(conditionValueMap, link.fields_in_condition(), &conditionValueTrees);
195        if (conditionValueTrees.size() != 1) {
196            ALOGE("Not able to find unambiguous field value in condition atom.");
197            continue;
198        }
199        hashableDimensionKeys->push_back(HashableDimensionKey(conditionValueTrees[0]));
200    }
201}
202
203}  // namespace statsd
204}  // namespace os
205}  // namespace android
206