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
173c0b95ceb520c6b23871da90c23f89c55b76b560Yao Chen#define DEBUG false
185154a379303ab90a2b2914676a4441917a329b5dYao Chen
195154a379303ab90a2b2914676a4441917a329b5dYao Chen#include "Log.h"
205154a379303ab90a2b2914676a4441917a329b5dYao Chen#include "MaxDurationTracker.h"
21b356151e63140085cb96fa16804ee18b3862a4fcYao Chen#include "guardrail/StatsdStats.h"
225154a379303ab90a2b2914676a4441917a329b5dYao Chen
235154a379303ab90a2b2914676a4441917a329b5dYao Chennamespace android {
245154a379303ab90a2b2914676a4441917a329b5dYao Chennamespace os {
255154a379303ab90a2b2914676a4441917a329b5dYao Chennamespace statsd {
265154a379303ab90a2b2914676a4441917a329b5dYao Chen
2794e197cceb2ba7df13ff8de04f60bfeec64015d9Yangster-macMaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const int64_t& id,
289369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac                                       const MetricDimensionKey& eventKey,
299369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac                                       sp<ConditionWizard> wizard, int conditionIndex,
308a8d16ceea1e5b7a2f8c41e17b5d993035f50f5dYao Chen                                       const vector<Matcher>& dimensionInCondition, bool nesting,
31b142cc8add29c8c97f6134d35873d23db666027cYangster-mac                                       int64_t currentBucketStartNs, int64_t currentBucketNum,
32b142cc8add29c8c97f6134d35873d23db666027cYangster-mac                                       int64_t startTimeNs, int64_t bucketSizeNs,
3313fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster                                       bool conditionSliced, bool fullLink,
34857aaa520804d846a050e1eeb85d82977c983666Bookatz                                       const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
359369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    : DurationTracker(key, id, eventKey, wizard, conditionIndex, dimensionInCondition, nesting,
3627785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen                      currentBucketStartNs, currentBucketNum, startTimeNs, bucketSizeNs,
3713fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster                      conditionSliced, fullLink, anomalyTrackers) {
3813fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster    if (mWizard != nullptr) {
3913fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster        mSameConditionDimensionsInTracker =
4013fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster            mWizard->equalOutputDimensions(conditionIndex, mDimensionInCondition);
4113fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster    }
429369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac}
439369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac
44b142cc8add29c8c97f6134d35873d23db666027cYangster-macunique_ptr<DurationTracker> MaxDurationTracker::clone(const int64_t eventTime) {
459369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    auto clonedTracker = make_unique<MaxDurationTracker>(*this);
4613fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster    for (auto it = clonedTracker->mInfos.begin(); it != clonedTracker->mInfos.end();) {
4713fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster        if (it->second.state  != kStopped) {
4813fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster            it->second.lastStartTime = eventTime;
4913fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster            it->second.lastDuration = 0;
5013fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster            it++;
5113fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster        } else {
5213fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster            it = clonedTracker->mInfos.erase(it);
5313fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster        }
5413fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster    }
5513fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster    if (clonedTracker->mInfos.empty()) {
5613fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster        return nullptr;
5713fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster    } else {
5813fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster        return clonedTracker;
599369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    }
60b356151e63140085cb96fa16804ee18b3862a4fcYao Chen}
61b356151e63140085cb96fa16804ee18b3862a4fcYao Chen
62b356151e63140085cb96fa16804ee18b3862a4fcYao Chenbool MaxDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
63b356151e63140085cb96fa16804ee18b3862a4fcYao Chen    // ===========GuardRail==============
64b356151e63140085cb96fa16804ee18b3862a4fcYao Chen    if (mInfos.find(newKey) != mInfos.end()) {
65b356151e63140085cb96fa16804ee18b3862a4fcYao Chen        // if the key existed, we are good!
66b356151e63140085cb96fa16804ee18b3862a4fcYao Chen        return false;
67b356151e63140085cb96fa16804ee18b3862a4fcYao Chen    }
68b356151e63140085cb96fa16804ee18b3862a4fcYao Chen    // 1. Report the tuple count if the tuple count > soft limit
69b356151e63140085cb96fa16804ee18b3862a4fcYao Chen    if (mInfos.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
70b356151e63140085cb96fa16804ee18b3862a4fcYao Chen        size_t newTupleCount = mInfos.size() + 1;
718a8d16ceea1e5b7a2f8c41e17b5d993035f50f5dYao Chen        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mTrackerId, newTupleCount);
72b356151e63140085cb96fa16804ee18b3862a4fcYao Chen        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
73b356151e63140085cb96fa16804ee18b3862a4fcYao Chen        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
7494e197cceb2ba7df13ff8de04f60bfeec64015d9Yangster-mac            ALOGE("MaxDurTracker %lld dropping data for dimension key %s",
7513fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster                (long long)mTrackerId, newKey.toString().c_str());
76b356151e63140085cb96fa16804ee18b3862a4fcYao Chen            return true;
77b356151e63140085cb96fa16804ee18b3862a4fcYao Chen        }
78b356151e63140085cb96fa16804ee18b3862a4fcYao Chen    }
79b356151e63140085cb96fa16804ee18b3862a4fcYao Chen    return false;
805154a379303ab90a2b2914676a4441917a329b5dYao Chen}
815154a379303ab90a2b2914676a4441917a329b5dYao Chen
825154a379303ab90a2b2914676a4441917a329b5dYao Chenvoid MaxDurationTracker::noteStart(const HashableDimensionKey& key, bool condition,
83b142cc8add29c8c97f6134d35873d23db666027cYangster-mac                                   const int64_t eventTime, const ConditionKey& conditionKey) {
845154a379303ab90a2b2914676a4441917a329b5dYao Chen    // this will construct a new DurationInfo if this key didn't exist.
85b356151e63140085cb96fa16804ee18b3862a4fcYao Chen    if (hitGuardRail(key)) {
86b356151e63140085cb96fa16804ee18b3862a4fcYao Chen        return;
87b356151e63140085cb96fa16804ee18b3862a4fcYao Chen    }
88b356151e63140085cb96fa16804ee18b3862a4fcYao Chen
895154a379303ab90a2b2914676a4441917a329b5dYao Chen    DurationInfo& duration = mInfos[key];
90d59a6589faeb8a1b7b3c23e5ac95671bda736cddYao Chen    if (mConditionSliced) {
91d59a6589faeb8a1b7b3c23e5ac95671bda736cddYao Chen        duration.conditionKeys = conditionKey;
92d59a6589faeb8a1b7b3c23e5ac95671bda736cddYao Chen    }
9313fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster    VLOG("MaxDuration: key %s start condition %d", key.toString().c_str(), condition);
945154a379303ab90a2b2914676a4441917a329b5dYao Chen
955154a379303ab90a2b2914676a4441917a329b5dYao Chen    switch (duration.state) {
965154a379303ab90a2b2914676a4441917a329b5dYao Chen        case kStarted:
970ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen            duration.startCount++;
985154a379303ab90a2b2914676a4441917a329b5dYao Chen            break;
995154a379303ab90a2b2914676a4441917a329b5dYao Chen        case kPaused:
1000ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen            duration.startCount++;
1015154a379303ab90a2b2914676a4441917a329b5dYao Chen            break;
1025154a379303ab90a2b2914676a4441917a329b5dYao Chen        case kStopped:
1035154a379303ab90a2b2914676a4441917a329b5dYao Chen            if (!condition) {
1045154a379303ab90a2b2914676a4441917a329b5dYao Chen                // event started, but we need to wait for the condition to become true.
1055154a379303ab90a2b2914676a4441917a329b5dYao Chen                duration.state = DurationState::kPaused;
1065154a379303ab90a2b2914676a4441917a329b5dYao Chen            } else {
1075154a379303ab90a2b2914676a4441917a329b5dYao Chen                duration.state = DurationState::kStarted;
1085154a379303ab90a2b2914676a4441917a329b5dYao Chen                duration.lastStartTime = eventTime;
1092e414b99f44f00000d84765b3a095490415695afDavid Chen                startAnomalyAlarm(eventTime);
1105154a379303ab90a2b2914676a4441917a329b5dYao Chen            }
1110ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen            duration.startCount = 1;
1125154a379303ab90a2b2914676a4441917a329b5dYao Chen            break;
1135154a379303ab90a2b2914676a4441917a329b5dYao Chen    }
1145154a379303ab90a2b2914676a4441917a329b5dYao Chen}
1155154a379303ab90a2b2914676a4441917a329b5dYao Chen
116e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
117b142cc8add29c8c97f6134d35873d23db666027cYangster-macvoid MaxDurationTracker::noteStop(const HashableDimensionKey& key, const int64_t eventTime,
1180ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen                                  bool forceStop) {
11913fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster    VLOG("MaxDuration: key %s stop", key.toString().c_str());
1205154a379303ab90a2b2914676a4441917a329b5dYao Chen    if (mInfos.find(key) == mInfos.end()) {
1215154a379303ab90a2b2914676a4441917a329b5dYao Chen        // we didn't see a start event before. do nothing.
1225154a379303ab90a2b2914676a4441917a329b5dYao Chen        return;
1235154a379303ab90a2b2914676a4441917a329b5dYao Chen    }
1245154a379303ab90a2b2914676a4441917a329b5dYao Chen    DurationInfo& duration = mInfos[key];
1255154a379303ab90a2b2914676a4441917a329b5dYao Chen
1265154a379303ab90a2b2914676a4441917a329b5dYao Chen    switch (duration.state) {
1275154a379303ab90a2b2914676a4441917a329b5dYao Chen        case DurationState::kStopped:
1285154a379303ab90a2b2914676a4441917a329b5dYao Chen            // already stopped, do nothing.
1295154a379303ab90a2b2914676a4441917a329b5dYao Chen            break;
1305154a379303ab90a2b2914676a4441917a329b5dYao Chen        case DurationState::kStarted: {
1310ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen            duration.startCount--;
1320ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen            if (forceStop || !mNested || duration.startCount <= 0) {
1333e8cd35b551827234aa115700e50abb6c4721597Bookatz                stopAnomalyAlarm(eventTime);
1340ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen                duration.state = DurationState::kStopped;
1350ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen                int64_t durationTime = eventTime - duration.lastStartTime;
13613fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster                VLOG("Max, key %s, Stop %lld %lld %lld", key.toString().c_str(),
1370ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen                     (long long)duration.lastStartTime, (long long)eventTime,
1380ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen                     (long long)durationTime);
13927785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen                duration.lastDuration += durationTime;
1402e414b99f44f00000d84765b3a095490415695afDavid Chen                if (anyStarted()) {
1412e414b99f44f00000d84765b3a095490415695afDavid Chen                    // In case any other dimensions are still started, we need to keep the alarm
1422e414b99f44f00000d84765b3a095490415695afDavid Chen                    // set.
1432e414b99f44f00000d84765b3a095490415695afDavid Chen                    startAnomalyAlarm(eventTime);
1442e414b99f44f00000d84765b3a095490415695afDavid Chen                }
1450ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen                VLOG("  record duration: %lld ", (long long)duration.lastDuration);
1460ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen            }
1475154a379303ab90a2b2914676a4441917a329b5dYao Chen            break;
1485154a379303ab90a2b2914676a4441917a329b5dYao Chen        }
1495154a379303ab90a2b2914676a4441917a329b5dYao Chen        case DurationState::kPaused: {
1500ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen            duration.startCount--;
1510ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen            if (forceStop || !mNested || duration.startCount <= 0) {
1520ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen                duration.state = DurationState::kStopped;
1530ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen            }
1545154a379303ab90a2b2914676a4441917a329b5dYao Chen            break;
1555154a379303ab90a2b2914676a4441917a329b5dYao Chen        }
1565154a379303ab90a2b2914676a4441917a329b5dYao Chen    }
1575154a379303ab90a2b2914676a4441917a329b5dYao Chen
1585154a379303ab90a2b2914676a4441917a329b5dYao Chen    if (duration.lastDuration > mDuration) {
1595154a379303ab90a2b2914676a4441917a329b5dYao Chen        mDuration = duration.lastDuration;
1605154a379303ab90a2b2914676a4441917a329b5dYao Chen        VLOG("Max: new max duration: %lld", (long long)mDuration);
1615154a379303ab90a2b2914676a4441917a329b5dYao Chen    }
1625154a379303ab90a2b2914676a4441917a329b5dYao Chen    // Once an atom duration ends, we erase it. Next time, if we see another atom event with the
1635154a379303ab90a2b2914676a4441917a329b5dYao Chen    // same name, they are still considered as different atom durations.
1640ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen    if (duration.state == DurationState::kStopped) {
1650ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen        mInfos.erase(key);
1660ea19901ef78de19437c08bbcbb7af6663ad6f4bYao Chen    }
1675154a379303ab90a2b2914676a4441917a329b5dYao Chen}
168e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
1692e414b99f44f00000d84765b3a095490415695afDavid Chenbool MaxDurationTracker::anyStarted() {
1702e414b99f44f00000d84765b3a095490415695afDavid Chen    for (auto& pair : mInfos) {
1712e414b99f44f00000d84765b3a095490415695afDavid Chen        if (pair.second.state == kStarted) {
1722e414b99f44f00000d84765b3a095490415695afDavid Chen            return true;
1732e414b99f44f00000d84765b3a095490415695afDavid Chen        }
1742e414b99f44f00000d84765b3a095490415695afDavid Chen    }
1752e414b99f44f00000d84765b3a095490415695afDavid Chen    return false;
1762e414b99f44f00000d84765b3a095490415695afDavid Chen}
1772e414b99f44f00000d84765b3a095490415695afDavid Chen
178b142cc8add29c8c97f6134d35873d23db666027cYangster-macvoid MaxDurationTracker::noteStopAll(const int64_t eventTime) {
179e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    std::set<HashableDimensionKey> keys;
180e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    for (const auto& pair : mInfos) {
181e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac        keys.insert(pair.first);
182e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    }
183e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    for (auto& key : keys) {
184e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac        noteStop(key, eventTime, true);
1855154a379303ab90a2b2914676a4441917a329b5dYao Chen    }
1865154a379303ab90a2b2914676a4441917a329b5dYao Chen}
1875154a379303ab90a2b2914676a4441917a329b5dYao Chen
18827785a8a4a684c831c18f7189a6fa1b98c3573e6David Chenbool MaxDurationTracker::flushCurrentBucket(
189b142cc8add29c8c97f6134d35873d23db666027cYangster-mac        const int64_t& eventTimeNs,
19027785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen        std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) {
1915154a379303ab90a2b2914676a4441917a329b5dYao Chen    VLOG("MaxDurationTracker flushing.....");
1925154a379303ab90a2b2914676a4441917a329b5dYao Chen
1935154a379303ab90a2b2914676a4441917a329b5dYao Chen    // adjust the bucket start time
19427785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    int numBucketsForward = 0;
195b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    int64_t fullBucketEnd = getCurrentBucketEndTimeNs();
196b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    int64_t currentBucketEndTimeNs;
19727785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    if (eventTimeNs >= fullBucketEnd) {
19827785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen        numBucketsForward = 1 + (eventTimeNs - fullBucketEnd) / mBucketSizeNs;
19927785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen        currentBucketEndTimeNs = fullBucketEnd;
20027785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    } else {
20127785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen        // This must be a partial bucket.
20227785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen        currentBucketEndTimeNs = eventTimeNs;
20327785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    }
2045154a379303ab90a2b2914676a4441917a329b5dYao Chen
2055154a379303ab90a2b2914676a4441917a329b5dYao Chen    bool hasPendingEvent =
2065154a379303ab90a2b2914676a4441917a329b5dYao Chen            false;  // has either a kStarted or kPaused event across bucket boundaries
20727785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    // meaning we need to carry them over to the new bucket.
20859cc0a2237fe0527c9871f0236e9bc76146990b7Yao Chen    for (auto it = mInfos.begin(); it != mInfos.end();) {
2095154a379303ab90a2b2914676a4441917a329b5dYao Chen        if (it->second.state == DurationState::kStopped) {
2105154a379303ab90a2b2914676a4441917a329b5dYao Chen            // No need to keep buckets for events that were stopped before.
21159cc0a2237fe0527c9871f0236e9bc76146990b7Yao Chen            it = mInfos.erase(it);
2125154a379303ab90a2b2914676a4441917a329b5dYao Chen        } else {
21359cc0a2237fe0527c9871f0236e9bc76146990b7Yao Chen            ++it;
2145154a379303ab90a2b2914676a4441917a329b5dYao Chen            hasPendingEvent = true;
2155154a379303ab90a2b2914676a4441917a329b5dYao Chen        }
2165154a379303ab90a2b2914676a4441917a329b5dYao Chen    }
2175154a379303ab90a2b2914676a4441917a329b5dYao Chen
21827785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    // mDuration is updated in noteStop to the maximum duration that ended in the current bucket.
2195154a379303ab90a2b2914676a4441917a329b5dYao Chen    if (mDuration != 0) {
22027785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen        DurationBucket info;
22127785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen        info.mBucketStartNs = mCurrentBucketStartTimeNs;
22227785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen        info.mBucketEndNs = currentBucketEndTimeNs;
2232b0f88678b2877a8e9f83cea60f097322b078367yro        info.mDuration = mDuration;
224f60e0bad5908c51c954ca8dc763c8efd394c56dcYao Chen        (*output)[mEventKey].push_back(info);
2255154a379303ab90a2b2914676a4441917a329b5dYao Chen        VLOG("  final duration for last bucket: %lld", (long long)mDuration);
2265154a379303ab90a2b2914676a4441917a329b5dYao Chen    }
2275154a379303ab90a2b2914676a4441917a329b5dYao Chen
22827785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    if (numBucketsForward > 0) {
22927785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen        mCurrentBucketStartTimeNs = fullBucketEnd + (numBucketsForward - 1) * mBucketSizeNs;
23027785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen        mCurrentBucketNum += numBucketsForward;
23127785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    } else {  // We must be forming a partial bucket.
23227785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen        mCurrentBucketStartTimeNs = eventTimeNs;
2335154a379303ab90a2b2914676a4441917a329b5dYao Chen    }
234e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
23527785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    mDuration = 0;
2365154a379303ab90a2b2914676a4441917a329b5dYao Chen    // If this tracker has no pending events, tell owner to remove.
2375154a379303ab90a2b2914676a4441917a329b5dYao Chen    return !hasPendingEvent;
2385154a379303ab90a2b2914676a4441917a329b5dYao Chen}
2395154a379303ab90a2b2914676a4441917a329b5dYao Chen
24027785a8a4a684c831c18f7189a6fa1b98c3573e6David Chenbool MaxDurationTracker::flushIfNeeded(
241b142cc8add29c8c97f6134d35873d23db666027cYangster-mac        int64_t eventTimeNs, unordered_map<MetricDimensionKey, vector<DurationBucket>>* output) {
24227785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    if (eventTimeNs < getCurrentBucketEndTimeNs()) {
24327785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen        return false;
24427785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    }
24527785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen    return flushCurrentBucket(eventTimeNs, output);
24627785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen}
24727785a8a4a684c831c18f7189a6fa1b98c3573e6David Chen
248427d372552490a2c5ac4041fe345b15f69451f57Yao Chenvoid MaxDurationTracker::onSlicedConditionMayChange(bool overallCondition,
249b142cc8add29c8c97f6134d35873d23db666027cYangster-mac                                                    const int64_t timestamp) {
2505154a379303ab90a2b2914676a4441917a329b5dYao Chen    // Now for each of the on-going event, check if the condition has changed for them.
2515154a379303ab90a2b2914676a4441917a329b5dYao Chen    for (auto& pair : mInfos) {
2525154a379303ab90a2b2914676a4441917a329b5dYao Chen        if (pair.second.state == kStopped) {
2535154a379303ab90a2b2914676a4441917a329b5dYao Chen            continue;
2545154a379303ab90a2b2914676a4441917a329b5dYao Chen        }
2559369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac        std::unordered_set<HashableDimensionKey> conditionDimensionKeySet;
2569369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac        ConditionState conditionState = mWizard->query(
2579369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac            mConditionTrackerIndex, pair.second.conditionKeys, mDimensionInCondition,
25813fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster            !mSameConditionDimensionsInTracker,
25913fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster            !mHasLinksToAllConditionDimensionsInTracker,
2609369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac            &conditionDimensionKeySet);
2618a8d16ceea1e5b7a2f8c41e17b5d993035f50f5dYao Chen        bool conditionMet =
2628a8d16ceea1e5b7a2f8c41e17b5d993035f50f5dYao Chen                (conditionState == ConditionState::kTrue) &&
2638a8d16ceea1e5b7a2f8c41e17b5d993035f50f5dYao Chen                (mDimensionInCondition.size() == 0 ||
2648a8d16ceea1e5b7a2f8c41e17b5d993035f50f5dYao Chen                 conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition()) !=
2658a8d16ceea1e5b7a2f8c41e17b5d993035f50f5dYao Chen                         conditionDimensionKeySet.end());
26613fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster        VLOG("key: %s, condition: %d", pair.first.toString().c_str(), conditionMet);
2675154a379303ab90a2b2914676a4441917a329b5dYao Chen        noteConditionChanged(pair.first, conditionMet, timestamp);
2685154a379303ab90a2b2914676a4441917a329b5dYao Chen    }
2695154a379303ab90a2b2914676a4441917a329b5dYao Chen}
2705154a379303ab90a2b2914676a4441917a329b5dYao Chen
271b142cc8add29c8c97f6134d35873d23db666027cYangster-macvoid MaxDurationTracker::onConditionChanged(bool condition, const int64_t timestamp) {
2725154a379303ab90a2b2914676a4441917a329b5dYao Chen    for (auto& pair : mInfos) {
2735154a379303ab90a2b2914676a4441917a329b5dYao Chen        noteConditionChanged(pair.first, condition, timestamp);
2745154a379303ab90a2b2914676a4441917a329b5dYao Chen    }
2755154a379303ab90a2b2914676a4441917a329b5dYao Chen}
2765154a379303ab90a2b2914676a4441917a329b5dYao Chen
2775154a379303ab90a2b2914676a4441917a329b5dYao Chenvoid MaxDurationTracker::noteConditionChanged(const HashableDimensionKey& key, bool conditionMet,
278b142cc8add29c8c97f6134d35873d23db666027cYangster-mac                                              const int64_t timestamp) {
2795154a379303ab90a2b2914676a4441917a329b5dYao Chen    auto it = mInfos.find(key);
2805154a379303ab90a2b2914676a4441917a329b5dYao Chen    if (it == mInfos.end()) {
2815154a379303ab90a2b2914676a4441917a329b5dYao Chen        return;
2825154a379303ab90a2b2914676a4441917a329b5dYao Chen    }
2835154a379303ab90a2b2914676a4441917a329b5dYao Chen
2845154a379303ab90a2b2914676a4441917a329b5dYao Chen    switch (it->second.state) {
2855154a379303ab90a2b2914676a4441917a329b5dYao Chen        case kStarted:
2862e414b99f44f00000d84765b3a095490415695afDavid Chen            // If condition becomes false, kStarted -> kPaused. Record the current duration and
2872e414b99f44f00000d84765b3a095490415695afDavid Chen            // stop anomaly alarm.
2885154a379303ab90a2b2914676a4441917a329b5dYao Chen            if (!conditionMet) {
2893e8cd35b551827234aa115700e50abb6c4721597Bookatz                stopAnomalyAlarm(timestamp);
2905154a379303ab90a2b2914676a4441917a329b5dYao Chen                it->second.state = DurationState::kPaused;
2915154a379303ab90a2b2914676a4441917a329b5dYao Chen                it->second.lastDuration += (timestamp - it->second.lastStartTime);
2922e414b99f44f00000d84765b3a095490415695afDavid Chen                if (anyStarted()) {
2932e414b99f44f00000d84765b3a095490415695afDavid Chen                    // In case any other dimensions are still started, we need to set the alarm.
2942e414b99f44f00000d84765b3a095490415695afDavid Chen                    startAnomalyAlarm(timestamp);
2952e414b99f44f00000d84765b3a095490415695afDavid Chen                }
29613fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster                VLOG("MaxDurationTracker Key: %s Started->Paused ", key.toString().c_str());
2975154a379303ab90a2b2914676a4441917a329b5dYao Chen            }
2985154a379303ab90a2b2914676a4441917a329b5dYao Chen            break;
2995154a379303ab90a2b2914676a4441917a329b5dYao Chen        case kStopped:
3002e414b99f44f00000d84765b3a095490415695afDavid Chen            // Nothing to do if it's stopped.
3015154a379303ab90a2b2914676a4441917a329b5dYao Chen            break;
3025154a379303ab90a2b2914676a4441917a329b5dYao Chen        case kPaused:
3032e414b99f44f00000d84765b3a095490415695afDavid Chen            // If condition becomes true, kPaused -> kStarted. and the start time is the condition
3045154a379303ab90a2b2914676a4441917a329b5dYao Chen            // change time.
3055154a379303ab90a2b2914676a4441917a329b5dYao Chen            if (conditionMet) {
3065154a379303ab90a2b2914676a4441917a329b5dYao Chen                it->second.state = DurationState::kStarted;
3075154a379303ab90a2b2914676a4441917a329b5dYao Chen                it->second.lastStartTime = timestamp;
3082e414b99f44f00000d84765b3a095490415695afDavid Chen                startAnomalyAlarm(timestamp);
30913fb7e4eeaf7aee408821afe7ee55a5167e49e59Yangster                VLOG("MaxDurationTracker Key: %s Paused->Started", key.toString().c_str());
3105154a379303ab90a2b2914676a4441917a329b5dYao Chen            }
3115154a379303ab90a2b2914676a4441917a329b5dYao Chen            break;
3125154a379303ab90a2b2914676a4441917a329b5dYao Chen    }
3132e414b99f44f00000d84765b3a095490415695afDavid Chen    // Note that we don't update mDuration here since it's only updated during noteStop.
314e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac}
315e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
316857aaa520804d846a050e1eeb85d82977c983666Bookatzint64_t MaxDurationTracker::predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
317be10ddfe46ba6371bcd02cb57a06782e6b18d371Yangster-mac                                                      const int64_t currentTimestamp) const {
3182e414b99f44f00000d84765b3a095490415695afDavid Chen    // The allowed time we can continue in the current state is the
3192e414b99f44f00000d84765b3a095490415695afDavid Chen    // (anomaly threshold) - max(elapsed time of the started mInfos).
3202e414b99f44f00000d84765b3a095490415695afDavid Chen    int64_t maxElapsed = 0;
3212e414b99f44f00000d84765b3a095490415695afDavid Chen    for (auto it = mInfos.begin(); it != mInfos.end(); ++it) {
3222e414b99f44f00000d84765b3a095490415695afDavid Chen        if (it->second.state == DurationState::kStarted) {
3232e414b99f44f00000d84765b3a095490415695afDavid Chen            int64_t duration =
3242e414b99f44f00000d84765b3a095490415695afDavid Chen                    it->second.lastDuration + (currentTimestamp - it->second.lastStartTime);
3252e414b99f44f00000d84765b3a095490415695afDavid Chen            if (duration > maxElapsed) {
3262e414b99f44f00000d84765b3a095490415695afDavid Chen                maxElapsed = duration;
3272e414b99f44f00000d84765b3a095490415695afDavid Chen            }
3282e414b99f44f00000d84765b3a095490415695afDavid Chen        }
3292e414b99f44f00000d84765b3a095490415695afDavid Chen    }
3300dbc7a434345fa318ee129eaa5cf83681de4936bBookatz    int64_t anomalyTimeNs = currentTimestamp + anomalyTracker.getAnomalyThreshold() - maxElapsed;
3310dbc7a434345fa318ee129eaa5cf83681de4936bBookatz    int64_t refractoryEndNs = anomalyTracker.getRefractoryPeriodEndsSec(mEventKey) * NS_PER_SEC;
3320dbc7a434345fa318ee129eaa5cf83681de4936bBookatz    return std::max(anomalyTimeNs, refractoryEndNs);
3335154a379303ab90a2b2914676a4441917a329b5dYao Chen}
3345154a379303ab90a2b2914676a4441917a329b5dYao Chen
335884c8c130fde0d02ada1316f7c27f0f55e7e48b9Yao Chenvoid MaxDurationTracker::dumpStates(FILE* out, bool verbose) const {
336884c8c130fde0d02ada1316f7c27f0f55e7e48b9Yao Chen    fprintf(out, "\t\t sub-durations %lu\n", (unsigned long)mInfos.size());
337884c8c130fde0d02ada1316f7c27f0f55e7e48b9Yao Chen    fprintf(out, "\t\t current duration %lld\n", (long long)mDuration);
338884c8c130fde0d02ada1316f7c27f0f55e7e48b9Yao Chen}
339884c8c130fde0d02ada1316f7c27f0f55e7e48b9Yao Chen
3405154a379303ab90a2b2914676a4441917a329b5dYao Chen}  // namespace statsd
3415154a379303ab90a2b2914676a4441917a329b5dYao Chen}  // namespace os
3422b0f88678b2877a8e9f83cea60f097322b078367yro}  // namespace android
343