blob: 1965ce6015ff0dae8bd6326713c492eaba90a18a [file] [log] [blame]
Yao Chen580ea3212018-02-26 14:21:54 -08001/*
2 * Copyright 2018, 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#define DEBUG false // STOPSHIP if true
17#include "Log.h"
18
19#include "StateTracker.h"
20#include "guardrail/StatsdStats.h"
21
22namespace android {
23namespace os {
24namespace statsd {
25
26using std::string;
27using std::unordered_set;
28using std::vector;
29
30StateTracker::StateTracker(const ConfigKey& key, const int64_t& id, const int index,
31 const SimplePredicate& simplePredicate,
32 const unordered_map<int64_t, int>& trackerNameIndexMap,
33 const vector<Matcher> primaryKeys)
34 : ConditionTracker(id, index), mConfigKey(key), mPrimaryKeys(primaryKeys) {
35 if (simplePredicate.has_start()) {
36 auto pair = trackerNameIndexMap.find(simplePredicate.start());
37 if (pair == trackerNameIndexMap.end()) {
38 ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start());
39 return;
40 }
41 mStartLogMatcherIndex = pair->second;
42 mTrackerIndex.insert(mStartLogMatcherIndex);
43 } else {
44 ALOGW("Condition %lld must have a start matcher", (long long)id);
45 return;
46 }
47
48 if (simplePredicate.has_dimensions()) {
49 translateFieldMatcher(simplePredicate.dimensions(), &mOutputDimensions);
50 if (mOutputDimensions.size() > 0) {
51 mSliced = true;
52 mDimensionTag = mOutputDimensions[0].mMatcher.getTag();
53 } else {
54 ALOGW("Condition %lld has invalid dimensions", (long long)id);
55 return;
56 }
57 } else {
58 ALOGW("Condition %lld being a state tracker, but has no dimension", (long long)id);
59 return;
60 }
61
62 if (simplePredicate.initial_value() == SimplePredicate_InitialValue_FALSE) {
63 mInitialValue = ConditionState::kFalse;
64 } else {
65 mInitialValue = ConditionState::kUnknown;
66 }
67
68 mNonSlicedConditionState = mInitialValue;
69 mInitialized = true;
70}
71
72StateTracker::~StateTracker() {
73 VLOG("~StateTracker()");
74}
75
76bool StateTracker::init(const vector<Predicate>& allConditionConfig,
77 const vector<sp<ConditionTracker>>& allConditionTrackers,
78 const unordered_map<int64_t, int>& conditionIdIndexMap,
79 vector<bool>& stack) {
80 return mInitialized;
81}
82
83void StateTracker::dumpState() {
84 VLOG("StateTracker %lld DUMP:", (long long)mConditionId);
85 for (const auto& value : mSlicedState) {
86 VLOG("\t%s -> %s", value.first.toString().c_str(), value.second.toString().c_str());
87 }
88 VLOG("Last Changed to True: ");
89 for (const auto& value : mLastChangedToTrueDimensions) {
90 VLOG("%s", value.toString().c_str());
91 }
92 VLOG("Last Changed to False: ");
93 for (const auto& value : mLastChangedToFalseDimensions) {
94 VLOG("%s", value.toString().c_str());
95 }
96}
97
98bool StateTracker::hitGuardRail(const HashableDimensionKey& newKey) {
99 if (mSlicedState.find(newKey) != mSlicedState.end()) {
100 // if the condition is not sliced or the key is not new, we are good!
101 return false;
102 }
103 // 1. Report the tuple count if the tuple count > soft limit
104 if (mSlicedState.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
105 size_t newTupleCount = mSlicedState.size() + 1;
106 StatsdStats::getInstance().noteConditionDimensionSize(mConfigKey, mConditionId, newTupleCount);
107 // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
108 if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
109 ALOGE("Predicate %lld dropping data for dimension key %s",
Yangster13fb7e42018-03-07 17:30:49 -0800110 (long long)mConditionId, newKey.toString().c_str());
Yao Chen580ea3212018-02-26 14:21:54 -0800111 return true;
112 }
113 }
114 return false;
115}
116
117void StateTracker::evaluateCondition(const LogEvent& event,
118 const vector<MatchingState>& eventMatcherValues,
119 const vector<sp<ConditionTracker>>& mAllConditions,
120 vector<ConditionState>& conditionCache,
121 vector<bool>& conditionChangedCache) {
122 mLastChangedToTrueDimensions.clear();
123 mLastChangedToFalseDimensions.clear();
124 if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
125 // it has been evaluated.
126 VLOG("Yes, already evaluated, %lld %d", (long long)mConditionId, conditionCache[mIndex]);
127 return;
128 }
129
130 if (mStartLogMatcherIndex >= 0 &&
131 eventMatcherValues[mStartLogMatcherIndex] != MatchingState::kMatched) {
132 conditionCache[mIndex] =
133 mSlicedState.size() > 0 ? ConditionState::kTrue : ConditionState::kFalse;
134 conditionChangedCache[mIndex] = false;
135 return;
136 }
137
138 VLOG("StateTracker evaluate event %s", event.ToString().c_str());
139
Yangster-mace06cfd72018-03-10 23:22:59 -0800140 // Primary key can exclusive fields must be simple fields. so there won't be more than
141 // one keys matched.
142 HashableDimensionKey primaryKey;
143 HashableDimensionKey state;
Yao Chen427d37252018-03-22 15:21:52 -0700144 if ((mPrimaryKeys.size() > 0 && !filterValues(mPrimaryKeys, event.getValues(), &primaryKey)) ||
Yangster-mace06cfd72018-03-10 23:22:59 -0800145 !filterValues(mOutputDimensions, event.getValues(), &state)) {
146 ALOGE("Failed to filter fields in the event?? panic now!");
Yao Chen580ea3212018-02-26 14:21:54 -0800147 conditionCache[mIndex] =
148 mSlicedState.size() > 0 ? ConditionState::kTrue : ConditionState::kFalse;
149 conditionChangedCache[mIndex] = false;
150 return;
151 }
Yao Chen580ea3212018-02-26 14:21:54 -0800152 hitGuardRail(primaryKey);
153
154 VLOG("StateTracker: key %s state %s", primaryKey.toString().c_str(), state.toString().c_str());
155
156 auto it = mSlicedState.find(primaryKey);
157 if (it == mSlicedState.end()) {
158 mSlicedState[primaryKey] = state;
159 conditionCache[mIndex] = ConditionState::kTrue;
160 mLastChangedToTrueDimensions.insert(state);
161 conditionChangedCache[mIndex] = true;
162 } else if (!(it->second == state)) {
163 mLastChangedToFalseDimensions.insert(it->second);
164 mLastChangedToTrueDimensions.insert(state);
165 mSlicedState[primaryKey] = state;
166 conditionCache[mIndex] = ConditionState::kTrue;
167 conditionChangedCache[mIndex] = true;
168 } else {
169 conditionCache[mIndex] = ConditionState::kTrue;
170 conditionChangedCache[mIndex] = false;
171 }
172
173 if (DEBUG) {
174 dumpState();
175 }
176 return;
177}
178
179void StateTracker::isConditionMet(
180 const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
Yangster13fb7e42018-03-07 17:30:49 -0800181 const vector<Matcher>& dimensionFields,
182 const bool isSubOutputDimensionFields,
183 const bool isPartialLink,
184 vector<ConditionState>& conditionCache,
Yao Chen580ea3212018-02-26 14:21:54 -0800185 std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
186 if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
187 // it has been evaluated.
188 VLOG("Yes, already evaluated, %lld %d", (long long)mConditionId, conditionCache[mIndex]);
189 return;
190 }
191
192 const auto pair = conditionParameters.find(mConditionId);
193 if (pair == conditionParameters.end()) {
194 if (mSlicedState.size() > 0) {
195 conditionCache[mIndex] = ConditionState::kTrue;
196
197 for (const auto& state : mSlicedState) {
198 dimensionsKeySet.insert(state.second);
199 }
200 } else {
201 conditionCache[mIndex] = ConditionState::kUnknown;
202 }
203 return;
204 }
205
Yangster13fb7e42018-03-07 17:30:49 -0800206 const auto& primaryKey = pair->second;
Yao Chen580ea3212018-02-26 14:21:54 -0800207 conditionCache[mIndex] = mInitialValue;
Yangster13fb7e42018-03-07 17:30:49 -0800208 auto it = mSlicedState.find(primaryKey);
209 if (it != mSlicedState.end()) {
210 conditionCache[mIndex] = ConditionState::kTrue;
211 dimensionsKeySet.insert(it->second);
Yao Chen580ea3212018-02-26 14:21:54 -0800212 }
213}
214
215ConditionState StateTracker::getMetConditionDimension(
216 const std::vector<sp<ConditionTracker>>& allConditions,
217 const vector<Matcher>& dimensionFields,
Yangster13fb7e42018-03-07 17:30:49 -0800218 const bool isSubOutputDimensionFields,
Yao Chen580ea3212018-02-26 14:21:54 -0800219 std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
220 if (mSlicedState.size() > 0) {
221 for (const auto& state : mSlicedState) {
222 dimensionsKeySet.insert(state.second);
223 }
224 return ConditionState::kTrue;
225 }
226
227 return mInitialValue;
228}
229
230} // namespace statsd
231} // namespace os
232} // namespace android