blob: f23ec50abb5099dda447d0b9df3da96e31733be2 [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"
Joe Onorato9fc9edf2017-10-15 20:08:52 -070022
Joe Onorato9fc9edf2017-10-15 20:08:52 -070023namespace android {
24namespace os {
25namespace statsd {
26
Yao Chencaf339d2017-10-06 16:01:10 -070027using std::unordered_map;
Yao Chencaf339d2017-10-06 16:01:10 -070028
Yao Chencaf339d2017-10-06 16:01:10 -070029SimpleConditionTracker::SimpleConditionTracker(
Yangster-mac94e197c2018-01-02 16:03:03 -080030 const ConfigKey& key, const int64_t& id, const int index,
Stefan Lafon12d01fa2017-12-04 20:56:09 -080031 const SimplePredicate& simplePredicate,
Yangster-mac94e197c2018-01-02 16:03:03 -080032 const unordered_map<int64_t, int>& trackerNameIndexMap)
Yangster13fb7e42018-03-07 17:30:49 -080033 : ConditionTracker(id, index), mConfigKey(key), mContainANYPositionInInternalDimensions(false) {
Yangster-mac94e197c2018-01-02 16:03:03 -080034 VLOG("creating SimpleConditionTracker %lld", (long long)mConditionId);
Stefan Lafon12d01fa2017-12-04 20:56:09 -080035 mCountNesting = simplePredicate.count_nesting();
Yao Chencaf339d2017-10-06 16:01:10 -070036
Stefan Lafon12d01fa2017-12-04 20:56:09 -080037 if (simplePredicate.has_start()) {
38 auto pair = trackerNameIndexMap.find(simplePredicate.start());
Yao Chencaf339d2017-10-06 16:01:10 -070039 if (pair == trackerNameIndexMap.end()) {
Yangster-mac94e197c2018-01-02 16:03:03 -080040 ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start());
Yao Chencaf339d2017-10-06 16:01:10 -070041 return;
42 }
43 mStartLogMatcherIndex = pair->second;
44 mTrackerIndex.insert(mStartLogMatcherIndex);
45 } else {
46 mStartLogMatcherIndex = -1;
47 }
48
Stefan Lafon12d01fa2017-12-04 20:56:09 -080049 if (simplePredicate.has_stop()) {
50 auto pair = trackerNameIndexMap.find(simplePredicate.stop());
Yao Chencaf339d2017-10-06 16:01:10 -070051 if (pair == trackerNameIndexMap.end()) {
Yangster-mac94e197c2018-01-02 16:03:03 -080052 ALOGW("Stop matcher %lld not found in the config", (long long)simplePredicate.stop());
Yao Chencaf339d2017-10-06 16:01:10 -070053 return;
54 }
55 mStopLogMatcherIndex = pair->second;
Yao Chen4b146852017-10-10 15:34:42 -070056 mTrackerIndex.insert(mStopLogMatcherIndex);
Yao Chencaf339d2017-10-06 16:01:10 -070057 } else {
58 mStopLogMatcherIndex = -1;
59 }
60
Stefan Lafon12d01fa2017-12-04 20:56:09 -080061 if (simplePredicate.has_stop_all()) {
62 auto pair = trackerNameIndexMap.find(simplePredicate.stop_all());
Yao Chencaf339d2017-10-06 16:01:10 -070063 if (pair == trackerNameIndexMap.end()) {
Yangster-mac94e197c2018-01-02 16:03:03 -080064 ALOGW("Stop all matcher %lld found in the config", (long long)simplePredicate.stop_all());
Yao Chencaf339d2017-10-06 16:01:10 -070065 return;
66 }
67 mStopAllLogMatcherIndex = pair->second;
68 mTrackerIndex.insert(mStopAllLogMatcherIndex);
69 } else {
70 mStopAllLogMatcherIndex = -1;
71 }
72
Yao Chen8a8d16c2018-02-08 14:50:40 -080073 if (simplePredicate.has_dimensions()) {
74 translateFieldMatcher(simplePredicate.dimensions(), &mOutputDimensions);
75 if (mOutputDimensions.size() > 0) {
76 mSliced = true;
77 mDimensionTag = mOutputDimensions[0].mMatcher.getTag();
78 }
Yangster13fb7e42018-03-07 17:30:49 -080079 mContainANYPositionInInternalDimensions = HasPositionANY(simplePredicate.dimensions());
Yao Chen5154a3792017-10-30 22:57:06 -070080 }
81
Stefan Lafon12d01fa2017-12-04 20:56:09 -080082 if (simplePredicate.initial_value() == SimplePredicate_InitialValue_FALSE) {
Yao Chen967b2052017-11-07 16:36:43 -080083 mInitialValue = ConditionState::kFalse;
84 } else {
85 mInitialValue = ConditionState::kUnknown;
86 }
87
Yao Chencaf339d2017-10-06 16:01:10 -070088 mInitialized = true;
89}
90
91SimpleConditionTracker::~SimpleConditionTracker() {
92 VLOG("~SimpleConditionTracker()");
93}
94
Stefan Lafon12d01fa2017-12-04 20:56:09 -080095bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig,
Yao Chencaf339d2017-10-06 16:01:10 -070096 const vector<sp<ConditionTracker>>& allConditionTrackers,
Yangster-mac94e197c2018-01-02 16:03:03 -080097 const unordered_map<int64_t, int>& conditionIdIndexMap,
Yao Chencaf339d2017-10-06 16:01:10 -070098 vector<bool>& stack) {
99 // SimpleConditionTracker does not have dependency on other conditions, thus we just return
100 // if the initialization was successful.
101 return mInitialized;
102}
103
Yao Chen580ea3212018-02-26 14:21:54 -0800104void SimpleConditionTracker::dumpState() {
105 VLOG("%lld DUMP:", (long long)mConditionId);
106 for (const auto& pair : mSlicedConditionState) {
Yangster13fb7e42018-03-07 17:30:49 -0800107 VLOG("\t%s : %d", pair.first.toString().c_str(), pair.second);
Yao Chen729093d2017-10-16 10:33:26 -0700108 }
Yao Chen580ea3212018-02-26 14:21:54 -0800109
110 VLOG("Changed to true keys: \n");
111 for (const auto& key : mLastChangedToTrueDimensions) {
112 VLOG("%s", key.toString().c_str());
113 }
114 VLOG("Changed to false keys: \n");
115 for (const auto& key : mLastChangedToFalseDimensions) {
116 VLOG("%s", key.toString().c_str());
117 }
Yao Chen729093d2017-10-16 10:33:26 -0700118}
119
Yao Chen967b2052017-11-07 16:36:43 -0800120void SimpleConditionTracker::handleStopAll(std::vector<ConditionState>& conditionCache,
121 std::vector<bool>& conditionChangedCache) {
122 // Unless the default condition is false, and there was nothing started, otherwise we have
123 // triggered a condition change.
124 conditionChangedCache[mIndex] =
125 (mInitialValue == ConditionState::kFalse && mSlicedConditionState.empty()) ? false
126 : true;
127
Yao Chen580ea3212018-02-26 14:21:54 -0800128 for (const auto& cond : mSlicedConditionState) {
129 if (cond.second > 0) {
130 mLastChangedToFalseDimensions.insert(cond.first);
131 }
132 }
133
Yao Chen967b2052017-11-07 16:36:43 -0800134 // After StopAll, we know everything has stopped. From now on, default condition is false.
135 mInitialValue = ConditionState::kFalse;
136 mSlicedConditionState.clear();
137 conditionCache[mIndex] = ConditionState::kFalse;
138}
139
Yao Chenb3561512017-11-21 18:07:17 -0800140bool SimpleConditionTracker::hitGuardRail(const HashableDimensionKey& newKey) {
141 if (!mSliced || mSlicedConditionState.find(newKey) != mSlicedConditionState.end()) {
142 // if the condition is not sliced or the key is not new, we are good!
143 return false;
144 }
145 // 1. Report the tuple count if the tuple count > soft limit
146 if (mSlicedConditionState.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
147 size_t newTupleCount = mSlicedConditionState.size() + 1;
Yangster-mac94e197c2018-01-02 16:03:03 -0800148 StatsdStats::getInstance().noteConditionDimensionSize(mConfigKey, mConditionId, newTupleCount);
Yao Chenb3561512017-11-21 18:07:17 -0800149 // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
150 if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800151 ALOGE("Predicate %lld dropping data for dimension key %s",
Yangster13fb7e42018-03-07 17:30:49 -0800152 (long long)mConditionId, newKey.toString().c_str());
Yao Chenb3561512017-11-21 18:07:17 -0800153 return true;
154 }
155 }
156 return false;
157}
158
Yao Chen967b2052017-11-07 16:36:43 -0800159void SimpleConditionTracker::handleConditionEvent(const HashableDimensionKey& outputKey,
Yao Chen8a8d16c2018-02-08 14:50:40 -0800160 bool matchStart, ConditionState* conditionCache,
161 bool* conditionChangedCache) {
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)) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800166 (*conditionChangedCache) = false;
Yao Chenb3561512017-11-21 18:07:17 -0800167 // Tells the caller it's evaluated.
Yao Chen8a8d16c2018-02-08 14:50:40 -0800168 (*conditionCache) = ConditionState::kUnknown;
Yao Chenb3561512017-11-21 18:07:17 -0800169 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) {
Yangster13fb7e42018-03-07 17:30:49 -0800175 mSlicedConditionState[outputKey] = 1;
Yao Chen967b2052017-11-07 16:36:43 -0800176 changed = true;
Yao Chen580ea3212018-02-26 14:21:54 -0800177 mLastChangedToTrueDimensions.insert(outputKey);
Yao Chen967b2052017-11-07 16:36:43 -0800178 } else if (mInitialValue != ConditionState::kFalse) {
179 // it's a stop and we don't have history about it.
180 // If the default condition is not false, it means this stop is valuable to us.
Yangster13fb7e42018-03-07 17:30:49 -0800181 mSlicedConditionState[outputKey] = 0;
Yao Chen580ea3212018-02-26 14:21:54 -0800182 mLastChangedToFalseDimensions.insert(outputKey);
Yao Chen967b2052017-11-07 16:36:43 -0800183 changed = true;
184 }
185 } else {
186 // we have history about this output key.
187 auto& startedCount = outputIt->second;
188 // assign the old value first.
189 newCondition = startedCount > 0 ? ConditionState::kTrue : ConditionState::kFalse;
190 if (matchStart) {
191 if (startedCount == 0) {
Yao Chen580ea3212018-02-26 14:21:54 -0800192 mLastChangedToTrueDimensions.insert(outputKey);
Yao Chen967b2052017-11-07 16:36:43 -0800193 // This condition for this output key will change from false -> true
194 changed = true;
195 }
196
197 // it's ok to do ++ here, even if we don't count nesting. The >1 counts will be treated
198 // as 1 if not counting nesting.
199 startedCount++;
200 newCondition = ConditionState::kTrue;
201 } else {
202 // This is a stop event.
203 if (startedCount > 0) {
204 if (mCountNesting) {
205 startedCount--;
206 if (startedCount == 0) {
207 newCondition = ConditionState::kFalse;
208 }
209 } else {
210 // not counting nesting, so ignore the number of starts, stop now.
211 startedCount = 0;
212 newCondition = ConditionState::kFalse;
213 }
214 // if everything has stopped for this output key, condition true -> false;
215 if (startedCount == 0) {
Yao Chen580ea3212018-02-26 14:21:54 -0800216 mLastChangedToFalseDimensions.insert(outputKey);
Yao Chen967b2052017-11-07 16:36:43 -0800217 changed = true;
218 }
219 }
220
221 // if default condition is false, it means we don't need to keep the false values.
222 if (mInitialValue == ConditionState::kFalse && startedCount == 0) {
223 mSlicedConditionState.erase(outputIt);
Yangster13fb7e42018-03-07 17:30:49 -0800224 VLOG("erase key %s", outputKey.toString().c_str());
Yao Chen967b2052017-11-07 16:36:43 -0800225 }
226 }
227 }
228
229 // dump all dimensions for debugging
230 if (DEBUG) {
Yao Chen580ea3212018-02-26 14:21:54 -0800231 dumpState();
Yao Chen967b2052017-11-07 16:36:43 -0800232 }
233
Yao Chen8a8d16c2018-02-08 14:50:40 -0800234 (*conditionChangedCache) = changed;
235 (*conditionCache) = newCondition;
Yangster13fb7e42018-03-07 17:30:49 -0800236
Yangster-mac94e197c2018-01-02 16:03:03 -0800237 VLOG("SimplePredicate %lld nonSlicedChange? %d", (long long)mConditionId,
Yao Chen967b2052017-11-07 16:36:43 -0800238 conditionChangedCache[mIndex] == true);
239}
240
Yangster-mac93694462018-01-22 20:49:31 -0800241void SimpleConditionTracker::evaluateCondition(
242 const LogEvent& event,
243 const vector<MatchingState>& eventMatcherValues,
244 const vector<sp<ConditionTracker>>& mAllConditions,
245 vector<ConditionState>& conditionCache,
246 vector<bool>& conditionChangedCache) {
Yao Chencaf339d2017-10-06 16:01:10 -0700247 if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
248 // it has been evaluated.
Yangster-mac94e197c2018-01-02 16:03:03 -0800249 VLOG("Yes, already evaluated, %lld %d",
250 (long long)mConditionId, conditionCache[mIndex]);
Yao Chen967b2052017-11-07 16:36:43 -0800251 return;
Yao Chencaf339d2017-10-06 16:01:10 -0700252 }
Yao Chen580ea3212018-02-26 14:21:54 -0800253 mLastChangedToTrueDimensions.clear();
254 mLastChangedToFalseDimensions.clear();
Yao Chencaf339d2017-10-06 16:01:10 -0700255
David Chenc18abed2017-11-22 16:47:59 -0800256 if (mStopAllLogMatcherIndex >= 0 && mStopAllLogMatcherIndex < int(eventMatcherValues.size()) &&
Yao Chen967b2052017-11-07 16:36:43 -0800257 eventMatcherValues[mStopAllLogMatcherIndex] == MatchingState::kMatched) {
258 handleStopAll(conditionCache, conditionChangedCache);
259 return;
260 }
Yao Chen729093d2017-10-16 10:33:26 -0700261
Yao Chen967b2052017-11-07 16:36:43 -0800262 int matchedState = -1;
Yao Chencaf339d2017-10-06 16:01:10 -0700263 // Note: The order to evaluate the following start, stop, stop_all matters.
264 // The priority of overwrite is stop_all > stop > start.
265 if (mStartLogMatcherIndex >= 0 &&
266 eventMatcherValues[mStartLogMatcherIndex] == MatchingState::kMatched) {
Yao Chen967b2052017-11-07 16:36:43 -0800267 matchedState = 1;
Yao Chencaf339d2017-10-06 16:01:10 -0700268 }
269
270 if (mStopLogMatcherIndex >= 0 &&
271 eventMatcherValues[mStopLogMatcherIndex] == MatchingState::kMatched) {
Yao Chen967b2052017-11-07 16:36:43 -0800272 matchedState = 0;
Yao Chencaf339d2017-10-06 16:01:10 -0700273 }
274
Yao Chen967b2052017-11-07 16:36:43 -0800275 if (matchedState < 0) {
Yao Chend41c4222017-11-15 19:26:14 -0800276 // The event doesn't match this condition. So we just report existing condition values.
Yao Chen967b2052017-11-07 16:36:43 -0800277 conditionChangedCache[mIndex] = false;
Yao Chend41c4222017-11-15 19:26:14 -0800278 if (mSliced) {
Yao Chen427d3722018-03-22 15:21:52 -0700279 // if the condition result is sliced. The overall condition is true if any of the sliced
280 // condition is true
Yangster-mac93694462018-01-22 20:49:31 -0800281 conditionCache[mIndex] = mInitialValue;
Yao Chen427d3722018-03-22 15:21:52 -0700282 for (const auto& slicedCondition : mSlicedConditionState) {
283 if (slicedCondition.second > 0) {
284 conditionCache[mIndex] = ConditionState::kTrue;
285 break;
286 }
287 }
Yao Chend41c4222017-11-15 19:26:14 -0800288 } else {
Yangster7c334a12017-11-22 14:24:24 -0800289 const auto& itr = mSlicedConditionState.find(DEFAULT_DIMENSION_KEY);
290 if (itr == mSlicedConditionState.end()) {
291 // condition not sliced, but we haven't seen the matched start or stop yet. so
292 // return initial value.
293 conditionCache[mIndex] = mInitialValue;
294 } else {
295 // return the cached condition.
296 conditionCache[mIndex] =
297 itr->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
298 }
Yao Chend41c4222017-11-15 19:26:14 -0800299 }
Yao Chen967b2052017-11-07 16:36:43 -0800300 return;
Yao Chen729093d2017-10-16 10:33:26 -0700301 }
302
Yao Chen8a8d16c2018-02-08 14:50:40 -0800303 ConditionState overallState = mInitialValue;
304 bool overallChanged = false;
305
306 if (mOutputDimensions.size() == 0) {
307 handleConditionEvent(DEFAULT_DIMENSION_KEY, matchedState == 1, &overallState,
308 &overallChanged);
Yangster13fb7e42018-03-07 17:30:49 -0800309 } else if (!mContainANYPositionInInternalDimensions) {
310 HashableDimensionKey outputValue;
311 filterValues(mOutputDimensions, event.getValues(), &outputValue);
312
313 // If this event has multiple nodes in the attribution chain, this log event probably will
314 // generate multiple dimensions. If so, we will find if the condition changes for any
315 // dimension and ask the corresponding metric producer to verify whether the actual sliced
316 // condition has changed or not.
317 // A high level assumption is that a predicate is either sliced or unsliced. We will never
318 // have both sliced and unsliced version of a predicate.
319 handleConditionEvent(outputValue, matchedState == 1, &overallState, &overallChanged);
Yangster-mac20877162017-12-22 17:19:39 -0800320 } else {
Yangster-mace06cfd72018-03-10 23:22:59 -0800321 ALOGE("The condition tracker should not be sliced by ANY position matcher.");
Yangster-mac20877162017-12-22 17:19:39 -0800322 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800323 conditionCache[mIndex] = overallState;
324 conditionChangedCache[mIndex] = overallChanged;
Yao Chen729093d2017-10-16 10:33:26 -0700325}
326
327void SimpleConditionTracker::isConditionMet(
Yao Chen8a8d16c2018-02-08 14:50:40 -0800328 const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
Yangster13fb7e42018-03-07 17:30:49 -0800329 const bool isPartialLink,
tsaichristine76853372019-08-06 17:17:03 -0700330 vector<ConditionState>& conditionCache) const {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800331
Yangster-mac93694462018-01-22 20:49:31 -0800332 if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
333 // it has been evaluated.
334 VLOG("Yes, already evaluated, %lld %d",
335 (long long)mConditionId, conditionCache[mIndex]);
Yao Chen729093d2017-10-16 10:33:26 -0700336 return;
337 }
Yangster-mac93694462018-01-22 20:49:31 -0800338 const auto pair = conditionParameters.find(mConditionId);
339
340 if (pair == conditionParameters.end()) {
341 ConditionState conditionState = ConditionState::kNotEvaluated;
tsaichristine76853372019-08-06 17:17:03 -0700342 conditionState = conditionState | mInitialValue;
343 if (!mSliced) {
344 const auto& itr = mSlicedConditionState.find(DEFAULT_DIMENSION_KEY);
345 if (itr != mSlicedConditionState.end()) {
346 ConditionState sliceState =
347 itr->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
348 conditionState = conditionState | sliceState;
Yangster-mac93694462018-01-22 20:49:31 -0800349 }
350 }
351 conditionCache[mIndex] = conditionState;
352 return;
353 }
Yao Chen729093d2017-10-16 10:33:26 -0700354
Yangster-mac20877162017-12-22 17:19:39 -0800355 ConditionState conditionState = ConditionState::kNotEvaluated;
Yangster13fb7e42018-03-07 17:30:49 -0800356 const HashableDimensionKey& key = pair->second;
357 if (isPartialLink) {
358 // For unseen key, check whether the require dimensions are subset of sliced condition
359 // output.
360 conditionState = conditionState | mInitialValue;
361 for (const auto& slice : mSlicedConditionState) {
362 ConditionState sliceState =
363 slice.second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
364 if (slice.first.contains(key)) {
365 conditionState = conditionState | sliceState;
Yangster13fb7e42018-03-07 17:30:49 -0800366 }
367 }
368 } else {
Yangster-mac20877162017-12-22 17:19:39 -0800369 auto startedCountIt = mSlicedConditionState.find(key);
Yangster13fb7e42018-03-07 17:30:49 -0800370 conditionState = conditionState | mInitialValue;
Yangster-mac20877162017-12-22 17:19:39 -0800371 if (startedCountIt != mSlicedConditionState.end()) {
Yangster-mac93694462018-01-22 20:49:31 -0800372 ConditionState sliceState =
373 startedCountIt->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
374 conditionState = conditionState | sliceState;
Yangster-mac20877162017-12-22 17:19:39 -0800375 }
Yangster13fb7e42018-03-07 17:30:49 -0800376
377 }
Yangster-mac20877162017-12-22 17:19:39 -0800378 conditionCache[mIndex] = conditionState;
Yangster-mac94e197c2018-01-02 16:03:03 -0800379 VLOG("Predicate %lld return %d", (long long)mConditionId, conditionCache[mIndex]);
Yao Chencaf339d2017-10-06 16:01:10 -0700380}
381
Yao Chencaf339d2017-10-06 16:01:10 -0700382} // namespace statsd
383} // namespace os
384} // namespace android