Loading cmds/statsd/Android.mk +2 −2 Original line number Diff line number Diff line Loading @@ -151,19 +151,19 @@ LOCAL_SRC_FILES := \ $(statsd_common_src) \ tests/AnomalyMonitor_test.cpp \ tests/anomaly/AnomalyTracker_test.cpp \ tests/ConditionTracker_test.cpp \ tests/ConfigManager_test.cpp \ tests/indexed_priority_queue_test.cpp \ tests/LogEntryMatcher_test.cpp \ tests/LogReader_test.cpp \ tests/MetricsManager_test.cpp \ tests/UidMap_test.cpp \ tests/condition/CombinationConditionTracker_test.cpp \ tests/condition/SimpleConditionTracker_test.cpp \ tests/metrics/OringDurationTracker_test.cpp \ tests/metrics/MaxDurationTracker_test.cpp \ tests/metrics/CountMetricProducer_test.cpp \ tests/metrics/EventMetricProducer_test.cpp LOCAL_STATIC_LIBRARIES := \ libgmock Loading cmds/statsd/src/condition/CombinationConditionTracker.cpp +16 −18 Original line number Diff line number Diff line Loading @@ -115,25 +115,25 @@ void CombinationConditionTracker::isConditionMet( evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache); } bool CombinationConditionTracker::evaluateCondition( void CombinationConditionTracker::evaluateCondition( const LogEvent& event, const std::vector<MatchingState>& eventMatcherValues, const std::vector<sp<ConditionTracker>>& mAllConditions, std::vector<ConditionState>& nonSlicedConditionCache, std::vector<bool>& nonSlicedChangedCache, vector<bool>& slicedConditionChanged) { std::vector<bool>& conditionChangedCache) { // value is up to date. if (nonSlicedConditionCache[mIndex] != ConditionState::kNotEvaluated) { return false; return; } for (const int childIndex : mChildren) { if (nonSlicedConditionCache[childIndex] == ConditionState::kNotEvaluated) { const sp<ConditionTracker>& child = mAllConditions[childIndex]; child->evaluateCondition(event, eventMatcherValues, mAllConditions, nonSlicedConditionCache, nonSlicedChangedCache, slicedConditionChanged); nonSlicedConditionCache, conditionChangedCache); } } if (!mSliced) { ConditionState newCondition = evaluateCombinationCondition(mChildren, mLogicalOperation, nonSlicedConditionCache); Loading @@ -142,22 +142,20 @@ bool CombinationConditionTracker::evaluateCondition( nonSlicedConditionCache[mIndex] = mNonSlicedConditionState; nonSlicedChangedCache[mIndex] = nonSlicedChanged; if (mSliced) { conditionChangedCache[mIndex] = nonSlicedChanged; } else { for (const int childIndex : mChildren) { // If any of the sliced condition in children condition changes, the combination // condition may be changed too. if (slicedConditionChanged[childIndex]) { slicedConditionChanged[mIndex] = true; if (conditionChangedCache[childIndex]) { conditionChangedCache[mIndex] = true; break; } } nonSlicedConditionCache[mIndex] = ConditionState::kUnknown; ALOGD("CombinationCondition %s sliced may changed? %d", mName.c_str(), slicedConditionChanged[mIndex] == true); conditionChangedCache[mIndex] == true); } return nonSlicedChanged; } } // namespace statsd Loading cmds/statsd/src/condition/CombinationConditionTracker.h +2 −3 Original line number Diff line number Diff line Loading @@ -35,12 +35,11 @@ public: const std::unordered_map<std::string, int>& conditionNameIndexMap, std::vector<bool>& stack) override; bool evaluateCondition(const LogEvent& event, void evaluateCondition(const LogEvent& event, const std::vector<MatchingState>& eventMatcherValues, const std::vector<sp<ConditionTracker>>& mAllConditions, std::vector<ConditionState>& conditionCache, std::vector<bool>& changedCache, std::vector<bool>& slicedConditionMayChanged) override; std::vector<bool>& changedCache) override; void isConditionMet(const std::map<std::string, HashableDimensionKey>& conditionParameters, const std::vector<sp<ConditionTracker>>& allConditions, Loading cmds/statsd/src/condition/ConditionTracker.h +5 −10 Original line number Diff line number Diff line Loading @@ -56,25 +56,20 @@ public: std::vector<bool>& stack) = 0; // evaluate current condition given the new event. // return true if the condition state changed, false if the condition state is not changed. // event: the new log event // eventMatcherValues: the results of the LogMatcherTrackers. LogMatcherTrackers always process // event before ConditionTrackers, because ConditionTracker depends on // LogMatchingTrackers. // mAllConditions: the list of all ConditionTracker // conditionCache: the cached non-sliced condition of the ConditionTrackers for this new event. // nonSlicedConditionChanged: the bit map to record whether non-sliced condition has changed. // slicedConditionMayChanged: the bit map to record whether sliced condition may have changed. // Because sliced condition needs parameters to determine the value. So the sliced // condition is not pushed to metrics. We only inform the relevant metrics that the sliced // condition may have changed, and metrics should pull the conditions that they are // interested in. virtual bool evaluateCondition(const LogEvent& event, // conditionChanged: the bit map to record whether the condition has changed. // If the condition has dimension, then any sub condition changes will report // conditionChanged. virtual void evaluateCondition(const LogEvent& event, const std::vector<MatchingState>& eventMatcherValues, const std::vector<sp<ConditionTracker>>& mAllConditions, std::vector<ConditionState>& conditionCache, std::vector<bool>& nonSlicedConditionChanged, std::vector<bool>& slicedConditionMayChanged) = 0; std::vector<bool>& conditionChanged) = 0; // Return the current condition state. virtual ConditionState isConditionMet() { Loading cmds/statsd/src/condition/SimpleConditionTracker.cpp +129 −82 Original line number Diff line number Diff line Loading @@ -74,13 +74,21 @@ SimpleConditionTracker::SimpleConditionTracker( mStopAllLogMatcherIndex = -1; } mDimension.insert(mDimension.begin(), simpleCondition.dimension().begin(), mOutputDimension.insert(mOutputDimension.begin(), simpleCondition.dimension().begin(), simpleCondition.dimension().end()); if (mDimension.size() > 0) { if (mOutputDimension.size() > 0) { mSliced = true; } if (simpleCondition.initial_value() == SimpleCondition_InitialValue_FALSE) { mInitialValue = ConditionState::kFalse; } else { mInitialValue = ConditionState::kUnknown; } mNonSlicedConditionState = mInitialValue; mInitialized = true; } Loading @@ -97,127 +105,166 @@ bool SimpleConditionTracker::init(const vector<Condition>& allConditionConfig, return mInitialized; } void print(unordered_map<HashableDimensionKey, ConditionState>& conditions, const string& name) { void print(map<HashableDimensionKey, int>& conditions, const string& name) { VLOG("%s DUMP:", name.c_str()); for (const auto& pair : conditions) { VLOG("\t%s %d", pair.first.c_str(), pair.second); VLOG("\t%s : %d", pair.first.c_str(), pair.second); } } bool SimpleConditionTracker::evaluateCondition(const LogEvent& event, const vector<MatchingState>& eventMatcherValues, const vector<sp<ConditionTracker>>& mAllConditions, vector<ConditionState>& conditionCache, vector<bool>& nonSlicedConditionChanged, std::vector<bool>& slicedConditionChanged) { if (conditionCache[mIndex] != ConditionState::kNotEvaluated) { // it has been evaluated. VLOG("Yes, already evaluated, %s %d", mName.c_str(), mNonSlicedConditionState); return false; void SimpleConditionTracker::handleStopAll(std::vector<ConditionState>& conditionCache, std::vector<bool>& conditionChangedCache) { // Unless the default condition is false, and there was nothing started, otherwise we have // triggered a condition change. conditionChangedCache[mIndex] = (mInitialValue == ConditionState::kFalse && mSlicedConditionState.empty()) ? false : true; // After StopAll, we know everything has stopped. From now on, default condition is false. mInitialValue = ConditionState::kFalse; mSlicedConditionState.clear(); conditionCache[mIndex] = ConditionState::kFalse; } // Ignore nesting, because we know we cannot trust ourselves on tracking nesting conditions. ConditionState newCondition = mNonSlicedConditionState; bool matched = false; // Note: The order to evaluate the following start, stop, stop_all matters. // The priority of overwrite is stop_all > stop > start. if (mStartLogMatcherIndex >= 0 && eventMatcherValues[mStartLogMatcherIndex] == MatchingState::kMatched) { matched = true; newCondition = ConditionState::kTrue; void SimpleConditionTracker::handleConditionEvent(const HashableDimensionKey& outputKey, bool matchStart, std::vector<ConditionState>& conditionCache, std::vector<bool>& conditionChangedCache) { bool changed = false; auto outputIt = mSlicedConditionState.find(outputKey); ConditionState newCondition; if (outputIt == mSlicedConditionState.end()) { // We get a new output key. newCondition = matchStart ? ConditionState::kTrue : ConditionState::kFalse; if (matchStart && mInitialValue != ConditionState::kTrue) { mSlicedConditionState[outputKey] = 1; changed = true; } else if (mInitialValue != ConditionState::kFalse) { // it's a stop and we don't have history about it. // If the default condition is not false, it means this stop is valuable to us. mSlicedConditionState[outputKey] = 0; changed = true; } } else { // we have history about this output key. auto& startedCount = outputIt->second; // assign the old value first. newCondition = startedCount > 0 ? ConditionState::kTrue : ConditionState::kFalse; if (matchStart) { if (startedCount == 0) { // This condition for this output key will change from false -> true changed = true; } if (mStopLogMatcherIndex >= 0 && eventMatcherValues[mStopLogMatcherIndex] == MatchingState::kMatched) { matched = true; // it's ok to do ++ here, even if we don't count nesting. The >1 counts will be treated // as 1 if not counting nesting. startedCount++; newCondition = ConditionState::kTrue; } else { // This is a stop event. if (startedCount > 0) { if (mCountNesting) { startedCount--; if (startedCount == 0) { newCondition = ConditionState::kFalse; } bool stopAll = false; if (mStopAllLogMatcherIndex >= 0 && eventMatcherValues[mStopAllLogMatcherIndex] == MatchingState::kMatched) { matched = true; } else { // not counting nesting, so ignore the number of starts, stop now. startedCount = 0; newCondition = ConditionState::kFalse; stopAll = true; } // if everything has stopped for this output key, condition true -> false; if (startedCount == 0) { changed = true; } } if (matched == false) { slicedConditionChanged[mIndex] = false; nonSlicedConditionChanged[mIndex] = false; conditionCache[mIndex] = mNonSlicedConditionState; return false; // if default condition is false, it means we don't need to keep the false values. if (mInitialValue == ConditionState::kFalse && startedCount == 0) { mSlicedConditionState.erase(outputIt); VLOG("erase key %s", outputKey.c_str()); } } } bool nonSlicedChanged = mNonSlicedConditionState != newCondition; // dump all dimensions for debugging if (DEBUG) { print(mSlicedConditionState, mName); } bool slicedChanged = false; conditionChangedCache[mIndex] = changed; conditionCache[mIndex] = newCondition; if (stopAll) { // TODO: handle stop all; all dimension should be cleared. VLOG("SimpleCondition %s nonSlicedChange? %d", mName.c_str(), conditionChangedCache[mIndex] == true); } if (mDimension.size() > 0) { HashableDimensionKey hashableKey = getHashableKey(getDimensionKey(event, mDimension)); if (mSlicedConditionState.find(hashableKey) == mSlicedConditionState.end() || mSlicedConditionState[hashableKey] != newCondition) { slicedChanged = true; mSlicedConditionState[hashableKey] = newCondition; void SimpleConditionTracker::evaluateCondition(const LogEvent& event, const vector<MatchingState>& eventMatcherValues, const vector<sp<ConditionTracker>>& mAllConditions, vector<ConditionState>& conditionCache, vector<bool>& conditionChangedCache) { if (conditionCache[mIndex] != ConditionState::kNotEvaluated) { // it has been evaluated. VLOG("Yes, already evaluated, %s %d", mName.c_str(), mNonSlicedConditionState); return; } VLOG("key: %s %d", hashableKey.c_str(), newCondition); // dump all dimensions for debugging if (DEBUG) { print(mSlicedConditionState, mName); if (mStopAllLogMatcherIndex >= 0 && eventMatcherValues[mStopAllLogMatcherIndex] == MatchingState::kMatched) { handleStopAll(conditionCache, conditionChangedCache); return; } int matchedState = -1; // Note: The order to evaluate the following start, stop, stop_all matters. // The priority of overwrite is stop_all > stop > start. if (mStartLogMatcherIndex >= 0 && eventMatcherValues[mStartLogMatcherIndex] == MatchingState::kMatched) { matchedState = 1; } // even if this SimpleCondition is not sliced, it may be part of a sliced CombinationCondition // if the nonSliced condition changed, it may affect the sliced condition in the parent node. // so mark the slicedConditionChanged to be true. // For example: APP_IN_BACKGROUND_OR_SCREEN_OFF // APP_IN_BACKGROUND is sliced [App_A->True, App_B->False]. // SCREEN_OFF is not sliced, and it changes from False -> True; // We need to populate this change to parent condition. Because for App_B, // the APP_IN_BACKGROUND_OR_SCREEN_OFF condition would change from False->True. slicedConditionChanged[mIndex] = mSliced ? slicedChanged : nonSlicedChanged; nonSlicedConditionChanged[mIndex] = nonSlicedChanged; if (mStopLogMatcherIndex >= 0 && eventMatcherValues[mStopLogMatcherIndex] == MatchingState::kMatched) { matchedState = 0; } VLOG("SimpleCondition %s nonSlicedChange? %d SlicedChanged? %d", mName.c_str(), nonSlicedConditionChanged[mIndex] == true, slicedConditionChanged[mIndex] == true); mNonSlicedConditionState = newCondition; if (matchedState < 0) { conditionChangedCache[mIndex] = false; conditionCache[mIndex] = mNonSlicedConditionState; return; } return nonSlicedConditionChanged[mIndex]; // outputKey is the output key values. e.g, uid:1234 const HashableDimensionKey outputKey = getHashableKey(getDimensionKey(event, mOutputDimension)); handleConditionEvent(outputKey, matchedState == 1, conditionCache, conditionChangedCache); } void SimpleConditionTracker::isConditionMet( const map<string, HashableDimensionKey>& conditionParameters, const vector<sp<ConditionTracker>>& allConditions, vector<ConditionState>& conditionCache) { const auto pair = conditionParameters.find(mName); if (pair == conditionParameters.end()) { // the query does not need my sliced condition. just return the non sliced condition. conditionCache[mIndex] = mNonSlicedConditionState; VLOG("Condition %s return %d", mName.c_str(), mNonSlicedConditionState); HashableDimensionKey key = (pair == conditionParameters.end()) ? DEFAULT_DIMENSION_KEY : pair->second; if (pair == conditionParameters.end() && mOutputDimension.size() > 0) { ALOGE("Condition %s output has dimension, but it's not specified in the query!", mName.c_str()); conditionCache[mIndex] = mInitialValue; return; } const HashableDimensionKey& key = pair->second; VLOG("simpleCondition %s query key: %s", mName.c_str(), key.c_str()); if (mSlicedConditionState.find(key) == mSlicedConditionState.end()) { // never seen this key before. the condition is unknown to us. conditionCache[mIndex] = ConditionState::kUnknown; auto startedCountIt = mSlicedConditionState.find(key); if (startedCountIt == mSlicedConditionState.end()) { conditionCache[mIndex] = mInitialValue; } else { conditionCache[mIndex] = mSlicedConditionState[key]; conditionCache[mIndex] = startedCountIt->second > 0 ? ConditionState::kTrue : ConditionState::kFalse; } VLOG("Condition %s return %d", mName.c_str(), conditionCache[mIndex]); if (DEBUG) { print(mSlicedConditionState, mName); } } } // namespace statsd Loading Loading
cmds/statsd/Android.mk +2 −2 Original line number Diff line number Diff line Loading @@ -151,19 +151,19 @@ LOCAL_SRC_FILES := \ $(statsd_common_src) \ tests/AnomalyMonitor_test.cpp \ tests/anomaly/AnomalyTracker_test.cpp \ tests/ConditionTracker_test.cpp \ tests/ConfigManager_test.cpp \ tests/indexed_priority_queue_test.cpp \ tests/LogEntryMatcher_test.cpp \ tests/LogReader_test.cpp \ tests/MetricsManager_test.cpp \ tests/UidMap_test.cpp \ tests/condition/CombinationConditionTracker_test.cpp \ tests/condition/SimpleConditionTracker_test.cpp \ tests/metrics/OringDurationTracker_test.cpp \ tests/metrics/MaxDurationTracker_test.cpp \ tests/metrics/CountMetricProducer_test.cpp \ tests/metrics/EventMetricProducer_test.cpp LOCAL_STATIC_LIBRARIES := \ libgmock Loading
cmds/statsd/src/condition/CombinationConditionTracker.cpp +16 −18 Original line number Diff line number Diff line Loading @@ -115,25 +115,25 @@ void CombinationConditionTracker::isConditionMet( evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache); } bool CombinationConditionTracker::evaluateCondition( void CombinationConditionTracker::evaluateCondition( const LogEvent& event, const std::vector<MatchingState>& eventMatcherValues, const std::vector<sp<ConditionTracker>>& mAllConditions, std::vector<ConditionState>& nonSlicedConditionCache, std::vector<bool>& nonSlicedChangedCache, vector<bool>& slicedConditionChanged) { std::vector<bool>& conditionChangedCache) { // value is up to date. if (nonSlicedConditionCache[mIndex] != ConditionState::kNotEvaluated) { return false; return; } for (const int childIndex : mChildren) { if (nonSlicedConditionCache[childIndex] == ConditionState::kNotEvaluated) { const sp<ConditionTracker>& child = mAllConditions[childIndex]; child->evaluateCondition(event, eventMatcherValues, mAllConditions, nonSlicedConditionCache, nonSlicedChangedCache, slicedConditionChanged); nonSlicedConditionCache, conditionChangedCache); } } if (!mSliced) { ConditionState newCondition = evaluateCombinationCondition(mChildren, mLogicalOperation, nonSlicedConditionCache); Loading @@ -142,22 +142,20 @@ bool CombinationConditionTracker::evaluateCondition( nonSlicedConditionCache[mIndex] = mNonSlicedConditionState; nonSlicedChangedCache[mIndex] = nonSlicedChanged; if (mSliced) { conditionChangedCache[mIndex] = nonSlicedChanged; } else { for (const int childIndex : mChildren) { // If any of the sliced condition in children condition changes, the combination // condition may be changed too. if (slicedConditionChanged[childIndex]) { slicedConditionChanged[mIndex] = true; if (conditionChangedCache[childIndex]) { conditionChangedCache[mIndex] = true; break; } } nonSlicedConditionCache[mIndex] = ConditionState::kUnknown; ALOGD("CombinationCondition %s sliced may changed? %d", mName.c_str(), slicedConditionChanged[mIndex] == true); conditionChangedCache[mIndex] == true); } return nonSlicedChanged; } } // namespace statsd Loading
cmds/statsd/src/condition/CombinationConditionTracker.h +2 −3 Original line number Diff line number Diff line Loading @@ -35,12 +35,11 @@ public: const std::unordered_map<std::string, int>& conditionNameIndexMap, std::vector<bool>& stack) override; bool evaluateCondition(const LogEvent& event, void evaluateCondition(const LogEvent& event, const std::vector<MatchingState>& eventMatcherValues, const std::vector<sp<ConditionTracker>>& mAllConditions, std::vector<ConditionState>& conditionCache, std::vector<bool>& changedCache, std::vector<bool>& slicedConditionMayChanged) override; std::vector<bool>& changedCache) override; void isConditionMet(const std::map<std::string, HashableDimensionKey>& conditionParameters, const std::vector<sp<ConditionTracker>>& allConditions, Loading
cmds/statsd/src/condition/ConditionTracker.h +5 −10 Original line number Diff line number Diff line Loading @@ -56,25 +56,20 @@ public: std::vector<bool>& stack) = 0; // evaluate current condition given the new event. // return true if the condition state changed, false if the condition state is not changed. // event: the new log event // eventMatcherValues: the results of the LogMatcherTrackers. LogMatcherTrackers always process // event before ConditionTrackers, because ConditionTracker depends on // LogMatchingTrackers. // mAllConditions: the list of all ConditionTracker // conditionCache: the cached non-sliced condition of the ConditionTrackers for this new event. // nonSlicedConditionChanged: the bit map to record whether non-sliced condition has changed. // slicedConditionMayChanged: the bit map to record whether sliced condition may have changed. // Because sliced condition needs parameters to determine the value. So the sliced // condition is not pushed to metrics. We only inform the relevant metrics that the sliced // condition may have changed, and metrics should pull the conditions that they are // interested in. virtual bool evaluateCondition(const LogEvent& event, // conditionChanged: the bit map to record whether the condition has changed. // If the condition has dimension, then any sub condition changes will report // conditionChanged. virtual void evaluateCondition(const LogEvent& event, const std::vector<MatchingState>& eventMatcherValues, const std::vector<sp<ConditionTracker>>& mAllConditions, std::vector<ConditionState>& conditionCache, std::vector<bool>& nonSlicedConditionChanged, std::vector<bool>& slicedConditionMayChanged) = 0; std::vector<bool>& conditionChanged) = 0; // Return the current condition state. virtual ConditionState isConditionMet() { Loading
cmds/statsd/src/condition/SimpleConditionTracker.cpp +129 −82 Original line number Diff line number Diff line Loading @@ -74,13 +74,21 @@ SimpleConditionTracker::SimpleConditionTracker( mStopAllLogMatcherIndex = -1; } mDimension.insert(mDimension.begin(), simpleCondition.dimension().begin(), mOutputDimension.insert(mOutputDimension.begin(), simpleCondition.dimension().begin(), simpleCondition.dimension().end()); if (mDimension.size() > 0) { if (mOutputDimension.size() > 0) { mSliced = true; } if (simpleCondition.initial_value() == SimpleCondition_InitialValue_FALSE) { mInitialValue = ConditionState::kFalse; } else { mInitialValue = ConditionState::kUnknown; } mNonSlicedConditionState = mInitialValue; mInitialized = true; } Loading @@ -97,127 +105,166 @@ bool SimpleConditionTracker::init(const vector<Condition>& allConditionConfig, return mInitialized; } void print(unordered_map<HashableDimensionKey, ConditionState>& conditions, const string& name) { void print(map<HashableDimensionKey, int>& conditions, const string& name) { VLOG("%s DUMP:", name.c_str()); for (const auto& pair : conditions) { VLOG("\t%s %d", pair.first.c_str(), pair.second); VLOG("\t%s : %d", pair.first.c_str(), pair.second); } } bool SimpleConditionTracker::evaluateCondition(const LogEvent& event, const vector<MatchingState>& eventMatcherValues, const vector<sp<ConditionTracker>>& mAllConditions, vector<ConditionState>& conditionCache, vector<bool>& nonSlicedConditionChanged, std::vector<bool>& slicedConditionChanged) { if (conditionCache[mIndex] != ConditionState::kNotEvaluated) { // it has been evaluated. VLOG("Yes, already evaluated, %s %d", mName.c_str(), mNonSlicedConditionState); return false; void SimpleConditionTracker::handleStopAll(std::vector<ConditionState>& conditionCache, std::vector<bool>& conditionChangedCache) { // Unless the default condition is false, and there was nothing started, otherwise we have // triggered a condition change. conditionChangedCache[mIndex] = (mInitialValue == ConditionState::kFalse && mSlicedConditionState.empty()) ? false : true; // After StopAll, we know everything has stopped. From now on, default condition is false. mInitialValue = ConditionState::kFalse; mSlicedConditionState.clear(); conditionCache[mIndex] = ConditionState::kFalse; } // Ignore nesting, because we know we cannot trust ourselves on tracking nesting conditions. ConditionState newCondition = mNonSlicedConditionState; bool matched = false; // Note: The order to evaluate the following start, stop, stop_all matters. // The priority of overwrite is stop_all > stop > start. if (mStartLogMatcherIndex >= 0 && eventMatcherValues[mStartLogMatcherIndex] == MatchingState::kMatched) { matched = true; newCondition = ConditionState::kTrue; void SimpleConditionTracker::handleConditionEvent(const HashableDimensionKey& outputKey, bool matchStart, std::vector<ConditionState>& conditionCache, std::vector<bool>& conditionChangedCache) { bool changed = false; auto outputIt = mSlicedConditionState.find(outputKey); ConditionState newCondition; if (outputIt == mSlicedConditionState.end()) { // We get a new output key. newCondition = matchStart ? ConditionState::kTrue : ConditionState::kFalse; if (matchStart && mInitialValue != ConditionState::kTrue) { mSlicedConditionState[outputKey] = 1; changed = true; } else if (mInitialValue != ConditionState::kFalse) { // it's a stop and we don't have history about it. // If the default condition is not false, it means this stop is valuable to us. mSlicedConditionState[outputKey] = 0; changed = true; } } else { // we have history about this output key. auto& startedCount = outputIt->second; // assign the old value first. newCondition = startedCount > 0 ? ConditionState::kTrue : ConditionState::kFalse; if (matchStart) { if (startedCount == 0) { // This condition for this output key will change from false -> true changed = true; } if (mStopLogMatcherIndex >= 0 && eventMatcherValues[mStopLogMatcherIndex] == MatchingState::kMatched) { matched = true; // it's ok to do ++ here, even if we don't count nesting. The >1 counts will be treated // as 1 if not counting nesting. startedCount++; newCondition = ConditionState::kTrue; } else { // This is a stop event. if (startedCount > 0) { if (mCountNesting) { startedCount--; if (startedCount == 0) { newCondition = ConditionState::kFalse; } bool stopAll = false; if (mStopAllLogMatcherIndex >= 0 && eventMatcherValues[mStopAllLogMatcherIndex] == MatchingState::kMatched) { matched = true; } else { // not counting nesting, so ignore the number of starts, stop now. startedCount = 0; newCondition = ConditionState::kFalse; stopAll = true; } // if everything has stopped for this output key, condition true -> false; if (startedCount == 0) { changed = true; } } if (matched == false) { slicedConditionChanged[mIndex] = false; nonSlicedConditionChanged[mIndex] = false; conditionCache[mIndex] = mNonSlicedConditionState; return false; // if default condition is false, it means we don't need to keep the false values. if (mInitialValue == ConditionState::kFalse && startedCount == 0) { mSlicedConditionState.erase(outputIt); VLOG("erase key %s", outputKey.c_str()); } } } bool nonSlicedChanged = mNonSlicedConditionState != newCondition; // dump all dimensions for debugging if (DEBUG) { print(mSlicedConditionState, mName); } bool slicedChanged = false; conditionChangedCache[mIndex] = changed; conditionCache[mIndex] = newCondition; if (stopAll) { // TODO: handle stop all; all dimension should be cleared. VLOG("SimpleCondition %s nonSlicedChange? %d", mName.c_str(), conditionChangedCache[mIndex] == true); } if (mDimension.size() > 0) { HashableDimensionKey hashableKey = getHashableKey(getDimensionKey(event, mDimension)); if (mSlicedConditionState.find(hashableKey) == mSlicedConditionState.end() || mSlicedConditionState[hashableKey] != newCondition) { slicedChanged = true; mSlicedConditionState[hashableKey] = newCondition; void SimpleConditionTracker::evaluateCondition(const LogEvent& event, const vector<MatchingState>& eventMatcherValues, const vector<sp<ConditionTracker>>& mAllConditions, vector<ConditionState>& conditionCache, vector<bool>& conditionChangedCache) { if (conditionCache[mIndex] != ConditionState::kNotEvaluated) { // it has been evaluated. VLOG("Yes, already evaluated, %s %d", mName.c_str(), mNonSlicedConditionState); return; } VLOG("key: %s %d", hashableKey.c_str(), newCondition); // dump all dimensions for debugging if (DEBUG) { print(mSlicedConditionState, mName); if (mStopAllLogMatcherIndex >= 0 && eventMatcherValues[mStopAllLogMatcherIndex] == MatchingState::kMatched) { handleStopAll(conditionCache, conditionChangedCache); return; } int matchedState = -1; // Note: The order to evaluate the following start, stop, stop_all matters. // The priority of overwrite is stop_all > stop > start. if (mStartLogMatcherIndex >= 0 && eventMatcherValues[mStartLogMatcherIndex] == MatchingState::kMatched) { matchedState = 1; } // even if this SimpleCondition is not sliced, it may be part of a sliced CombinationCondition // if the nonSliced condition changed, it may affect the sliced condition in the parent node. // so mark the slicedConditionChanged to be true. // For example: APP_IN_BACKGROUND_OR_SCREEN_OFF // APP_IN_BACKGROUND is sliced [App_A->True, App_B->False]. // SCREEN_OFF is not sliced, and it changes from False -> True; // We need to populate this change to parent condition. Because for App_B, // the APP_IN_BACKGROUND_OR_SCREEN_OFF condition would change from False->True. slicedConditionChanged[mIndex] = mSliced ? slicedChanged : nonSlicedChanged; nonSlicedConditionChanged[mIndex] = nonSlicedChanged; if (mStopLogMatcherIndex >= 0 && eventMatcherValues[mStopLogMatcherIndex] == MatchingState::kMatched) { matchedState = 0; } VLOG("SimpleCondition %s nonSlicedChange? %d SlicedChanged? %d", mName.c_str(), nonSlicedConditionChanged[mIndex] == true, slicedConditionChanged[mIndex] == true); mNonSlicedConditionState = newCondition; if (matchedState < 0) { conditionChangedCache[mIndex] = false; conditionCache[mIndex] = mNonSlicedConditionState; return; } return nonSlicedConditionChanged[mIndex]; // outputKey is the output key values. e.g, uid:1234 const HashableDimensionKey outputKey = getHashableKey(getDimensionKey(event, mOutputDimension)); handleConditionEvent(outputKey, matchedState == 1, conditionCache, conditionChangedCache); } void SimpleConditionTracker::isConditionMet( const map<string, HashableDimensionKey>& conditionParameters, const vector<sp<ConditionTracker>>& allConditions, vector<ConditionState>& conditionCache) { const auto pair = conditionParameters.find(mName); if (pair == conditionParameters.end()) { // the query does not need my sliced condition. just return the non sliced condition. conditionCache[mIndex] = mNonSlicedConditionState; VLOG("Condition %s return %d", mName.c_str(), mNonSlicedConditionState); HashableDimensionKey key = (pair == conditionParameters.end()) ? DEFAULT_DIMENSION_KEY : pair->second; if (pair == conditionParameters.end() && mOutputDimension.size() > 0) { ALOGE("Condition %s output has dimension, but it's not specified in the query!", mName.c_str()); conditionCache[mIndex] = mInitialValue; return; } const HashableDimensionKey& key = pair->second; VLOG("simpleCondition %s query key: %s", mName.c_str(), key.c_str()); if (mSlicedConditionState.find(key) == mSlicedConditionState.end()) { // never seen this key before. the condition is unknown to us. conditionCache[mIndex] = ConditionState::kUnknown; auto startedCountIt = mSlicedConditionState.find(key); if (startedCountIt == mSlicedConditionState.end()) { conditionCache[mIndex] = mInitialValue; } else { conditionCache[mIndex] = mSlicedConditionState[key]; conditionCache[mIndex] = startedCountIt->second > 0 ? ConditionState::kTrue : ConditionState::kFalse; } VLOG("Condition %s return %d", mName.c_str(), conditionCache[mIndex]); if (DEBUG) { print(mSlicedConditionState, mName); } } } // namespace statsd Loading