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