blob: 7a1bb0c71373afd57d2dc57b346982afb1822a5c [file] [log] [blame]
Yao Chencaf339d2017-10-06 16:01:10 -07001/*
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
Yao Chen5110bed2017-10-23 12:50:02 -070017#define DEBUG false // STOPSHIP if true
Joe Onorato9fc9edf2017-10-15 20:08:52 -070018#include "Log.h"
Yao Chencaf339d2017-10-06 16:01:10 -070019
20#include "SimpleConditionTracker.h"
Yao Chenb3561512017-11-21 18:07:17 -080021#include "guardrail/StatsdStats.h"
Yangster-mac5503f5c2018-01-15 23:20:44 -080022#include "dimension.h"
Joe Onorato9fc9edf2017-10-15 20:08:52 -070023
Yao Chencaf339d2017-10-06 16:01:10 -070024#include <log/logprint.h>
25
Joe Onorato9fc9edf2017-10-15 20:08:52 -070026namespace android {
27namespace os {
28namespace statsd {
29
Yao Chen729093d2017-10-16 10:33:26 -070030using std::map;
Yao Chencaf339d2017-10-06 16:01:10 -070031using std::string;
32using std::unique_ptr;
33using std::unordered_map;
34using std::vector;
35
Yao Chencaf339d2017-10-06 16:01:10 -070036SimpleConditionTracker::SimpleConditionTracker(
Yangster-mac94e197c2018-01-02 16:03:03 -080037 const ConfigKey& key, const int64_t& id, const int index,
Stefan Lafon12d01fa2017-12-04 20:56:09 -080038 const SimplePredicate& simplePredicate,
Yangster-mac94e197c2018-01-02 16:03:03 -080039 const unordered_map<int64_t, int>& trackerNameIndexMap)
40 : ConditionTracker(id, index), mConfigKey(key) {
41 VLOG("creating SimpleConditionTracker %lld", (long long)mConditionId);
Stefan Lafon12d01fa2017-12-04 20:56:09 -080042 mCountNesting = simplePredicate.count_nesting();
Yao Chencaf339d2017-10-06 16:01:10 -070043
Stefan Lafon12d01fa2017-12-04 20:56:09 -080044 if (simplePredicate.has_start()) {
45 auto pair = trackerNameIndexMap.find(simplePredicate.start());
Yao Chencaf339d2017-10-06 16:01:10 -070046 if (pair == trackerNameIndexMap.end()) {
Yangster-mac94e197c2018-01-02 16:03:03 -080047 ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start());
Yao Chencaf339d2017-10-06 16:01:10 -070048 return;
49 }
50 mStartLogMatcherIndex = pair->second;
51 mTrackerIndex.insert(mStartLogMatcherIndex);
52 } else {
53 mStartLogMatcherIndex = -1;
54 }
55
Stefan Lafon12d01fa2017-12-04 20:56:09 -080056 if (simplePredicate.has_stop()) {
57 auto pair = trackerNameIndexMap.find(simplePredicate.stop());
Yao Chencaf339d2017-10-06 16:01:10 -070058 if (pair == trackerNameIndexMap.end()) {
Yangster-mac94e197c2018-01-02 16:03:03 -080059 ALOGW("Stop matcher %lld not found in the config", (long long)simplePredicate.stop());
Yao Chencaf339d2017-10-06 16:01:10 -070060 return;
61 }
62 mStopLogMatcherIndex = pair->second;
Yao Chen4b146852017-10-10 15:34:42 -070063 mTrackerIndex.insert(mStopLogMatcherIndex);
Yao Chencaf339d2017-10-06 16:01:10 -070064 } else {
65 mStopLogMatcherIndex = -1;
66 }
67
Stefan Lafon12d01fa2017-12-04 20:56:09 -080068 if (simplePredicate.has_stop_all()) {
69 auto pair = trackerNameIndexMap.find(simplePredicate.stop_all());
Yao Chencaf339d2017-10-06 16:01:10 -070070 if (pair == trackerNameIndexMap.end()) {
Yangster-mac94e197c2018-01-02 16:03:03 -080071 ALOGW("Stop all matcher %lld found in the config", (long long)simplePredicate.stop_all());
Yao Chencaf339d2017-10-06 16:01:10 -070072 return;
73 }
74 mStopAllLogMatcherIndex = pair->second;
75 mTrackerIndex.insert(mStopAllLogMatcherIndex);
76 } else {
77 mStopAllLogMatcherIndex = -1;
78 }
79
Yangster-mac20877162017-12-22 17:19:39 -080080 mOutputDimensions = simplePredicate.dimensions();
Yao Chen5154a3792017-10-30 22:57:06 -070081
Yangster-mac20877162017-12-22 17:19:39 -080082 if (mOutputDimensions.child_size() > 0) {
Yao Chen5154a3792017-10-30 22:57:06 -070083 mSliced = true;
84 }
85
Stefan Lafon12d01fa2017-12-04 20:56:09 -080086 if (simplePredicate.initial_value() == SimplePredicate_InitialValue_FALSE) {
Yao Chen967b2052017-11-07 16:36:43 -080087 mInitialValue = ConditionState::kFalse;
88 } else {
89 mInitialValue = ConditionState::kUnknown;
90 }
91
92 mNonSlicedConditionState = mInitialValue;
93
Yao Chencaf339d2017-10-06 16:01:10 -070094 mInitialized = true;
95}
96
97SimpleConditionTracker::~SimpleConditionTracker() {
98 VLOG("~SimpleConditionTracker()");
99}
100
Stefan Lafon12d01fa2017-12-04 20:56:09 -0800101bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig,
Yao Chencaf339d2017-10-06 16:01:10 -0700102 const vector<sp<ConditionTracker>>& allConditionTrackers,
Yangster-mac94e197c2018-01-02 16:03:03 -0800103 const unordered_map<int64_t, int>& conditionIdIndexMap,
Yao Chencaf339d2017-10-06 16:01:10 -0700104 vector<bool>& stack) {
105 // SimpleConditionTracker does not have dependency on other conditions, thus we just return
106 // if the initialization was successful.
107 return mInitialized;
108}
109
Yangster-mac94e197c2018-01-02 16:03:03 -0800110void print(map<HashableDimensionKey, int>& conditions, const int64_t& id) {
111 VLOG("%lld DUMP:", (long long)id);
Yao Chen729093d2017-10-16 10:33:26 -0700112 for (const auto& pair : conditions) {
Yao Chen967b2052017-11-07 16:36:43 -0800113 VLOG("\t%s : %d", pair.first.c_str(), pair.second);
Yao Chen729093d2017-10-16 10:33:26 -0700114 }
115}
116
Yao Chen967b2052017-11-07 16:36:43 -0800117void SimpleConditionTracker::handleStopAll(std::vector<ConditionState>& conditionCache,
118 std::vector<bool>& conditionChangedCache) {
119 // Unless the default condition is false, and there was nothing started, otherwise we have
120 // triggered a condition change.
121 conditionChangedCache[mIndex] =
122 (mInitialValue == ConditionState::kFalse && mSlicedConditionState.empty()) ? false
123 : true;
124
125 // After StopAll, we know everything has stopped. From now on, default condition is false.
126 mInitialValue = ConditionState::kFalse;
127 mSlicedConditionState.clear();
128 conditionCache[mIndex] = ConditionState::kFalse;
129}
130
Yao Chenb3561512017-11-21 18:07:17 -0800131bool SimpleConditionTracker::hitGuardRail(const HashableDimensionKey& newKey) {
132 if (!mSliced || mSlicedConditionState.find(newKey) != mSlicedConditionState.end()) {
133 // if the condition is not sliced or the key is not new, we are good!
134 return false;
135 }
136 // 1. Report the tuple count if the tuple count > soft limit
137 if (mSlicedConditionState.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
138 size_t newTupleCount = mSlicedConditionState.size() + 1;
Yangster-mac94e197c2018-01-02 16:03:03 -0800139 StatsdStats::getInstance().noteConditionDimensionSize(mConfigKey, mConditionId, newTupleCount);
Yao Chenb3561512017-11-21 18:07:17 -0800140 // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
141 if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800142 ALOGE("Predicate %lld dropping data for dimension key %s",
143 (long long)mConditionId, newKey.c_str());
Yao Chenb3561512017-11-21 18:07:17 -0800144 return true;
145 }
146 }
147 return false;
148}
149
Yao Chen967b2052017-11-07 16:36:43 -0800150void SimpleConditionTracker::handleConditionEvent(const HashableDimensionKey& outputKey,
151 bool matchStart,
152 std::vector<ConditionState>& conditionCache,
153 std::vector<bool>& conditionChangedCache) {
Yangster-mac20877162017-12-22 17:19:39 -0800154 if ((int)conditionChangedCache.size() <= mIndex) {
155 ALOGE("handleConditionEvent: param conditionChangedCache not initialized.");
156 return;
157 }
158 if ((int)conditionCache.size() <= mIndex) {
159 ALOGE("handleConditionEvent: param conditionCache not initialized.");
160 return;
161 }
Yao Chen967b2052017-11-07 16:36:43 -0800162 bool changed = false;
163 auto outputIt = mSlicedConditionState.find(outputKey);
164 ConditionState newCondition;
Yao Chenb3561512017-11-21 18:07:17 -0800165 if (hitGuardRail(outputKey)) {
166 conditionChangedCache[mIndex] = false;
167 // Tells the caller it's evaluated.
168 conditionCache[mIndex] = ConditionState::kUnknown;
169 return;
170 }
Yao Chen967b2052017-11-07 16:36:43 -0800171 if (outputIt == mSlicedConditionState.end()) {
172 // We get a new output key.
173 newCondition = matchStart ? ConditionState::kTrue : ConditionState::kFalse;
174 if (matchStart && mInitialValue != ConditionState::kTrue) {
Yangster-mac5503f5c2018-01-15 23:20:44 -0800175 mSlicedConditionState.insert(std::make_pair(outputKey, 1));
Yao Chen967b2052017-11-07 16:36:43 -0800176 changed = true;
177 } else if (mInitialValue != ConditionState::kFalse) {
178 // it's a stop and we don't have history about it.
179 // If the default condition is not false, it means this stop is valuable to us.
Yangster-mac5503f5c2018-01-15 23:20:44 -0800180 mSlicedConditionState.insert(std::make_pair(outputKey, 0));
Yao Chen967b2052017-11-07 16:36:43 -0800181 changed = true;
182 }
183 } else {
184 // we have history about this output key.
185 auto& startedCount = outputIt->second;
186 // assign the old value first.
187 newCondition = startedCount > 0 ? ConditionState::kTrue : ConditionState::kFalse;
188 if (matchStart) {
189 if (startedCount == 0) {
190 // This condition for this output key will change from false -> true
191 changed = true;
192 }
193
194 // it's ok to do ++ here, even if we don't count nesting. The >1 counts will be treated
195 // as 1 if not counting nesting.
196 startedCount++;
197 newCondition = ConditionState::kTrue;
198 } else {
199 // This is a stop event.
200 if (startedCount > 0) {
201 if (mCountNesting) {
202 startedCount--;
203 if (startedCount == 0) {
204 newCondition = ConditionState::kFalse;
205 }
206 } else {
207 // not counting nesting, so ignore the number of starts, stop now.
208 startedCount = 0;
209 newCondition = ConditionState::kFalse;
210 }
211 // if everything has stopped for this output key, condition true -> false;
212 if (startedCount == 0) {
213 changed = true;
214 }
215 }
216
217 // if default condition is false, it means we don't need to keep the false values.
218 if (mInitialValue == ConditionState::kFalse && startedCount == 0) {
219 mSlicedConditionState.erase(outputIt);
220 VLOG("erase key %s", outputKey.c_str());
221 }
222 }
223 }
224
225 // dump all dimensions for debugging
226 if (DEBUG) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800227 print(mSlicedConditionState, mConditionId);
Yao Chen967b2052017-11-07 16:36:43 -0800228 }
229
230 conditionChangedCache[mIndex] = changed;
231 conditionCache[mIndex] = newCondition;
232
Yangster-mac94e197c2018-01-02 16:03:03 -0800233 VLOG("SimplePredicate %lld nonSlicedChange? %d", (long long)mConditionId,
Yao Chen967b2052017-11-07 16:36:43 -0800234 conditionChangedCache[mIndex] == true);
235}
236
237void SimpleConditionTracker::evaluateCondition(const LogEvent& event,
Yao Chencaf339d2017-10-06 16:01:10 -0700238 const vector<MatchingState>& eventMatcherValues,
239 const vector<sp<ConditionTracker>>& mAllConditions,
240 vector<ConditionState>& conditionCache,
Yao Chen967b2052017-11-07 16:36:43 -0800241 vector<bool>& conditionChangedCache) {
Yao Chencaf339d2017-10-06 16:01:10 -0700242 if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
243 // it has been evaluated.
Yangster-mac94e197c2018-01-02 16:03:03 -0800244 VLOG("Yes, already evaluated, %lld %d",
245 (long long)mConditionId, conditionCache[mIndex]);
Yao Chen967b2052017-11-07 16:36:43 -0800246 return;
Yao Chencaf339d2017-10-06 16:01:10 -0700247 }
248
David Chenc18abed2017-11-22 16:47:59 -0800249 if (mStopAllLogMatcherIndex >= 0 && mStopAllLogMatcherIndex < int(eventMatcherValues.size()) &&
Yao Chen967b2052017-11-07 16:36:43 -0800250 eventMatcherValues[mStopAllLogMatcherIndex] == MatchingState::kMatched) {
251 handleStopAll(conditionCache, conditionChangedCache);
252 return;
253 }
Yao Chen729093d2017-10-16 10:33:26 -0700254
Yao Chen967b2052017-11-07 16:36:43 -0800255 int matchedState = -1;
Yao Chencaf339d2017-10-06 16:01:10 -0700256 // Note: The order to evaluate the following start, stop, stop_all matters.
257 // The priority of overwrite is stop_all > stop > start.
258 if (mStartLogMatcherIndex >= 0 &&
259 eventMatcherValues[mStartLogMatcherIndex] == MatchingState::kMatched) {
Yao Chen967b2052017-11-07 16:36:43 -0800260 matchedState = 1;
Yao Chencaf339d2017-10-06 16:01:10 -0700261 }
262
263 if (mStopLogMatcherIndex >= 0 &&
264 eventMatcherValues[mStopLogMatcherIndex] == MatchingState::kMatched) {
Yao Chen967b2052017-11-07 16:36:43 -0800265 matchedState = 0;
Yao Chencaf339d2017-10-06 16:01:10 -0700266 }
267
Yao Chen967b2052017-11-07 16:36:43 -0800268 if (matchedState < 0) {
Yao Chend41c4222017-11-15 19:26:14 -0800269 // The event doesn't match this condition. So we just report existing condition values.
Yao Chen967b2052017-11-07 16:36:43 -0800270 conditionChangedCache[mIndex] = false;
Yao Chend41c4222017-11-15 19:26:14 -0800271 if (mSliced) {
272 // if the condition result is sliced. metrics won't directly get value from the
273 // cache, so just set any value other than kNotEvaluated.
274 conditionCache[mIndex] = ConditionState::kUnknown;
Yao Chend41c4222017-11-15 19:26:14 -0800275 } else {
Yangster7c334a12017-11-22 14:24:24 -0800276 const auto& itr = mSlicedConditionState.find(DEFAULT_DIMENSION_KEY);
277 if (itr == mSlicedConditionState.end()) {
278 // condition not sliced, but we haven't seen the matched start or stop yet. so
279 // return initial value.
280 conditionCache[mIndex] = mInitialValue;
281 } else {
282 // return the cached condition.
283 conditionCache[mIndex] =
284 itr->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
285 }
Yao Chend41c4222017-11-15 19:26:14 -0800286 }
Yangster7c334a12017-11-22 14:24:24 -0800287
Yao Chen967b2052017-11-07 16:36:43 -0800288 return;
Yao Chen729093d2017-10-16 10:33:26 -0700289 }
290
Yangster-mac20877162017-12-22 17:19:39 -0800291 // outputKey is the output values. e.g, uid:1234
292 const std::vector<DimensionsValue> outputValues = getDimensionKeys(event, mOutputDimensions);
293 if (outputValues.size() == 0) {
294 // The original implementation would generate an empty string dimension hash when condition
295 // is not sliced.
296 handleConditionEvent(
297 DEFAULT_DIMENSION_KEY, matchedState == 1, conditionCache, conditionChangedCache);
298 } else if (outputValues.size() == 1) {
299 handleConditionEvent(HashableDimensionKey(outputValues[0]), matchedState == 1,
300 conditionCache, conditionChangedCache);
301 } else {
302 // If this event has multiple nodes in the attribution chain, this log event probably will
303 // generate multiple dimensions. If so, we will find if the condition changes for any
304 // dimension and ask the corresponding metric producer to verify whether the actual sliced
305 // condition has changed or not.
306 // A high level assumption is that a predicate is either sliced or unsliced. We will never
307 // have both sliced and unsliced version of a predicate.
308 for (const DimensionsValue& outputValue : outputValues) {
309 vector<ConditionState> dimensionalConditionCache(conditionCache.size(),
310 ConditionState::kNotEvaluated);
311 vector<bool> dimensionalConditionChangedCache(conditionChangedCache.size(), false);
312
313 handleConditionEvent(HashableDimensionKey(outputValue), matchedState == 1,
314 dimensionalConditionCache, dimensionalConditionChangedCache);
315
316 OrConditionState(dimensionalConditionCache, &conditionCache);
317 OrBooleanVector(dimensionalConditionChangedCache, &conditionChangedCache);
318 }
319 }
Yao Chen729093d2017-10-16 10:33:26 -0700320}
321
322void SimpleConditionTracker::isConditionMet(
Yangster-mac20877162017-12-22 17:19:39 -0800323 const ConditionKey& conditionParameters,
Yangster7c334a12017-11-22 14:24:24 -0800324 const vector<sp<ConditionTracker>>& allConditions,
325 vector<ConditionState>& conditionCache) const {
Yangster-mac94e197c2018-01-02 16:03:03 -0800326 const auto pair = conditionParameters.find(mConditionId);
Yao Chen967b2052017-11-07 16:36:43 -0800327
Yangster-mac20877162017-12-22 17:19:39 -0800328 if (pair == conditionParameters.end() && mOutputDimensions.child_size() > 0) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800329 ALOGE("Predicate %lld output has dimension, but it's not specified in the query!",
330 (long long)mConditionId);
Yao Chen967b2052017-11-07 16:36:43 -0800331 conditionCache[mIndex] = mInitialValue;
Yao Chen729093d2017-10-16 10:33:26 -0700332 return;
333 }
Yangster-mac20877162017-12-22 17:19:39 -0800334 std::vector<HashableDimensionKey> defaultKeys = {DEFAULT_DIMENSION_KEY};
335 const std::vector<HashableDimensionKey> &keys =
336 (pair == conditionParameters.end()) ? defaultKeys : pair->second;
Yao Chen729093d2017-10-16 10:33:26 -0700337
Yangster-mac20877162017-12-22 17:19:39 -0800338 ConditionState conditionState = ConditionState::kNotEvaluated;
339 for (const auto& key : keys) {
340 auto startedCountIt = mSlicedConditionState.find(key);
341 if (startedCountIt != mSlicedConditionState.end()) {
342 conditionState = conditionState |
343 (startedCountIt->second > 0 ? ConditionState::kTrue : ConditionState::kFalse);
344 } else {
Yangster-mac5503f5c2018-01-15 23:20:44 -0800345 // For unseen key, check whether the require dimensions are subset of sliced condition
346 // output.
347 bool seenDimension = false;
348 for (const auto& slice : mSlicedConditionState) {
349 if (IsSubDimension(slice.first.getDimensionsValue(),
350 key.getDimensionsValue())) {
351 seenDimension = true;
352 conditionState = conditionState |
353 (slice.second > 0 ? ConditionState::kTrue : ConditionState::kFalse);
354 }
355 if (conditionState == ConditionState::kTrue) {
356 break;
357 }
358 }
359 if (!seenDimension) {
360 conditionState = conditionState | mInitialValue;
361 }
Yangster-mac20877162017-12-22 17:19:39 -0800362 }
Yao Chen729093d2017-10-16 10:33:26 -0700363 }
Yangster-mac20877162017-12-22 17:19:39 -0800364 conditionCache[mIndex] = conditionState;
Yangster-mac94e197c2018-01-02 16:03:03 -0800365 VLOG("Predicate %lld return %d", (long long)mConditionId, conditionCache[mIndex]);
Yao Chencaf339d2017-10-06 16:01:10 -0700366}
367
368} // namespace statsd
369} // namespace os
370} // namespace android