15154a379303ab90a2b2914676a4441917a329b5dYao Chen/*
25154a379303ab90a2b2914676a4441917a329b5dYao Chen * Copyright (C) 2017 The Android Open Source Project
35154a379303ab90a2b2914676a4441917a329b5dYao Chen *
45154a379303ab90a2b2914676a4441917a329b5dYao Chen * Licensed under the Apache License, Version 2.0 (the "License");
55154a379303ab90a2b2914676a4441917a329b5dYao Chen * you may not use this file except in compliance with the License.
65154a379303ab90a2b2914676a4441917a329b5dYao Chen * You may obtain a copy of the License at
75154a379303ab90a2b2914676a4441917a329b5dYao Chen *
85154a379303ab90a2b2914676a4441917a329b5dYao Chen *      http://www.apache.org/licenses/LICENSE-2.0
95154a379303ab90a2b2914676a4441917a329b5dYao Chen *
105154a379303ab90a2b2914676a4441917a329b5dYao Chen * Unless required by applicable law or agreed to in writing, software
115154a379303ab90a2b2914676a4441917a329b5dYao Chen * distributed under the License is distributed on an "AS IS" BASIS,
125154a379303ab90a2b2914676a4441917a329b5dYao Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135154a379303ab90a2b2914676a4441917a329b5dYao Chen * See the License for the specific language governing permissions and
145154a379303ab90a2b2914676a4441917a329b5dYao Chen * limitations under the License.
155154a379303ab90a2b2914676a4441917a329b5dYao Chen */
165154a379303ab90a2b2914676a4441917a329b5dYao Chen
175154a379303ab90a2b2914676a4441917a329b5dYao Chen#ifndef DURATION_TRACKER_H
185154a379303ab90a2b2914676a4441917a329b5dYao Chen#define DURATION_TRACKER_H
195154a379303ab90a2b2914676a4441917a329b5dYao Chen
20857aaa520804d846a050e1eeb85d82977c983666Bookatz#include "anomaly/DurationAnomalyTracker.h"
215154a379303ab90a2b2914676a4441917a329b5dYao Chen#include "condition/ConditionWizard.h"
22b356151e63140085cb96fa16804ee18b3862a4fcYao Chen#include "config/ConfigKey.h"
235154a379303ab90a2b2914676a4441917a329b5dYao Chen#include "stats_util.h"
245154a379303ab90a2b2914676a4441917a329b5dYao Chen
255154a379303ab90a2b2914676a4441917a329b5dYao Chennamespace android {
265154a379303ab90a2b2914676a4441917a329b5dYao Chennamespace os {
275154a379303ab90a2b2914676a4441917a329b5dYao Chennamespace statsd {
285154a379303ab90a2b2914676a4441917a329b5dYao Chen
295154a379303ab90a2b2914676a4441917a329b5dYao Chenenum DurationState {
305154a379303ab90a2b2914676a4441917a329b5dYao Chen    kStopped = 0,  // The event is stopped.
315154a379303ab90a2b2914676a4441917a329b5dYao Chen    kStarted = 1,  // The event is on going.
325154a379303ab90a2b2914676a4441917a329b5dYao Chen    kPaused = 2,   // The event is started, but condition is false, clock is paused. When condition
335154a379303ab90a2b2914676a4441917a329b5dYao Chen                   // turns to true, kPaused will become kStarted.
345154a379303ab90a2b2914676a4441917a329b5dYao Chen};
355154a379303ab90a2b2914676a4441917a329b5dYao Chen
365154a379303ab90a2b2914676a4441917a329b5dYao Chen// Hold duration information for one atom level duration in current on-going bucket.
375154a379303ab90a2b2914676a4441917a329b5dYao Chenstruct DurationInfo {
385154a379303ab90a2b2914676a4441917a329b5dYao Chen    DurationState state;
390ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen
400ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen    // the number of starts seen.
410ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen    int32_t startCount;
420ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen
435154a379303ab90a2b2914676a4441917a329b5dYao Chen    // most recent start time.
445154a379303ab90a2b2914676a4441917a329b5dYao Chen    int64_t lastStartTime;
455154a379303ab90a2b2914676a4441917a329b5dYao Chen    // existing duration in current bucket.
465154a379303ab90a2b2914676a4441917a329b5dYao Chen    int64_t lastDuration;
475154a379303ab90a2b2914676a4441917a329b5dYao Chen    // TODO: Optimize the way we track sliced condition in duration metrics.
485154a379303ab90a2b2914676a4441917a329b5dYao Chen    // cache the HashableDimensionKeys we need to query the condition for this duration event.
495154a379303ab90a2b2914676a4441917a329b5dYao Chen    ConditionKey conditionKeys;
505154a379303ab90a2b2914676a4441917a329b5dYao Chen
510ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen    DurationInfo() : state(kStopped), startCount(0), lastStartTime(0), lastDuration(0){};
525154a379303ab90a2b2914676a4441917a329b5dYao Chen};
535154a379303ab90a2b2914676a4441917a329b5dYao Chen
542b0f88678b2877a8e9f83cea60f097322b078367yrostruct DurationBucket {
55b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    int64_t mBucketStartNs;
56b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    int64_t mBucketEndNs;
57b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    int64_t mDuration;
582b0f88678b2877a8e9f83cea60f097322b078367yro};
592b0f88678b2877a8e9f83cea60f097322b078367yro
605154a379303ab90a2b2914676a4441917a329b5dYao Chenclass DurationTracker {
615154a379303ab90a2b2914676a4441917a329b5dYao Chenpublic:
629369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    DurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
639369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac                    sp<ConditionWizard> wizard, int conditionIndex,
648a8d16ceea1e5b7a2f8c41e17b5d993035f50f5dYao Chen                    const std::vector<Matcher>& dimensionInCondition, bool nesting,
65b142cc8add29c8c97f6134d35873d23db666027cYangster-mac                    int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs,
66b142cc8add29c8c97f6134d35873d23db666027cYangster-mac                    int64_t bucketSizeNs, bool conditionSliced, bool fullLink,
67857aaa520804d846a050e1eeb85d82977c983666Bookatz                    const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
68b356151e63140085cb96fa16804ee18b3862a4fcYao Chen        : mConfigKey(key),
6994e197cceb2ba7df13ff8de04f60bfeec64015d9Yangster-mac          mTrackerId(id),
70b356151e63140085cb96fa16804ee18b3862a4fcYao Chen          mEventKey(eventKey),
71e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac          mWizard(wizard),
725154a379303ab90a2b2914676a4441917a329b5dYao Chen          mConditionTrackerIndex(conditionIndex),
735154a379303ab90a2b2914676a4441917a329b5dYao Chen          mBucketSizeNs(bucketSizeNs),
749369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac          mDimensionInCondition(dimensionInCondition),
750ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen          mNested(nesting),
760ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen          mCurrentBucketStartTimeNs(currentBucketStartNs),
77e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac          mDuration(0),
7827785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen          mDurationFullBucket(0),
7927785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen          mCurrentBucketNum(currentBucketNum),
8027785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen          mStartTimeNs(startTimeNs),
81d59a6589faeb8a1b7b3c23e5ac95671bda736cddYao Chen          mConditionSliced(conditionSliced),
8213fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster          mHasLinksToAllConditionDimensionsInTracker(fullLink),
83e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac          mAnomalyTrackers(anomalyTrackers){};
847c334a129e93e405a72e8299a1cd928af079d14fYangster
855154a379303ab90a2b2914676a4441917a329b5dYao Chen    virtual ~DurationTracker(){};
867c334a129e93e405a72e8299a1cd928af079d14fYangster
87b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    virtual unique_ptr<DurationTracker> clone(const int64_t eventTime) = 0;
889369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac
895154a379303ab90a2b2914676a4441917a329b5dYao Chen    virtual void noteStart(const HashableDimensionKey& key, bool condition,
90b142cc8add29c8c97f6134d35873d23db666027cYangster-mac                           const int64_t eventTime, const ConditionKey& conditionKey) = 0;
91b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    virtual void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
920ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen                          const bool stopAll) = 0;
93b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    virtual void noteStopAll(const int64_t eventTime) = 0;
947c334a129e93e405a72e8299a1cd928af079d14fYangster
95b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    virtual void onSlicedConditionMayChange(bool overallCondition, const int64_t timestamp) = 0;
96b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    virtual void onConditionChanged(bool condition, const int64_t timestamp) = 0;
977c334a129e93e405a72e8299a1cd928af079d14fYangster
985154a379303ab90a2b2914676a4441917a329b5dYao Chen    // Flush stale buckets if needed, and return true if the tracker has no on-going duration
995154a379303ab90a2b2914676a4441917a329b5dYao Chen    // events, so that the owner can safely remove the tracker.
100f60e0bad5908c51c954ca8dc763c8efd394c56dcYao Chen    virtual bool flushIfNeeded(
101b142cc8add29c8c97f6134d35873d23db666027cYangster-mac            int64_t timestampNs,
1029369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac            std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) = 0;
1035154a379303ab90a2b2914676a4441917a329b5dYao Chen
10427785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    // Should only be called during an app upgrade or from this tracker's flushIfNeeded. If from
10527785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    // an app upgrade, we assume that we're trying to form a partial bucket.
10627785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    virtual bool flushCurrentBucket(
107b142cc8add29c8c97f6134d35873d23db666027cYangster-mac            const int64_t& eventTimeNs,
10827785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen            std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) = 0;
10927785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen
110e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Predict the anomaly timestamp given the current status.
111857aaa520804d846a050e1eeb85d82977c983666Bookatz    virtual int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
112be10ddfe46ba6371bcd02cb57a06782e6b18d371Yangster-mac                                              const int64_t currentTimestamp) const = 0;
113884c8c130fde0d02ada1316f7c27f0f55e7e48b9Yao Chen    // Dump internal states for debugging
114884c8c130fde0d02ada1316f7c27f0f55e7e48b9Yao Chen    virtual void dumpStates(FILE* out, bool verbose) const = 0;
115e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
1169369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    void setEventKey(const MetricDimensionKey& eventKey) {
1179369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac         mEventKey = eventKey;
1189369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    }
1199369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac
1205154a379303ab90a2b2914676a4441917a329b5dYao Chenprotected:
121b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    int64_t getCurrentBucketEndTimeNs() const {
122be10ddfe46ba6371bcd02cb57a06782e6b18d371Yangster-mac        return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
123be10ddfe46ba6371bcd02cb57a06782e6b18d371Yangster-mac    }
124be10ddfe46ba6371bcd02cb57a06782e6b18d371Yangster-mac
125e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Starts the anomaly alarm.
126b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    void startAnomalyAlarm(const int64_t eventTime) {
127e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac        for (auto& anomalyTracker : mAnomalyTrackers) {
128e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac            if (anomalyTracker != nullptr) {
129b142cc8add29c8c97f6134d35873d23db666027cYangster-mac                const int64_t alarmTimestampNs =
130be10ddfe46ba6371bcd02cb57a06782e6b18d371Yangster-mac                    predictAnomalyTimestampNs(*anomalyTracker, eventTime);
131be10ddfe46ba6371bcd02cb57a06782e6b18d371Yangster-mac                if (alarmTimestampNs > 0) {
132be10ddfe46ba6371bcd02cb57a06782e6b18d371Yangster-mac                    anomalyTracker->startAlarm(mEventKey, alarmTimestampNs);
133be10ddfe46ba6371bcd02cb57a06782e6b18d371Yangster-mac                }
134e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac            }
135e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac        }
136e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    }
137e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
1383e8cd35b551827234aa115700e50abb6c4721597Bookatz    // Stops the anomaly alarm. If it should have already fired, declare the anomaly now.
139b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    void stopAnomalyAlarm(const int64_t timestamp) {
140e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac        for (auto& anomalyTracker : mAnomalyTrackers) {
141e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac            if (anomalyTracker != nullptr) {
1423e8cd35b551827234aa115700e50abb6c4721597Bookatz                anomalyTracker->stopAlarm(mEventKey, timestamp);
143e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac            }
144e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac        }
145e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    }
146e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
147e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    void addPastBucketToAnomalyTrackers(const int64_t& bucketValue, const int64_t& bucketNum) {
148e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac        for (auto& anomalyTracker : mAnomalyTrackers) {
149e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac            if (anomalyTracker != nullptr) {
150e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac                anomalyTracker->addPastBucket(mEventKey, bucketValue, bucketNum);
151e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac            }
152e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac        }
153e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    }
154e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
155b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    void detectAndDeclareAnomaly(const int64_t& timestamp, const int64_t& currBucketNum,
156e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac                                 const int64_t& currentBucketValue) {
157e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac        for (auto& anomalyTracker : mAnomalyTrackers) {
158e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac            if (anomalyTracker != nullptr) {
159e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac                anomalyTracker->detectAndDeclareAnomaly(timestamp, currBucketNum, mEventKey,
160e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac                                                        currentBucketValue);
161e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac            }
162e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac        }
163e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    }
164e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
16527785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    // Convenience to compute the current bucket's end time, which is always aligned with the
16627785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    // start time of the metric.
167b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    int64_t getCurrentBucketEndTimeNs() {
16827785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen        return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
16927785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    }
17027785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen
171b356151e63140085cb96fa16804ee18b3862a4fcYao Chen    // A reference to the DurationMetricProducer's config key.
172b356151e63140085cb96fa16804ee18b3862a4fcYao Chen    const ConfigKey& mConfigKey;
173b356151e63140085cb96fa16804ee18b3862a4fcYao Chen
17494e197cceb2ba7df13ff8de04f60bfeec64015d9Yangster-mac    const int64_t mTrackerId;
175e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
1769369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    MetricDimensionKey mEventKey;
177e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
1785154a379303ab90a2b2914676a4441917a329b5dYao Chen    sp<ConditionWizard> mWizard;
1795154a379303ab90a2b2914676a4441917a329b5dYao Chen
1800ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen    const int mConditionTrackerIndex;
1815154a379303ab90a2b2914676a4441917a329b5dYao Chen
1820ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen    const int64_t mBucketSizeNs;
1830ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen
1848a8d16ceea1e5b7a2f8c41e17b5d993035f50f5dYao Chen    const std::vector<Matcher>& mDimensionInCondition;
1859369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac
1860ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen    const bool mNested;
1875154a379303ab90a2b2914676a4441917a329b5dYao Chen
188b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    int64_t mCurrentBucketStartTimeNs;
1895154a379303ab90a2b2914676a4441917a329b5dYao Chen
19027785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    int64_t mDuration;  // current recorded duration result (for partial bucket)
19127785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen
19227785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    int64_t mDurationFullBucket;  // Sum of past partial buckets in current full bucket.
193e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
194b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    int64_t mCurrentBucketNum;
195e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
196b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    const int64_t mStartTimeNs;
19727785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen
198d59a6589faeb8a1b7b3c23e5ac95671bda736cddYao Chen    const bool mConditionSliced;
199d59a6589faeb8a1b7b3c23e5ac95671bda736cddYao Chen
20013fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster    bool mSameConditionDimensionsInTracker;
20113fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster    bool mHasLinksToAllConditionDimensionsInTracker;
20213fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster
203857aaa520804d846a050e1eeb85d82977c983666Bookatz    std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers;
204e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
205e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
2061bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm);
2071bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm);
2085154a379303ab90a2b2914676a4441917a329b5dYao Chen};
2095154a379303ab90a2b2914676a4441917a329b5dYao Chen
2105154a379303ab90a2b2914676a4441917a329b5dYao Chen}  // namespace statsd
2115154a379303ab90a2b2914676a4441917a329b5dYao Chen}  // namespace os
2125154a379303ab90a2b2914676a4441917a329b5dYao Chen}  // namespace android
2135154a379303ab90a2b2914676a4441917a329b5dYao Chen
2142b0f88678b2877a8e9f83cea60f097322b078367yro#endif  // DURATION_TRACKER_H
215