diff options
14 files changed, 1121 insertions, 155 deletions
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp index 3b65f8225ee9..4574b2e34547 100644 --- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp +++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp @@ -25,8 +25,9 @@ namespace statsd { using std::unordered_map; using std::vector; -CombinationConditionTracker::CombinationConditionTracker(const int64_t& id, const int index) - : ConditionTracker(id, index) { +CombinationConditionTracker::CombinationConditionTracker(const int64_t& id, const int index, + const uint64_t protoHash) + : ConditionTracker(id, index, protoHash) { VLOG("creating CombinationConditionTracker %lld", (long long)mConditionId); } @@ -122,6 +123,49 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf return true; } +bool CombinationConditionTracker::onConfigUpdated( + const vector<Predicate>& allConditionProtos, const int index, + const vector<sp<ConditionTracker>>& allConditionTrackers, + const unordered_map<int64_t, int>& atomMatchingTrackerMap, + const unordered_map<int64_t, int>& conditionTrackerMap) { + ConditionTracker::onConfigUpdated(allConditionProtos, index, allConditionTrackers, + atomMatchingTrackerMap, conditionTrackerMap); + mTrackerIndex.clear(); + mChildren.clear(); + mUnSlicedChildren.clear(); + mSlicedChildren.clear(); + Predicate_Combination combinationCondition = allConditionProtos[mIndex].combination(); + + for (const int64_t child : combinationCondition.predicate()) { + const auto& it = conditionTrackerMap.find(child); + + if (it == conditionTrackerMap.end()) { + ALOGW("Predicate %lld not found in the config", (long long)child); + return false; + } + + int childIndex = it->second; + const sp<ConditionTracker>& childTracker = allConditionTrackers[childIndex]; + + // Ensures that the child's tracker indices are updated. + if (!childTracker->onConfigUpdated(allConditionProtos, childIndex, allConditionTrackers, + atomMatchingTrackerMap, conditionTrackerMap)) { + ALOGW("Child update failed %lld ", (long long)child); + return false; + } + + if (allConditionTrackers[childIndex]->isSliced()) { + mSlicedChildren.push_back(childIndex); + } else { + mUnSlicedChildren.push_back(childIndex); + } + mChildren.push_back(childIndex); + mTrackerIndex.insert(childTracker->getAtomMatchingTrackerIndex().begin(), + childTracker->getAtomMatchingTrackerIndex().end()); + } + return true; +} + void CombinationConditionTracker::isConditionMet( const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions, const bool isPartialLink, diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h index a7fac3deaabe..672d61c82268 100644 --- a/cmds/statsd/src/condition/CombinationConditionTracker.h +++ b/cmds/statsd/src/condition/CombinationConditionTracker.h @@ -24,9 +24,9 @@ namespace android { namespace os { namespace statsd { -class CombinationConditionTracker : public virtual ConditionTracker { +class CombinationConditionTracker : public ConditionTracker { public: - CombinationConditionTracker(const int64_t& id, const int index); + CombinationConditionTracker(const int64_t& id, const int index, const uint64_t protoHash); ~CombinationConditionTracker(); @@ -35,6 +35,11 @@ public: const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack, std::vector<ConditionState>& conditionCache) override; + bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index, + const std::vector<sp<ConditionTracker>>& allConditionTrackers, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap, + const std::unordered_map<int64_t, int>& conditionTrackerMap) override; + void evaluateCondition(const LogEvent& event, const std::vector<MatchingState>& eventMatcherValues, const std::vector<sp<ConditionTracker>>& mAllConditions, @@ -102,6 +107,7 @@ private: std::vector<int> mSlicedChildren; std::vector<int> mUnSlicedChildren; + FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions); }; } // namespace statsd diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h index 4e1253506be7..3bf4e636be89 100644 --- a/cmds/statsd/src/condition/ConditionTracker.h +++ b/cmds/statsd/src/condition/ConditionTracker.h @@ -31,18 +31,17 @@ namespace statsd { class ConditionTracker : public virtual RefBase { public: - ConditionTracker(const int64_t& id, const int index) + ConditionTracker(const int64_t& id, const int index, const uint64_t protoHash) : mConditionId(id), mIndex(index), mInitialized(false), mTrackerIndex(), mUnSlicedPartCondition(ConditionState::kUnknown), - mSliced(false){}; + mSliced(false), + mProtoHash(protoHash){}; virtual ~ConditionTracker(){}; - inline const int64_t& getId() { return mConditionId; } - // Initialize this ConditionTracker. This initialization is done recursively (DFS). It can also // be done in the constructor, but we do it separately because (1) easy to return a bool to // indicate whether the initialization is successful. (2) makes unit test easier. @@ -50,7 +49,7 @@ public: // fill the condition cache with the current condition. // allConditionConfig: the list of all Predicate config from statsd_config. // allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also - // need to call init() on children conditions) + // need to call init() on child conditions) // conditionIdIndexMap: the mapping from condition id to its index. // stack: a bit map to keep track which nodes have been visited on the stack in the recursion. // conditionCache: tracks initial conditions of all ConditionTrackers. returns the @@ -60,6 +59,26 @@ public: const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack, std::vector<ConditionState>& conditionCache) = 0; + // Update appropriate state on config updates. Primarily, all indices need to be updated. + // This predicate and all of its children are guaranteed to be preserved across the update. + // This function is recursive and will call onConfigUpdated on child conditions. It does not + // manage cycle detection since all preserved conditions should not have any cycles. + // + // allConditionProtos: the new predicates. + // index: the new index of this tracker in allConditionProtos and allConditionTrackers. + // allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also + // need to call onConfigUpdated() on child conditions) + // [atomMatchingTrackerMap]: map of atom matcher id to index after the config update + // [conditionTrackerMap]: map of condition tracker id to index after the config update. + // returns whether or not the update is successful + virtual bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index, + const std::vector<sp<ConditionTracker>>& allConditionTrackers, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap, + const std::unordered_map<int64_t, int>& conditionTrackerMap) { + mIndex = index; + return true; + } + // evaluate current condition given the new event. // event: the new log event // eventMatcherValues: the results of the AtomMatchingTrackers. AtomMatchingTrackers always @@ -112,6 +131,10 @@ public: return mConditionId; } + inline uint64_t getProtoHash() const { + return mProtoHash; + } + virtual void getTrueSlicedDimensions( const std::vector<sp<ConditionTracker>>& allConditions, std::set<HashableDimensionKey>* dimensions) const = 0; @@ -133,7 +156,7 @@ protected: const int64_t mConditionId; // the index of this condition in the manager's condition list. - const int mIndex; + int mIndex; // if it's properly initialized. bool mInitialized; @@ -151,6 +174,12 @@ protected: ConditionState mUnSlicedPartCondition; bool mSliced; + + // Hash of the Predicate's proto bytes from StatsdConfig. + // Used to determine if the definition of this condition has changed across a config update. + const uint64_t mProtoHash; + + FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions); }; } // namespace statsd diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp index f45759b6a77e..1dcc8f96131a 100644 --- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp +++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp @@ -27,54 +27,21 @@ namespace statsd { using std::unordered_map; SimpleConditionTracker::SimpleConditionTracker( - const ConfigKey& key, const int64_t& id, const int index, + const ConfigKey& key, const int64_t& id, const uint64_t protoHash, const int index, const SimplePredicate& simplePredicate, - const unordered_map<int64_t, int>& trackerNameIndexMap) - : ConditionTracker(id, index), mConfigKey(key), mContainANYPositionInInternalDimensions(false) { + const unordered_map<int64_t, int>& atomMatchingTrackerMap) + : ConditionTracker(id, index, protoHash), + mConfigKey(key), + mContainANYPositionInInternalDimensions(false) { VLOG("creating SimpleConditionTracker %lld", (long long)mConditionId); mCountNesting = simplePredicate.count_nesting(); - if (simplePredicate.has_start()) { - auto pair = trackerNameIndexMap.find(simplePredicate.start()); - if (pair == trackerNameIndexMap.end()) { - ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start()); - return; - } - mStartLogMatcherIndex = pair->second; - mTrackerIndex.insert(mStartLogMatcherIndex); - } else { - mStartLogMatcherIndex = -1; - } - - if (simplePredicate.has_stop()) { - auto pair = trackerNameIndexMap.find(simplePredicate.stop()); - if (pair == trackerNameIndexMap.end()) { - ALOGW("Stop matcher %lld not found in the config", (long long)simplePredicate.stop()); - return; - } - mStopLogMatcherIndex = pair->second; - mTrackerIndex.insert(mStopLogMatcherIndex); - } else { - mStopLogMatcherIndex = -1; - } - - if (simplePredicate.has_stop_all()) { - auto pair = trackerNameIndexMap.find(simplePredicate.stop_all()); - if (pair == trackerNameIndexMap.end()) { - ALOGW("Stop all matcher %lld found in the config", (long long)simplePredicate.stop_all()); - return; - } - mStopAllLogMatcherIndex = pair->second; - mTrackerIndex.insert(mStopAllLogMatcherIndex); - } else { - mStopAllLogMatcherIndex = -1; - } + setMatcherIndices(simplePredicate, atomMatchingTrackerMap); if (simplePredicate.has_dimensions()) { translateFieldMatcher(simplePredicate.dimensions(), &mOutputDimensions); if (mOutputDimensions.size() > 0) { mSliced = true; - mDimensionTag = mOutputDimensions[0].mMatcher.getTag(); } mContainANYPositionInInternalDimensions = HasPositionANY(simplePredicate.dimensions()); } @@ -106,6 +73,59 @@ bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig, return mInitialized; } +bool SimpleConditionTracker::onConfigUpdated( + const vector<Predicate>& allConditionProtos, const int index, + const vector<sp<ConditionTracker>>& allConditionTrackers, + const unordered_map<int64_t, int>& atomMatchingTrackerMap, + const unordered_map<int64_t, int>& conditionTrackerMap) { + ConditionTracker::onConfigUpdated(allConditionProtos, index, allConditionTrackers, + atomMatchingTrackerMap, conditionTrackerMap); + setMatcherIndices(allConditionProtos[index].simple_predicate(), atomMatchingTrackerMap); + return true; +} + +void SimpleConditionTracker::setMatcherIndices( + const SimplePredicate& simplePredicate, + const unordered_map<int64_t, int>& atomMatchingTrackerMap) { + mTrackerIndex.clear(); + if (simplePredicate.has_start()) { + auto pair = atomMatchingTrackerMap.find(simplePredicate.start()); + if (pair == atomMatchingTrackerMap.end()) { + ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start()); + return; + } + mStartLogMatcherIndex = pair->second; + mTrackerIndex.insert(mStartLogMatcherIndex); + } else { + mStartLogMatcherIndex = -1; + } + + if (simplePredicate.has_stop()) { + auto pair = atomMatchingTrackerMap.find(simplePredicate.stop()); + if (pair == atomMatchingTrackerMap.end()) { + ALOGW("Stop matcher %lld not found in the config", (long long)simplePredicate.stop()); + return; + } + mStopLogMatcherIndex = pair->second; + mTrackerIndex.insert(mStopLogMatcherIndex); + } else { + mStopLogMatcherIndex = -1; + } + + if (simplePredicate.has_stop_all()) { + auto pair = atomMatchingTrackerMap.find(simplePredicate.stop_all()); + if (pair == atomMatchingTrackerMap.end()) { + ALOGW("Stop all matcher %lld found in the config", + (long long)simplePredicate.stop_all()); + return; + } + mStopAllLogMatcherIndex = pair->second; + mTrackerIndex.insert(mStopAllLogMatcherIndex); + } else { + mStopAllLogMatcherIndex = -1; + } +} + void SimpleConditionTracker::dumpState() { VLOG("%lld DUMP:", (long long)mConditionId); for (const auto& pair : mSlicedConditionState) { diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h index 1a9e35e38207..7a8b40108448 100644 --- a/cmds/statsd/src/condition/SimpleConditionTracker.h +++ b/cmds/statsd/src/condition/SimpleConditionTracker.h @@ -27,11 +27,11 @@ namespace android { namespace os { namespace statsd { -class SimpleConditionTracker : public virtual ConditionTracker { +class SimpleConditionTracker : public ConditionTracker { public: - SimpleConditionTracker(const ConfigKey& key, const int64_t& id, const int index, - const SimplePredicate& simplePredicate, - const std::unordered_map<int64_t, int>& trackerNameIndexMap); + SimpleConditionTracker(const ConfigKey& key, const int64_t& id, const uint64_t protoHash, + const int index, const SimplePredicate& simplePredicate, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap); ~SimpleConditionTracker(); @@ -40,6 +40,11 @@ public: const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack, std::vector<ConditionState>& conditionCache) override; + bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index, + const std::vector<sp<ConditionTracker>>& allConditionTrackers, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap, + const std::unordered_map<int64_t, int>& conditionTrackerMap) override; + void evaluateCondition(const LogEvent& event, const std::vector<MatchingState>& eventMatcherValues, const std::vector<sp<ConditionTracker>>& mAllConditions, @@ -112,10 +117,11 @@ private: std::set<HashableDimensionKey> mLastChangedToTrueDimensions; std::set<HashableDimensionKey> mLastChangedToFalseDimensions; - int mDimensionTag; - std::map<HashableDimensionKey, int> mSlicedConditionState; + void setMatcherIndices(const SimplePredicate& predicate, + const std::unordered_map<int64_t, int>& logTrackerMap); + void handleStopAll(std::vector<ConditionState>& conditionCache, std::vector<bool>& changedCache); @@ -129,6 +135,7 @@ private: FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedCondition); FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim); FRIEND_TEST(SimpleConditionTrackerTest, TestStopAll); + FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index 5a520326116a..a0c701ea4229 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -80,7 +80,7 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, mConfigValid = initStatsdConfig( key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap, - mAllConditionTrackers, mAllMetricProducers, mAllAnomalyTrackers, + mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mAllAnomalyTrackers, mAllPeriodicAlarmTrackers, mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap, mActivationAtomTrackerToMetricMap, mDeactivationAtomTrackerToMetricMap, mAlertTrackerMap, mMetricIndexesWithActivation, @@ -204,13 +204,20 @@ bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t time const sp<AlarmMonitor>& periodicAlarmMonitor) { vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers; unordered_map<int64_t, int> newAtomMatchingTrackerMap; + vector<sp<ConditionTracker>> newConditionTrackers; + unordered_map<int64_t, int> newConditionTrackerMap; mTagIds.clear(); + mTrackerToConditionMap.clear(); mConfigValid = updateStatsdConfig( mConfigKey, config, mUidMap, mPullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap, mTagIds, - newAtomMatchingTrackers, newAtomMatchingTrackerMap); + timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap, + mAllConditionTrackers, mConditionTrackerMap, mTagIds, newAtomMatchingTrackers, + newAtomMatchingTrackerMap, newConditionTrackers, newConditionTrackerMap, + mTrackerToConditionMap); mAllAtomMatchingTrackers = newAtomMatchingTrackers; mAtomMatchingTrackerMap = newAtomMatchingTrackerMap; + mAllConditionTrackers = newConditionTrackers; + mConditionTrackerMap = newConditionTrackerMap; return mConfigValid; } diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index 6f4b2d7e9fa4..bd0c8161a884 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -242,9 +242,12 @@ private: // To make updating configs faster, we map the id of a AtomMatchingTracker, MetricProducer, and // ConditionTracker to its index in the corresponding vector. - // Maps the id of an atom matcher to its index in mAllAtomMatchingTrackers. + // Maps the id of an atom matching tracker to its index in mAllAtomMatchingTrackers. std::unordered_map<int64_t, int> mAtomMatchingTrackerMap; + // Maps the id of a condition tracker to its index in mAllConditionTrackers. + std::unordered_map<int64_t, int> mConditionTrackerMap; + // To make the log processing more efficient, we want to do as much filtering as possible // before we go into individual trackers and conditions to match. diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp index 0983dc0b2c83..bd60b6bfcb8e 100644 --- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp +++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp @@ -15,6 +15,7 @@ */ #define DEBUG false // STOPSHIP if true +#include "Log.h" #include "config_update_utils.h" @@ -44,7 +45,7 @@ bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherI // Check if new matcher. const auto& oldAtomMatchingTrackerIt = oldAtomMatchingTrackerMap.find(id); if (oldAtomMatchingTrackerIt == oldAtomMatchingTrackerMap.end()) { - matchersToUpdate[matcherIdx] = UPDATE_REPLACE; + matchersToUpdate[matcherIdx] = UPDATE_NEW; return true; } @@ -103,11 +104,13 @@ bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherI return true; } -bool updateAtomTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, - const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, - const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, - set<int>& allTagIds, unordered_map<int64_t, int>& newAtomMatchingTrackerMap, - vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers) { +bool updateAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, + const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, + const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, + set<int>& allTagIds, + unordered_map<int64_t, int>& newAtomMatchingTrackerMap, + vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers, + set<int64_t>& replacedMatchers) { const int atomMatcherCount = config.atom_matcher_size(); vector<AtomMatcher> matcherProtos; @@ -157,7 +160,10 @@ bool updateAtomTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, newAtomMatchingTrackers.push_back(tracker); break; } - case UPDATE_REPLACE: { + case UPDATE_REPLACE: + replacedMatchers.insert(id); + [[fallthrough]]; // Intentionally fallthrough to create the new matcher. + case UPDATE_NEW: { sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(matcher, i, uidMap); if (tracker == nullptr) { return false; @@ -187,6 +193,207 @@ bool updateAtomTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, return true; } +// Recursive function to determine if a condition needs to be updated. Populates conditionsToUpdate. +// Returns whether the function was successful or not. +bool determineConditionUpdateStatus(const StatsdConfig& config, const int conditionIdx, + const unordered_map<int64_t, int>& oldConditionTrackerMap, + const vector<sp<ConditionTracker>>& oldConditionTrackers, + const unordered_map<int64_t, int>& newConditionTrackerMap, + const set<int64_t>& replacedMatchers, + vector<UpdateStatus>& conditionsToUpdate, + vector<bool>& cycleTracker) { + // Have already examined this condition. + if (conditionsToUpdate[conditionIdx] != UPDATE_UNKNOWN) { + return true; + } + + const Predicate& predicate = config.predicate(conditionIdx); + int64_t id = predicate.id(); + // Check if new condition. + const auto& oldConditionTrackerIt = oldConditionTrackerMap.find(id); + if (oldConditionTrackerIt == oldConditionTrackerMap.end()) { + conditionsToUpdate[conditionIdx] = UPDATE_NEW; + return true; + } + + // This is an existing condition. Check if it has changed. + string serializedCondition; + if (!predicate.SerializeToString(&serializedCondition)) { + ALOGE("Unable to serialize matcher %lld", (long long)id); + return false; + } + uint64_t newProtoHash = Hash64(serializedCondition); + if (newProtoHash != oldConditionTrackers[oldConditionTrackerIt->second]->getProtoHash()) { + conditionsToUpdate[conditionIdx] = UPDATE_REPLACE; + return true; + } + + switch (predicate.contents_case()) { + case Predicate::ContentsCase::kSimplePredicate: { + // Need to check if any of the underlying matchers changed. + const SimplePredicate& simplePredicate = predicate.simple_predicate(); + if (simplePredicate.has_start()) { + if (replacedMatchers.find(simplePredicate.start()) != replacedMatchers.end()) { + conditionsToUpdate[conditionIdx] = UPDATE_REPLACE; + return true; + } + } + if (simplePredicate.has_stop()) { + if (replacedMatchers.find(simplePredicate.stop()) != replacedMatchers.end()) { + conditionsToUpdate[conditionIdx] = UPDATE_REPLACE; + return true; + } + } + if (simplePredicate.has_stop_all()) { + if (replacedMatchers.find(simplePredicate.stop_all()) != replacedMatchers.end()) { + conditionsToUpdate[conditionIdx] = UPDATE_REPLACE; + return true; + } + } + conditionsToUpdate[conditionIdx] = UPDATE_PRESERVE; + return true; + } + case Predicate::ContentsCase::kCombination: { + // Need to recurse on the children to see if any of the child predicates changed. + cycleTracker[conditionIdx] = true; + UpdateStatus status = UPDATE_PRESERVE; + for (const int64_t childPredicateId : predicate.combination().predicate()) { + const auto& childIt = newConditionTrackerMap.find(childPredicateId); + if (childIt == newConditionTrackerMap.end()) { + ALOGW("Predicate %lld not found in the config", (long long)childPredicateId); + return false; + } + const int childIdx = childIt->second; + if (cycleTracker[childIdx]) { + ALOGE("Cycle detected in predicate config"); + return false; + } + if (!determineConditionUpdateStatus(config, childIdx, oldConditionTrackerMap, + oldConditionTrackers, newConditionTrackerMap, + replacedMatchers, conditionsToUpdate, + cycleTracker)) { + return false; + } + + if (conditionsToUpdate[childIdx] == UPDATE_REPLACE) { + status = UPDATE_REPLACE; + break; + } + } + conditionsToUpdate[conditionIdx] = status; + cycleTracker[conditionIdx] = false; + return true; + } + default: { + ALOGE("Predicate \"%lld\" malformed", (long long)id); + return false; + } + } + + return true; +} + +bool updateConditions(const ConfigKey& key, const StatsdConfig& config, + const unordered_map<int64_t, int>& atomMatchingTrackerMap, + const set<int64_t>& replacedMatchers, + const unordered_map<int64_t, int>& oldConditionTrackerMap, + const vector<sp<ConditionTracker>>& oldConditionTrackers, + unordered_map<int64_t, int>& newConditionTrackerMap, + vector<sp<ConditionTracker>>& newConditionTrackers, + unordered_map<int, vector<int>>& trackerToConditionMap, + vector<ConditionState>& conditionCache, set<int64_t>& replacedConditions) { + vector<Predicate> conditionProtos; + const int conditionTrackerCount = config.predicate_size(); + conditionProtos.reserve(conditionTrackerCount); + newConditionTrackers.reserve(conditionTrackerCount); + conditionCache.assign(conditionTrackerCount, ConditionState::kNotEvaluated); + + for (int i = 0; i < conditionTrackerCount; i++) { + const Predicate& condition = config.predicate(i); + if (newConditionTrackerMap.find(condition.id()) != newConditionTrackerMap.end()) { + ALOGE("Duplicate Predicate found!"); + return false; + } + newConditionTrackerMap[condition.id()] = i; + conditionProtos.push_back(condition); + } + + vector<UpdateStatus> conditionsToUpdate(conditionTrackerCount, UPDATE_UNKNOWN); + vector<bool> cycleTracker(conditionTrackerCount, false); + for (int i = 0; i < conditionTrackerCount; i++) { + if (!determineConditionUpdateStatus(config, i, oldConditionTrackerMap, oldConditionTrackers, + newConditionTrackerMap, replacedMatchers, + conditionsToUpdate, cycleTracker)) { + return false; + } + } + + // Update status has been determined for all conditions. Now perform the update. + set<int> preservedConditions; + for (int i = 0; i < conditionTrackerCount; i++) { + const Predicate& predicate = config.predicate(i); + const int64_t id = predicate.id(); + switch (conditionsToUpdate[i]) { + case UPDATE_PRESERVE: { + preservedConditions.insert(i); + const auto& oldConditionTrackerIt = oldConditionTrackerMap.find(id); + if (oldConditionTrackerIt == oldConditionTrackerMap.end()) { + ALOGE("Could not find Predicate %lld in the previous config, but expected it " + "to be there", + (long long)id); + return false; + } + const int oldIndex = oldConditionTrackerIt->second; + newConditionTrackers.push_back(oldConditionTrackers[oldIndex]); + break; + } + case UPDATE_REPLACE: + replacedConditions.insert(id); + [[fallthrough]]; // Intentionally fallthrough to create the new condition tracker. + case UPDATE_NEW: { + sp<ConditionTracker> tracker = + createConditionTracker(key, predicate, i, atomMatchingTrackerMap); + if (tracker == nullptr) { + return false; + } + newConditionTrackers.push_back(tracker); + break; + } + default: { + ALOGE("Condition \"%lld\" update state is unknown. This should never happen", + (long long)id); + return false; + } + } + } + + // Update indices of preserved predicates. + for (const int conditionIndex : preservedConditions) { + if (!newConditionTrackers[conditionIndex]->onConfigUpdated( + conditionProtos, conditionIndex, newConditionTrackers, atomMatchingTrackerMap, + newConditionTrackerMap)) { + ALOGE("Failed to update condition %lld", + (long long)newConditionTrackers[conditionIndex]->getConditionId()); + return false; + } + } + + std::fill(cycleTracker.begin(), cycleTracker.end(), false); + for (int conditionIndex = 0; conditionIndex < conditionTrackerCount; conditionIndex++) { + const sp<ConditionTracker>& conditionTracker = newConditionTrackers[conditionIndex]; + // Calling init on preserved conditions is OK. It is needed to fill the condition cache. + if (!conditionTracker->init(conditionProtos, newConditionTrackers, newConditionTrackerMap, + cycleTracker, conditionCache)) { + return false; + } + for (const int trackerIndex : conditionTracker->getAtomMatchingTrackerIndex()) { + vector<int>& conditionList = trackerToConditionMap[trackerIndex]; + conditionList.push_back(conditionIndex); + } + } + return true; +} + bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap, const sp<StatsPullerManager>& pullerManager, const sp<AlarmMonitor>& anomalyAlarmMonitor, @@ -194,14 +401,34 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const const int64_t currentTimeNs, const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, + const vector<sp<ConditionTracker>>& oldConditionTrackers, + const unordered_map<int64_t, int>& oldConditionTrackerMap, set<int>& allTagIds, vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers, - unordered_map<int64_t, int>& newAtomMatchingTrackerMap) { - if (!updateAtomTrackers(config, uidMap, oldAtomMatchingTrackerMap, oldAtomMatchingTrackers, - allTagIds, newAtomMatchingTrackerMap, newAtomMatchingTrackers)) { + unordered_map<int64_t, int>& newAtomMatchingTrackerMap, + vector<sp<ConditionTracker>>& newConditionTrackers, + unordered_map<int64_t, int>& newConditionTrackerMap, + unordered_map<int, vector<int>>& trackerToConditionMap) { + set<int64_t> replacedMatchers; + set<int64_t> replacedConditions; + vector<ConditionState> conditionCache; + + if (!updateAtomMatchingTrackers(config, uidMap, oldAtomMatchingTrackerMap, + oldAtomMatchingTrackers, allTagIds, newAtomMatchingTrackerMap, + newAtomMatchingTrackers, replacedMatchers)) { ALOGE("updateAtomMatchingTrackers failed"); return false; } + VLOG("updateAtomMatchingTrackers succeeded"); + + if (!updateConditions(key, config, newAtomMatchingTrackerMap, replacedMatchers, + oldConditionTrackerMap, oldConditionTrackers, newConditionTrackerMap, + newConditionTrackers, trackerToConditionMap, conditionCache, + replacedConditions)) { + ALOGE("updateConditions failed"); + return false; + } + VLOG("updateConditions succeeded"); return true; } diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h index ae7b2162e034..7ba684a65e88 100644 --- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h +++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h @@ -19,6 +19,7 @@ #include <vector> #include "anomaly/AlarmMonitor.h" +#include "condition/ConditionTracker.h" #include "external/StatsPullerManager.h" #include "matchers/AtomMatchingTracker.h" @@ -31,30 +32,33 @@ namespace statsd { // All other functions are intermediate steps, created to make unit testing easier. // Possible update states for a component. PRESERVE means we should keep the existing one. -// REPLACE means we should create a new one, either because it didn't exist or it changed. +// REPLACE means we should create a new one because the existing one changed +// NEW means we should create a new one because one does not currently exist. enum UpdateStatus { UPDATE_UNKNOWN = 0, UPDATE_PRESERVE = 1, UPDATE_REPLACE = 2, + UPDATE_NEW = 3, }; // Recursive function to determine if a matcher needs to be updated. // input: // [config]: the input StatsdConfig // [matcherIdx]: the index of the current matcher to be updated -// [newAtomMatchingTrackerMap]: matcher id to index mapping in the input StatsdConfig // [oldAtomMatchingTrackerMap]: matcher id to index mapping in the existing MetricsManager // [oldAtomMatchingTrackers]: stores the existing AtomMatchingTrackers +// [newAtomMatchingTrackerMap]: matcher id to index mapping in the input StatsdConfig // output: // [matchersToUpdate]: vector of the update status of each matcher. The matcherIdx index will // be updated from UPDATE_UNKNOWN after this call. // [cycleTracker]: intermediate param used during recursion. -bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherIdx, - const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, - const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, - const unordered_map<int64_t, int>& newAtomMatchingTrackerMap, - vector<UpdateStatus>& matchersToUpdate, - vector<bool>& cycleTracker); +// Returns whether the function was successful or not. +bool determineMatcherUpdateStatus( + const StatsdConfig& config, const int matcherIdx, + const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, + const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, + const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap, + std::vector<UpdateStatus>& matchersToUpdate, std::vector<bool>& cycleTracker); // Updates the AtomMatchingTrackers. // input: @@ -64,12 +68,61 @@ bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherI // output: // [allTagIds]: contains the set of all interesting tag ids to this config. // [newAtomMatchingTrackerMap]: new matcher id to index mapping -// [newAtomMatchers]: stores the new AtomMatchingTrackers -bool updateAtomTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, - const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, - const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, - set<int>& allTagIds, unordered_map<int64_t, int>& newAtomMatchingTrackerMap, - vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers); +// [newAtomMatchingTrackers]: stores the new AtomMatchingTrackers +// [replacedMatchers]: set of matcher ids that changed and have been replaced +bool updateAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, + const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, + const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, + std::set<int>& allTagIds, + std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap, + std::vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers, + std::set<int64_t>& replacedMatchers); + +// Recursive function to determine if a condition needs to be updated. +// input: +// [config]: the input StatsdConfig +// [conditionIdx]: the index of the current condition to be updated +// [oldConditionTrackerMap]: condition id to index mapping in the existing MetricsManager +// [oldConditionTrackers]: stores the existing ConditionTrackers +// [newConditionTrackerMap]: condition id to index mapping in the input StatsdConfig +// [replacedMatchers]: set of replaced matcher ids. conditions using these matchers must be replaced +// output: +// [conditionsToUpdate]: vector of the update status of each condition. The conditionIdx index will +// be updated from UPDATE_UNKNOWN after this call. +// [cycleTracker]: intermediate param used during recursion. +// Returns whether the function was successful or not. +bool determineConditionUpdateStatus(const StatsdConfig& config, const int conditionIdx, + const std::unordered_map<int64_t, int>& oldConditionTrackerMap, + const std::vector<sp<ConditionTracker>>& oldConditionTrackers, + const std::unordered_map<int64_t, int>& newConditionTrackerMap, + const std::set<int64_t>& replacedMatchers, + std::vector<UpdateStatus>& conditionsToUpdate, + std::vector<bool>& cycleTracker); + +// Updates ConditionTrackers +// input: +// [config]: the input config +// [atomMatchingTrackerMap]: AtomMatchingTracker name to index mapping from previous step. +// [replacedMatchers]: ids of replaced matchers. conditions depending on these must also be replaced +// [oldConditionTrackerMap]: existing matcher id to index mapping +// [oldConditionTrackers]: stores the existing ConditionTrackers +// output: +// [newConditionTrackerMap]: new condition id to index mapping +// [newConditionTrackers]: stores the sp to all the ConditionTrackers +// [trackerToConditionMap]: contains the mapping from the index of an atom matcher +// to indices of condition trackers that use the matcher +// [conditionCache]: stores the current conditions for each ConditionTracker +// [replacedConditions]: set of matcher ids that have changed and have been replaced +bool updateConditions(const ConfigKey& key, const StatsdConfig& config, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap, + const std::set<int64_t>& replacedMatchers, + const std::unordered_map<int64_t, int>& oldConditionTrackerMap, + const std::vector<sp<ConditionTracker>>& oldConditionTrackers, + std::unordered_map<int64_t, int>& newConditionTrackerMap, + std::vector<sp<ConditionTracker>>& newConditionTrackers, + std::unordered_map<int, std::vector<int>>& trackerToConditionMap, + std::vector<ConditionState>& conditionCache, + std::set<int64_t>& replacedConditions); // Updates the existing MetricsManager from a new StatsdConfig. // Parameters are the members of MetricsManager. See MetricsManager for declaration. @@ -79,10 +132,15 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs, const int64_t currentTimeNs, const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, - const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, + const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, + const std::vector<sp<ConditionTracker>>& oldConditionTrackers, + const std::unordered_map<int64_t, int>& oldConditionTrackerMap, std::set<int>& allTagIds, std::vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers, - unordered_map<int64_t, int>& newAtomMatchingTrackerMap); + std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap, + std::vector<sp<ConditionTracker>>& newConditionTrackers, + std::unordered_map<int64_t, int>& newConditionTrackerMap, + std::unordered_map<int, std::vector<int>>& trackerToConditionMap); } // namespace statsd } // namespace os diff --git a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp index e40fbdb250f1..2e3e43413d54 100644 --- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp @@ -74,16 +74,37 @@ sp<AtomMatchingTracker> createAtomMatchingTracker(const AtomMatcher& logMatcher, case AtomMatcher::ContentsCase::kSimpleAtomMatcher: return new SimpleAtomMatchingTracker(logMatcher.id(), index, protoHash, logMatcher.simple_atom_matcher(), uidMap); - break; case AtomMatcher::ContentsCase::kCombination: return new CombinationAtomMatchingTracker(logMatcher.id(), index, protoHash); - break; default: ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id()); return nullptr; } } +sp<ConditionTracker> createConditionTracker( + const ConfigKey& key, const Predicate& predicate, const int index, + const unordered_map<int64_t, int>& atomMatchingTrackerMap) { + string serializedPredicate; + if (!predicate.SerializeToString(&serializedPredicate)) { + ALOGE("Unable to serialize predicate %lld", (long long)predicate.id()); + return nullptr; + } + uint64_t protoHash = Hash64(serializedPredicate); + switch (predicate.contents_case()) { + case Predicate::ContentsCase::kSimplePredicate: { + return new SimpleConditionTracker(key, predicate.id(), protoHash, index, + predicate.simple_predicate(), atomMatchingTrackerMap); + } + case Predicate::ContentsCase::kCombination: { + return new CombinationConditionTracker(predicate.id(), index, protoHash); + } + default: + ALOGE("Predicate \"%lld\" malformed", (long long)predicate.id()); + return nullptr; + } +} + bool handleMetricWithAtomMatchingTrackers( const int64_t what, const int metricIndex, const bool usedForDimension, const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, @@ -266,8 +287,7 @@ bool initAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidM for (int i = 0; i < atomMatcherCount; i++) { const AtomMatcher& logMatcher = config.atom_matcher(i); - int index = allAtomMatchingTrackers.size(); - sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(logMatcher, index, uidMap); + sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(logMatcher, i, uidMap); if (tracker == nullptr) { return false; } @@ -276,7 +296,7 @@ bool initAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidM ALOGE("Duplicate AtomMatcher found!"); return false; } - atomMatchingTrackerMap[logMatcher.id()] = index; + atomMatchingTrackerMap[logMatcher.id()] = i; matcherConfigs.push_back(logMatcher); } @@ -307,28 +327,17 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config, for (int i = 0; i < conditionTrackerCount; i++) { const Predicate& condition = config.predicate(i); - int index = allConditionTrackers.size(); - switch (condition.contents_case()) { - case Predicate::ContentsCase::kSimplePredicate: { - allConditionTrackers.push_back(new SimpleConditionTracker( - key, condition.id(), index, condition.simple_predicate(), - atomMatchingTrackerMap)); - break; - } - case Predicate::ContentsCase::kCombination: { - allConditionTrackers.push_back( - new CombinationConditionTracker(condition.id(), index)); - break; - } - default: - ALOGE("Predicate \"%lld\" malformed", (long long)condition.id()); - return false; + sp<ConditionTracker> tracker = + createConditionTracker(key, condition, i, atomMatchingTrackerMap); + if (tracker == nullptr) { + return false; } + allConditionTrackers.push_back(tracker); if (conditionTrackerMap.find(condition.id()) != conditionTrackerMap.end()) { ALOGE("Duplicate Predicate found!"); return false; } - conditionTrackerMap[condition.id()] = index; + conditionTrackerMap[condition.id()] = i; conditionConfigs.push_back(condition); } @@ -934,6 +943,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, unordered_map<int64_t, int>& atomMatchingTrackerMap, vector<sp<ConditionTracker>>& allConditionTrackers, + unordered_map<int64_t, int>& conditionTrackerMap, vector<sp<MetricProducer>>& allMetricProducers, vector<sp<AnomalyTracker>>& allAnomalyTrackers, vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers, @@ -944,7 +954,6 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap, unordered_map<int64_t, int>& alertTrackerMap, vector<int>& metricsWithActivation, std::set<int64_t>& noReportMetricIds) { - unordered_map<int64_t, int> conditionTrackerMap; vector<ConditionState> initialConditionCache; unordered_map<int64_t, int> metricProducerMap; unordered_map<int64_t, int> stateAtomIdMap; diff --git a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h index 4cfd1b0465ea..6eabcf4971d3 100644 --- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h +++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h @@ -42,6 +42,17 @@ namespace statsd { sp<AtomMatchingTracker> createAtomMatchingTracker(const AtomMatcher& logMatcher, const int index, const sp<UidMap>& uidMap); +// Create a ConditionTracker. +// input: +// [predicate]: the input Predicate from the StatsdConfig +// [index]: the index of the condition tracker +// [atomMatchingTrackerMap]: map of atom matcher id to its index in allAtomMatchingTrackers +// output: +// new ConditionTracker, or null if the tracker is unable to be created +sp<ConditionTracker> createConditionTracker( + const ConfigKey& key, const Predicate& predicate, const int index, + const unordered_map<int64_t, int>& atomMatchingTrackerMap); + // Helper functions for MetricsManager to initialize from StatsdConfig. // *Note*: only initStatsdConfig() should be called from outside. // All other functions are intermediate @@ -77,7 +88,6 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config, std::unordered_map<int64_t, int>& conditionTrackerMap, std::vector<sp<ConditionTracker>>& allConditionTrackers, std::unordered_map<int, std::vector<int>>& trackerToConditionMap, - std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks, std::vector<ConditionState>& initialConditionCache); // Initialize State maps using State protos in the config. These maps will @@ -111,7 +121,6 @@ bool initMetrics( const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager, const std::unordered_map<int64_t, int>& atomMatchingTrackerMap, const std::unordered_map<int64_t, int>& conditionTrackerMap, - const std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks, const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, const unordered_map<int64_t, int>& stateAtomIdMap, const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps, @@ -135,6 +144,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, std::unordered_map<int64_t, int>& atomMatchingTrackerMap, std::vector<sp<ConditionTracker>>& allConditionTrackers, + std::unordered_map<int64_t, int>& conditionTrackerMap, std::vector<sp<MetricProducer>>& allMetricProducers, vector<sp<AnomalyTracker>>& allAnomalyTrackers, vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers, diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp index 07b5311b1207..8998b5f98df5 100644 --- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp +++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp @@ -39,6 +39,7 @@ const ConfigKey kConfigKey(0, 12345); const int ATTRIBUTION_NODE_FIELD_ID = 1; const int ATTRIBUTION_UID_FIELD_ID = 1; const int TAG_ID = 1; +const uint64_t protoHash = 0x123456789; SimplePredicate getWakeLockHeldCondition(bool countNesting, bool defaultFalse, bool outputSlicedUid, Position position) { @@ -123,7 +124,7 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueFalse) { trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0; trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1; - SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), + SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash, 0 /*tracker index*/, simplePredicate, trackerNameIndexMap); @@ -177,7 +178,7 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueUnknown) { trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0; trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1; - SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), + SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash, 0 /*tracker index*/, simplePredicate, trackerNameIndexMap); @@ -231,8 +232,9 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) { trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0; trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1; - SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), 0 /*tracker index*/, - simplePredicate, trackerNameIndexMap); + SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash, + 0 /*tracker index*/, simplePredicate, + trackerNameIndexMap); EXPECT_FALSE(conditionTracker.isSliced()); // This event is not accessed in this test besides dimensions which is why this is okay. @@ -317,7 +319,7 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) { trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0; trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1; - SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), + SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash, 0 /*condition tracker index*/, simplePredicate, trackerNameIndexMap); EXPECT_FALSE(conditionTracker.isSliced()); @@ -392,7 +394,7 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) { trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1; trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2; - SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), + SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash, 0 /*condition tracker index*/, simplePredicate, trackerNameIndexMap); @@ -514,7 +516,7 @@ TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) { trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1; trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2; - SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), + SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash, 0 /*condition tracker index*/, simplePredicate, trackerNameIndexMap); @@ -610,7 +612,7 @@ TEST(SimpleConditionTrackerTest, TestStopAll) { trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1; trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2; - SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), + SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash, 0 /*condition tracker index*/, simplePredicate, trackerNameIndexMap); diff --git a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp index 8c698eb15d8d..890884bc5d83 100644 --- a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp +++ b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp @@ -14,6 +14,7 @@ #include "src/metrics/parsing_utils/config_update_utils.h" +#include <gmock/gmock.h> #include <gtest/gtest.h> #include <private/android_filesystem_config.h> #include <stdio.h> @@ -23,6 +24,8 @@ #include <vector> #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" +#include "src/condition/CombinationConditionTracker.h" +#include "src/condition/SimpleConditionTracker.h" #include "src/matchers/CombinationAtomMatchingTracker.h" #include "src/metrics/parsing_utils/metrics_manager_util.h" #include "tests/statsd_test_util.h" @@ -53,6 +56,7 @@ set<int> allTagIds; vector<sp<AtomMatchingTracker>> oldAtomMatchingTrackers; unordered_map<int64_t, int> oldAtomMatchingTrackerMap; vector<sp<ConditionTracker>> oldConditionTrackers; +unordered_map<int64_t, int> oldConditionTrackerMap; vector<sp<MetricProducer>> oldMetricProducers; std::vector<sp<AnomalyTracker>> oldAnomalyTrackers; std::vector<sp<AlarmTracker>> oldAlarmTrackers; @@ -75,6 +79,7 @@ public: oldAtomMatchingTrackers.clear(); oldAtomMatchingTrackerMap.clear(); oldConditionTrackers.clear(); + oldConditionTrackerMap.clear(); oldMetricProducers.clear(); oldAnomalyTrackers.clear(); oldAlarmTrackers.clear(); @@ -93,8 +98,8 @@ bool initConfig(const StatsdConfig& config) { return initStatsdConfig( key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseNs, timeBaseNs, allTagIds, oldAtomMatchingTrackers, oldAtomMatchingTrackerMap, - oldConditionTrackers, oldMetricProducers, oldAnomalyTrackers, oldAlarmTrackers, - conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + oldConditionTrackers, oldConditionTrackerMap, oldMetricProducers, oldAnomalyTrackers, + oldAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, noReportMetricIds); } @@ -144,6 +149,30 @@ TEST_F(ConfigUpdateTest, TestSimpleMatcherReplace) { EXPECT_EQ(matchersToUpdate[0], UPDATE_REPLACE); } +TEST_F(ConfigUpdateTest, TestSimpleMatcherNew) { + StatsdConfig config; + AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10); + *config.add_atom_matcher() = matcher; + + EXPECT_TRUE(initConfig(config)); + + StatsdConfig newConfig; + // Different id, so should be a new matcher. + AtomMatcher newMatcher = CreateSimpleAtomMatcher("DIFFERENT_NAME", /*atom=*/10); + int64_t matcherId = newMatcher.id(); + EXPECT_NE(matcherId, matcher.id()); + *newConfig.add_atom_matcher() = newMatcher; + + vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN); + vector<bool> cycleTracker(1, false); + unordered_map<int64_t, int> newAtomMatchingTrackerMap; + newAtomMatchingTrackerMap[matcherId] = 0; + EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 0, oldAtomMatchingTrackerMap, + oldAtomMatchingTrackers, newAtomMatchingTrackerMap, + matchersToUpdate, cycleTracker)); + EXPECT_EQ(matchersToUpdate[0], UPDATE_NEW); +} + TEST_F(ConfigUpdateTest, TestCombinationMatcherPreserve) { StatsdConfig config; AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10); @@ -338,9 +367,10 @@ TEST_F(ConfigUpdateTest, TestUpdateMatchers) { set<int> newTagIds; unordered_map<int64_t, int> newAtomMatchingTrackerMap; vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers; - EXPECT_TRUE(updateAtomTrackers(newConfig, uidMap, oldAtomMatchingTrackerMap, - oldAtomMatchingTrackers, newTagIds, newAtomMatchingTrackerMap, - newAtomMatchingTrackers)); + set<int64_t> replacedMatchers; + EXPECT_TRUE(updateAtomMatchingTrackers( + newConfig, uidMap, oldAtomMatchingTrackerMap, oldAtomMatchingTrackers, newTagIds, + newAtomMatchingTrackerMap, newAtomMatchingTrackers, replacedMatchers)); ASSERT_EQ(newTagIds.size(), 3); EXPECT_EQ(newTagIds.count(10), 1); @@ -405,8 +435,454 @@ TEST_F(ConfigUpdateTest, TestUpdateMatchers) { EXPECT_EQ(childMatchers->size(), 2); EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 1), childMatchers->end()); EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 4), childMatchers->end()); + + // Expect replacedMatchers to have simple2 and combination2 + ASSERT_EQ(replacedMatchers.size(), 2); + EXPECT_NE(replacedMatchers.find(simple2Id), replacedMatchers.end()); + EXPECT_NE(replacedMatchers.find(combination2Id), replacedMatchers.end()); +} + +TEST_F(ConfigUpdateTest, TestSimpleConditionPreserve) { + StatsdConfig config; + AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = startMatcher; + AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = stopMatcher; + + Predicate predicate = CreateScreenIsOnPredicate(); + *config.add_predicate() = predicate; + + // Create an initial config. + EXPECT_TRUE(initConfig(config)); + + set<int64_t> replacedMatchers; + vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN); + vector<bool> cycleTracker(1, false); + unordered_map<int64_t, int> newConditionTrackerMap; + newConditionTrackerMap[predicate.id()] = 0; + EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap, + oldConditionTrackers, newConditionTrackerMap, + replacedMatchers, conditionsToUpdate, cycleTracker)); + EXPECT_EQ(conditionsToUpdate[0], UPDATE_PRESERVE); +} + +TEST_F(ConfigUpdateTest, TestSimpleConditionReplace) { + StatsdConfig config; + AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = startMatcher; + AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = stopMatcher; + + Predicate predicate = CreateScreenIsOnPredicate(); + *config.add_predicate() = predicate; + + EXPECT_TRUE(initConfig(config)); + + // Modify the predicate. + config.mutable_predicate(0)->mutable_simple_predicate()->set_count_nesting(true); + + set<int64_t> replacedMatchers; + vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN); + vector<bool> cycleTracker(1, false); + unordered_map<int64_t, int> newConditionTrackerMap; + newConditionTrackerMap[predicate.id()] = 0; + EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap, + oldConditionTrackers, newConditionTrackerMap, + replacedMatchers, conditionsToUpdate, cycleTracker)); + EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE); +} + +TEST_F(ConfigUpdateTest, TestSimpleConditionDepsChange) { + StatsdConfig config; + AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher(); + int64_t startMatcherId = startMatcher.id(); + *config.add_atom_matcher() = startMatcher; + AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = stopMatcher; + + Predicate predicate = CreateScreenIsOnPredicate(); + *config.add_predicate() = predicate; + + EXPECT_TRUE(initConfig(config)); + + // Start matcher was replaced. + set<int64_t> replacedMatchers; + replacedMatchers.insert(startMatcherId); + + vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN); + vector<bool> cycleTracker(1, false); + unordered_map<int64_t, int> newConditionTrackerMap; + newConditionTrackerMap[predicate.id()] = 0; + EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap, + oldConditionTrackers, newConditionTrackerMap, + replacedMatchers, conditionsToUpdate, cycleTracker)); + EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE); +} + +TEST_F(ConfigUpdateTest, TestCombinationConditionPreserve) { + StatsdConfig config; + AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = screenOnMatcher; + AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = screenOffMatcher; + + Predicate simple1 = CreateScreenIsOnPredicate(); + *config.add_predicate() = simple1; + Predicate simple2 = CreateScreenIsOffPredicate(); + *config.add_predicate() = simple2; + + Predicate combination1; + combination1.set_id(StringToId("COMBINATION1")); + Predicate_Combination* combinationInternal = combination1.mutable_combination(); + combinationInternal->set_operation(LogicalOperation::NAND); + combinationInternal->add_predicate(simple1.id()); + combinationInternal->add_predicate(simple2.id()); + *config.add_predicate() = combination1; + + EXPECT_TRUE(initConfig(config)); + + // Same predicates, different order + StatsdConfig newConfig; + unordered_map<int64_t, int> newConditionTrackerMap; + *newConfig.add_predicate() = combination1; + newConditionTrackerMap[combination1.id()] = 0; + *newConfig.add_predicate() = simple2; + newConditionTrackerMap[simple2.id()] = 1; + *newConfig.add_predicate() = simple1; + newConditionTrackerMap[simple1.id()] = 2; + + set<int64_t> replacedMatchers; + vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN); + vector<bool> cycleTracker(3, false); + // Only update the combination. It should recurse the two child predicates and preserve all 3. + EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap, + oldConditionTrackers, newConditionTrackerMap, + replacedMatchers, conditionsToUpdate, cycleTracker)); + EXPECT_EQ(conditionsToUpdate[0], UPDATE_PRESERVE); + EXPECT_EQ(conditionsToUpdate[1], UPDATE_PRESERVE); + EXPECT_EQ(conditionsToUpdate[2], UPDATE_PRESERVE); } +TEST_F(ConfigUpdateTest, TestCombinationConditionReplace) { + StatsdConfig config; + AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = screenOnMatcher; + AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = screenOffMatcher; + + Predicate simple1 = CreateScreenIsOnPredicate(); + *config.add_predicate() = simple1; + Predicate simple2 = CreateScreenIsOffPredicate(); + *config.add_predicate() = simple2; + + Predicate combination1; + combination1.set_id(StringToId("COMBINATION1")); + Predicate_Combination* combinationInternal = combination1.mutable_combination(); + combinationInternal->set_operation(LogicalOperation::NAND); + combinationInternal->add_predicate(simple1.id()); + combinationInternal->add_predicate(simple2.id()); + *config.add_predicate() = combination1; + + EXPECT_TRUE(initConfig(config)); + + // Changing the logical operation changes the predicate definition, so it should be replaced. + combination1.mutable_combination()->set_operation(LogicalOperation::OR); + + StatsdConfig newConfig; + unordered_map<int64_t, int> newConditionTrackerMap; + *newConfig.add_predicate() = combination1; + newConditionTrackerMap[combination1.id()] = 0; + *newConfig.add_predicate() = simple2; + newConditionTrackerMap[simple2.id()] = 1; + *newConfig.add_predicate() = simple1; + newConditionTrackerMap[simple1.id()] = 2; + + set<int64_t> replacedMatchers; + vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN); + vector<bool> cycleTracker(3, false); + // Only update the combination. The simple conditions should not be evaluated. + EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap, + oldConditionTrackers, newConditionTrackerMap, + replacedMatchers, conditionsToUpdate, cycleTracker)); + EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE); + EXPECT_EQ(conditionsToUpdate[1], UPDATE_UNKNOWN); + EXPECT_EQ(conditionsToUpdate[2], UPDATE_UNKNOWN); +} + +TEST_F(ConfigUpdateTest, TestCombinationConditionDepsChange) { + StatsdConfig config; + AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = screenOnMatcher; + AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = screenOffMatcher; + + Predicate simple1 = CreateScreenIsOnPredicate(); + *config.add_predicate() = simple1; + Predicate simple2 = CreateScreenIsOffPredicate(); + *config.add_predicate() = simple2; + + Predicate combination1; + combination1.set_id(StringToId("COMBINATION1")); + Predicate_Combination* combinationInternal = combination1.mutable_combination(); + combinationInternal->set_operation(LogicalOperation::NAND); + combinationInternal->add_predicate(simple1.id()); + combinationInternal->add_predicate(simple2.id()); + *config.add_predicate() = combination1; + + EXPECT_TRUE(initConfig(config)); + + simple2.mutable_simple_predicate()->set_count_nesting(false); + + StatsdConfig newConfig; + unordered_map<int64_t, int> newConditionTrackerMap; + *newConfig.add_predicate() = combination1; + newConditionTrackerMap[combination1.id()] = 0; + *newConfig.add_predicate() = simple2; + newConditionTrackerMap[simple2.id()] = 1; + *newConfig.add_predicate() = simple1; + newConditionTrackerMap[simple1.id()] = 2; + + set<int64_t> replacedMatchers; + vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN); + vector<bool> cycleTracker(3, false); + // Only update the combination. Simple2 and combination1 must be evaluated. + EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap, + oldConditionTrackers, newConditionTrackerMap, + replacedMatchers, conditionsToUpdate, cycleTracker)); + EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE); + EXPECT_EQ(conditionsToUpdate[1], UPDATE_REPLACE); +} + +TEST_F(ConfigUpdateTest, TestUpdateConditions) { + StatsdConfig config; + + // Add atom matchers. These are mostly needed for initStatsdConfig + AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher(); + int64_t matcher1Id = matcher1.id(); + *config.add_atom_matcher() = matcher1; + + AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher(); + int64_t matcher2Id = matcher2.id(); + *config.add_atom_matcher() = matcher2; + + AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher(); + int64_t matcher3Id = matcher3.id(); + *config.add_atom_matcher() = matcher3; + + AtomMatcher matcher4 = CreateFinishScheduledJobAtomMatcher(); + int64_t matcher4Id = matcher4.id(); + *config.add_atom_matcher() = matcher4; + + AtomMatcher matcher5 = CreateBatterySaverModeStartAtomMatcher(); + int64_t matcher5Id = matcher5.id(); + *config.add_atom_matcher() = matcher5; + + AtomMatcher matcher6 = CreateBatterySaverModeStopAtomMatcher(); + int64_t matcher6Id = matcher6.id(); + *config.add_atom_matcher() = matcher6; + + // Add the predicates. + // Will be preserved. + Predicate simple1 = CreateScreenIsOnPredicate(); + int64_t simple1Id = simple1.id(); + *config.add_predicate() = simple1; + + // Will be preserved. + Predicate simple2 = CreateScheduledJobPredicate(); + int64_t simple2Id = simple2.id(); + *config.add_predicate() = simple2; + + // Will be replaced. + Predicate simple3 = CreateBatterySaverModePredicate(); + int64_t simple3Id = simple3.id(); + *config.add_predicate() = simple3; + + // Will be preserved + Predicate combination1; + combination1.set_id(StringToId("COMBINATION1")); + combination1.mutable_combination()->set_operation(LogicalOperation::AND); + combination1.mutable_combination()->add_predicate(simple1Id); + combination1.mutable_combination()->add_predicate(simple2Id); + int64_t combination1Id = combination1.id(); + *config.add_predicate() = combination1; + + // Will be replaced since simple3 will be replaced. + Predicate combination2; + combination2.set_id(StringToId("COMBINATION2")); + combination2.mutable_combination()->set_operation(LogicalOperation::OR); + combination2.mutable_combination()->add_predicate(simple1Id); + combination2.mutable_combination()->add_predicate(simple3Id); + int64_t combination2Id = combination2.id(); + *config.add_predicate() = combination2; + + // Will be removed. + Predicate combination3; + combination3.set_id(StringToId("COMBINATION3")); + combination3.mutable_combination()->set_operation(LogicalOperation::NOT); + combination3.mutable_combination()->add_predicate(simple2Id); + int64_t combination3Id = combination3.id(); + *config.add_predicate() = combination3; + + EXPECT_TRUE(initConfig(config)); + + // Mark marcher 5 as replaced. Causes simple3, and therefore combination2 to be replaced. + set<int64_t> replacedMatchers; + replacedMatchers.insert(matcher6Id); + + // Change the condition of simple1 to true. + ASSERT_EQ(oldConditionTrackers[0]->getConditionId(), simple1Id); + LogEvent event(/*uid=*/0, /*pid=*/0); // Empty event is fine since there are no dimensions. + // Mark the stop matcher as matched, condition should be false. + vector<MatchingState> eventMatcherValues(6, MatchingState::kNotMatched); + eventMatcherValues[1] = MatchingState::kMatched; + vector<ConditionState> tmpConditionCache(6, ConditionState::kNotEvaluated); + vector<bool> conditionChangeCache(6, false); + oldConditionTrackers[0]->evaluateCondition(event, eventMatcherValues, oldConditionTrackers, + tmpConditionCache, conditionChangeCache); + EXPECT_EQ(tmpConditionCache[0], ConditionState::kFalse); + EXPECT_EQ(conditionChangeCache[0], true); + + // New combination matcher. Should have an initial condition of true since it is NOT(simple1). + Predicate combination4; + combination4.set_id(StringToId("COMBINATION4")); + combination4.mutable_combination()->set_operation(LogicalOperation::NOT); + combination4.mutable_combination()->add_predicate(simple1Id); + int64_t combination4Id = combination4.id(); + *config.add_predicate() = combination4; + + // Map the matchers in reverse order to force the indices to change. + std::unordered_map<int64_t, int> newAtomMatchingTrackerMap; + const int matcher6Index = 0; + newAtomMatchingTrackerMap[matcher6Id] = 0; + const int matcher5Index = 1; + newAtomMatchingTrackerMap[matcher5Id] = 1; + const int matcher4Index = 2; + newAtomMatchingTrackerMap[matcher4Id] = 2; + const int matcher3Index = 3; + newAtomMatchingTrackerMap[matcher3Id] = 3; + const int matcher2Index = 4; + newAtomMatchingTrackerMap[matcher2Id] = 4; + const int matcher1Index = 5; + newAtomMatchingTrackerMap[matcher1Id] = 5; + + StatsdConfig newConfig; + *newConfig.add_predicate() = simple3; + const int simple3Index = 0; + *newConfig.add_predicate() = combination2; + const int combination2Index = 1; + *newConfig.add_predicate() = combination4; + const int combination4Index = 2; + *newConfig.add_predicate() = simple2; + const int simple2Index = 3; + *newConfig.add_predicate() = combination1; + const int combination1Index = 4; + *newConfig.add_predicate() = simple1; + const int simple1Index = 5; + + unordered_map<int64_t, int> newConditionTrackerMap; + vector<sp<ConditionTracker>> newConditionTrackers; + unordered_map<int, vector<int>> trackerToConditionMap; + std::vector<ConditionState> conditionCache; + std::set<int64_t> replacedConditions; + EXPECT_TRUE(updateConditions(key, newConfig, newAtomMatchingTrackerMap, replacedMatchers, + oldConditionTrackerMap, oldConditionTrackers, + newConditionTrackerMap, newConditionTrackers, + trackerToConditionMap, conditionCache, replacedConditions)); + + unordered_map<int64_t, int> expectedConditionTrackerMap = { + {simple1Id, simple1Index}, {simple2Id, simple2Index}, + {simple3Id, simple3Index}, {combination1Id, combination1Index}, + {combination2Id, combination2Index}, {combination4Id, combination4Index}, + }; + EXPECT_THAT(newConditionTrackerMap, ContainerEq(expectedConditionTrackerMap)); + + ASSERT_EQ(newConditionTrackers.size(), 6); + // Make sure all conditions are initialized: + for (const sp<ConditionTracker>& tracker : newConditionTrackers) { + EXPECT_TRUE(tracker->mInitialized); + } + + // Make sure preserved conditions are the same. + EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(simple1Id)], + newConditionTrackers[newConditionTrackerMap.at(simple1Id)]); + EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(simple2Id)], + newConditionTrackers[newConditionTrackerMap.at(simple2Id)]); + EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(combination1Id)], + newConditionTrackers[newConditionTrackerMap.at(combination1Id)]); + + // Make sure replaced conditions are different and included in replacedConditions. + EXPECT_NE(oldConditionTrackers[oldConditionTrackerMap.at(simple3Id)], + newConditionTrackers[newConditionTrackerMap.at(simple3Id)]); + EXPECT_NE(oldConditionTrackers[oldConditionTrackerMap.at(combination2Id)], + newConditionTrackers[newConditionTrackerMap.at(combination2Id)]); + EXPECT_THAT(replacedConditions, ContainerEq(set({simple3Id, combination2Id}))); + + // Verify the trackerToConditionMap + ASSERT_EQ(trackerToConditionMap.size(), 6); + const vector<int>& matcher1Conditions = trackerToConditionMap[matcher1Index]; + EXPECT_THAT(matcher1Conditions, UnorderedElementsAre(simple1Index, combination1Index, + combination2Index, combination4Index)); + const vector<int>& matcher2Conditions = trackerToConditionMap[matcher2Index]; + EXPECT_THAT(matcher2Conditions, UnorderedElementsAre(simple1Index, combination1Index, + combination2Index, combination4Index)); + const vector<int>& matcher3Conditions = trackerToConditionMap[matcher3Index]; + EXPECT_THAT(matcher3Conditions, UnorderedElementsAre(simple2Index, combination1Index)); + const vector<int>& matcher4Conditions = trackerToConditionMap[matcher4Index]; + EXPECT_THAT(matcher4Conditions, UnorderedElementsAre(simple2Index, combination1Index)); + const vector<int>& matcher5Conditions = trackerToConditionMap[matcher5Index]; + EXPECT_THAT(matcher5Conditions, UnorderedElementsAre(simple3Index, combination2Index)); + const vector<int>& matcher6Conditions = trackerToConditionMap[matcher6Index]; + EXPECT_THAT(matcher6Conditions, UnorderedElementsAre(simple3Index, combination2Index)); + + // Verify the conditionCache. Specifically, simple1 is false and combination4 is true. + ASSERT_EQ(conditionCache.size(), 6); + EXPECT_EQ(conditionCache[simple1Index], ConditionState::kFalse); + EXPECT_EQ(conditionCache[simple2Index], ConditionState::kUnknown); + EXPECT_EQ(conditionCache[simple3Index], ConditionState::kUnknown); + EXPECT_EQ(conditionCache[combination1Index], ConditionState::kUnknown); + EXPECT_EQ(conditionCache[combination2Index], ConditionState::kUnknown); + EXPECT_EQ(conditionCache[combination4Index], ConditionState::kTrue); + + // Verify tracker indices/ids are correct. + EXPECT_EQ(newConditionTrackers[simple1Index]->getConditionId(), simple1Id); + EXPECT_EQ(newConditionTrackers[simple1Index]->mIndex, simple1Index); + EXPECT_TRUE(newConditionTrackers[simple1Index]->IsSimpleCondition()); + EXPECT_EQ(newConditionTrackers[simple2Index]->getConditionId(), simple2Id); + EXPECT_EQ(newConditionTrackers[simple2Index]->mIndex, simple2Index); + EXPECT_TRUE(newConditionTrackers[simple2Index]->IsSimpleCondition()); + EXPECT_EQ(newConditionTrackers[simple3Index]->getConditionId(), simple3Id); + EXPECT_EQ(newConditionTrackers[simple3Index]->mIndex, simple3Index); + EXPECT_TRUE(newConditionTrackers[simple3Index]->IsSimpleCondition()); + EXPECT_EQ(newConditionTrackers[combination1Index]->getConditionId(), combination1Id); + EXPECT_EQ(newConditionTrackers[combination1Index]->mIndex, combination1Index); + EXPECT_FALSE(newConditionTrackers[combination1Index]->IsSimpleCondition()); + EXPECT_EQ(newConditionTrackers[combination2Index]->getConditionId(), combination2Id); + EXPECT_EQ(newConditionTrackers[combination2Index]->mIndex, combination2Index); + EXPECT_FALSE(newConditionTrackers[combination2Index]->IsSimpleCondition()); + EXPECT_EQ(newConditionTrackers[combination4Index]->getConditionId(), combination4Id); + EXPECT_EQ(newConditionTrackers[combination4Index]->mIndex, combination4Index); + EXPECT_FALSE(newConditionTrackers[combination4Index]->IsSimpleCondition()); + + // Verify preserved trackers have indices updated. + SimpleConditionTracker* simpleTracker1 = + static_cast<SimpleConditionTracker*>(newConditionTrackers[simple1Index].get()); + EXPECT_EQ(simpleTracker1->mStartLogMatcherIndex, matcher1Index); + EXPECT_EQ(simpleTracker1->mStopLogMatcherIndex, matcher2Index); + EXPECT_EQ(simpleTracker1->mStopAllLogMatcherIndex, -1); + + SimpleConditionTracker* simpleTracker2 = + static_cast<SimpleConditionTracker*>(newConditionTrackers[simple2Index].get()); + EXPECT_EQ(simpleTracker2->mStartLogMatcherIndex, matcher3Index); + EXPECT_EQ(simpleTracker2->mStopLogMatcherIndex, matcher4Index); + EXPECT_EQ(simpleTracker2->mStopAllLogMatcherIndex, -1); + + CombinationConditionTracker* combinationTracker1 = static_cast<CombinationConditionTracker*>( + newConditionTrackers[combination1Index].get()); + EXPECT_THAT(combinationTracker1->mChildren, UnorderedElementsAre(simple1Index, simple2Index)); + EXPECT_THAT(combinationTracker1->mUnSlicedChildren, + UnorderedElementsAre(simple1Index, simple2Index)); + EXPECT_THAT(combinationTracker1->mSlicedChildren, IsEmpty()); +} } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp index d6db4c12ae4d..e6583c9686ec 100644 --- a/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp +++ b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp @@ -384,8 +384,9 @@ TEST(MetricsManagerTest, TestInitialConditions) { StatsdConfig config = buildConfigWithDifferentPredicates(); set<int> allTagIds; vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; - unordered_map<int64_t, int> logTrackerMap; + unordered_map<int64_t, int> atomMatchingTrackerMap; vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; vector<sp<MetricProducer>> allMetricProducers; std::vector<sp<AnomalyTracker>> allAnomalyTrackers; std::vector<sp<AlarmTracker>> allAlarmTrackers; @@ -400,9 +401,9 @@ TEST(MetricsManagerTest, TestInitialConditions) { EXPECT_TRUE(initStatsdConfig( kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap, - allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, - conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, noReportMetricIds)); ASSERT_EQ(4u, allMetricProducers.size()); @@ -433,8 +434,9 @@ TEST(MetricsManagerTest, TestGoodConfig) { StatsdConfig config = buildGoodConfig(); set<int> allTagIds; vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; - unordered_map<int64_t, int> logTrackerMap; + unordered_map<int64_t, int> atomMatchingTrackerMap; vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; vector<sp<MetricProducer>> allMetricProducers; std::vector<sp<AnomalyTracker>> allAnomalyTrackers; std::vector<sp<AlarmTracker>> allAlarmTrackers; @@ -449,9 +451,9 @@ TEST(MetricsManagerTest, TestGoodConfig) { EXPECT_TRUE(initStatsdConfig( kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap, - allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, - conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, noReportMetricIds)); ASSERT_EQ(1u, allMetricProducers.size()); @@ -470,8 +472,9 @@ TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) { StatsdConfig config = buildDimensionMetricsWithMultiTags(); set<int> allTagIds; vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; - unordered_map<int64_t, int> logTrackerMap; + unordered_map<int64_t, int> atomMatchingTrackerMap; vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; vector<sp<MetricProducer>> allMetricProducers; std::vector<sp<AnomalyTracker>> allAnomalyTrackers; std::vector<sp<AlarmTracker>> allAlarmTrackers; @@ -486,9 +489,9 @@ TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) { EXPECT_FALSE(initStatsdConfig( kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap, - allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, - conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, noReportMetricIds)); } @@ -501,8 +504,9 @@ TEST(MetricsManagerTest, TestCircleLogMatcherDependency) { StatsdConfig config = buildCircleMatchers(); set<int> allTagIds; vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; - unordered_map<int64_t, int> logTrackerMap; + unordered_map<int64_t, int> atomMatchingTrackerMap; vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; vector<sp<MetricProducer>> allMetricProducers; std::vector<sp<AnomalyTracker>> allAnomalyTrackers; std::vector<sp<AlarmTracker>> allAlarmTrackers; @@ -517,9 +521,9 @@ TEST(MetricsManagerTest, TestCircleLogMatcherDependency) { EXPECT_FALSE(initStatsdConfig( kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap, - allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, - conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, noReportMetricIds)); } @@ -532,8 +536,9 @@ TEST(MetricsManagerTest, TestMissingMatchers) { StatsdConfig config = buildMissingMatchers(); set<int> allTagIds; vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; - unordered_map<int64_t, int> logTrackerMap; + unordered_map<int64_t, int> atomMatchingTrackerMap; vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; vector<sp<MetricProducer>> allMetricProducers; std::vector<sp<AnomalyTracker>> allAnomalyTrackers; std::vector<sp<AlarmTracker>> allAlarmTrackers; @@ -547,9 +552,9 @@ TEST(MetricsManagerTest, TestMissingMatchers) { std::set<int64_t> noReportMetricIds; EXPECT_FALSE(initStatsdConfig( kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap, - allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, - conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, noReportMetricIds)); } @@ -562,8 +567,9 @@ TEST(MetricsManagerTest, TestMissingPredicate) { StatsdConfig config = buildMissingPredicate(); set<int> allTagIds; vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; - unordered_map<int64_t, int> logTrackerMap; + unordered_map<int64_t, int> atomMatchingTrackerMap; vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; vector<sp<MetricProducer>> allMetricProducers; std::vector<sp<AnomalyTracker>> allAnomalyTrackers; std::vector<sp<AlarmTracker>> allAlarmTrackers; @@ -577,9 +583,9 @@ TEST(MetricsManagerTest, TestMissingPredicate) { std::set<int64_t> noReportMetricIds; EXPECT_FALSE(initStatsdConfig( kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap, - allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, - conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, noReportMetricIds)); } @@ -592,8 +598,9 @@ TEST(MetricsManagerTest, TestCirclePredicateDependency) { StatsdConfig config = buildCirclePredicates(); set<int> allTagIds; vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; - unordered_map<int64_t, int> logTrackerMap; + unordered_map<int64_t, int> atomMatchingTrackerMap; vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; vector<sp<MetricProducer>> allMetricProducers; std::vector<sp<AnomalyTracker>> allAnomalyTrackers; std::vector<sp<AlarmTracker>> allAlarmTrackers; @@ -608,9 +615,9 @@ TEST(MetricsManagerTest, TestCirclePredicateDependency) { EXPECT_FALSE(initStatsdConfig( kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap, - allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, - conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, noReportMetricIds)); } @@ -623,8 +630,9 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) { StatsdConfig config = buildAlertWithUnknownMetric(); set<int> allTagIds; vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers; - unordered_map<int64_t, int> logTrackerMap; + unordered_map<int64_t, int> atomMatchingTrackerMap; vector<sp<ConditionTracker>> allConditionTrackers; + unordered_map<int64_t, int> conditionTrackerMap; vector<sp<MetricProducer>> allMetricProducers; std::vector<sp<AnomalyTracker>> allAnomalyTrackers; std::vector<sp<AlarmTracker>> allAlarmTrackers; @@ -639,9 +647,9 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) { EXPECT_FALSE(initStatsdConfig( kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap, - allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, - conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap, + allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, noReportMetricIds)); } @@ -649,6 +657,7 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) { TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerInvalidMatcher) { sp<UidMap> uidMap = new UidMap(); AtomMatcher matcher; + // Matcher has no contents_case (simple/combination), so it is invalid. matcher.set_id(21); EXPECT_EQ(createAtomMatchingTracker(matcher, 0, uidMap), nullptr); } @@ -699,6 +708,65 @@ TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerCombination) { ASSERT_EQ(atomIds.size(), 0); } +TEST(MetricsManagerTest, TestCreateConditionTrackerInvalid) { + const ConfigKey key(123, 456); + // Predicate has no contents_case (simple/combination), so it is invalid. + Predicate predicate; + predicate.set_id(21); + unordered_map<int64_t, int> atomTrackerMap; + EXPECT_EQ(createConditionTracker(key, predicate, 0, atomTrackerMap), nullptr); +} + +TEST(MetricsManagerTest, TestCreateConditionTrackerSimple) { + int index = 1; + int64_t id = 987; + const ConfigKey key(123, 456); + + int startMatcherIndex = 2, stopMatcherIndex = 0, stopAllMatcherIndex = 1; + int64_t startMatcherId = 246, stopMatcherId = 153, stopAllMatcherId = 975; + + Predicate predicate; + predicate.set_id(id); + SimplePredicate* simplePredicate = predicate.mutable_simple_predicate(); + simplePredicate->set_start(startMatcherId); + simplePredicate->set_stop(stopMatcherId); + simplePredicate->set_stop_all(stopAllMatcherId); + + unordered_map<int64_t, int> atomTrackerMap; + atomTrackerMap[startMatcherId] = startMatcherIndex; + atomTrackerMap[stopMatcherId] = stopMatcherIndex; + atomTrackerMap[stopAllMatcherId] = stopAllMatcherIndex; + + sp<ConditionTracker> tracker = createConditionTracker(key, predicate, index, atomTrackerMap); + EXPECT_EQ(tracker->getConditionId(), id); + EXPECT_EQ(tracker->isSliced(), false); + EXPECT_TRUE(tracker->IsSimpleCondition()); + const set<int>& interestedMatchers = tracker->getAtomMatchingTrackerIndex(); + ASSERT_EQ(interestedMatchers.size(), 3); + ASSERT_EQ(interestedMatchers.count(startMatcherIndex), 1); + ASSERT_EQ(interestedMatchers.count(stopMatcherIndex), 1); + ASSERT_EQ(interestedMatchers.count(stopAllMatcherIndex), 1); +} + +TEST(MetricsManagerTest, TestCreateConditionTrackerCombination) { + int index = 1; + int64_t id = 987; + const ConfigKey key(123, 456); + + Predicate predicate; + predicate.set_id(id); + Predicate_Combination* combinationPredicate = predicate.mutable_combination(); + combinationPredicate->set_operation(LogicalOperation::AND); + combinationPredicate->add_predicate(888); + combinationPredicate->add_predicate(777); + + // Combination conditions must be initialized to set most state. + unordered_map<int64_t, int> atomTrackerMap; + sp<ConditionTracker> tracker = createConditionTracker(key, predicate, index, atomTrackerMap); + EXPECT_EQ(tracker->getConditionId(), id); + EXPECT_FALSE(tracker->IsSimpleCondition()); +} + } // namespace statsd } // namespace os } // namespace android |