blob: 25257213a5d0f73054548c0ba44c8c665711d0a3 [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
Yao Chencaf339d2017-10-06 16:01:10 -070023#include <log/logprint.h>
24
Joe Onorato9fc9edf2017-10-15 20:08:52 -070025namespace android {
26namespace os {
27namespace statsd {
28
Yao Chen729093d2017-10-16 10:33:26 -070029using std::map;
Yao Chencaf339d2017-10-06 16:01:10 -070030using std::string;
31using std::unique_ptr;
32using std::unordered_map;
33using std::vector;
34
Yao Chencaf339d2017-10-06 16:01:10 -070035SimpleConditionTracker::SimpleConditionTracker(
Yangster-mac94e197c2018-01-02 16:03:03 -080036 const ConfigKey& key, const int64_t& id, const int index,
Stefan Lafon12d01fa2017-12-04 20:56:09 -080037 const SimplePredicate& simplePredicate,
Yangster-mac94e197c2018-01-02 16:03:03 -080038 const unordered_map<int64_t, int>& trackerNameIndexMap)
39 : ConditionTracker(id, index), mConfigKey(key) {
40 VLOG("creating SimpleConditionTracker %lld", (long long)mConditionId);
Stefan Lafon12d01fa2017-12-04 20:56:09 -080041 mCountNesting = simplePredicate.count_nesting();
Yao Chencaf339d2017-10-06 16:01:10 -070042
Stefan Lafon12d01fa2017-12-04 20:56:09 -080043 if (simplePredicate.has_start()) {
44 auto pair = trackerNameIndexMap.find(simplePredicate.start());
Yao Chencaf339d2017-10-06 16:01:10 -070045 if (pair == trackerNameIndexMap.end()) {
Yangster-mac94e197c2018-01-02 16:03:03 -080046 ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start());
Yao Chencaf339d2017-10-06 16:01:10 -070047 return;
48 }
49 mStartLogMatcherIndex = pair->second;
50 mTrackerIndex.insert(mStartLogMatcherIndex);
51 } else {
52 mStartLogMatcherIndex = -1;
53 }
54
Stefan Lafon12d01fa2017-12-04 20:56:09 -080055 if (simplePredicate.has_stop()) {
56 auto pair = trackerNameIndexMap.find(simplePredicate.stop());
Yao Chencaf339d2017-10-06 16:01:10 -070057 if (pair == trackerNameIndexMap.end()) {
Yangster-mac94e197c2018-01-02 16:03:03 -080058 ALOGW("Stop matcher %lld not found in the config", (long long)simplePredicate.stop());
Yao Chencaf339d2017-10-06 16:01:10 -070059 return;
60 }
61 mStopLogMatcherIndex = pair->second;
Yao Chen4b146852017-10-10 15:34:42 -070062 mTrackerIndex.insert(mStopLogMatcherIndex);
Yao Chencaf339d2017-10-06 16:01:10 -070063 } else {
64 mStopLogMatcherIndex = -1;
65 }
66
Stefan Lafon12d01fa2017-12-04 20:56:09 -080067 if (simplePredicate.has_stop_all()) {
68 auto pair = trackerNameIndexMap.find(simplePredicate.stop_all());
Yao Chencaf339d2017-10-06 16:01:10 -070069 if (pair == trackerNameIndexMap.end()) {
Yangster-mac94e197c2018-01-02 16:03:03 -080070 ALOGW("Stop all matcher %lld found in the config", (long long)simplePredicate.stop_all());
Yao Chencaf339d2017-10-06 16:01:10 -070071 return;
72 }
73 mStopAllLogMatcherIndex = pair->second;
74 mTrackerIndex.insert(mStopAllLogMatcherIndex);
75 } else {
76 mStopAllLogMatcherIndex = -1;
77 }
78
Yangster-mac20877162017-12-22 17:19:39 -080079 mOutputDimensions = simplePredicate.dimensions();
Yao Chen5154a372017-10-30 22:57:06 -070080
Yangster-mac20877162017-12-22 17:19:39 -080081 if (mOutputDimensions.child_size() > 0) {
Yao Chen5154a372017-10-30 22:57:06 -070082 mSliced = true;
83 }
84
Stefan Lafon12d01fa2017-12-04 20:56:09 -080085 if (simplePredicate.initial_value() == SimplePredicate_InitialValue_FALSE) {
Yao Chen967b2052017-11-07 16:36:43 -080086 mInitialValue = ConditionState::kFalse;
87 } else {
88 mInitialValue = ConditionState::kUnknown;
89 }
90
91 mNonSlicedConditionState = mInitialValue;
92
Yao Chencaf339d2017-10-06 16:01:10 -070093 mInitialized = true;
94}
95
96SimpleConditionTracker::~SimpleConditionTracker() {
97 VLOG("~SimpleConditionTracker()");
98}
99
Stefan Lafon12d01fa2017-12-04 20:56:09 -0800100bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig,
Yao Chencaf339d2017-10-06 16:01:10 -0700101 const vector<sp<ConditionTracker>>& allConditionTrackers,
Yangster-mac94e197c2018-01-02 16:03:03 -0800102 const unordered_map<int64_t, int>& conditionIdIndexMap,
Yao Chencaf339d2017-10-06 16:01:10 -0700103 vector<bool>& stack) {
104 // SimpleConditionTracker does not have dependency on other conditions, thus we just return
105 // if the initialization was successful.
106 return mInitialized;
107}
108
Yangster-mac94e197c2018-01-02 16:03:03 -0800109void print(map<HashableDimensionKey, int>& conditions, const int64_t& id) {
110 VLOG("%lld DUMP:", (long long)id);
Yao Chen729093d2017-10-16 10:33:26 -0700111 for (const auto& pair : conditions) {
Yao Chen967b2052017-11-07 16:36:43 -0800112 VLOG("\t%s : %d", pair.first.c_str(), pair.second);
Yao Chen729093d2017-10-16 10:33:26 -0700113 }
114}
115
Yao Chen967b2052017-11-07 16:36:43 -0800116void SimpleConditionTracker::handleStopAll(std::vector<ConditionState>& conditionCache,
117 std::vector<bool>& conditionChangedCache) {
118 // Unless the default condition is false, and there was nothing started, otherwise we have
119 // triggered a condition change.
120 conditionChangedCache[mIndex] =
121 (mInitialValue == ConditionState::kFalse && mSlicedConditionState.empty()) ? false
122 : true;
123
124 // After StopAll, we know everything has stopped. From now on, default condition is false.
125 mInitialValue = ConditionState::kFalse;
126 mSlicedConditionState.clear();
127 conditionCache[mIndex] = ConditionState::kFalse;
128}
129
Yao Chenb3561512017-11-21 18:07:17 -0800130bool SimpleConditionTracker::hitGuardRail(const HashableDimensionKey& newKey) {
131 if (!mSliced || mSlicedConditionState.find(newKey) != mSlicedConditionState.end()) {
132 // if the condition is not sliced or the key is not new, we are good!
133 return false;
134 }
135 // 1. Report the tuple count if the tuple count > soft limit
136 if (mSlicedConditionState.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
137 size_t newTupleCount = mSlicedConditionState.size() + 1;
Yangster-mac94e197c2018-01-02 16:03:03 -0800138 StatsdStats::getInstance().noteConditionDimensionSize(mConfigKey, mConditionId, newTupleCount);
Yao Chenb3561512017-11-21 18:07:17 -0800139 // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
140 if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800141 ALOGE("Predicate %lld dropping data for dimension key %s",
142 (long long)mConditionId, newKey.c_str());
Yao Chenb3561512017-11-21 18:07:17 -0800143 return true;
144 }
145 }
146 return false;
147}
148
Yao Chen967b2052017-11-07 16:36:43 -0800149void SimpleConditionTracker::handleConditionEvent(const HashableDimensionKey& outputKey,
150 bool matchStart,
151 std::vector<ConditionState>& conditionCache,
152 std::vector<bool>& conditionChangedCache) {
Yangster-mac20877162017-12-22 17:19:39 -0800153 if ((int)conditionChangedCache.size() <= mIndex) {
154 ALOGE("handleConditionEvent: param conditionChangedCache not initialized.");
155 return;
156 }
157 if ((int)conditionCache.size() <= mIndex) {
158 ALOGE("handleConditionEvent: param conditionCache not initialized.");
159 return;
160 }
Yao Chen967b2052017-11-07 16:36:43 -0800161 bool changed = false;
162 auto outputIt = mSlicedConditionState.find(outputKey);
163 ConditionState newCondition;
Yao Chenb3561512017-11-21 18:07:17 -0800164 if (hitGuardRail(outputKey)) {
165 conditionChangedCache[mIndex] = false;
166 // Tells the caller it's evaluated.
167 conditionCache[mIndex] = ConditionState::kUnknown;
168 return;
169 }
Yao Chen967b2052017-11-07 16:36:43 -0800170 if (outputIt == mSlicedConditionState.end()) {
171 // We get a new output key.
172 newCondition = matchStart ? ConditionState::kTrue : ConditionState::kFalse;
173 if (matchStart && mInitialValue != ConditionState::kTrue) {
174 mSlicedConditionState[outputKey] = 1;
175 changed = true;
176 } else if (mInitialValue != ConditionState::kFalse) {
177 // it's a stop and we don't have history about it.
178 // If the default condition is not false, it means this stop is valuable to us.
179 mSlicedConditionState[outputKey] = 0;
180 changed = true;
181 }
182 } else {
183 // we have history about this output key.
184 auto& startedCount = outputIt->second;
185 // assign the old value first.
186 newCondition = startedCount > 0 ? ConditionState::kTrue : ConditionState::kFalse;
187 if (matchStart) {
188 if (startedCount == 0) {
189 // This condition for this output key will change from false -> true
190 changed = true;
191 }
192
193 // it's ok to do ++ here, even if we don't count nesting. The >1 counts will be treated
194 // as 1 if not counting nesting.
195 startedCount++;
196 newCondition = ConditionState::kTrue;
197 } else {
198 // This is a stop event.
199 if (startedCount > 0) {
200 if (mCountNesting) {
201 startedCount--;
202 if (startedCount == 0) {
203 newCondition = ConditionState::kFalse;
204 }
205 } else {
206 // not counting nesting, so ignore the number of starts, stop now.
207 startedCount = 0;
208 newCondition = ConditionState::kFalse;
209 }
210 // if everything has stopped for this output key, condition true -> false;
211 if (startedCount == 0) {
212 changed = true;
213 }
214 }
215
216 // if default condition is false, it means we don't need to keep the false values.
217 if (mInitialValue == ConditionState::kFalse && startedCount == 0) {
218 mSlicedConditionState.erase(outputIt);
219 VLOG("erase key %s", outputKey.c_str());
220 }
221 }
222 }
223
224 // dump all dimensions for debugging
225 if (DEBUG) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800226 print(mSlicedConditionState, mConditionId);
Yao Chen967b2052017-11-07 16:36:43 -0800227 }
228
229 conditionChangedCache[mIndex] = changed;
230 conditionCache[mIndex] = newCondition;
231
Yangster-mac94e197c2018-01-02 16:03:03 -0800232 VLOG("SimplePredicate %lld nonSlicedChange? %d", (long long)mConditionId,
Yao Chen967b2052017-11-07 16:36:43 -0800233 conditionChangedCache[mIndex] == true);
234}
235
236void SimpleConditionTracker::evaluateCondition(const LogEvent& event,
Yao Chencaf339d2017-10-06 16:01:10 -0700237 const vector<MatchingState>& eventMatcherValues,
238 const vector<sp<ConditionTracker>>& mAllConditions,
239 vector<ConditionState>& conditionCache,
Yao Chen967b2052017-11-07 16:36:43 -0800240 vector<bool>& conditionChangedCache) {
Yao Chencaf339d2017-10-06 16:01:10 -0700241 if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
242 // it has been evaluated.
Yangster-mac94e197c2018-01-02 16:03:03 -0800243 VLOG("Yes, already evaluated, %lld %d",
244 (long long)mConditionId, conditionCache[mIndex]);
Yao Chen967b2052017-11-07 16:36:43 -0800245 return;
Yao Chencaf339d2017-10-06 16:01:10 -0700246 }
247
David Chenc18abed2017-11-22 16:47:59 -0800248 if (mStopAllLogMatcherIndex >= 0 && mStopAllLogMatcherIndex < int(eventMatcherValues.size()) &&
Yao Chen967b2052017-11-07 16:36:43 -0800249 eventMatcherValues[mStopAllLogMatcherIndex] == MatchingState::kMatched) {
250 handleStopAll(conditionCache, conditionChangedCache);
251 return;
252 }
Yao Chen729093d2017-10-16 10:33:26 -0700253
Yao Chen967b2052017-11-07 16:36:43 -0800254 int matchedState = -1;
Yao Chencaf339d2017-10-06 16:01:10 -0700255 // Note: The order to evaluate the following start, stop, stop_all matters.
256 // The priority of overwrite is stop_all > stop > start.
257 if (mStartLogMatcherIndex >= 0 &&
258 eventMatcherValues[mStartLogMatcherIndex] == MatchingState::kMatched) {
Yao Chen967b2052017-11-07 16:36:43 -0800259 matchedState = 1;
Yao Chencaf339d2017-10-06 16:01:10 -0700260 }
261
262 if (mStopLogMatcherIndex >= 0 &&
263 eventMatcherValues[mStopLogMatcherIndex] == MatchingState::kMatched) {
Yao Chen967b2052017-11-07 16:36:43 -0800264 matchedState = 0;
Yao Chencaf339d2017-10-06 16:01:10 -0700265 }
266
Yao Chen967b2052017-11-07 16:36:43 -0800267 if (matchedState < 0) {
Yao Chend41c4222017-11-15 19:26:14 -0800268 // The event doesn't match this condition. So we just report existing condition values.
Yao Chen967b2052017-11-07 16:36:43 -0800269 conditionChangedCache[mIndex] = false;
Yao Chend41c4222017-11-15 19:26:14 -0800270 if (mSliced) {
271 // if the condition result is sliced. metrics won't directly get value from the
272 // cache, so just set any value other than kNotEvaluated.
273 conditionCache[mIndex] = ConditionState::kUnknown;
Yao Chend41c4222017-11-15 19:26:14 -0800274 } else {
Yangster7c334a12017-11-22 14:24:24 -0800275 const auto& itr = mSlicedConditionState.find(DEFAULT_DIMENSION_KEY);
276 if (itr == mSlicedConditionState.end()) {
277 // condition not sliced, but we haven't seen the matched start or stop yet. so
278 // return initial value.
279 conditionCache[mIndex] = mInitialValue;
280 } else {
281 // return the cached condition.
282 conditionCache[mIndex] =
283 itr->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
284 }
Yao Chend41c4222017-11-15 19:26:14 -0800285 }
Yangster7c334a12017-11-22 14:24:24 -0800286
Yao Chen967b2052017-11-07 16:36:43 -0800287 return;
Yao Chen729093d2017-10-16 10:33:26 -0700288 }
289
Yangster-mac20877162017-12-22 17:19:39 -0800290 // outputKey is the output values. e.g, uid:1234
291 const std::vector<DimensionsValue> outputValues = getDimensionKeys(event, mOutputDimensions);
292 if (outputValues.size() == 0) {
293 // The original implementation would generate an empty string dimension hash when condition
294 // is not sliced.
295 handleConditionEvent(
296 DEFAULT_DIMENSION_KEY, matchedState == 1, conditionCache, conditionChangedCache);
297 } else if (outputValues.size() == 1) {
298 handleConditionEvent(HashableDimensionKey(outputValues[0]), matchedState == 1,
299 conditionCache, conditionChangedCache);
300 } else {
301 // If this event has multiple nodes in the attribution chain, this log event probably will
302 // generate multiple dimensions. If so, we will find if the condition changes for any
303 // dimension and ask the corresponding metric producer to verify whether the actual sliced
304 // condition has changed or not.
305 // A high level assumption is that a predicate is either sliced or unsliced. We will never
306 // have both sliced and unsliced version of a predicate.
307 for (const DimensionsValue& outputValue : outputValues) {
308 vector<ConditionState> dimensionalConditionCache(conditionCache.size(),
309 ConditionState::kNotEvaluated);
310 vector<bool> dimensionalConditionChangedCache(conditionChangedCache.size(), false);
311
312 handleConditionEvent(HashableDimensionKey(outputValue), matchedState == 1,
313 dimensionalConditionCache, dimensionalConditionChangedCache);
314
315 OrConditionState(dimensionalConditionCache, &conditionCache);
316 OrBooleanVector(dimensionalConditionChangedCache, &conditionChangedCache);
317 }
318 }
Yao Chen729093d2017-10-16 10:33:26 -0700319}
320
321void SimpleConditionTracker::isConditionMet(
Yangster-mac20877162017-12-22 17:19:39 -0800322 const ConditionKey& conditionParameters,
Yangster7c334a12017-11-22 14:24:24 -0800323 const vector<sp<ConditionTracker>>& allConditions,
324 vector<ConditionState>& conditionCache) const {
Yangster-mac94e197c2018-01-02 16:03:03 -0800325 const auto pair = conditionParameters.find(mConditionId);
Yao Chen967b2052017-11-07 16:36:43 -0800326
Yangster-mac20877162017-12-22 17:19:39 -0800327 if (pair == conditionParameters.end() && mOutputDimensions.child_size() > 0) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800328 ALOGE("Predicate %lld output has dimension, but it's not specified in the query!",
329 (long long)mConditionId);
Yao Chen967b2052017-11-07 16:36:43 -0800330 conditionCache[mIndex] = mInitialValue;
Yao Chen729093d2017-10-16 10:33:26 -0700331 return;
332 }
Yangster-mac20877162017-12-22 17:19:39 -0800333 std::vector<HashableDimensionKey> defaultKeys = {DEFAULT_DIMENSION_KEY};
334 const std::vector<HashableDimensionKey> &keys =
335 (pair == conditionParameters.end()) ? defaultKeys : pair->second;
Yao Chen729093d2017-10-16 10:33:26 -0700336
Yangster-mac20877162017-12-22 17:19:39 -0800337 ConditionState conditionState = ConditionState::kNotEvaluated;
338 for (const auto& key : keys) {
339 auto startedCountIt = mSlicedConditionState.find(key);
340 if (startedCountIt != mSlicedConditionState.end()) {
341 conditionState = conditionState |
342 (startedCountIt->second > 0 ? ConditionState::kTrue : ConditionState::kFalse);
343 } else {
344 conditionState = conditionState | mInitialValue;
345 }
Yao Chen729093d2017-10-16 10:33:26 -0700346 }
Yangster-mac20877162017-12-22 17:19:39 -0800347 conditionCache[mIndex] = conditionState;
Yangster-mac94e197c2018-01-02 16:03:03 -0800348 VLOG("Predicate %lld return %d", (long long)mConditionId, conditionCache[mIndex]);
Yao Chencaf339d2017-10-06 16:01:10 -0700349}
350
351} // namespace statsd
352} // namespace os
353} // namespace android