Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d07d0ff0 authored by Tej Singh's avatar Tej Singh
Browse files

Partial config update for alerts/subscriptions

Preserves alerts if the definition didn't change and the underlying
metric didnt change.

All alerts need to be readded to the metric b/c metrics will always
clear the alerts on config updates. In the existing code, the metric
producer created the AnomalyTracker (since duration metrics need
DurationAnomalyTrackers). Preserved alerts already have an
AnomalyTracker. Therefore, we need a second overload of
addAnomalyTracker within MetricProducer to add existing ones. Note that
we don't need to worry about the type of AnomlayTracker, since if the
alert is preserved, both the AnomalyTracker and metric must not have
changed, so they will both be the correct type.

Subscriptions are also redone - alerts will clear their subscriptions,
and all subscriptions will be readded.

For duration metric, we now need to propagate adding anomaly trackers to
the DurationTrackers since it's now possible to add anomaly trackers
after the durationTrackers have been created.

Test: atest statsd_test
Bug: 162323547
Change-Id: Id3afa04b252f3a3523114407a389be25b9171a97
parent c44ef9e2
Loading
Loading
Loading
Loading
+13 −8
Original line number Diff line number Diff line
@@ -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);
+28 −3
Original line number Diff line number Diff line
@@ -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_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
+3 −3
Original line number Diff line number Diff line
@@ -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.
+17 −5
Original line number Diff line number Diff line
@@ -234,14 +234,26 @@ sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(
            return nullptr;
        }
    }
    sp<DurationAnomalyTracker> anomalyTracker =
    sp<AnomalyTracker> anomalyTracker =
            new DurationAnomalyTracker(alert, mConfigKey, anomalyAlarmMonitor);
    if (anomalyTracker != nullptr) {
        mAnomalyTrackers.push_back(anomalyTracker);
    }
    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,
+5 −3
Original line number Diff line number Diff line
@@ -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
Loading