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
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 3acafaa..b2c0b32 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 @@
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 @@
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 @@
}
// Handles Stopall events.
- if (matcherIndex == mStopAllIndex) {
+ if ((int)matcherIndex == mStopAllIndex) {
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
whatIt.second->noteStopAll(event.GetElapsedTimestampNs());
}
@@ -598,7 +679,7 @@
}
// 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 3a94d9c..01198a9 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -40,8 +40,8 @@
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 @@
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 @@
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 18e62d2..92c1a6e 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -569,6 +569,7 @@
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 8d59d13..657b2e4 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -89,6 +89,12 @@
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 @@
sp<ConditionWizard> mWizard;
- const int mConditionTrackerIndex;
+ int mConditionTrackerIndex;
const int64_t mBucketSizeNs;
@@ -217,6 +223,8 @@
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 d32f5a9..cfc6e3f 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 @@
}
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 @@
}
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 34e265c..b7dc2c7 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 @@
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 @@
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 @@
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 @@
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 @@
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 f909aff..6d1e6dd 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 @@
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 a20be15..dc951be 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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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);