Perform update for value metric

Like other metrics, preserved metrics have indices and maps updated.
New/replaced metrics get recreated as if it was a brand new metric.

Test: atest statsd_test
Bug: 162321957
Change-Id: Ia3896d47d861f7193bf81fc7c7bb10db3103fc40
This commit is contained in:
Tej Singh
2020-10-20 00:58:20 -07:00
parent 8fa18790bf
commit 890f24a60a
6 changed files with 495 additions and 101 deletions

View File

@@ -18,12 +18,14 @@
#include "Log.h"
#include "ValueMetricProducer.h"
#include "../guardrail/StatsdStats.h"
#include "../stats_log_util.h"
#include <limits.h>
#include <stdlib.h>
#include "../guardrail/StatsdStats.h"
#include "../stats_log_util.h"
#include "metrics/parsing_utils/metrics_manager_util.h"
using android::util::FIELD_COUNT_REPEATED;
using android::util::FIELD_TYPE_BOOL;
using android::util::FIELD_TYPE_DOUBLE;
@@ -184,6 +186,48 @@ ValueMetricProducer::~ValueMetricProducer() {
}
}
bool ValueMetricProducer::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 ValueMetric& metric = config.value_metric(configIndex);
// Update appropriate indices: mWhatMatcherIndex, mConditionIndex and MetricsManager maps.
if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex, /*enforceOneAtom=*/false,
allAtomMatchingTrackers, newAtomMatchingTrackerMap,
trackerToMetricMap, mWhatMatcherIndex)) {
return false;
}
if (metric.has_condition() &&
!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
metric.links(), allConditionTrackers, mConditionTrackerIndex,
conditionToMetricMap)) {
return false;
}
sp<EventMatcherWizard> tmpEventWizard = mEventMatcherWizard;
mEventMatcherWizard = matcherWizard;
return true;
}
void ValueMetricProducer::onStateChanged(int64_t eventTimeNs, int32_t atomId,
const HashableDimensionKey& primaryKey,
const FieldValue& oldState, const FieldValue& newState) {

View File

@@ -47,7 +47,7 @@ struct PastValueBucket {
// - a condition change
// - an app upgrade
// - an alarm set to the end of the bucket
class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
class ValueMetricProducer : public MetricProducer, public virtual PullDataReceiver {
public:
ValueMetricProducer(
const ConfigKey& key, const ValueMetric& valueMetric, const int conditionIndex,
@@ -155,7 +155,23 @@ private:
// causes the bucket to be invalidated will not notify StatsdStats.
void skipCurrentBucket(const int64_t dropTimeNs, const BucketDropReason reason);
const int mWhatMatcherIndex;
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;
int mWhatMatcherIndex;
sp<EventMatcherWizard> mEventMatcherWizard;
@@ -370,6 +386,8 @@ private:
FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestPulledValue);
FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestPulledValueWhileConditionFalse);
FRIEND_TEST(ConfigUpdateTest, TestUpdateValueMetrics);
friend class ValueMetricProducerTestHelper;
};

View File

@@ -580,7 +580,6 @@ bool determineAllMetricUpdateStatuses(const StatsdConfig& config,
return false;
}
}
// TODO: determine update status for value metrics.
return true;
}
@@ -749,8 +748,8 @@ bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64
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);
newMetricProducerMap[metric.id()] = metricIndex;
optional<sp<MetricProducer>> producer;
switch (metricsToUpdate[metricIndex]) {
case UPDATE_PRESERVE: {
@@ -784,6 +783,45 @@ bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64
}
newMetricProducers.push_back(producer.value());
}
for (int i = 0; i < config.value_metric_size(); i++, metricIndex++) {
const ValueMetric& metric = config.value_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 = createValueMetricProducerAndUpdateMetadata(
key, config, timeBaseNs, currentTimeNs, pullerManager, metric, metricIndex,
allAtomMatchingTrackers, newAtomMatchingTrackerMap, allConditionTrackers,
conditionTrackerMap, initialConditionCache, wizard, matcherWizard,
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.gauge_metric_size(); i++, metricIndex++) {
const GaugeMetric& metric = config.gauge_metric(i);
newMetricProducerMap[metric.id()] = metricIndex;

View File

@@ -599,6 +599,108 @@ optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata(
eventDeactivationMap)};
}
optional<sp<MetricProducer>> createValueMetricProducerAndUpdateMetadata(
const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
const ValueMetric& 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 sp<EventMatcherWizard>& matcherWizard,
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 ValueMetric \"%lld\"", (long long)metric.id());
return nullopt;
}
if (!metric.has_value_field()) {
ALOGE("cannot find \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
return nullopt;
}
std::vector<Matcher> fieldMatchers;
translateFieldMatcher(metric.value_field(), &fieldMatchers);
if (fieldMatchers.size() < 1) {
ALOGE("incorrect \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
return nullopt;
}
int trackerIndex;
if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex,
metric.has_dimensions_in_what(),
allAtomMatchingTrackers, atomMatchingTrackerMap,
trackerToMetricMap, trackerIndex)) {
return nullopt;
}
sp<AtomMatchingTracker> atomMatcher = allAtomMatchingTrackers.at(trackerIndex);
// If it is pulled atom, it should be simple matcher with one tagId.
if (atomMatcher->getAtomIds().size() != 1) {
return nullopt;
}
int atomTagId = *(atomMatcher->getAtomIds().begin());
int pullTagId = pullerManager->PullerForMatcherExists(atomTagId) ? atomTagId : -1;
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) {
ALOGE("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 (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap,
allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
return nullopt;
}
} else if (metric.state_link_size() > 0) {
ALOGE("ValueMetric 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 ValueMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
metricHash, trackerIndex, matcherWizard, pullTagId, timeBaseNs,
currentTimeNs, pullerManager, eventActivationMap,
eventDeactivationMap, slicedStateAtoms, stateGroupMap)};
}
optional<sp<MetricProducer>> createGaugeMetricProducerAndUpdateMetadata(
const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
@@ -911,97 +1013,20 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
// build ValueMetricProducer
for (int i = 0; i < config.value_metric_size(); i++) {
const ValueMetric& metric = config.value_metric(i);
if (!metric.has_what()) {
ALOGW("cannot find \"what\" in ValueMetric \"%lld\"", (long long)metric.id());
return false;
}
if (!metric.has_value_field()) {
ALOGW("cannot find \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
return false;
}
std::vector<Matcher> fieldMatchers;
translateFieldMatcher(metric.value_field(), &fieldMatchers);
if (fieldMatchers.size() < 1) {
ALOGW("incorrect \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
return false;
}
int metricIndex = allMetricProducers.size();
const ValueMetric& metric = config.value_metric(i);
metricMap.insert({metric.id(), metricIndex});
int trackerIndex;
if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex,
metric.has_dimensions_in_what(),
allAtomMatchingTrackers, atomMatchingTrackerMap,
trackerToMetricMap, trackerIndex)) {
return false;
}
sp<AtomMatchingTracker> atomMatcher = allAtomMatchingTrackers.at(trackerIndex);
// If it is pulled atom, it should be simple matcher with one tagId.
if (atomMatcher->getAtomIds().size() != 1) {
return false;
}
int atomTagId = *(atomMatcher->getAtomIds().begin());
int pullTagId = pullerManager->PullerForMatcherExists(atomTagId) ? atomTagId : -1;
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 (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap,
allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
return false;
}
} else {
if (metric.state_link_size() > 0) {
ALOGW("ValueMetric 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 = createValueMetricProducerAndUpdateMetadata(
key, config, timeBaseTimeNs, currentTimeNs, pullerManager, metric, metricIndex,
allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
conditionTrackerMap, initialConditionCache, wizard, matcherWizard, 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> valueProducer = new ValueMetricProducer(
key, metric, conditionIndex, initialConditionCache, wizard, metricHash,
trackerIndex, matcherWizard, pullTagId, timeBaseTimeNs, currentTimeNs,
pullerManager, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
stateGroupMap);
allMetricProducers.push_back(valueProducer);
allMetricProducers.push_back(producer.value());
}
// Gauge metrics.

View File

@@ -148,6 +148,27 @@ optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata(
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
std::vector<int>& metricsWithActivation);
// Creates a CountMetricProducer 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>> createValueMetricProducerAndUpdateMetadata(
const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
const ValueMetric& 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 sp<EventMatcherWizard>& matcherWizard,
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 a GaugeMetricProducer 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>> createGaugeMetricProducerAndUpdateMetadata(

View File

@@ -29,6 +29,7 @@
#include "src/matchers/CombinationAtomMatchingTracker.h"
#include "src/metrics/DurationMetricProducer.h"
#include "src/metrics/GaugeMetricProducer.h"
#include "src/metrics/ValueMetricProducer.h"
#include "src/metrics/parsing_utils/metrics_manager_util.h"
#include "tests/statsd_test_util.h"
@@ -2685,6 +2686,243 @@ TEST_F(ConfigUpdateTest, TestUpdateDurationMetrics) {
EXPECT_EQ(oldConditionWizard->getStrongCount(), 1);
}
TEST_F(ConfigUpdateTest, TestUpdateValueMetrics) {
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 = CreateStartScheduledJobAtomMatcher();
int64_t matcher3Id = matcher3.id();
*config.add_atom_matcher() = matcher3;
AtomMatcher matcher4 = CreateTemperatureAtomMatcher();
int64_t matcher4Id = matcher4.id();
*config.add_atom_matcher() = matcher4;
AtomMatcher matcher5 = CreateSimpleAtomMatcher("SubsystemSleep", util::SUBSYSTEM_SLEEP_STATE);
int64_t matcher5Id = matcher5.id();
*config.add_atom_matcher() = matcher5;
Predicate predicate1 = CreateScreenIsOnPredicate();
int64_t predicate1Id = predicate1.id();
*config.add_predicate() = predicate1;
Predicate predicate2 = CreateScreenIsOffPredicate();
int64_t predicate2Id = predicate2.id();
*config.add_predicate() = predicate2;
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 value metrics.
// Note that these will not work as "real" metrics since the value field is always 2.
// Will be preserved.
ValueMetric value1 = createValueMetric("VALUE1", matcher4, predicate1Id, {state1Id});
int64_t value1Id = value1.id();
*config.add_value_metric() = value1;
// Will be replaced - definition change.
ValueMetric value2 = createValueMetric("VALUE2", matcher1, nullopt, {});
int64_t value2Id = value2.id();
*config.add_value_metric() = value2;
// Will be replaced - condition change.
ValueMetric value3 = createValueMetric("VALUE3", matcher5, predicate2Id, {});
int64_t value3Id = value3.id();
*config.add_value_metric() = value3;
// Will be replaced - state change.
ValueMetric value4 = createValueMetric("VALUE4", matcher3, nullopt, {state2Id});
int64_t value4Id = value4.id();
*config.add_value_metric() = value4;
// Will be deleted.
ValueMetric value5 = createValueMetric("VALUE5", matcher2, nullopt, {});
int64_t value5Id = value5.id();
*config.add_value_metric() = value5;
EXPECT_TRUE(initConfig(config));
// Used later to ensure the condition wizard is replaced. Get it before doing the update.
sp<EventMatcherWizard> oldMatcherWizard =
static_cast<ValueMetricProducer*>(oldMetricProducers[0].get())->mEventMatcherWizard;
EXPECT_EQ(oldMatcherWizard->getStrongCount(), 6);
// Change value2, causing it to be replaced.
value2.set_aggregation_type(ValueMetric::AVG);
// Mark predicate 2 as replaced. Causes value3 to be replaced.
set<int64_t> replacedConditions = {predicate2Id};
// Mark state 2 as replaced. Causes value4 to be replaced.
set<int64_t> replacedStates = {state2Id};
// New value metric.
ValueMetric value6 = createValueMetric("VALUE6", matcher5, predicate1Id, {state1Id});
int64_t value6Id = value6.id();
// Map the matchers and predicates in reverse order to force the indices to change.
std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
const int matcher5Index = 0;
newAtomMatchingTrackerMap[matcher5Id] = 0;
const int matcher4Index = 1;
newAtomMatchingTrackerMap[matcher4Id] = 1;
const int matcher3Index = 2;
newAtomMatchingTrackerMap[matcher3Id] = 2;
const int matcher2Index = 3;
newAtomMatchingTrackerMap[matcher2Id] = 3;
const int matcher1Index = 4;
newAtomMatchingTrackerMap[matcher1Id] = 4;
// Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(5);
std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
newAtomMatchingTrackers.begin());
std::unordered_map<int64_t, int> newConditionTrackerMap;
const int predicate2Index = 0;
newConditionTrackerMap[predicate2Id] = 0;
const int predicate1Index = 1;
newConditionTrackerMap[predicate1Id] = 1;
// Use the existing conditionTrackers. A bit hacky, but saves code and we don't rely on them.
vector<sp<ConditionTracker>> newConditionTrackers(2);
std::reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
newConditionTrackers.begin());
// Say that predicate1 & predicate2 is unknown since the initial condition never changed.
vector<ConditionState> conditionCache = {ConditionState::kUnknown, ConditionState::kUnknown};
StatsdConfig newConfig;
*newConfig.add_value_metric() = value6;
const int value6Index = 0;
*newConfig.add_value_metric() = value3;
const int value3Index = 1;
*newConfig.add_value_metric() = value1;
const int value1Index = 2;
*newConfig.add_value_metric() = value4;
const int value4Index = 3;
*newConfig.add_value_metric() = value2;
const int value2Index = 4;
*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 = {
{value1Id, value1Index}, {value2Id, value2Index}, {value3Id, value3Index},
{value4Id, value4Index}, {value6Id, value6Index},
};
EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
// Make sure preserved metrics are the same.
ASSERT_EQ(newMetricProducers.size(), 5);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(value1Id)],
newMetricProducers[newMetricProducerMap.at(value1Id)]);
// Make sure replaced metrics are different.
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(value2Id)],
newMetricProducers[newMetricProducerMap.at(value2Id)]);
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(value3Id)],
newMetricProducers[newMetricProducerMap.at(value3Id)]);
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(value4Id)],
newMetricProducers[newMetricProducerMap.at(value4Id)]);
// Verify the conditionToMetricMap.
ASSERT_EQ(conditionToMetricMap.size(), 2);
const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
EXPECT_THAT(condition1Metrics, UnorderedElementsAre(value1Index, value6Index));
const vector<int>& condition2Metrics = conditionToMetricMap[predicate2Index];
EXPECT_THAT(condition2Metrics, UnorderedElementsAre(value3Index));
// Verify the trackerToMetricMap.
ASSERT_EQ(trackerToMetricMap.size(), 4);
const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(value2Index));
const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(value4Index));
const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index];
EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(value1Index));
const vector<int>& matcher5Metrics = trackerToMetricMap[matcher5Index];
EXPECT_THAT(matcher5Metrics, UnorderedElementsAre(value3Index, value6Index));
// 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/states are correct.
ValueMetricProducer* valueProducer1 =
static_cast<ValueMetricProducer*>(newMetricProducers[value1Index].get());
EXPECT_EQ(valueProducer1->getMetricId(), value1Id);
EXPECT_EQ(valueProducer1->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(valueProducer1->mCondition, ConditionState::kUnknown);
EXPECT_EQ(valueProducer1->mWhatMatcherIndex, matcher4Index);
ValueMetricProducer* valueProducer2 =
static_cast<ValueMetricProducer*>(newMetricProducers[value2Index].get());
EXPECT_EQ(valueProducer2->getMetricId(), value2Id);
EXPECT_EQ(valueProducer2->mConditionTrackerIndex, -1);
EXPECT_EQ(valueProducer2->mCondition, ConditionState::kTrue);
EXPECT_EQ(valueProducer2->mWhatMatcherIndex, matcher1Index);
ValueMetricProducer* valueProducer3 =
static_cast<ValueMetricProducer*>(newMetricProducers[value3Index].get());
EXPECT_EQ(valueProducer3->getMetricId(), value3Id);
EXPECT_EQ(valueProducer3->mConditionTrackerIndex, predicate2Index);
EXPECT_EQ(valueProducer3->mCondition, ConditionState::kUnknown);
EXPECT_EQ(valueProducer3->mWhatMatcherIndex, matcher5Index);
ValueMetricProducer* valueProducer4 =
static_cast<ValueMetricProducer*>(newMetricProducers[value4Index].get());
EXPECT_EQ(valueProducer4->getMetricId(), value4Id);
EXPECT_EQ(valueProducer4->mConditionTrackerIndex, -1);
EXPECT_EQ(valueProducer4->mCondition, ConditionState::kTrue);
EXPECT_EQ(valueProducer4->mWhatMatcherIndex, matcher3Index);
ValueMetricProducer* valueProducer6 =
static_cast<ValueMetricProducer*>(newMetricProducers[value6Index].get());
EXPECT_EQ(valueProducer6->getMetricId(), value6Id);
EXPECT_EQ(valueProducer6->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(valueProducer6->mCondition, ConditionState::kUnknown);
EXPECT_EQ(valueProducer6->mWhatMatcherIndex, matcher5Index);
sp<EventMatcherWizard> newMatcherWizard = valueProducer1->mEventMatcherWizard;
EXPECT_NE(newMatcherWizard, oldMatcherWizard);
EXPECT_EQ(newMatcherWizard->getStrongCount(), 6);
oldMetricProducers.clear();
// Only reference to the old wizard should be the one in the test.
EXPECT_EQ(oldMatcherWizard->getStrongCount(), 1);
}
TEST_F(ConfigUpdateTest, TestUpdateMetricActivations) {
StatsdConfig config;
// Add atom matchers
@@ -2849,6 +3087,11 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
int64_t gaugeMetricId = gaugeMetric.id();
*config.add_gauge_metric() = gaugeMetric;
// Preserved.
ValueMetric valueMetric = createValueMetric("VALUE1", matcher3, predicate1Id, {});
int64_t valueMetricId = valueMetric.id();
*config.add_value_metric() = valueMetric;
// Preserved.
DurationMetric durationMetric = createDurationMetric("DURATION1", predicate1Id, nullopt, {});
int64_t durationMetricId = durationMetric.id();
@@ -2858,7 +3101,7 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
// 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(), 5);
EXPECT_EQ(oldConditionWizard->getStrongCount(), 6);
// Mark matcher 2 as replaced. Causes eventMetric to be replaced.
set<int64_t> replacedMatchers;
@@ -2889,6 +3132,7 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
newConditionTrackers.begin());
vector<ConditionState> conditionCache = {ConditionState::kUnknown};
// The order matters. we parse in the order of: count, duration, event, value, gauge.
StatsdConfig newConfig;
*newConfig.add_count_metric() = countMetric;
const int countMetricIndex = 0;
@@ -2896,8 +3140,10 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
const int durationMetricIndex = 1;
*newConfig.add_event_metric() = eventMetric;
const int eventMetricIndex = 2;
*newConfig.add_value_metric() = valueMetric;
const int valueMetricIndex = 3;
*newConfig.add_gauge_metric() = gaugeMetric;
const int gaugeMetricIndex = 3;
const int gaugeMetricIndex = 4;
// Add the predicate since duration metric needs it.
*newConfig.add_predicate() = predicate1;
@@ -2922,19 +3168,20 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
metricsWithActivation));
unordered_map<int64_t, int> expectedMetricProducerMap = {
{countMetricId, countMetricIndex},
{durationMetricId, durationMetricIndex},
{eventMetricId, eventMetricIndex},
{countMetricId, countMetricIndex}, {durationMetricId, durationMetricIndex},
{eventMetricId, eventMetricIndex}, {valueMetricId, valueMetricIndex},
{gaugeMetricId, gaugeMetricIndex},
};
EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
// Make sure preserved metrics are the same.
ASSERT_EQ(newMetricProducers.size(), 4);
ASSERT_EQ(newMetricProducers.size(), 5);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(countMetricId)],
newMetricProducers[newMetricProducerMap.at(countMetricId)]);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(durationMetricId)],
newMetricProducers[newMetricProducerMap.at(durationMetricId)]);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(valueMetricId)],
newMetricProducers[newMetricProducerMap.at(valueMetricId)]);
// Make sure replaced metrics are different.
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(eventMetricId)],
@@ -2945,7 +3192,8 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
// Verify the conditionToMetricMap.
ASSERT_EQ(conditionToMetricMap.size(), 1);
const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
EXPECT_THAT(condition1Metrics, UnorderedElementsAre(countMetricIndex, gaugeMetricIndex));
EXPECT_THAT(condition1Metrics,
UnorderedElementsAre(countMetricIndex, gaugeMetricIndex, valueMetricIndex));
// Verify the trackerToMetricMap.
ASSERT_EQ(trackerToMetricMap.size(), 3);
@@ -2954,7 +3202,7 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
const vector<int>& matcher2Metrics = trackerToMetricMap[matcher2Index];
EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(eventMetricIndex, durationMetricIndex));
const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(gaugeMetricIndex));
EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(gaugeMetricIndex, valueMetricIndex));
// Verify event activation/deactivation maps.
ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0);
@@ -2977,7 +3225,7 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
sp<ConditionWizard> newConditionWizard = newMetricProducers[0]->mWizard;
EXPECT_NE(newConditionWizard, oldConditionWizard);
EXPECT_EQ(newConditionWizard->getStrongCount(), 5);
EXPECT_EQ(newConditionWizard->getStrongCount(), 6);
oldMetricProducers.clear();
// Only reference to the old wizard should be the one in the test.
EXPECT_EQ(oldConditionWizard->getStrongCount(), 1);