Merge changes Ia2fb33e9,Id3afa04b
* changes: Update Alarms/Subscriptions Partial config update for alerts/subscriptions
This commit is contained in:
committed by
Android (Google) Code Review
commit
4c5831a696
@@ -73,6 +73,7 @@ protected:
|
||||
|
||||
FRIEND_TEST(AlarmTrackerTest, TestTriggerTimestamp);
|
||||
FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateAlarms);
|
||||
};
|
||||
|
||||
} // namespace statsd
|
||||
|
||||
@@ -37,14 +37,6 @@ namespace statsd {
|
||||
AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
|
||||
: mAlert(alert), mConfigKey(configKey), mNumOfPastBuckets(mAlert.num_buckets() - 1) {
|
||||
VLOG("AnomalyTracker() called");
|
||||
if (mAlert.num_buckets() <= 0) {
|
||||
ALOGE("Cannot create AnomalyTracker with %lld buckets", (long long)mAlert.num_buckets());
|
||||
return;
|
||||
}
|
||||
if (!mAlert.has_trigger_if_sum_gt()) {
|
||||
ALOGE("Cannot create AnomalyTracker without threshold");
|
||||
return;
|
||||
}
|
||||
resetStorage(); // initialization
|
||||
}
|
||||
|
||||
@@ -52,6 +44,10 @@ AnomalyTracker::~AnomalyTracker() {
|
||||
VLOG("~AnomalyTracker() called");
|
||||
}
|
||||
|
||||
void AnomalyTracker::onConfigUpdated() {
|
||||
mSubscriptions.clear();
|
||||
}
|
||||
|
||||
void AnomalyTracker::resetStorage() {
|
||||
VLOG("resetStorage() called.");
|
||||
mPastBuckets.clear();
|
||||
@@ -259,6 +255,15 @@ bool AnomalyTracker::isInRefractoryPeriod(const int64_t& timestampNs,
|
||||
return false;
|
||||
}
|
||||
|
||||
std::pair<bool, uint64_t> AnomalyTracker::getProtoHash() const {
|
||||
string serializedAlert;
|
||||
if (!mAlert.SerializeToString(&serializedAlert)) {
|
||||
ALOGW("Unable to serialize alert %lld", (long long)mAlert.id());
|
||||
return {false, 0};
|
||||
}
|
||||
return {true, Hash64(serializedAlert)};
|
||||
}
|
||||
|
||||
void AnomalyTracker::informSubscribers(const MetricDimensionKey& key, int64_t metric_id,
|
||||
int64_t metricValue) {
|
||||
triggerSubscribers(mAlert.id(), metric_id, key, metricValue, mConfigKey, mSubscriptions);
|
||||
|
||||
@@ -16,15 +16,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <gtest/gtest_prod.h>
|
||||
#include <stdlib.h>
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
#include "AlarmMonitor.h"
|
||||
#include "config/ConfigKey.h"
|
||||
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
|
||||
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
|
||||
#include "frameworks/base/cmds/statsd/src/statsd_metadata.pb.h" // AlertMetadata
|
||||
#include "hash.h"
|
||||
#include "stats_util.h" // HashableDimensionKey and DimToValMap
|
||||
|
||||
namespace android {
|
||||
@@ -41,6 +41,9 @@ public:
|
||||
|
||||
virtual ~AnomalyTracker();
|
||||
|
||||
// Reset appropriate state on a config update. Clear subscriptions so they can be reset.
|
||||
void onConfigUpdated();
|
||||
|
||||
// Add subscriptions that depend on this alert.
|
||||
void addSubscription(const Subscription& subscription) {
|
||||
mSubscriptions.push_back(subscription);
|
||||
@@ -106,6 +109,26 @@ public:
|
||||
return mNumOfPastBuckets;
|
||||
}
|
||||
|
||||
std::pair<bool, uint64_t> getProtoHash() const;
|
||||
|
||||
// Sets an alarm for the given timestamp.
|
||||
// Replaces previous alarm if one already exists.
|
||||
virtual void startAlarm(const MetricDimensionKey& dimensionKey, const int64_t& eventTime) {
|
||||
return; // The base AnomalyTracker class doesn't have alarms.
|
||||
}
|
||||
|
||||
// Stops the alarm.
|
||||
// If it should have already fired, but hasn't yet (e.g. because the AlarmManager is delayed),
|
||||
// declare the anomaly now.
|
||||
virtual void stopAlarm(const MetricDimensionKey& dimensionKey, const int64_t& timestampNs) {
|
||||
return; // The base AnomalyTracker class doesn't have alarms.
|
||||
}
|
||||
|
||||
// Stop all the alarms owned by this tracker. Does not declare any anomalies.
|
||||
virtual void cancelAllAlarms() {
|
||||
return; // The base AnomalyTracker class doesn't have alarms.
|
||||
}
|
||||
|
||||
// Declares an anomaly for each alarm in firedAlarms that belongs to this AnomalyTracker,
|
||||
// and removes it from firedAlarms. Does NOT remove the alarm from the AlarmMonitor.
|
||||
virtual void informAlarmsFired(const int64_t& timestampNs,
|
||||
@@ -197,6 +220,8 @@ protected:
|
||||
FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
|
||||
FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
|
||||
FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);
|
||||
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateAlerts);
|
||||
};
|
||||
|
||||
} // namespace statsd
|
||||
|
||||
@@ -34,15 +34,15 @@ public:
|
||||
|
||||
// Sets an alarm for the given timestamp.
|
||||
// Replaces previous alarm if one already exists.
|
||||
void startAlarm(const MetricDimensionKey& dimensionKey, const int64_t& eventTime);
|
||||
void startAlarm(const MetricDimensionKey& dimensionKey, const int64_t& eventTime) override;
|
||||
|
||||
// Stops the alarm.
|
||||
// If it should have already fired, but hasn't yet (e.g. because the AlarmManager is delayed),
|
||||
// declare the anomaly now.
|
||||
void stopAlarm(const MetricDimensionKey& dimensionKey, const int64_t& timestampNs);
|
||||
void stopAlarm(const MetricDimensionKey& dimensionKey, const int64_t& timestampNs) override;
|
||||
|
||||
// Stop all the alarms owned by this tracker. Does not declare any anomalies.
|
||||
void cancelAllAlarms();
|
||||
void cancelAllAlarms() override;
|
||||
|
||||
// Declares an anomaly for each alarm in firedAlarms that belongs to this DurationAnomalyTracker
|
||||
// and removes it from firedAlarms. The AlarmMonitor is not informed.
|
||||
|
||||
@@ -234,14 +234,26 @@ sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, mConfigKey, anomalyAlarmMonitor);
|
||||
if (anomalyTracker != nullptr) {
|
||||
mAnomalyTrackers.push_back(anomalyTracker);
|
||||
}
|
||||
sp<AnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, mConfigKey, anomalyAlarmMonitor);
|
||||
addAnomalyTrackerLocked(anomalyTracker);
|
||||
return anomalyTracker;
|
||||
}
|
||||
|
||||
// Adds an AnomalyTracker that has already been created.
|
||||
// Note: this gets called on config updates, and will only get called if the metric and the
|
||||
// associated alert are preserved, which means the AnomalyTracker must be a DurationAnomalyTracker.
|
||||
void DurationMetricProducer::addAnomalyTracker(sp<AnomalyTracker>& anomalyTracker) {
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
addAnomalyTrackerLocked(anomalyTracker);
|
||||
}
|
||||
|
||||
void DurationMetricProducer::addAnomalyTrackerLocked(sp<AnomalyTracker>& anomalyTracker) {
|
||||
mAnomalyTrackers.push_back(anomalyTracker);
|
||||
for (const auto& [_, durationTracker] : mCurrentSlicedDurationTrackerMap) {
|
||||
durationTracker->addAnomalyTracker(anomalyTracker);
|
||||
}
|
||||
}
|
||||
void DurationMetricProducer::onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
|
||||
const HashableDimensionKey& primaryKey,
|
||||
const FieldValue& oldState,
|
||||
|
||||
@@ -55,6 +55,8 @@ public:
|
||||
sp<AnomalyTracker> addAnomalyTracker(const Alert &alert,
|
||||
const sp<AlarmMonitor>& anomalyAlarmMonitor) override;
|
||||
|
||||
void addAnomalyTracker(sp<AnomalyTracker>& anomalyTracker) override;
|
||||
|
||||
void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
|
||||
const HashableDimensionKey& primaryKey, const FieldValue& oldState,
|
||||
const FieldValue& newState) override;
|
||||
@@ -128,6 +130,8 @@ private:
|
||||
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
|
||||
std::vector<int>& metricsWithActivation) override;
|
||||
|
||||
void addAnomalyTrackerLocked(sp<AnomalyTracker>& anomalyTracker);
|
||||
|
||||
const DurationMetric_AggregationType mAggregationType;
|
||||
|
||||
// Index of the SimpleAtomMatcher which defines the start.
|
||||
@@ -164,9 +168,6 @@ private:
|
||||
std::unique_ptr<DurationTracker> createDurationTracker(
|
||||
const MetricDimensionKey& eventKey) const;
|
||||
|
||||
// This hides the base class's std::vector<sp<AnomalyTracker>> mAnomalyTrackers
|
||||
std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers;
|
||||
|
||||
// Util function to check whether the specified dimension hits the guardrail.
|
||||
bool hitGuardRailLocked(const MetricDimensionKey& newKey);
|
||||
|
||||
@@ -185,6 +186,7 @@ private:
|
||||
FRIEND_TEST(DurationMetricProducerTest_PartialBucket, TestMaxDurationWithSplitInNextBucket);
|
||||
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics);
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateAlerts);
|
||||
};
|
||||
|
||||
} // namespace statsd
|
||||
|
||||
@@ -101,6 +101,7 @@ bool MetricProducer::onConfigUpdatedLocked(
|
||||
}
|
||||
mEventActivationMap = newEventActivationMap;
|
||||
mEventDeactivationMap = newEventDeactivationMap;
|
||||
mAnomalyTrackers.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -155,6 +155,7 @@ public:
|
||||
// Update appropriate state on config updates. Primarily, all indices need to be updated.
|
||||
// This metric and all of its dependencies are guaranteed to be preserved across the update.
|
||||
// This function also updates several maps used by metricsManager.
|
||||
// This function clears all anomaly trackers. All anomaly trackers need to be added again.
|
||||
bool onConfigUpdated(
|
||||
const StatsdConfig& config, const int configIndex, const int metricIndex,
|
||||
const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
|
||||
@@ -237,9 +238,6 @@ public:
|
||||
dumpLatency, str_set, protoOutput);
|
||||
}
|
||||
|
||||
// Update appropriate state on config updates. Primarily, all indices need to be updated.
|
||||
// This metric and all of its dependencies are guaranteed to be preserved across the update.
|
||||
// This function also updates several maps used by metricsManager.
|
||||
virtual bool onConfigUpdatedLocked(
|
||||
const StatsdConfig& config, const int configIndex, const int metricIndex,
|
||||
const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
|
||||
@@ -338,16 +336,20 @@ public:
|
||||
return mSlicedStateAtoms;
|
||||
}
|
||||
|
||||
/* If alert is valid, adds an AnomalyTracker and returns it. If invalid, returns nullptr. */
|
||||
/* Adds an AnomalyTracker and returns it. */
|
||||
virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert,
|
||||
const sp<AlarmMonitor>& anomalyAlarmMonitor) {
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, mConfigKey);
|
||||
if (anomalyTracker != nullptr) {
|
||||
mAnomalyTrackers.push_back(anomalyTracker);
|
||||
}
|
||||
mAnomalyTrackers.push_back(anomalyTracker);
|
||||
return anomalyTracker;
|
||||
}
|
||||
|
||||
/* Adds an AnomalyTracker that has already been created */
|
||||
virtual void addAnomalyTracker(sp<AnomalyTracker>& anomalyTracker) {
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
mAnomalyTrackers.push_back(anomalyTracker);
|
||||
}
|
||||
// End: getters/setters
|
||||
protected:
|
||||
/**
|
||||
@@ -571,6 +573,7 @@ protected:
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateGaugeMetrics);
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics);
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateMetricsMultipleTypes);
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateAlerts);
|
||||
};
|
||||
|
||||
} // namespace statsd
|
||||
|
||||
@@ -209,6 +209,9 @@ bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t time
|
||||
map<int64_t, uint64_t> newStateProtoHashes;
|
||||
vector<sp<MetricProducer>> newMetricProducers;
|
||||
unordered_map<int64_t, int> newMetricProducerMap;
|
||||
vector<sp<AnomalyTracker>> newAnomalyTrackers;
|
||||
unordered_map<int64_t, int> newAlertTrackerMap;
|
||||
vector<sp<AlarmTracker>> newPeriodicAlarmTrackers;
|
||||
mTagIds.clear();
|
||||
mConditionToMetricMap.clear();
|
||||
mTrackerToMetricMap.clear();
|
||||
@@ -221,11 +224,13 @@ bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t time
|
||||
mConfigKey, config, mUidMap, mPullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
|
||||
timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
|
||||
mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mMetricProducerMap,
|
||||
mStateProtoHashes, mTagIds, newAtomMatchingTrackers, newAtomMatchingTrackerMap,
|
||||
newConditionTrackers, newConditionTrackerMap, newMetricProducers, newMetricProducerMap,
|
||||
mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap,
|
||||
mActivationAtomTrackerToMetricMap, mDeactivationAtomTrackerToMetricMap,
|
||||
mMetricIndexesWithActivation, newStateProtoHashes, mNoReportMetricIds);
|
||||
mAllAnomalyTrackers, mAlertTrackerMap, mStateProtoHashes, mTagIds,
|
||||
newAtomMatchingTrackers, newAtomMatchingTrackerMap, newConditionTrackers,
|
||||
newConditionTrackerMap, newMetricProducers, newMetricProducerMap, newAnomalyTrackers,
|
||||
newAlertTrackerMap, newPeriodicAlarmTrackers, mConditionToMetricMap,
|
||||
mTrackerToMetricMap, mTrackerToConditionMap, mActivationAtomTrackerToMetricMap,
|
||||
mDeactivationAtomTrackerToMetricMap, mMetricIndexesWithActivation, newStateProtoHashes,
|
||||
mNoReportMetricIds);
|
||||
mAllAtomMatchingTrackers = newAtomMatchingTrackers;
|
||||
mAtomMatchingTrackerMap = newAtomMatchingTrackerMap;
|
||||
mAllConditionTrackers = newConditionTrackers;
|
||||
@@ -233,6 +238,9 @@ bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t time
|
||||
mAllMetricProducers = newMetricProducers;
|
||||
mMetricProducerMap = newMetricProducerMap;
|
||||
mStateProtoHashes = newStateProtoHashes;
|
||||
mAllAnomalyTrackers = newAnomalyTrackers;
|
||||
mAlertTrackerMap = newAlertTrackerMap;
|
||||
mAllPeriodicAlarmTrackers = newPeriodicAlarmTrackers;
|
||||
return mConfigValid;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
|
||||
int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs,
|
||||
int64_t bucketSizeNs, bool conditionSliced, bool fullLink,
|
||||
const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
|
||||
const std::vector<sp<AnomalyTracker>>& anomalyTrackers)
|
||||
: mConfigKey(key),
|
||||
mTrackerId(id),
|
||||
mEventKey(eventKey),
|
||||
@@ -93,6 +93,7 @@ public:
|
||||
sp<ConditionWizard> tmpWizard = mWizard;
|
||||
mWizard = wizard;
|
||||
mConditionTrackerIndex = conditionTrackerIndex;
|
||||
mAnomalyTrackers.clear();
|
||||
};
|
||||
|
||||
virtual void noteStart(const HashableDimensionKey& key, bool condition, const int64_t eventTime,
|
||||
@@ -120,7 +121,7 @@ public:
|
||||
std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) = 0;
|
||||
|
||||
// Predict the anomaly timestamp given the current status.
|
||||
virtual int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
|
||||
virtual int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
|
||||
const int64_t currentTimestamp) const = 0;
|
||||
// Dump internal states for debugging
|
||||
virtual void dumpStates(FILE* out, bool verbose) const = 0;
|
||||
@@ -132,6 +133,10 @@ public:
|
||||
// Replace old value with new value for the given state atom.
|
||||
virtual void updateCurrentStateKey(const int32_t atomId, const FieldValue& newState) = 0;
|
||||
|
||||
void addAnomalyTracker(sp<AnomalyTracker>& anomalyTracker) {
|
||||
mAnomalyTrackers.push_back(anomalyTracker);
|
||||
}
|
||||
|
||||
protected:
|
||||
int64_t getCurrentBucketEndTimeNs() const {
|
||||
return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
|
||||
@@ -218,13 +223,14 @@ protected:
|
||||
|
||||
bool mHasLinksToAllConditionDimensionsInTracker;
|
||||
|
||||
std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers;
|
||||
std::vector<sp<AnomalyTracker>> mAnomalyTrackers;
|
||||
|
||||
FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
|
||||
FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm);
|
||||
FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm);
|
||||
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics);
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateAlerts);
|
||||
};
|
||||
|
||||
} // namespace statsd
|
||||
|
||||
@@ -30,7 +30,7 @@ MaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const int64_t& id,
|
||||
int64_t currentBucketStartNs, int64_t currentBucketNum,
|
||||
int64_t startTimeNs, int64_t bucketSizeNs,
|
||||
bool conditionSliced, bool fullLink,
|
||||
const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
|
||||
const vector<sp<AnomalyTracker>>& anomalyTrackers)
|
||||
: DurationTracker(key, id, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
|
||||
currentBucketNum, startTimeNs, bucketSizeNs, conditionSliced, fullLink,
|
||||
anomalyTrackers) {
|
||||
@@ -288,7 +288,7 @@ void MaxDurationTracker::noteConditionChanged(const HashableDimensionKey& key, b
|
||||
// Note that we don't update mDuration here since it's only updated during noteStop.
|
||||
}
|
||||
|
||||
int64_t MaxDurationTracker::predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
|
||||
int64_t MaxDurationTracker::predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
|
||||
const int64_t currentTimestamp) const {
|
||||
// The allowed time we can continue in the current state is the
|
||||
// (anomaly threshold) - max(elapsed time of the started mInfos).
|
||||
|
||||
@@ -29,12 +29,10 @@ namespace statsd {
|
||||
class MaxDurationTracker : public DurationTracker {
|
||||
public:
|
||||
MaxDurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
|
||||
sp<ConditionWizard> wizard, int conditionIndex,
|
||||
bool nesting,
|
||||
int64_t currentBucketStartNs, int64_t currentBucketNum,
|
||||
int64_t startTimeNs, int64_t bucketSizeNs, bool conditionSliced,
|
||||
bool fullLink,
|
||||
const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers);
|
||||
sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
|
||||
int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs,
|
||||
int64_t bucketSizeNs, bool conditionSliced, bool fullLink,
|
||||
const std::vector<sp<AnomalyTracker>>& anomalyTrackers);
|
||||
|
||||
MaxDurationTracker(const MaxDurationTracker& tracker) = default;
|
||||
|
||||
@@ -57,7 +55,7 @@ public:
|
||||
void onStateChanged(const int64_t timestamp, const int32_t atomId,
|
||||
const FieldValue& newState) override;
|
||||
|
||||
int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
|
||||
int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
|
||||
const int64_t currentTimestamp) const override;
|
||||
void dumpStates(FILE* out, bool verbose) const override;
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ OringDurationTracker::OringDurationTracker(
|
||||
const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
|
||||
sp<ConditionWizard> wizard, int conditionIndex, bool nesting, int64_t currentBucketStartNs,
|
||||
int64_t currentBucketNum, int64_t startTimeNs, int64_t bucketSizeNs, bool conditionSliced,
|
||||
bool fullLink, const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
|
||||
bool fullLink, const vector<sp<AnomalyTracker>>& anomalyTrackers)
|
||||
: DurationTracker(key, id, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
|
||||
currentBucketNum, startTimeNs, bucketSizeNs, conditionSliced, fullLink,
|
||||
anomalyTrackers),
|
||||
@@ -344,9 +344,8 @@ void OringDurationTracker::onStateChanged(const int64_t timestamp, const int32_t
|
||||
updateCurrentStateKey(atomId, newState);
|
||||
}
|
||||
|
||||
int64_t OringDurationTracker::predictAnomalyTimestampNs(
|
||||
const DurationAnomalyTracker& anomalyTracker, const int64_t eventTimestampNs) const {
|
||||
|
||||
int64_t OringDurationTracker::predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
|
||||
const int64_t eventTimestampNs) const {
|
||||
// The anomaly threshold.
|
||||
const int64_t thresholdNs = anomalyTracker.getAnomalyThreshold();
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
int conditionIndex, bool nesting, int64_t currentBucketStartNs,
|
||||
int64_t currentBucketNum, int64_t startTimeNs, int64_t bucketSizeNs,
|
||||
bool conditionSliced, bool fullLink,
|
||||
const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers);
|
||||
const std::vector<sp<AnomalyTracker>>& anomalyTrackers);
|
||||
|
||||
OringDurationTracker(const OringDurationTracker& tracker) = default;
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
int64_t timestampNs,
|
||||
std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) override;
|
||||
|
||||
int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
|
||||
int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
|
||||
const int64_t currentTimestamp) const override;
|
||||
void dumpStates(FILE* out, bool verbose) const override;
|
||||
|
||||
|
||||
@@ -115,7 +115,6 @@ bool updateAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& ui
|
||||
vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
|
||||
set<int64_t>& replacedMatchers) {
|
||||
const int atomMatcherCount = config.atom_matcher_size();
|
||||
|
||||
vector<AtomMatcher> matcherProtos;
|
||||
matcherProtos.reserve(atomMatcherCount);
|
||||
newAtomMatchingTrackers.reserve(atomMatcherCount);
|
||||
@@ -891,6 +890,111 @@ bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64
|
||||
return true;
|
||||
}
|
||||
|
||||
bool determineAlertUpdateStatus(const Alert& alert,
|
||||
const unordered_map<int64_t, int>& oldAlertTrackerMap,
|
||||
const vector<sp<AnomalyTracker>>& oldAnomalyTrackers,
|
||||
const set<int64_t>& replacedMetrics, UpdateStatus& updateStatus) {
|
||||
// Check if new alert.
|
||||
const auto& oldAnomalyTrackerIt = oldAlertTrackerMap.find(alert.id());
|
||||
if (oldAnomalyTrackerIt == oldAlertTrackerMap.end()) {
|
||||
updateStatus = UPDATE_NEW;
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is an existing alert, check if it has changed.
|
||||
string serializedAlert;
|
||||
if (!alert.SerializeToString(&serializedAlert)) {
|
||||
ALOGW("Unable to serialize alert %lld", (long long)alert.id());
|
||||
return false;
|
||||
}
|
||||
uint64_t newProtoHash = Hash64(serializedAlert);
|
||||
const auto [success, oldProtoHash] =
|
||||
oldAnomalyTrackers[oldAnomalyTrackerIt->second]->getProtoHash();
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
if (newProtoHash != oldProtoHash) {
|
||||
updateStatus = UPDATE_REPLACE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the metric this alert relies on has changed.
|
||||
if (replacedMetrics.find(alert.metric_id()) != replacedMetrics.end()) {
|
||||
updateStatus = UPDATE_REPLACE;
|
||||
return true;
|
||||
}
|
||||
|
||||
updateStatus = UPDATE_PRESERVE;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool updateAlerts(const StatsdConfig& config, const unordered_map<int64_t, int>& metricProducerMap,
|
||||
const set<int64_t>& replacedMetrics,
|
||||
const unordered_map<int64_t, int>& oldAlertTrackerMap,
|
||||
const vector<sp<AnomalyTracker>>& oldAnomalyTrackers,
|
||||
const sp<AlarmMonitor>& anomalyAlarmMonitor,
|
||||
vector<sp<MetricProducer>>& allMetricProducers,
|
||||
unordered_map<int64_t, int>& newAlertTrackerMap,
|
||||
vector<sp<AnomalyTracker>>& newAnomalyTrackers) {
|
||||
int alertCount = config.alert_size();
|
||||
vector<UpdateStatus> alertUpdateStatuses(alertCount);
|
||||
for (int i = 0; i < alertCount; i++) {
|
||||
if (!determineAlertUpdateStatus(config.alert(i), oldAlertTrackerMap, oldAnomalyTrackers,
|
||||
replacedMetrics, alertUpdateStatuses[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < alertCount; i++) {
|
||||
const Alert& alert = config.alert(i);
|
||||
newAlertTrackerMap[alert.id()] = newAnomalyTrackers.size();
|
||||
switch (alertUpdateStatuses[i]) {
|
||||
case UPDATE_PRESERVE: {
|
||||
// Find the alert and update it.
|
||||
const auto& oldAnomalyTrackerIt = oldAlertTrackerMap.find(alert.id());
|
||||
if (oldAnomalyTrackerIt == oldAlertTrackerMap.end()) {
|
||||
ALOGW("Could not find AnomalyTracker %lld in the previous config, but "
|
||||
"expected it to be there",
|
||||
(long long)alert.id());
|
||||
return false;
|
||||
}
|
||||
sp<AnomalyTracker> anomalyTracker = oldAnomalyTrackers[oldAnomalyTrackerIt->second];
|
||||
anomalyTracker->onConfigUpdated();
|
||||
// Add the alert to the relevant metric.
|
||||
const auto& metricProducerIt = metricProducerMap.find(alert.metric_id());
|
||||
if (metricProducerIt == metricProducerMap.end()) {
|
||||
ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(),
|
||||
(long long)alert.metric_id());
|
||||
return false;
|
||||
}
|
||||
allMetricProducers[metricProducerIt->second]->addAnomalyTracker(anomalyTracker);
|
||||
newAnomalyTrackers.push_back(anomalyTracker);
|
||||
break;
|
||||
}
|
||||
case UPDATE_REPLACE:
|
||||
case UPDATE_NEW: {
|
||||
optional<sp<AnomalyTracker>> anomalyTracker = createAnomalyTracker(
|
||||
alert, anomalyAlarmMonitor, metricProducerMap, allMetricProducers);
|
||||
if (!anomalyTracker) {
|
||||
return false;
|
||||
}
|
||||
newAnomalyTrackers.push_back(anomalyTracker.value());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ALOGE("Alert \"%lld\" update state is unknown. This should never happen",
|
||||
(long long)alert.id());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!initSubscribersForSubscriptionType(config, Subscription::ALERT, newAlertTrackerMap,
|
||||
newAnomalyTrackers)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
|
||||
const sp<StatsPullerManager>& pullerManager,
|
||||
const sp<AlarmMonitor>& anomalyAlarmMonitor,
|
||||
@@ -902,6 +1006,8 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const
|
||||
const unordered_map<int64_t, int>& oldConditionTrackerMap,
|
||||
const vector<sp<MetricProducer>>& oldMetricProducers,
|
||||
const unordered_map<int64_t, int>& oldMetricProducerMap,
|
||||
const vector<sp<AnomalyTracker>>& oldAnomalyTrackers,
|
||||
const unordered_map<int64_t, int>& oldAlertTrackerMap,
|
||||
const map<int64_t, uint64_t>& oldStateProtoHashes, set<int>& allTagIds,
|
||||
vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
|
||||
unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
|
||||
@@ -909,6 +1015,9 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const
|
||||
unordered_map<int64_t, int>& newConditionTrackerMap,
|
||||
vector<sp<MetricProducer>>& newMetricProducers,
|
||||
unordered_map<int64_t, int>& newMetricProducerMap,
|
||||
vector<sp<AnomalyTracker>>& newAnomalyTrackers,
|
||||
unordered_map<int64_t, int>& newAlertTrackerMap,
|
||||
vector<sp<AlarmTracker>>& newPeriodicAlarmTrackers,
|
||||
unordered_map<int, vector<int>>& conditionToMetricMap,
|
||||
unordered_map<int, vector<int>>& trackerToMetricMap,
|
||||
unordered_map<int, vector<int>>& trackerToConditionMap,
|
||||
@@ -962,10 +1071,23 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const
|
||||
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
|
||||
trackerToMetricMap, noReportMetricIds, activationTrackerToMetricMap,
|
||||
deactivationTrackerToMetricMap, metricsWithActivation, replacedMetrics)) {
|
||||
ALOGE("initMetricProducers failed");
|
||||
ALOGE("updateMetrics failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!updateAlerts(config, newMetricProducerMap, replacedMetrics, oldAlertTrackerMap,
|
||||
oldAnomalyTrackers, anomalyAlarmMonitor, newMetricProducers,
|
||||
newAlertTrackerMap, newAnomalyTrackers)) {
|
||||
ALOGE("updateAlerts failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Alarms do not have any state, so we can reuse the initialization logic.
|
||||
if (!initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs,
|
||||
newPeriodicAlarmTrackers)) {
|
||||
ALOGE("initAlarms failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "anomaly/AlarmMonitor.h"
|
||||
#include "anomaly/AlarmTracker.h"
|
||||
#include "condition/ConditionTracker.h"
|
||||
#include "external/StatsPullerManager.h"
|
||||
#include "matchers/AtomMatchingTracker.h"
|
||||
@@ -189,6 +190,45 @@ bool updateMetrics(
|
||||
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
|
||||
std::vector<int>& metricsWithActivation, std::set<int64_t>& replacedMetrics);
|
||||
|
||||
// Function to determine the update status (preserve/replace/new) of an alert.
|
||||
// [alert]: the input Alert
|
||||
// [oldAlertTrackerMap]: alert id to index mapping in the existing MetricsManager
|
||||
// [oldAnomalyTrackers]: stores the existing AnomalyTrackers
|
||||
// [replacedMetrics]: set of replaced metric ids. alerts using these metrics must be replaced
|
||||
// output:
|
||||
// [updateStatus]: update status of the alert. Will be changed from UPDATE_UNKNOWN
|
||||
// Returns whether the function was successful or not.
|
||||
bool determineAlertUpdateStatus(const Alert& alert,
|
||||
const std::unordered_map<int64_t, int>& oldAlertTrackerMap,
|
||||
const std::vector<sp<AnomalyTracker>>& oldAnomalyTrackers,
|
||||
const std::set<int64_t>& replacedMetrics,
|
||||
UpdateStatus& updateStatus);
|
||||
|
||||
// Update MetricProducers.
|
||||
// input:
|
||||
// [config]: the input config
|
||||
// [metricProducerMap]: metric id to index mapping in the new config
|
||||
// [replacedMetrics]: set of metric ids that have changed and were replaced
|
||||
// [oldAlertTrackerMap]: alert id to index mapping in the existing MetricsManager.
|
||||
// [oldAnomalyTrackers]: stores the existing AnomalyTrackers
|
||||
// [anomalyAlarmMonitor]: AlarmMonitor used for duration metric anomaly detection
|
||||
// [allMetricProducers]: stores the sp of the metric producers, AnomalyTrackers need to be added.
|
||||
// [stateAtomIdMap]: contains the mapping from state ids to atom ids
|
||||
// [allStateGroupMaps]: contains the mapping from atom ids and state values to
|
||||
// state group ids for all states
|
||||
// output:
|
||||
// [newAlertTrackerMap]: mapping of alert id to index in the new config
|
||||
// [newAnomalyTrackers]: contains the list of sp to the AnomalyTrackers created.
|
||||
bool updateAlerts(const StatsdConfig& config,
|
||||
const std::unordered_map<int64_t, int>& metricProducerMap,
|
||||
const std::set<int64_t>& replacedMetrics,
|
||||
const std::unordered_map<int64_t, int>& oldAlertTrackerMap,
|
||||
const std::vector<sp<AnomalyTracker>>& oldAnomalyTrackers,
|
||||
const sp<AlarmMonitor>& anomalyAlarmMonitor,
|
||||
std::vector<sp<MetricProducer>>& allMetricProducers,
|
||||
std::unordered_map<int64_t, int>& newAlertTrackerMap,
|
||||
std::vector<sp<AnomalyTracker>>& newAnomalyTrackers);
|
||||
|
||||
// Updates the existing MetricsManager from a new StatsdConfig.
|
||||
// Parameters are the members of MetricsManager. See MetricsManager for declaration.
|
||||
bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
|
||||
@@ -202,6 +242,8 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const
|
||||
const std::unordered_map<int64_t, int>& oldConditionTrackerMap,
|
||||
const std::vector<sp<MetricProducer>>& oldMetricProducers,
|
||||
const std::unordered_map<int64_t, int>& oldMetricProducerMap,
|
||||
const std::vector<sp<AnomalyTracker>>& oldAnomalyTrackers,
|
||||
const std::unordered_map<int64_t, int>& oldAlertTrackerMap,
|
||||
const std::map<int64_t, uint64_t>& oldStateProtoHashes,
|
||||
std::set<int>& allTagIds,
|
||||
std::vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
|
||||
@@ -210,6 +252,9 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const
|
||||
std::unordered_map<int64_t, int>& newConditionTrackerMap,
|
||||
std::vector<sp<MetricProducer>>& newMetricProducers,
|
||||
std::unordered_map<int64_t, int>& newMetricProducerMap,
|
||||
std::vector<sp<AnomalyTracker>>& newAlertTrackers,
|
||||
std::unordered_map<int64_t, int>& newAlertTrackerMap,
|
||||
std::vector<sp<AlarmTracker>>& newPeriodicAlarmTrackers,
|
||||
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
|
||||
std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
|
||||
std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
|
||||
|
||||
@@ -814,6 +814,35 @@ optional<sp<MetricProducer>> createGaugeMetricProducerAndUpdateMetadata(
|
||||
pullerManager, eventActivationMap, eventDeactivationMap)};
|
||||
}
|
||||
|
||||
optional<sp<AnomalyTracker>> createAnomalyTracker(
|
||||
const Alert& alert, const sp<AlarmMonitor>& anomalyAlarmMonitor,
|
||||
const unordered_map<int64_t, int>& metricProducerMap,
|
||||
vector<sp<MetricProducer>>& allMetricProducers) {
|
||||
const auto& itr = metricProducerMap.find(alert.metric_id());
|
||||
if (itr == metricProducerMap.end()) {
|
||||
ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(),
|
||||
(long long)alert.metric_id());
|
||||
return nullopt;
|
||||
}
|
||||
if (!alert.has_trigger_if_sum_gt()) {
|
||||
ALOGW("invalid alert: missing threshold");
|
||||
return nullopt;
|
||||
}
|
||||
if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) {
|
||||
ALOGW("invalid alert: threshold=%f num_buckets= %d", alert.trigger_if_sum_gt(),
|
||||
alert.num_buckets());
|
||||
return nullopt;
|
||||
}
|
||||
const int metricIndex = itr->second;
|
||||
sp<MetricProducer> metric = allMetricProducers[metricIndex];
|
||||
sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert, anomalyAlarmMonitor);
|
||||
if (anomalyTracker == nullptr) {
|
||||
// The ALOGW for this invalid alert was already displayed in addAnomalyTracker().
|
||||
return nullopt;
|
||||
}
|
||||
return {anomalyTracker};
|
||||
}
|
||||
|
||||
bool initAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
|
||||
unordered_map<int64_t, int>& atomMatchingTrackerMap,
|
||||
vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
|
||||
@@ -1079,49 +1108,17 @@ bool initAlerts(const StatsdConfig& config, const unordered_map<int64_t, int>& m
|
||||
vector<sp<AnomalyTracker>>& allAnomalyTrackers) {
|
||||
for (int i = 0; i < config.alert_size(); i++) {
|
||||
const Alert& alert = config.alert(i);
|
||||
const auto& itr = metricProducerMap.find(alert.metric_id());
|
||||
if (itr == metricProducerMap.end()) {
|
||||
ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(),
|
||||
(long long)alert.metric_id());
|
||||
return false;
|
||||
}
|
||||
if (!alert.has_trigger_if_sum_gt()) {
|
||||
ALOGW("invalid alert: missing threshold");
|
||||
return false;
|
||||
}
|
||||
if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) {
|
||||
ALOGW("invalid alert: threshold=%f num_buckets= %d", alert.trigger_if_sum_gt(),
|
||||
alert.num_buckets());
|
||||
return false;
|
||||
}
|
||||
const int metricIndex = itr->second;
|
||||
sp<MetricProducer> metric = allMetricProducers[metricIndex];
|
||||
sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert, anomalyAlarmMonitor);
|
||||
if (anomalyTracker == nullptr) {
|
||||
// The ALOGW for this invalid alert was already displayed in addAnomalyTracker().
|
||||
return false;
|
||||
}
|
||||
alertTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
|
||||
allAnomalyTrackers.push_back(anomalyTracker);
|
||||
optional<sp<AnomalyTracker>> anomalyTracker = createAnomalyTracker(
|
||||
alert, anomalyAlarmMonitor, metricProducerMap, allMetricProducers);
|
||||
if (!anomalyTracker) {
|
||||
return false;
|
||||
}
|
||||
allAnomalyTrackers.push_back(anomalyTracker.value());
|
||||
}
|
||||
for (int i = 0; i < config.subscription_size(); ++i) {
|
||||
const Subscription& subscription = config.subscription(i);
|
||||
if (subscription.rule_type() != Subscription::ALERT) {
|
||||
continue;
|
||||
}
|
||||
if (subscription.subscriber_information_case() ==
|
||||
Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
|
||||
ALOGW("subscription \"%lld\" has no subscriber info.\"", (long long)subscription.id());
|
||||
return false;
|
||||
}
|
||||
const auto& itr = alertTrackerMap.find(subscription.rule_id());
|
||||
if (itr == alertTrackerMap.end()) {
|
||||
ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
|
||||
(long long)subscription.id(), (long long)subscription.rule_id());
|
||||
return false;
|
||||
}
|
||||
const int anomalyTrackerIndex = itr->second;
|
||||
allAnomalyTrackers[anomalyTrackerIndex]->addSubscription(subscription);
|
||||
if (!initSubscribersForSubscriptionType(config, Subscription::ALERT, alertTrackerMap,
|
||||
allAnomalyTrackers)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1146,24 +1143,9 @@ bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
|
||||
allAlarmTrackers.push_back(
|
||||
new AlarmTracker(startMillis, currentTimeMillis, alarm, key, periodicAlarmMonitor));
|
||||
}
|
||||
for (int i = 0; i < config.subscription_size(); ++i) {
|
||||
const Subscription& subscription = config.subscription(i);
|
||||
if (subscription.rule_type() != Subscription::ALARM) {
|
||||
continue;
|
||||
}
|
||||
if (subscription.subscriber_information_case() ==
|
||||
Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
|
||||
ALOGW("subscription \"%lld\" has no subscriber info.\"", (long long)subscription.id());
|
||||
return false;
|
||||
}
|
||||
const auto& itr = alarmTrackerMap.find(subscription.rule_id());
|
||||
if (itr == alarmTrackerMap.end()) {
|
||||
ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
|
||||
(long long)subscription.id(), (long long)subscription.rule_id());
|
||||
return false;
|
||||
}
|
||||
const int trackerIndex = itr->second;
|
||||
allAlarmTrackers[trackerIndex]->addSubscription(subscription);
|
||||
if (!initSubscribersForSubscriptionType(config, Subscription::ALARM, alarmTrackerMap,
|
||||
allAlarmTrackers)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -188,6 +188,41 @@ optional<sp<MetricProducer>> createGaugeMetricProducerAndUpdateMetadata(
|
||||
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
|
||||
std::vector<int>& metricsWithActivation);
|
||||
|
||||
// Creates an AnomalyTracker and adds it to the appropriate metric.
|
||||
// Returns an sp to the AnomalyTracker, or nullopt if there was an error.
|
||||
optional<sp<AnomalyTracker>> createAnomalyTracker(
|
||||
const Alert& alert, const sp<AlarmMonitor>& anomalyAlarmMonitor,
|
||||
const std::unordered_map<int64_t, int>& metricProducerMap,
|
||||
std::vector<sp<MetricProducer>>& allMetricProducers);
|
||||
|
||||
// Templated function for adding subscriptions to alarms or alerts. Returns true if successful.
|
||||
template <typename T>
|
||||
bool initSubscribersForSubscriptionType(const StatsdConfig& config,
|
||||
const Subscription_RuleType ruleType,
|
||||
const std::unordered_map<int64_t, int>& ruleMap,
|
||||
std::vector<T>& allRules) {
|
||||
for (int i = 0; i < config.subscription_size(); ++i) {
|
||||
const Subscription& subscription = config.subscription(i);
|
||||
if (subscription.rule_type() != ruleType) {
|
||||
continue;
|
||||
}
|
||||
if (subscription.subscriber_information_case() ==
|
||||
Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
|
||||
ALOGW("subscription \"%lld\" has no subscriber info.\"", (long long)subscription.id());
|
||||
return false;
|
||||
}
|
||||
const auto& itr = ruleMap.find(subscription.rule_id());
|
||||
if (itr == ruleMap.end()) {
|
||||
ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
|
||||
(long long)subscription.id(), (long long)subscription.rule_id());
|
||||
return false;
|
||||
}
|
||||
const int ruleIndex = itr->second;
|
||||
allRules[ruleIndex]->addSubscription(subscription);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helper functions for MetricsManager to initialize from StatsdConfig.
|
||||
// *Note*: only initStatsdConfig() should be called from outside.
|
||||
// All other functions are intermediate
|
||||
@@ -271,6 +306,12 @@ bool initMetrics(
|
||||
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
|
||||
std::vector<int>& metricsWithActivation);
|
||||
|
||||
// Initialize alarms
|
||||
// Is called both on initialize new configs and config updates since alarms do not have any state.
|
||||
bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
|
||||
const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
|
||||
const int64_t currentTimeNs, std::vector<sp<AlarmTracker>>& allAlarmTrackers);
|
||||
|
||||
// Initialize MetricsManager from StatsdConfig.
|
||||
// Parameters are the members of MetricsManager. See MetricsManager for declaration.
|
||||
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
|
||||
|
||||
@@ -52,11 +52,15 @@ namespace statsd {
|
||||
namespace {
|
||||
|
||||
ConfigKey key(123, 456);
|
||||
const int64_t timeBaseNs = 1000;
|
||||
const int64_t timeBaseNs = 1000 * NS_PER_SEC;
|
||||
|
||||
sp<UidMap> uidMap = new UidMap();
|
||||
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
sp<AlarmMonitor> periodicAlarmMonitor;
|
||||
sp<AlarmMonitor> periodicAlarmMonitor = new AlarmMonitor(
|
||||
/*minDiffToUpdateRegisteredAlarmTimeSec=*/0,
|
||||
[](const shared_ptr<IStatsCompanionService>&, int64_t) {},
|
||||
[](const shared_ptr<IStatsCompanionService>&) {});
|
||||
set<int> allTagIds;
|
||||
vector<sp<AtomMatchingTracker>> oldAtomMatchingTrackers;
|
||||
unordered_map<int64_t, int> oldAtomMatchingTrackerMap;
|
||||
@@ -65,13 +69,13 @@ unordered_map<int64_t, int> oldConditionTrackerMap;
|
||||
vector<sp<MetricProducer>> oldMetricProducers;
|
||||
unordered_map<int64_t, int> oldMetricProducerMap;
|
||||
std::vector<sp<AnomalyTracker>> oldAnomalyTrackers;
|
||||
unordered_map<int64_t, int> oldAlertTrackerMap;
|
||||
std::vector<sp<AlarmTracker>> oldAlarmTrackers;
|
||||
unordered_map<int, std::vector<int>> tmpConditionToMetricMap;
|
||||
unordered_map<int, std::vector<int>> tmpTrackerToMetricMap;
|
||||
unordered_map<int, std::vector<int>> tmpTrackerToConditionMap;
|
||||
unordered_map<int, std::vector<int>> tmpActivationAtomTrackerToMetricMap;
|
||||
unordered_map<int, std::vector<int>> tmpDeactivationAtomTrackerToMetricMap;
|
||||
unordered_map<int64_t, int> alertTrackerMap;
|
||||
vector<int> metricsWithActivation;
|
||||
map<int64_t, uint64_t> oldStateHashes;
|
||||
std::set<int64_t> noReportMetricIds;
|
||||
@@ -96,7 +100,7 @@ public:
|
||||
tmpTrackerToConditionMap.clear();
|
||||
tmpActivationAtomTrackerToMetricMap.clear();
|
||||
tmpDeactivationAtomTrackerToMetricMap.clear();
|
||||
alertTrackerMap.clear();
|
||||
oldAlertTrackerMap.clear();
|
||||
metricsWithActivation.clear();
|
||||
oldStateHashes.clear();
|
||||
noReportMetricIds.clear();
|
||||
@@ -111,7 +115,7 @@ bool initConfig(const StatsdConfig& config) {
|
||||
oldConditionTrackers, oldConditionTrackerMap, oldMetricProducers, oldMetricProducerMap,
|
||||
oldAnomalyTrackers, oldAlarmTrackers, tmpConditionToMetricMap, tmpTrackerToMetricMap,
|
||||
tmpTrackerToConditionMap, tmpActivationAtomTrackerToMetricMap,
|
||||
tmpDeactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
|
||||
tmpDeactivationAtomTrackerToMetricMap, oldAlertTrackerMap, metricsWithActivation,
|
||||
oldStateHashes, noReportMetricIds);
|
||||
}
|
||||
|
||||
@@ -188,6 +192,32 @@ ValueMetric createValueMetric(string name, const AtomMatcher& what, optional<int
|
||||
}
|
||||
return metric;
|
||||
}
|
||||
|
||||
Alert createAlert(string name, int64_t metricId, int buckets, int64_t triggerSum) {
|
||||
Alert alert;
|
||||
alert.set_id(StringToId(name));
|
||||
alert.set_metric_id(metricId);
|
||||
alert.set_num_buckets(buckets);
|
||||
alert.set_trigger_if_sum_gt(triggerSum);
|
||||
return alert;
|
||||
}
|
||||
|
||||
Subscription createSubscription(string name, Subscription_RuleType type, int64_t ruleId) {
|
||||
Subscription subscription;
|
||||
subscription.set_id(StringToId(name));
|
||||
subscription.set_rule_type(type);
|
||||
subscription.set_rule_id(ruleId);
|
||||
subscription.mutable_broadcast_subscriber_details();
|
||||
return subscription;
|
||||
}
|
||||
|
||||
Alarm createAlarm(string name, int64_t offsetMillis, int64_t periodMillis) {
|
||||
Alarm alarm;
|
||||
alarm.set_id(StringToId(name));
|
||||
alarm.set_offset_millis(offsetMillis);
|
||||
alarm.set_period_millis(periodMillis);
|
||||
return alarm;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST_F(ConfigUpdateTest, TestSimpleMatcherPreserve) {
|
||||
@@ -3243,6 +3273,305 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
// Only reference to the old wizard should be the one in the test.
|
||||
EXPECT_EQ(oldConditionWizard->getStrongCount(), 1);
|
||||
}
|
||||
|
||||
TEST_F(ConfigUpdateTest, TestAlertPreserve) {
|
||||
StatsdConfig config;
|
||||
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
|
||||
*config.add_atom_matcher() = whatMatcher;
|
||||
|
||||
*config.add_count_metric() = createCountMetric("VALUE1", whatMatcher.id(), nullopt, {});
|
||||
|
||||
Alert alert = createAlert("Alert1", config.count_metric(0).id(), 1, 1);
|
||||
*config.add_alert() = alert;
|
||||
EXPECT_TRUE(initConfig(config));
|
||||
|
||||
UpdateStatus updateStatus = UPDATE_UNKNOWN;
|
||||
EXPECT_TRUE(determineAlertUpdateStatus(alert, oldAlertTrackerMap, oldAnomalyTrackers,
|
||||
/*replacedMetrics*/ {}, updateStatus));
|
||||
EXPECT_EQ(updateStatus, UPDATE_PRESERVE);
|
||||
}
|
||||
|
||||
TEST_F(ConfigUpdateTest, TestAlertMetricChanged) {
|
||||
StatsdConfig config;
|
||||
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
|
||||
*config.add_atom_matcher() = whatMatcher;
|
||||
|
||||
CountMetric metric = createCountMetric("VALUE1", whatMatcher.id(), nullopt, {});
|
||||
*config.add_count_metric() = metric;
|
||||
|
||||
Alert alert = createAlert("Alert1", config.count_metric(0).id(), 1, 1);
|
||||
*config.add_alert() = alert;
|
||||
EXPECT_TRUE(initConfig(config));
|
||||
|
||||
UpdateStatus updateStatus = UPDATE_UNKNOWN;
|
||||
EXPECT_TRUE(determineAlertUpdateStatus(alert, oldAlertTrackerMap, oldAnomalyTrackers,
|
||||
/*replacedMetrics*/ {metric.id()}, updateStatus));
|
||||
EXPECT_EQ(updateStatus, UPDATE_REPLACE);
|
||||
}
|
||||
|
||||
TEST_F(ConfigUpdateTest, TestAlertDefinitionChanged) {
|
||||
StatsdConfig config;
|
||||
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
|
||||
*config.add_atom_matcher() = whatMatcher;
|
||||
|
||||
*config.add_count_metric() = createCountMetric("VALUE1", whatMatcher.id(), nullopt, {});
|
||||
|
||||
Alert alert = createAlert("Alert1", config.count_metric(0).id(), 1, 1);
|
||||
*config.add_alert() = alert;
|
||||
EXPECT_TRUE(initConfig(config));
|
||||
|
||||
alert.set_num_buckets(2);
|
||||
|
||||
UpdateStatus updateStatus = UPDATE_UNKNOWN;
|
||||
EXPECT_TRUE(determineAlertUpdateStatus(alert, oldAlertTrackerMap, oldAnomalyTrackers,
|
||||
/*replacedMetrics*/ {}, updateStatus));
|
||||
EXPECT_EQ(updateStatus, UPDATE_REPLACE);
|
||||
}
|
||||
|
||||
TEST_F(ConfigUpdateTest, TestUpdateAlerts) {
|
||||
StatsdConfig config;
|
||||
// Add atom matchers/predicates/metrics. These are mostly needed for initStatsdConfig
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
|
||||
*config.add_predicate() = CreateScreenIsOnPredicate();
|
||||
|
||||
CountMetric countMetric = createCountMetric("COUNT1", config.atom_matcher(0).id(), nullopt, {});
|
||||
int64_t countMetricId = countMetric.id();
|
||||
*config.add_count_metric() = countMetric;
|
||||
|
||||
DurationMetric durationMetric =
|
||||
createDurationMetric("DURATION1", config.predicate(0).id(), nullopt, {});
|
||||
int64_t durationMetricId = durationMetric.id();
|
||||
*config.add_duration_metric() = durationMetric;
|
||||
|
||||
// Add alerts.
|
||||
// Preserved.
|
||||
Alert alert1 = createAlert("Alert1", durationMetricId, /*buckets*/ 1, /*triggerSum*/ 5000);
|
||||
int64_t alert1Id = alert1.id();
|
||||
*config.add_alert() = alert1;
|
||||
|
||||
// Replaced.
|
||||
Alert alert2 = createAlert("Alert2", countMetricId, /*buckets*/ 1, /*triggerSum*/ 2);
|
||||
int64_t alert2Id = alert2.id();
|
||||
*config.add_alert() = alert2;
|
||||
|
||||
// Replaced.
|
||||
Alert alert3 = createAlert("Alert3", durationMetricId, /*buckets*/ 3, /*triggerSum*/ 5000);
|
||||
int64_t alert3Id = alert3.id();
|
||||
*config.add_alert() = alert3;
|
||||
|
||||
// Add Subscriptions.
|
||||
Subscription subscription1 = createSubscription("S1", Subscription::ALERT, alert1Id);
|
||||
*config.add_subscription() = subscription1;
|
||||
Subscription subscription2 = createSubscription("S2", Subscription::ALERT, alert1Id);
|
||||
*config.add_subscription() = subscription2;
|
||||
Subscription subscription3 = createSubscription("S3", Subscription::ALERT, alert2Id);
|
||||
*config.add_subscription() = subscription3;
|
||||
|
||||
EXPECT_TRUE(initConfig(config));
|
||||
|
||||
// Add a duration tracker to the duration metric to ensure durationTrackers are updated
|
||||
// with the proper anomalyTrackers.
|
||||
unique_ptr<LogEvent> event = CreateScreenStateChangedEvent(
|
||||
timeBaseNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
|
||||
oldMetricProducers[1]->onMatchedLogEvent(0, *event.get());
|
||||
|
||||
// Change the count metric. Causes alert2 to be replaced.
|
||||
config.mutable_count_metric(0)->set_bucket(ONE_DAY);
|
||||
// Change num buckets on alert3, causing replacement.
|
||||
alert3.set_num_buckets(5);
|
||||
|
||||
// New alert.
|
||||
Alert alert4 = createAlert("Alert4", durationMetricId, /*buckets*/ 3, /*triggerSum*/ 10000);
|
||||
int64_t alert4Id = alert4.id();
|
||||
|
||||
// Move subscription2 to be on alert2 and make a new subscription.
|
||||
subscription2.set_rule_id(alert2Id);
|
||||
Subscription subscription4 = createSubscription("S4", Subscription::ALERT, alert2Id);
|
||||
|
||||
// Create the new config. Modify the old one to avoid adding the matchers/predicates.
|
||||
// Add alerts in different order so the map is changed.
|
||||
config.clear_alert();
|
||||
*config.add_alert() = alert4;
|
||||
const int alert4Index = 0;
|
||||
*config.add_alert() = alert3;
|
||||
const int alert3Index = 1;
|
||||
*config.add_alert() = alert1;
|
||||
const int alert1Index = 2;
|
||||
*config.add_alert() = alert2;
|
||||
const int alert2Index = 3;
|
||||
|
||||
// Subscription3 is removed.
|
||||
config.clear_subscription();
|
||||
*config.add_subscription() = subscription4;
|
||||
*config.add_subscription() = subscription2;
|
||||
*config.add_subscription() = subscription1;
|
||||
|
||||
// Output data structures from update metrics. Don't care about the outputs besides
|
||||
// replacedMetrics, but need to do this so that the metrics clear their anomaly trackers.
|
||||
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;
|
||||
set<int64_t> replacedMetrics;
|
||||
EXPECT_TRUE(updateMetrics(
|
||||
key, config, /*timeBaseNs=*/123, /*currentTimeNs=*/12345, new StatsPullerManager(),
|
||||
oldAtomMatchingTrackerMap, oldAtomMatchingTrackerMap, /*replacedMatchers*/ {},
|
||||
oldAtomMatchingTrackers, oldConditionTrackerMap, /*replacedConditions=*/{},
|
||||
oldConditionTrackers, {ConditionState::kUnknown}, /*stateAtomIdMap*/ {},
|
||||
/*allStateGroupMaps=*/{},
|
||||
/*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers, newMetricProducerMap,
|
||||
newMetricProducers, conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
|
||||
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
|
||||
metricsWithActivation, replacedMetrics));
|
||||
|
||||
EXPECT_EQ(replacedMetrics, set<int64_t>({countMetricId}));
|
||||
|
||||
unordered_map<int64_t, int> newAlertTrackerMap;
|
||||
vector<sp<AnomalyTracker>> newAnomalyTrackers;
|
||||
EXPECT_TRUE(updateAlerts(config, newMetricProducerMap, replacedMetrics, oldAlertTrackerMap,
|
||||
oldAnomalyTrackers, anomalyAlarmMonitor, newMetricProducers,
|
||||
newAlertTrackerMap, newAnomalyTrackers));
|
||||
|
||||
unordered_map<int64_t, int> expectedAlertMap = {
|
||||
{alert1Id, alert1Index},
|
||||
{alert2Id, alert2Index},
|
||||
{alert3Id, alert3Index},
|
||||
{alert4Id, alert4Index},
|
||||
};
|
||||
EXPECT_THAT(newAlertTrackerMap, ContainerEq(expectedAlertMap));
|
||||
|
||||
// Make sure preserved alerts are the same.
|
||||
ASSERT_EQ(newAnomalyTrackers.size(), 4);
|
||||
EXPECT_EQ(oldAnomalyTrackers[oldAlertTrackerMap.at(alert1Id)],
|
||||
newAnomalyTrackers[newAlertTrackerMap.at(alert1Id)]);
|
||||
|
||||
// Make sure replaced alerts are different.
|
||||
EXPECT_NE(oldAnomalyTrackers[oldAlertTrackerMap.at(alert2Id)],
|
||||
newAnomalyTrackers[newAlertTrackerMap.at(alert2Id)]);
|
||||
EXPECT_NE(oldAnomalyTrackers[oldAlertTrackerMap.at(alert3Id)],
|
||||
newAnomalyTrackers[newAlertTrackerMap.at(alert3Id)]);
|
||||
|
||||
// Verify the alerts have the correct anomaly trackers.
|
||||
ASSERT_EQ(newMetricProducers.size(), 2);
|
||||
EXPECT_THAT(newMetricProducers[0]->mAnomalyTrackers,
|
||||
UnorderedElementsAre(newAnomalyTrackers[alert2Index]));
|
||||
// For durationMetric, make sure the duration trackers get the updated anomalyTrackers.
|
||||
DurationMetricProducer* durationProducer =
|
||||
static_cast<DurationMetricProducer*>(newMetricProducers[1].get());
|
||||
EXPECT_THAT(
|
||||
durationProducer->mAnomalyTrackers,
|
||||
UnorderedElementsAre(newAnomalyTrackers[alert1Index], newAnomalyTrackers[alert3Index],
|
||||
newAnomalyTrackers[alert4Index]));
|
||||
ASSERT_EQ(durationProducer->mCurrentSlicedDurationTrackerMap.size(), 1);
|
||||
for (const auto& durationTrackerIt : durationProducer->mCurrentSlicedDurationTrackerMap) {
|
||||
EXPECT_EQ(durationTrackerIt.second->mAnomalyTrackers, durationProducer->mAnomalyTrackers);
|
||||
}
|
||||
|
||||
// Verify alerts have the correct subscriptions. Use subscription id as proxy for equivalency.
|
||||
vector<int64_t> alert1Subscriptions;
|
||||
for (const Subscription& subscription : newAnomalyTrackers[alert1Index]->mSubscriptions) {
|
||||
alert1Subscriptions.push_back(subscription.id());
|
||||
}
|
||||
EXPECT_THAT(alert1Subscriptions, UnorderedElementsAre(subscription1.id()));
|
||||
vector<int64_t> alert2Subscriptions;
|
||||
for (const Subscription& subscription : newAnomalyTrackers[alert2Index]->mSubscriptions) {
|
||||
alert2Subscriptions.push_back(subscription.id());
|
||||
}
|
||||
EXPECT_THAT(alert2Subscriptions, UnorderedElementsAre(subscription2.id(), subscription4.id()));
|
||||
EXPECT_THAT(newAnomalyTrackers[alert3Index]->mSubscriptions, IsEmpty());
|
||||
EXPECT_THAT(newAnomalyTrackers[alert4Index]->mSubscriptions, IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(ConfigUpdateTest, TestUpdateAlarms) {
|
||||
StatsdConfig config;
|
||||
// Add alarms.
|
||||
Alarm alarm1 = createAlarm("Alarm1", /*offset*/ 1 * MS_PER_SEC, /*period*/ 50 * MS_PER_SEC);
|
||||
int64_t alarm1Id = alarm1.id();
|
||||
*config.add_alarm() = alarm1;
|
||||
|
||||
Alarm alarm2 = createAlarm("Alarm2", /*offset*/ 1 * MS_PER_SEC, /*period*/ 2000 * MS_PER_SEC);
|
||||
int64_t alarm2Id = alarm2.id();
|
||||
*config.add_alarm() = alarm2;
|
||||
|
||||
Alarm alarm3 = createAlarm("Alarm3", /*offset*/ 10 * MS_PER_SEC, /*period*/ 5000 * MS_PER_SEC);
|
||||
int64_t alarm3Id = alarm3.id();
|
||||
*config.add_alarm() = alarm3;
|
||||
|
||||
// Add Subscriptions.
|
||||
Subscription subscription1 = createSubscription("S1", Subscription::ALARM, alarm1Id);
|
||||
*config.add_subscription() = subscription1;
|
||||
Subscription subscription2 = createSubscription("S2", Subscription::ALARM, alarm1Id);
|
||||
*config.add_subscription() = subscription2;
|
||||
Subscription subscription3 = createSubscription("S3", Subscription::ALARM, alarm2Id);
|
||||
*config.add_subscription() = subscription3;
|
||||
|
||||
EXPECT_TRUE(initConfig(config));
|
||||
|
||||
ASSERT_EQ(oldAlarmTrackers.size(), 3);
|
||||
// Config is created at statsd start time, so just add the offsets.
|
||||
EXPECT_EQ(oldAlarmTrackers[0]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1);
|
||||
EXPECT_EQ(oldAlarmTrackers[1]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1);
|
||||
EXPECT_EQ(oldAlarmTrackers[2]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 10);
|
||||
|
||||
// Change alarm2/alarm3.
|
||||
config.mutable_alarm(1)->set_offset_millis(5 * MS_PER_SEC);
|
||||
config.mutable_alarm(2)->set_period_millis(10000 * MS_PER_SEC);
|
||||
|
||||
// Move subscription2 to be on alarm2 and make a new subscription.
|
||||
config.mutable_subscription(1)->set_rule_id(alarm2Id);
|
||||
Subscription subscription4 = createSubscription("S4", Subscription::ALARM, alarm1Id);
|
||||
*config.add_subscription() = subscription4;
|
||||
|
||||
// Update time is 2 seconds after the base time.
|
||||
int64_t currentTimeNs = timeBaseNs + 2 * NS_PER_SEC;
|
||||
vector<sp<AlarmTracker>> newAlarmTrackers;
|
||||
EXPECT_TRUE(initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs,
|
||||
newAlarmTrackers));
|
||||
|
||||
ASSERT_EQ(newAlarmTrackers.size(), 3);
|
||||
// Config is updated 2 seconds after statsd start
|
||||
// The offset has passed for alarm1, but not for alarms 2/3.
|
||||
EXPECT_EQ(newAlarmTrackers[0]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1 + 50);
|
||||
EXPECT_EQ(newAlarmTrackers[1]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 5);
|
||||
EXPECT_EQ(newAlarmTrackers[2]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 10);
|
||||
|
||||
// Verify alarms have the correct subscriptions. Use subscription id as proxy for equivalency.
|
||||
vector<int64_t> alarm1Subscriptions;
|
||||
for (const Subscription& subscription : newAlarmTrackers[0]->mSubscriptions) {
|
||||
alarm1Subscriptions.push_back(subscription.id());
|
||||
}
|
||||
EXPECT_THAT(alarm1Subscriptions, UnorderedElementsAre(subscription1.id(), subscription4.id()));
|
||||
vector<int64_t> alarm2Subscriptions;
|
||||
for (const Subscription& subscription : newAlarmTrackers[1]->mSubscriptions) {
|
||||
alarm2Subscriptions.push_back(subscription.id());
|
||||
}
|
||||
EXPECT_THAT(alarm2Subscriptions, UnorderedElementsAre(subscription2.id(), subscription3.id()));
|
||||
EXPECT_THAT(newAlarmTrackers[2]->mSubscriptions, IsEmpty());
|
||||
|
||||
// Verify the alarm monitor is updated accordingly once the old alarms are removed.
|
||||
// Alarm2 fires the earliest.
|
||||
oldAlarmTrackers.clear();
|
||||
EXPECT_EQ(periodicAlarmMonitor->getRegisteredAlarmTimeSec(), timeBaseNs / NS_PER_SEC + 5);
|
||||
|
||||
// Do another update 60 seconds after config creation time, after the offsets of each alarm.
|
||||
currentTimeNs = timeBaseNs + 60 * NS_PER_SEC;
|
||||
newAlarmTrackers.clear();
|
||||
EXPECT_TRUE(initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs,
|
||||
newAlarmTrackers));
|
||||
|
||||
ASSERT_EQ(newAlarmTrackers.size(), 3);
|
||||
// Config is updated one minute after statsd start.
|
||||
// Two periods have passed for alarm 1, one has passed for alarms2/3.
|
||||
EXPECT_EQ(newAlarmTrackers[0]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1 + 2 * 50);
|
||||
EXPECT_EQ(newAlarmTrackers[1]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 5 + 2000);
|
||||
EXPECT_EQ(newAlarmTrackers[2]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 10 + 10000);
|
||||
}
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "src/condition/ConditionTracker.h"
|
||||
#include "src/matchers/AtomMatchingTracker.h"
|
||||
#include "src/metrics/CountMetricProducer.h"
|
||||
#include "src/metrics/DurationMetricProducer.h"
|
||||
#include "src/metrics/GaugeMetricProducer.h"
|
||||
#include "src/metrics/MetricProducer.h"
|
||||
#include "src/metrics/ValueMetricProducer.h"
|
||||
@@ -793,6 +794,93 @@ TEST(MetricsManagerTest, TestCreateConditionTrackerCombination) {
|
||||
EXPECT_FALSE(tracker->IsSimpleCondition());
|
||||
}
|
||||
|
||||
TEST(MetricsManagerTest, TestCreateAnomalyTrackerInvalidMetric) {
|
||||
Alert alert;
|
||||
alert.set_id(123);
|
||||
alert.set_metric_id(1);
|
||||
alert.set_trigger_if_sum_gt(1);
|
||||
alert.set_num_buckets(1);
|
||||
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
vector<sp<MetricProducer>> metricProducers;
|
||||
// Pass in empty metric producers, causing an error.
|
||||
EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, {}, metricProducers), nullopt);
|
||||
}
|
||||
|
||||
TEST(MetricsManagerTest, TestCreateAnomalyTrackerNoThreshold) {
|
||||
int64_t metricId = 1;
|
||||
Alert alert;
|
||||
alert.set_id(123);
|
||||
alert.set_metric_id(metricId);
|
||||
alert.set_num_buckets(1);
|
||||
|
||||
CountMetric metric;
|
||||
metric.set_id(metricId);
|
||||
metric.set_bucket(ONE_MINUTE);
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
vector<sp<MetricProducer>> metricProducers({new CountMetricProducer(
|
||||
kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, 0x0123456789, 0, 0)});
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, {{1, 0}}, metricProducers), nullopt);
|
||||
}
|
||||
|
||||
TEST(MetricsManagerTest, TestCreateAnomalyTrackerMissingBuckets) {
|
||||
int64_t metricId = 1;
|
||||
Alert alert;
|
||||
alert.set_id(123);
|
||||
alert.set_metric_id(metricId);
|
||||
alert.set_trigger_if_sum_gt(1);
|
||||
|
||||
CountMetric metric;
|
||||
metric.set_id(metricId);
|
||||
metric.set_bucket(ONE_MINUTE);
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
vector<sp<MetricProducer>> metricProducers({new CountMetricProducer(
|
||||
kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, 0x0123456789, 0, 0)});
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, {{1, 0}}, metricProducers), nullopt);
|
||||
}
|
||||
|
||||
TEST(MetricsManagerTest, TestCreateAnomalyTrackerGood) {
|
||||
int64_t metricId = 1;
|
||||
Alert alert;
|
||||
alert.set_id(123);
|
||||
alert.set_metric_id(metricId);
|
||||
alert.set_trigger_if_sum_gt(1);
|
||||
alert.set_num_buckets(1);
|
||||
|
||||
CountMetric metric;
|
||||
metric.set_id(metricId);
|
||||
metric.set_bucket(ONE_MINUTE);
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
vector<sp<MetricProducer>> metricProducers({new CountMetricProducer(
|
||||
kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, 0x0123456789, 0, 0)});
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
EXPECT_NE(createAnomalyTracker(alert, anomalyAlarmMonitor, {{1, 0}}, metricProducers), nullopt);
|
||||
}
|
||||
|
||||
TEST(MetricsManagerTest, TestCreateAnomalyTrackerDurationTooLong) {
|
||||
int64_t metricId = 1;
|
||||
Alert alert;
|
||||
alert.set_id(123);
|
||||
alert.set_metric_id(metricId);
|
||||
// Impossible for alert to fire since the time is bigger than bucketSize * numBuckets
|
||||
alert.set_trigger_if_sum_gt(MillisToNano(TimeUnitToBucketSizeInMillis(ONE_MINUTE)) + 1);
|
||||
alert.set_num_buckets(1);
|
||||
|
||||
DurationMetric metric;
|
||||
metric.set_id(metricId);
|
||||
metric.set_bucket(ONE_MINUTE);
|
||||
metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
|
||||
FieldMatcher dimensions;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
vector<sp<MetricProducer>> metricProducers({new DurationMetricProducer(
|
||||
kConfigKey, metric, -1 /*no condition*/, {}, 1 /* start index */, 2 /* stop index */,
|
||||
3 /* stop_all index */, false /*nesting*/, wizard, 0x0123456789, dimensions, 0, 0)});
|
||||
sp<AlarmMonitor> anomalyAlarmMonitor;
|
||||
EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, {{1, 0}}, metricProducers), nullopt);
|
||||
}
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
|
||||
Reference in New Issue
Block a user