diff options
| author | 2020-10-15 03:14:19 -0700 | |
|---|---|---|
| committer | 2020-10-19 15:51:05 -0700 | |
| commit | cfa32e13ef76fe2f30142b002bc7cc8c7d9748e2 (patch) | |
| tree | 34cbe7474b40d94d3979cbf64e76bd3c5e879778 | |
| parent | 07e6258728457211b3f215feb13ce90e76ff9212 (diff) | |
Perform update for duration metric
Creates a new metric if the metric is new/needs replacement.
Preserves the metrics that can be preserved. Ensures that indices are
updated, including within duration trackers.
Does not handle if a condition is true for a new metric based on an
existing condition.
Test: atest statsd_test
Bug: 162323124
Change-Id: Ibe0baf54678c1c6efde5aeba6a4b9b7fa2634c55
8 files changed, 678 insertions, 129 deletions
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp index 3acafaa3560e..b2c0b32bf5ef 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -17,14 +17,17 @@ #define DEBUG false #include "Log.h" + #include "DurationMetricProducer.h" -#include "guardrail/StatsdStats.h" -#include "stats_util.h" -#include "stats_log_util.h" #include <limits.h> #include <stdlib.h> +#include "guardrail/StatsdStats.h" +#include "metrics/parsing_utils/metrics_manager_util.h" +#include "stats_log_util.h" +#include "stats_util.h" + using android::util::FIELD_COUNT_REPEATED; using android::util::FIELD_TYPE_BOOL; using android::util::FIELD_TYPE_FLOAT; @@ -64,8 +67,8 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6; DurationMetricProducer::DurationMetricProducer( const ConfigKey& key, const DurationMetric& metric, const int conditionIndex, - const vector<ConditionState>& initialConditionCache, const size_t startIndex, - const size_t stopIndex, const size_t stopAllIndex, const bool nesting, + const vector<ConditionState>& initialConditionCache, const int startIndex, + const int stopIndex, const int stopAllIndex, const bool nesting, const sp<ConditionWizard>& wizard, const uint64_t protoHash, const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs, const unordered_map<int, shared_ptr<Activation>>& eventActivationMap, @@ -143,6 +146,84 @@ DurationMetricProducer::~DurationMetricProducer() { VLOG("~DurationMetric() called"); } +bool DurationMetricProducer::onConfigUpdatedLocked( + const StatsdConfig& config, const int configIndex, const int metricIndex, + const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, + const unordered_map<int64_t, int>& newAtomMatchingTrackerMap, + const sp<EventMatcherWizard>& matcherWizard, + const vector<sp<ConditionTracker>>& allConditionTrackers, + const unordered_map<int64_t, int>& conditionTrackerMap, const sp<ConditionWizard>& wizard, + const unordered_map<int64_t, int>& metricToActivationMap, + unordered_map<int, vector<int>>& trackerToMetricMap, + unordered_map<int, vector<int>>& conditionToMetricMap, + unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap, + unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap, + vector<int>& metricsWithActivation) { + if (!MetricProducer::onConfigUpdatedLocked( + config, configIndex, metricIndex, allAtomMatchingTrackers, + oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard, + allConditionTrackers, conditionTrackerMap, wizard, metricToActivationMap, + trackerToMetricMap, conditionToMetricMap, activationAtomTrackerToMetricMap, + deactivationAtomTrackerToMetricMap, metricsWithActivation)) { + return false; + } + + const DurationMetric& metric = config.duration_metric(configIndex); + const auto& what_it = conditionTrackerMap.find(metric.what()); + if (what_it == conditionTrackerMap.end()) { + ALOGE("DurationMetric's \"what\" is not present in the config"); + return false; + } + + const Predicate& durationWhat = config.predicate(what_it->second); + if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) { + ALOGE("DurationMetric's \"what\" must be a simple condition"); + return false; + } + + const SimplePredicate& simplePredicate = durationWhat.simple_predicate(); + + // Update indices: mStartIndex, mStopIndex, mStopAllIndex, mConditionIndex and MetricsManager + // maps. + if (!handleMetricWithAtomMatchingTrackers(simplePredicate.start(), metricIndex, + metric.has_dimensions_in_what(), + allAtomMatchingTrackers, newAtomMatchingTrackerMap, + trackerToMetricMap, mStartIndex)) { + ALOGE("Duration metrics must specify a valid start event matcher"); + return false; + } + + if (simplePredicate.has_stop() && + !handleMetricWithAtomMatchingTrackers(simplePredicate.stop(), metricIndex, + metric.has_dimensions_in_what(), + allAtomMatchingTrackers, newAtomMatchingTrackerMap, + trackerToMetricMap, mStopIndex)) { + return false; + } + + if (simplePredicate.has_stop_all() && + !handleMetricWithAtomMatchingTrackers(simplePredicate.stop_all(), metricIndex, + metric.has_dimensions_in_what(), + allAtomMatchingTrackers, newAtomMatchingTrackerMap, + trackerToMetricMap, mStopAllIndex)) { + return false; + } + + if (metric.has_condition() && + !handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap, + metric.links(), allConditionTrackers, mConditionTrackerIndex, + conditionToMetricMap)) { + return false; + } + + for (const auto& it : mCurrentSlicedDurationTrackerMap) { + it.second->onConfigUpdated(wizard, mConditionTrackerIndex); + } + + return true; +} + sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker( const Alert &alert, const sp<AlarmMonitor>& anomalyAlarmMonitor) { std::lock_guard<std::mutex> lock(mMutex); @@ -550,7 +631,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, } // Handles Stopall events. - if (matcherIndex == mStopAllIndex) { + if ((int)matcherIndex == mStopAllIndex) { for (auto& whatIt : mCurrentSlicedDurationTrackerMap) { whatIt.second->noteStopAll(event.GetElapsedTimestampNs()); } @@ -598,7 +679,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, } // Handles Stop events. - if (matcherIndex == mStopIndex) { + if ((int)matcherIndex == mStopIndex) { if (mUseWhatDimensionAsInternalDimension) { auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat); if (whatIt != mCurrentSlicedDurationTrackerMap.end()) { diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h index 3a94d9c775aa..01198a9271d3 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.h +++ b/cmds/statsd/src/metrics/DurationMetricProducer.h @@ -40,8 +40,8 @@ class DurationMetricProducer : public MetricProducer { public: DurationMetricProducer( const ConfigKey& key, const DurationMetric& durationMetric, const int conditionIndex, - const vector<ConditionState>& initialConditionCache, const size_t startIndex, - const size_t stopIndex, const size_t stopAllIndex, const bool nesting, + const vector<ConditionState>& initialConditionCache, const int startIndex, + const int stopIndex, const int stopAllIndex, const bool nesting, const sp<ConditionWizard>& wizard, const uint64_t protoHash, const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs, @@ -112,16 +112,32 @@ private: void flushCurrentBucketLocked(const int64_t& eventTimeNs, const int64_t& nextBucketStartTimeNs) override; + bool onConfigUpdatedLocked( + const StatsdConfig& config, const int configIndex, const int metricIndex, + const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, + const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap, + const sp<EventMatcherWizard>& matcherWizard, + const std::vector<sp<ConditionTracker>>& allConditionTrackers, + const std::unordered_map<int64_t, int>& conditionTrackerMap, + const sp<ConditionWizard>& wizard, + const std::unordered_map<int64_t, int>& metricToActivationMap, + std::unordered_map<int, std::vector<int>>& trackerToMetricMap, + std::unordered_map<int, std::vector<int>>& conditionToMetricMap, + std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap, + std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap, + std::vector<int>& metricsWithActivation) override; + const DurationMetric_AggregationType mAggregationType; // Index of the SimpleAtomMatcher which defines the start. - const size_t mStartIndex; + int mStartIndex; // Index of the SimpleAtomMatcher which defines the stop. - const size_t mStopIndex; + int mStopIndex; // Index of the SimpleAtomMatcher which defines the stop all for all dimensions. - const size_t mStopAllIndex; + int mStopAllIndex; // nest counting -- for the same key, stops must match the number of starts to make real stop const bool mNested; @@ -167,6 +183,8 @@ private: TestSumDurationWithSplitInFollowingBucket); FRIEND_TEST(DurationMetricProducerTest_PartialBucket, TestMaxDuration); FRIEND_TEST(DurationMetricProducerTest_PartialBucket, TestMaxDurationWithSplitInNextBucket); + + FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index 18e62d28ba46..92c1a6e62640 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -569,6 +569,7 @@ protected: FRIEND_TEST(ConfigUpdateTest, TestUpdateCountMetrics); FRIEND_TEST(ConfigUpdateTest, TestUpdateEventMetrics); FRIEND_TEST(ConfigUpdateTest, TestUpdateGaugeMetrics); + FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics); FRIEND_TEST(ConfigUpdateTest, TestUpdateMetricsMultipleTypes); }; diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h index 8d59d1362919..657b2e4c3ddf 100644 --- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h +++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h @@ -89,6 +89,12 @@ public: virtual ~DurationTracker(){}; + void onConfigUpdated(const sp<ConditionWizard>& wizard, const int conditionTrackerIndex) { + sp<ConditionWizard> tmpWizard = mWizard; + mWizard = wizard; + mConditionTrackerIndex = conditionTrackerIndex; + }; + virtual void noteStart(const HashableDimensionKey& key, bool condition, const int64_t eventTime, const ConditionKey& conditionKey) = 0; virtual void noteStop(const HashableDimensionKey& key, const int64_t eventTime, @@ -191,7 +197,7 @@ protected: sp<ConditionWizard> mWizard; - const int mConditionTrackerIndex; + int mConditionTrackerIndex; const int64_t mBucketSizeNs; @@ -217,6 +223,8 @@ protected: FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp); FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm); FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm); + + FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics); }; } // namespace statsd 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 d32f5a947d12..cfc6e3f008d5 100644 --- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp +++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp @@ -697,6 +697,43 @@ bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64 } newMetricProducers.push_back(producer.value()); } + for (int i = 0; i < config.duration_metric_size(); i++, metricIndex++) { + const DurationMetric& metric = config.duration_metric(i); + newMetricProducerMap[metric.id()] = metricIndex; + optional<sp<MetricProducer>> producer; + switch (metricsToUpdate[metricIndex]) { + case UPDATE_PRESERVE: { + producer = updateMetric( + config, i, metricIndex, metric.id(), allAtomMatchingTrackers, + oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard, + allConditionTrackers, conditionTrackerMap, wizard, oldMetricProducerMap, + oldMetricProducers, metricToActivationMap, trackerToMetricMap, + conditionToMetricMap, activationAtomTrackerToMetricMap, + deactivationAtomTrackerToMetricMap, metricsWithActivation); + break; + } + case UPDATE_REPLACE: + case UPDATE_NEW: { + producer = createDurationMetricProducerAndUpdateMetadata( + key, config, timeBaseNs, currentTimeNs, metric, metricIndex, + allAtomMatchingTrackers, newAtomMatchingTrackerMap, allConditionTrackers, + conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap, + allStateGroupMaps, metricToActivationMap, trackerToMetricMap, + conditionToMetricMap, activationAtomTrackerToMetricMap, + deactivationAtomTrackerToMetricMap, metricsWithActivation); + break; + } + default: { + ALOGE("Metric \"%lld\" update state is unknown. This should never happen", + (long long)metric.id()); + return false; + } + } + if (!producer) { + return false; + } + newMetricProducers.push_back(producer.value()); + } for (int i = 0; i < config.event_metric_size(); i++, metricIndex++) { newMetricProducerMap[config.event_metric(i).id()] = metricIndex; const EventMetric& metric = config.event_metric(i); @@ -770,7 +807,7 @@ bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64 } newMetricProducers.push_back(producer.value()); } - // TODO: perform update for value, duration metric. + // TODO: perform update for value metric. const set<int> atomsAllowedFromAnyUid(config.whitelisted_atom_ids().begin(), config.whitelisted_atom_ids().end()); 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 34e265c3b2ea..b7dc2c7fd0de 100644 --- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp @@ -365,7 +365,7 @@ optional<sp<MetricProducer>> createCountMetricProducerAndUpdateMetadata( unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap, vector<int>& metricsWithActivation) { if (!metric.has_id() || !metric.has_what()) { - ALOGW("cannot find metric id or \"what\" in CountMetric \"%lld\"", (long long)metric.id()); + ALOGE("cannot find metric id or \"what\" in CountMetric \"%lld\"", (long long)metric.id()); return nullopt; } int trackerIndex; @@ -423,6 +423,125 @@ optional<sp<MetricProducer>> createCountMetricProducerAndUpdateMetadata( eventDeactivationMap, slicedStateAtoms, stateGroupMap)}; } +optional<sp<MetricProducer>> createDurationMetricProducerAndUpdateMetadata( + const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs, + const int64_t currentTimeNs, const DurationMetric& metric, const int metricIndex, + const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + const unordered_map<int64_t, int>& atomMatchingTrackerMap, + vector<sp<ConditionTracker>>& allConditionTrackers, + const unordered_map<int64_t, int>& conditionTrackerMap, + const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard, + const unordered_map<int64_t, int>& stateAtomIdMap, + const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps, + const unordered_map<int64_t, int>& metricToActivationMap, + unordered_map<int, vector<int>>& trackerToMetricMap, + unordered_map<int, vector<int>>& conditionToMetricMap, + unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap, + unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap, + vector<int>& metricsWithActivation) { + if (!metric.has_id() || !metric.has_what()) { + ALOGE("cannot find metric id or \"what\" in DurationMetric \"%lld\"", + (long long)metric.id()); + return nullopt; + } + const auto& what_it = conditionTrackerMap.find(metric.what()); + if (what_it == conditionTrackerMap.end()) { + ALOGE("DurationMetric's \"what\" is not present in the condition trackers"); + return nullopt; + } + + const Predicate& durationWhat = config.predicate(what_it->second); + if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) { + ALOGE("DurationMetric's \"what\" must be a simple condition"); + return nullopt; + } + + const SimplePredicate& simplePredicate = durationWhat.simple_predicate(); + bool nesting = simplePredicate.count_nesting(); + + int startIndex = -1, stopIndex = -1, stopAllIndex = -1; + if (!simplePredicate.has_start() || + !handleMetricWithAtomMatchingTrackers( + simplePredicate.start(), metricIndex, metric.has_dimensions_in_what(), + allAtomMatchingTrackers, atomMatchingTrackerMap, trackerToMetricMap, startIndex)) { + ALOGE("Duration metrics must specify a valid start event matcher"); + return nullopt; + } + + if (simplePredicate.has_stop() && + !handleMetricWithAtomMatchingTrackers( + simplePredicate.stop(), metricIndex, metric.has_dimensions_in_what(), + allAtomMatchingTrackers, atomMatchingTrackerMap, trackerToMetricMap, stopIndex)) { + return nullopt; + } + + if (simplePredicate.has_stop_all() && + !handleMetricWithAtomMatchingTrackers(simplePredicate.stop_all(), metricIndex, + metric.has_dimensions_in_what(), + allAtomMatchingTrackers, atomMatchingTrackerMap, + trackerToMetricMap, stopAllIndex)) { + return nullopt; + } + + FieldMatcher internalDimensions = simplePredicate.dimensions(); + + int conditionIndex = -1; + if (metric.has_condition()) { + if (!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap, + metric.links(), allConditionTrackers, conditionIndex, + conditionToMetricMap)) { + return nullopt; + } + } else if (metric.links_size() > 0) { + ALOGW("metrics has a MetricConditionLink but doesn't have a condition"); + return nullopt; + } + + std::vector<int> slicedStateAtoms; + unordered_map<int, unordered_map<int, int64_t>> stateGroupMap; + if (metric.slice_by_state_size() > 0) { + if (metric.aggregation_type() == DurationMetric::MAX_SPARSE) { + ALOGE("DurationMetric with aggregation type MAX_SPARSE cannot be sliced by state"); + return nullopt; + } + if (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap, + allStateGroupMaps, slicedStateAtoms, stateGroupMap)) { + return nullopt; + } + } else if (metric.state_link_size() > 0) { + ALOGW("DurationMetric has a MetricStateLink but doesn't have a sliced state"); + return nullopt; + } + + // Check that all metric state links are a subset of dimensions_in_what fields. + std::vector<Matcher> dimensionsInWhat; + translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat); + for (const auto& stateLink : metric.state_link()) { + if (!handleMetricWithStateLink(stateLink.fields_in_what(), dimensionsInWhat)) { + return nullopt; + } + } + + unordered_map<int, shared_ptr<Activation>> eventActivationMap; + unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap; + if (!handleMetricActivation(config, metric.id(), metricIndex, metricToActivationMap, + atomMatchingTrackerMap, activationAtomTrackerToMetricMap, + deactivationAtomTrackerToMetricMap, metricsWithActivation, + eventActivationMap, eventDeactivationMap)) { + return nullopt; + } + + uint64_t metricHash; + if (!getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash)) { + return nullopt; + } + + return {new DurationMetricProducer( + key, metric, conditionIndex, initialConditionCache, startIndex, stopIndex, stopAllIndex, + nesting, wizard, metricHash, internalDimensions, timeBaseNs, currentTimeNs, + eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap)}; +} + optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata( const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs, const EventMetric& metric, const int metricIndex, @@ -438,7 +557,7 @@ optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata( unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap, vector<int>& metricsWithActivation) { if (!metric.has_id() || !metric.has_what()) { - ALOGW("cannot find the metric name or what in config"); + ALOGE("cannot find the metric name or what in config"); return nullopt; } int trackerIndex; @@ -497,7 +616,7 @@ optional<sp<MetricProducer>> createGaugeMetricProducerAndUpdateMetadata( unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap, vector<int>& metricsWithActivation) { if (!metric.has_id() || !metric.has_what()) { - ALOGW("cannot find metric id or \"what\" in GaugeMetric \"%lld\"", (long long)metric.id()); + ALOGE("cannot find metric id or \"what\" in GaugeMetric \"%lld\"", (long long)metric.id()); return nullopt; } @@ -760,114 +879,17 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t const DurationMetric& metric = config.duration_metric(i); metricMap.insert({metric.id(), metricIndex}); - auto what_it = conditionTrackerMap.find(metric.what()); - if (what_it == conditionTrackerMap.end()) { - ALOGE("DurationMetric's \"what\" is invalid"); - return false; - } - - const Predicate& durationWhat = config.predicate(what_it->second); - - if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) { - ALOGE("DurationMetric's \"what\" must be a simple condition"); - return false; - } - - const auto& simplePredicate = durationWhat.simple_predicate(); - - bool nesting = simplePredicate.count_nesting(); - - int trackerIndices[3] = {-1, -1, -1}; - if (!simplePredicate.has_start() || - !handleMetricWithAtomMatchingTrackers(simplePredicate.start(), metricIndex, - metric.has_dimensions_in_what(), - allAtomMatchingTrackers, atomMatchingTrackerMap, - trackerToMetricMap, trackerIndices[0])) { - ALOGE("Duration metrics must specify a valid the start event matcher"); - return false; - } - - if (simplePredicate.has_stop() && - !handleMetricWithAtomMatchingTrackers(simplePredicate.stop(), metricIndex, - metric.has_dimensions_in_what(), - allAtomMatchingTrackers, atomMatchingTrackerMap, - trackerToMetricMap, trackerIndices[1])) { - return false; - } - - if (simplePredicate.has_stop_all() && - !handleMetricWithAtomMatchingTrackers(simplePredicate.stop_all(), metricIndex, - metric.has_dimensions_in_what(), - allAtomMatchingTrackers, atomMatchingTrackerMap, - trackerToMetricMap, trackerIndices[2])) { - return false; - } - - FieldMatcher internalDimensions = simplePredicate.dimensions(); - - int conditionIndex = -1; - - if (metric.has_condition()) { - bool good = handleMetricWithConditions( - metric.condition(), metricIndex, conditionTrackerMap, metric.links(), - allConditionTrackers, conditionIndex, conditionToMetricMap); - if (!good) { - return false; - } - } else { - if (metric.links_size() > 0) { - ALOGW("metrics has a MetricConditionLink but doesn't have a condition"); - return false; - } - } - - std::vector<int> slicedStateAtoms; - unordered_map<int, unordered_map<int, int64_t>> stateGroupMap; - if (metric.slice_by_state_size() > 0) { - if (metric.aggregation_type() == DurationMetric::MAX_SPARSE) { - ALOGE("DurationMetric with aggregation type MAX_SPARSE cannot be sliced by state"); - return false; - } - if (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap, - allStateGroupMaps, slicedStateAtoms, stateGroupMap)) { - return false; - } - } else { - if (metric.state_link_size() > 0) { - ALOGW("DurationMetric has a MetricStateLink but doesn't have a sliced state"); - return false; - } - } - - // Check that all metric state links are a subset of dimensions_in_what fields. - std::vector<Matcher> dimensionsInWhat; - translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat); - for (const auto& stateLink : metric.state_link()) { - if (!handleMetricWithStateLink(stateLink.fields_in_what(), dimensionsInWhat)) { - return false; - } - } - - unordered_map<int, shared_ptr<Activation>> eventActivationMap; - unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap; - bool success = handleMetricActivation( - config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap, + optional<sp<MetricProducer>> producer = createDurationMetricProducerAndUpdateMetadata( + key, config, timeBaseTimeNs, currentTimeNs, metric, metricIndex, + allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers, + conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap, + allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - metricsWithActivation, eventActivationMap, eventDeactivationMap); - if (!success) return false; - - uint64_t metricHash; - if (!getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash)) { + metricsWithActivation); + if (!producer) { return false; } - - sp<MetricProducer> durationMetric = new DurationMetricProducer( - key, metric, conditionIndex, initialConditionCache, trackerIndices[0], - trackerIndices[1], trackerIndices[2], nesting, wizard, metricHash, - internalDimensions, timeBaseTimeNs, currentTimeNs, eventActivationMap, - eventDeactivationMap, slicedStateAtoms, stateGroupMap); - - allMetricProducers.push_back(durationMetric); + allMetricProducers.push_back(producer.value()); } // build EventMetricProducer 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 f909aff48faf..6d1e6dde7e89 100644 --- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h +++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h @@ -112,6 +112,25 @@ optional<sp<MetricProducer>> createCountMetricProducerAndUpdateMetadata( std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap, std::vector<int>& metricsWithActivation); +// Creates a DurationMetricProducer and updates the vectors/maps used by MetricsManager with +// the appropriate indices. Returns an sp to the producer, or nullopt if there was an error. +optional<sp<MetricProducer>> createDurationMetricProducerAndUpdateMetadata( + const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs, + const int64_t currentTimeNs, const DurationMetric& metric, const int metricIndex, + const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, + const std::unordered_map<int64_t, int>& atomMatchingTrackerMap, + std::vector<sp<ConditionTracker>>& allConditionTrackers, + const std::unordered_map<int64_t, int>& conditionTrackerMap, + const std::vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard, + const std::unordered_map<int64_t, int>& stateAtomIdMap, + const std::unordered_map<int64_t, std::unordered_map<int, int64_t>>& allStateGroupMaps, + const std::unordered_map<int64_t, int>& metricToActivationMap, + std::unordered_map<int, std::vector<int>>& trackerToMetricMap, + std::unordered_map<int, std::vector<int>>& conditionToMetricMap, + std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap, + std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap, + std::vector<int>& metricsWithActivation); + // Creates an EventMetricProducer and updates the vectors/maps used by MetricsManager with // the appropriate indices. Returns an sp to the producer, or nullopt if there was an error. optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata( 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 a20be15d9541..dc951be72fe1 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 @@ -27,6 +27,7 @@ #include "src/condition/CombinationConditionTracker.h" #include "src/condition/SimpleConditionTracker.h" #include "src/matchers/CombinationAtomMatchingTracker.h" +#include "src/metrics/DurationMetricProducer.h" #include "src/metrics/GaugeMetricProducer.h" #include "src/metrics/parsing_utils/metrics_manager_util.h" #include "tests/statsd_test_util.h" @@ -2212,6 +2213,352 @@ TEST_F(ConfigUpdateTest, TestUpdateGaugeMetrics) { EXPECT_EQ(oldMatcherWizard->getStrongCount(), 1); } +TEST_F(ConfigUpdateTest, TestUpdateDurationMetrics) { + StatsdConfig config; + // Add atom matchers/predicates/states. 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 = CreateAcquireWakelockAtomMatcher(); + int64_t matcher3Id = matcher3.id(); + *config.add_atom_matcher() = matcher3; + + AtomMatcher matcher4 = CreateReleaseWakelockAtomMatcher(); + int64_t matcher4Id = matcher4.id(); + *config.add_atom_matcher() = matcher4; + + AtomMatcher matcher5 = CreateMoveToForegroundAtomMatcher(); + int64_t matcher5Id = matcher5.id(); + *config.add_atom_matcher() = matcher5; + + AtomMatcher matcher6 = CreateMoveToBackgroundAtomMatcher(); + int64_t matcher6Id = matcher6.id(); + *config.add_atom_matcher() = matcher6; + + AtomMatcher matcher7 = CreateBatteryStateNoneMatcher(); + int64_t matcher7Id = matcher7.id(); + *config.add_atom_matcher() = matcher7; + + AtomMatcher matcher8 = CreateBatteryStateUsbMatcher(); + int64_t matcher8Id = matcher8.id(); + *config.add_atom_matcher() = matcher8; + + Predicate predicate1 = CreateScreenIsOnPredicate(); + int64_t predicate1Id = predicate1.id(); + *config.add_predicate() = predicate1; + + Predicate predicate2 = CreateScreenIsOffPredicate(); + int64_t predicate2Id = predicate2.id(); + *config.add_predicate() = predicate2; + + Predicate predicate3 = CreateDeviceUnpluggedPredicate(); + int64_t predicate3Id = predicate3.id(); + *config.add_predicate() = predicate3; + + Predicate predicate4 = CreateIsInBackgroundPredicate(); + *predicate4.mutable_simple_predicate()->mutable_dimensions() = + CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1}); + int64_t predicate4Id = predicate4.id(); + *config.add_predicate() = predicate4; + + Predicate predicate5 = CreateHoldingWakelockPredicate(); + *predicate5.mutable_simple_predicate()->mutable_dimensions() = + CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST}); + predicate5.mutable_simple_predicate()->set_stop_all(matcher7Id); + int64_t predicate5Id = predicate5.id(); + *config.add_predicate() = predicate5; + + State state1 = CreateScreenStateWithOnOffMap(0x123, 0x321); + int64_t state1Id = state1.id(); + *config.add_state() = state1; + + State state2 = CreateScreenState(); + int64_t state2Id = state2.id(); + *config.add_state() = state2; + + // Add a few duration metrics. + // Will be preserved. + DurationMetric duration1 = + createDurationMetric("DURATION1", predicate5Id, predicate4Id, {state2Id}); + *duration1.mutable_dimensions_in_what() = + CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST}); + MetricConditionLink* link = duration1.add_links(); + link->set_condition(predicate4Id); + *link->mutable_fields_in_what() = + CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST}); + *link->mutable_fields_in_condition() = + CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1} /*uid field*/); + int64_t duration1Id = duration1.id(); + *config.add_duration_metric() = duration1; + + // Will be replaced. + DurationMetric duration2 = createDurationMetric("DURATION2", predicate1Id, nullopt, {}); + int64_t duration2Id = duration2.id(); + *config.add_duration_metric() = duration2; + + // Will be replaced. + DurationMetric duration3 = createDurationMetric("DURATION3", predicate3Id, nullopt, {state1Id}); + int64_t duration3Id = duration3.id(); + *config.add_duration_metric() = duration3; + + // Will be replaced. + DurationMetric duration4 = createDurationMetric("DURATION4", predicate3Id, predicate2Id, {}); + int64_t duration4Id = duration4.id(); + *config.add_duration_metric() = duration4; + + // Will be deleted. + DurationMetric duration5 = createDurationMetric("DURATION5", predicate2Id, nullopt, {}); + int64_t duration5Id = duration5.id(); + *config.add_duration_metric() = duration5; + + EXPECT_TRUE(initConfig(config)); + + // Make some sliced conditions true. + int uid1 = 10; + int uid2 = 11; + vector<MatchingState> matchingStates(8, MatchingState::kNotMatched); + matchingStates[2] = kMatched; + vector<ConditionState> conditionCache(5, ConditionState::kNotEvaluated); + vector<bool> changedCache(5, false); + unique_ptr<LogEvent> event = CreateAcquireWakelockEvent(timeBaseNs + 3, {uid1}, {"tag"}, "wl1"); + oldConditionTrackers[4]->evaluateCondition(*event.get(), matchingStates, oldConditionTrackers, + conditionCache, changedCache); + EXPECT_TRUE(oldConditionTrackers[4]->isSliced()); + EXPECT_TRUE(changedCache[4]); + EXPECT_EQ(conditionCache[4], ConditionState::kTrue); + oldMetricProducers[0]->onMatchedLogEvent(2, *event.get()); + + fill(conditionCache.begin(), conditionCache.end(), ConditionState::kNotEvaluated); + fill(changedCache.begin(), changedCache.end(), false); + event = CreateAcquireWakelockEvent(timeBaseNs + 3, {uid2}, {"tag"}, "wl2"); + oldConditionTrackers[4]->evaluateCondition(*event.get(), matchingStates, oldConditionTrackers, + conditionCache, changedCache); + EXPECT_TRUE(changedCache[4]); + EXPECT_EQ(conditionCache[4], ConditionState::kTrue); + oldMetricProducers[0]->onMatchedLogEvent(2, *event.get()); + + // Used later to ensure the condition wizard is replaced. Get it before doing the update. + // The duration trackers have a pointer to the wizard, and 2 trackers were created above. + sp<ConditionWizard> oldConditionWizard = oldMetricProducers[0]->mWizard; + EXPECT_EQ(oldConditionWizard->getStrongCount(), 8); + + // Replace predicate1, predicate3, and state1. Causes duration2/3/4 to be replaced. + set<int64_t> replacedConditions({predicate1Id, predicate2Id}); + set<int64_t> replacedStates({state1Id}); + + // New duration metric. + DurationMetric duration6 = createDurationMetric("DURATION6", predicate4Id, predicate5Id, {}); + *duration6.mutable_dimensions_in_what() = + CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1} /*uid field*/); + link = duration6.add_links(); + link->set_condition(predicate5Id); + *link->mutable_fields_in_what() = + CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1} /*uid field*/); + *link->mutable_fields_in_condition() = + CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST}); + int64_t duration6Id = duration6.id(); + + // Map the matchers and predicates in reverse order to force the indices to change. + const int matcher8Index = 0, matcher7Index = 1, matcher6Index = 2, matcher5Index = 3, + matcher4Index = 4, matcher3Index = 5, matcher2Index = 6, matcher1Index = 7; + std::unordered_map<int64_t, int> newAtomMatchingTrackerMap({{matcher8Id, matcher8Index}, + {matcher7Id, matcher7Index}, + {matcher6Id, matcher6Index}, + {matcher5Id, matcher5Index}, + {matcher4Id, matcher4Index}, + {matcher3Id, matcher3Index}, + {matcher2Id, matcher2Index}, + {matcher1Id, matcher1Index}}); + // Use the existing matchers. A bit hacky, but saves code and we don't rely on them. + vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(8); + reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(), + newAtomMatchingTrackers.begin()); + + const int predicate5Index = 0, predicate4Index = 1, predicate3Index = 2, predicate2Index = 3, + predicate1Index = 4; + std::unordered_map<int64_t, int> newConditionTrackerMap({ + {predicate5Id, predicate5Index}, + {predicate4Id, predicate4Index}, + {predicate3Id, predicate3Index}, + {predicate2Id, predicate2Index}, + {predicate1Id, predicate1Index}, + }); + // Use the existing conditionTrackers and reinitialize them to get the initial condition cache. + vector<sp<ConditionTracker>> newConditionTrackers(5); + reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(), + newConditionTrackers.begin()); + vector<Predicate> conditionProtos(5); + reverse_copy(config.predicate().begin(), config.predicate().end(), conditionProtos.begin()); + for (int i = 0; i < newConditionTrackers.size(); i++) { + EXPECT_TRUE(newConditionTrackers[i]->onConfigUpdated( + conditionProtos, i, newConditionTrackers, newAtomMatchingTrackerMap, + newConditionTrackerMap)); + } + vector<bool> cycleTracker(5, false); + fill(conditionCache.begin(), conditionCache.end(), ConditionState::kNotEvaluated); + for (int i = 0; i < newConditionTrackers.size(); i++) { + EXPECT_TRUE(newConditionTrackers[i]->init(conditionProtos, newConditionTrackers, + newConditionTrackerMap, cycleTracker, + conditionCache)); + } + // Predicate5 should be true since 2 uids have wakelocks + EXPECT_EQ(conditionCache, vector({kTrue, kUnknown, kUnknown, kUnknown, kUnknown})); + + StatsdConfig newConfig; + *newConfig.add_duration_metric() = duration6; + const int duration6Index = 0; + *newConfig.add_duration_metric() = duration3; + const int duration3Index = 1; + *newConfig.add_duration_metric() = duration1; + const int duration1Index = 2; + *newConfig.add_duration_metric() = duration4; + const int duration4Index = 3; + *newConfig.add_duration_metric() = duration2; + const int duration2Index = 4; + + for (const Predicate& predicate : conditionProtos) { + *newConfig.add_predicate() = predicate; + } + *newConfig.add_state() = state1; + *newConfig.add_state() = state2; + unordered_map<int64_t, int> stateAtomIdMap; + unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps; + map<int64_t, uint64_t> stateProtoHashes; + EXPECT_TRUE(initStates(newConfig, stateAtomIdMap, allStateGroupMaps, stateProtoHashes)); + + // Output data structures to validate. + unordered_map<int64_t, int> newMetricProducerMap; + vector<sp<MetricProducer>> newMetricProducers; + unordered_map<int, vector<int>> conditionToMetricMap; + unordered_map<int, vector<int>> trackerToMetricMap; + set<int64_t> noReportMetricIds; + unordered_map<int, vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap; + vector<int> metricsWithActivation; + EXPECT_TRUE(updateMetrics( + key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345, new StatsPullerManager(), + oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, /*replacedMatchers=*/{}, + newAtomMatchingTrackers, newConditionTrackerMap, replacedConditions, + newConditionTrackers, conditionCache, stateAtomIdMap, allStateGroupMaps, replacedStates, + oldMetricProducerMap, oldMetricProducers, newMetricProducerMap, newMetricProducers, + conditionToMetricMap, trackerToMetricMap, noReportMetricIds, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, + metricsWithActivation)); + + unordered_map<int64_t, int> expectedMetricProducerMap = { + {duration1Id, duration1Index}, {duration2Id, duration2Index}, + {duration3Id, duration3Index}, {duration4Id, duration4Index}, + {duration6Id, duration6Index}, + }; + EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap)); + + // Make sure preserved metrics are the same. + ASSERT_EQ(newMetricProducers.size(), 5); + EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(duration1Id)], + newMetricProducers[newMetricProducerMap.at(duration1Id)]); + + // Make sure replaced metrics are different. + EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(duration2Id)], + newMetricProducers[newMetricProducerMap.at(duration2Id)]); + EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(duration3Id)], + newMetricProducers[newMetricProducerMap.at(duration3Id)]); + EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(duration4Id)], + newMetricProducers[newMetricProducerMap.at(duration4Id)]); + + // Verify the conditionToMetricMap. Note that the "what" is not in this map. + ASSERT_EQ(conditionToMetricMap.size(), 3); + const vector<int>& condition2Metrics = conditionToMetricMap[predicate2Index]; + EXPECT_THAT(condition2Metrics, UnorderedElementsAre(duration4Index)); + const vector<int>& condition4Metrics = conditionToMetricMap[predicate4Index]; + EXPECT_THAT(condition4Metrics, UnorderedElementsAre(duration1Index)); + const vector<int>& condition5Metrics = conditionToMetricMap[predicate5Index]; + EXPECT_THAT(condition5Metrics, UnorderedElementsAre(duration6Index)); + + // Verify the trackerToMetricMap. The start/stop/stopall indices from the "what" should be here. + ASSERT_EQ(trackerToMetricMap.size(), 8); + const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index]; + EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(duration2Index)); + const vector<int>& matcher2Metrics = trackerToMetricMap[matcher2Index]; + EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(duration2Index)); + const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index]; + EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(duration1Index)); + const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index]; + EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(duration1Index)); + const vector<int>& matcher5Metrics = trackerToMetricMap[matcher5Index]; + EXPECT_THAT(matcher5Metrics, UnorderedElementsAre(duration6Index)); + const vector<int>& matcher6Metrics = trackerToMetricMap[matcher6Index]; + EXPECT_THAT(matcher6Metrics, UnorderedElementsAre(duration6Index)); + const vector<int>& matcher7Metrics = trackerToMetricMap[matcher7Index]; + EXPECT_THAT(matcher7Metrics, + UnorderedElementsAre(duration1Index, duration3Index, duration4Index)); + const vector<int>& matcher8Metrics = trackerToMetricMap[matcher8Index]; + EXPECT_THAT(matcher8Metrics, UnorderedElementsAre(duration3Index, duration4Index)); + + // Verify event activation/deactivation maps. + ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0); + ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0); + ASSERT_EQ(metricsWithActivation.size(), 0); + + // Verify tracker indices/ids/conditions are correct. + DurationMetricProducer* durationProducer1 = + static_cast<DurationMetricProducer*>(newMetricProducers[duration1Index].get()); + EXPECT_EQ(durationProducer1->getMetricId(), duration1Id); + EXPECT_EQ(durationProducer1->mConditionTrackerIndex, predicate4Index); + EXPECT_EQ(durationProducer1->mCondition, ConditionState::kUnknown); + EXPECT_EQ(durationProducer1->mStartIndex, matcher3Index); + EXPECT_EQ(durationProducer1->mStopIndex, matcher4Index); + EXPECT_EQ(durationProducer1->mStopAllIndex, matcher7Index); + EXPECT_EQ(durationProducer1->mCurrentSlicedDurationTrackerMap.size(), 2); + for (const auto& durationTrackerIt : durationProducer1->mCurrentSlicedDurationTrackerMap) { + EXPECT_EQ(durationTrackerIt.second->mConditionTrackerIndex, predicate4Index); + } + DurationMetricProducer* durationProducer2 = + static_cast<DurationMetricProducer*>(newMetricProducers[duration2Index].get()); + EXPECT_EQ(durationProducer2->getMetricId(), duration2Id); + EXPECT_EQ(durationProducer2->mConditionTrackerIndex, -1); + EXPECT_EQ(durationProducer2->mCondition, ConditionState::kTrue); + EXPECT_EQ(durationProducer2->mStartIndex, matcher1Index); + EXPECT_EQ(durationProducer2->mStopIndex, matcher2Index); + EXPECT_EQ(durationProducer2->mStopAllIndex, -1); + DurationMetricProducer* durationProducer3 = + static_cast<DurationMetricProducer*>(newMetricProducers[duration3Index].get()); + EXPECT_EQ(durationProducer3->getMetricId(), duration3Id); + EXPECT_EQ(durationProducer3->mConditionTrackerIndex, -1); + EXPECT_EQ(durationProducer3->mCondition, ConditionState::kTrue); + EXPECT_EQ(durationProducer3->mStartIndex, matcher7Index); + EXPECT_EQ(durationProducer3->mStopIndex, matcher8Index); + EXPECT_EQ(durationProducer3->mStopAllIndex, -1); + DurationMetricProducer* durationProducer4 = + static_cast<DurationMetricProducer*>(newMetricProducers[duration4Index].get()); + EXPECT_EQ(durationProducer4->getMetricId(), duration4Id); + EXPECT_EQ(durationProducer4->mConditionTrackerIndex, predicate2Index); + EXPECT_EQ(durationProducer4->mCondition, ConditionState::kUnknown); + EXPECT_EQ(durationProducer4->mStartIndex, matcher7Index); + EXPECT_EQ(durationProducer4->mStopIndex, matcher8Index); + EXPECT_EQ(durationProducer4->mStopAllIndex, -1); + DurationMetricProducer* durationProducer6 = + static_cast<DurationMetricProducer*>(newMetricProducers[duration6Index].get()); + EXPECT_EQ(durationProducer6->getMetricId(), duration6Id); + EXPECT_EQ(durationProducer6->mConditionTrackerIndex, predicate5Index); + // TODO(b/167491517): should this be unknown since the condition is sliced? + EXPECT_EQ(durationProducer6->mCondition, ConditionState::kTrue); + EXPECT_EQ(durationProducer6->mStartIndex, matcher6Index); + EXPECT_EQ(durationProducer6->mStopIndex, matcher5Index); + EXPECT_EQ(durationProducer6->mStopAllIndex, -1); + + sp<ConditionWizard> newConditionWizard = newMetricProducers[0]->mWizard; + EXPECT_NE(newConditionWizard, oldConditionWizard); + EXPECT_EQ(newConditionWizard->getStrongCount(), 8); + oldMetricProducers.clear(); + // Only reference to the old wizard should be the one in the test. + EXPECT_EQ(oldConditionWizard->getStrongCount(), 1); +} + TEST_F(ConfigUpdateTest, TestUpdateMetricActivations) { StatsdConfig config; // Add atom matchers @@ -2376,11 +2723,16 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) { int64_t gaugeMetricId = gaugeMetric.id(); *config.add_gauge_metric() = gaugeMetric; + // Preserved. + DurationMetric durationMetric = createDurationMetric("DURATION1", predicate1Id, nullopt, {}); + int64_t durationMetricId = durationMetric.id(); + *config.add_duration_metric() = durationMetric; + EXPECT_TRUE(initConfig(config)); // Used later to ensure the condition wizard is replaced. Get it before doing the update. sp<ConditionWizard> oldConditionWizard = oldMetricProducers[0]->mWizard; - EXPECT_EQ(oldConditionWizard->getStrongCount(), 4); + EXPECT_EQ(oldConditionWizard->getStrongCount(), 5); // Mark matcher 2 as replaced. Causes eventMetric to be replaced. set<int64_t> replacedMatchers; @@ -2414,10 +2766,15 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) { StatsdConfig newConfig; *newConfig.add_count_metric() = countMetric; const int countMetricIndex = 0; + *newConfig.add_duration_metric() = durationMetric; + const int durationMetricIndex = 1; *newConfig.add_event_metric() = eventMetric; - const int eventMetricIndex = 1; + const int eventMetricIndex = 2; *newConfig.add_gauge_metric() = gaugeMetric; - const int gaugeMetricIndex = 2; + const int gaugeMetricIndex = 3; + + // Add the predicate since duration metric needs it. + *newConfig.add_predicate() = predicate1; // Output data structures to validate. unordered_map<int64_t, int> newMetricProducerMap; @@ -2440,15 +2797,18 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) { unordered_map<int64_t, int> expectedMetricProducerMap = { {countMetricId, countMetricIndex}, + {durationMetricId, durationMetricIndex}, {eventMetricId, eventMetricIndex}, {gaugeMetricId, gaugeMetricIndex}, }; EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap)); // Make sure preserved metrics are the same. - ASSERT_EQ(newMetricProducers.size(), 3); + ASSERT_EQ(newMetricProducers.size(), 4); EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(countMetricId)], newMetricProducers[newMetricProducerMap.at(countMetricId)]); + EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(durationMetricId)], + newMetricProducers[newMetricProducerMap.at(durationMetricId)]); // Make sure replaced metrics are different. EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(eventMetricId)], @@ -2464,9 +2824,9 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) { // Verify the trackerToMetricMap. ASSERT_EQ(trackerToMetricMap.size(), 3); const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index]; - EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(countMetricIndex)); + EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(countMetricIndex, durationMetricIndex)); const vector<int>& matcher2Metrics = trackerToMetricMap[matcher2Index]; - EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(eventMetricIndex)); + EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(eventMetricIndex, durationMetricIndex)); const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index]; EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(gaugeMetricIndex)); @@ -2479,6 +2839,9 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) { EXPECT_EQ(newMetricProducers[countMetricIndex]->getMetricId(), countMetricId); EXPECT_EQ(newMetricProducers[countMetricIndex]->mConditionTrackerIndex, predicate1Index); EXPECT_EQ(newMetricProducers[countMetricIndex]->mCondition, ConditionState::kUnknown); + EXPECT_EQ(newMetricProducers[durationMetricIndex]->getMetricId(), durationMetricId); + EXPECT_EQ(newMetricProducers[durationMetricIndex]->mConditionTrackerIndex, -1); + EXPECT_EQ(newMetricProducers[durationMetricIndex]->mCondition, ConditionState::kTrue); EXPECT_EQ(newMetricProducers[eventMetricIndex]->getMetricId(), eventMetricId); EXPECT_EQ(newMetricProducers[eventMetricIndex]->mConditionTrackerIndex, -1); EXPECT_EQ(newMetricProducers[eventMetricIndex]->mCondition, ConditionState::kTrue); @@ -2488,7 +2851,7 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) { sp<ConditionWizard> newConditionWizard = newMetricProducers[0]->mWizard; EXPECT_NE(newConditionWizard, oldConditionWizard); - EXPECT_EQ(newConditionWizard->getStrongCount(), 4); + EXPECT_EQ(newConditionWizard->getStrongCount(), 5); oldMetricProducers.clear(); // Only reference to the old wizard should be the one in the test. EXPECT_EQ(oldConditionWizard->getStrongCount(), 1); |