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
This commit is contained in:
Tej Singh
2020-10-15 03:14:19 -07:00
parent 07e6258728
commit cfa32e13ef
8 changed files with 678 additions and 129 deletions

View File

@@ -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()) {

View File

@@ -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

View File

@@ -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);
};

View File

@@ -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

View File

@@ -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());

View File

@@ -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

View File

@@ -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(

View File

@@ -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);