1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef DURATION_TRACKER_H 18 #define DURATION_TRACKER_H 19 20 #include "anomaly/DurationAnomalyTracker.h" 21 #include "condition/ConditionWizard.h" 22 #include "config/ConfigKey.h" 23 #include "stats_util.h" 24 25 namespace android { 26 namespace os { 27 namespace statsd { 28 29 enum DurationState { 30 kStopped = 0, // The event is stopped. 31 kStarted = 1, // The event is on going. 32 kPaused = 2, // The event is started, but condition is false, clock is paused. When condition 33 // turns to true, kPaused will become kStarted. 34 }; 35 36 // Hold duration information for one atom level duration in current on-going bucket. 37 struct DurationInfo { 38 DurationState state; 39 40 // the number of starts seen. 41 int32_t startCount; 42 43 // most recent start time. 44 int64_t lastStartTime; 45 // existing duration in current bucket. 46 int64_t lastDuration; 47 // cache the HashableDimensionKeys we need to query the condition for this duration event. 48 ConditionKey conditionKeys; 49 DurationInfoDurationInfo50 DurationInfo() : state(kStopped), startCount(0), lastStartTime(0), lastDuration(0){}; 51 }; 52 53 struct DurationBucket { 54 int64_t mBucketStartNs; 55 int64_t mBucketEndNs; 56 int64_t mDuration; 57 }; 58 59 class DurationTracker { 60 public: DurationTracker(const ConfigKey & key,const int64_t & id,const MetricDimensionKey & eventKey,sp<ConditionWizard> wizard,int conditionIndex,const std::vector<Matcher> & dimensionInCondition,bool nesting,int64_t currentBucketStartNs,int64_t currentBucketNum,int64_t startTimeNs,int64_t bucketSizeNs,bool conditionSliced,bool fullLink,const std::vector<sp<DurationAnomalyTracker>> & anomalyTrackers)61 DurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey, 62 sp<ConditionWizard> wizard, int conditionIndex, 63 const std::vector<Matcher>& dimensionInCondition, bool nesting, 64 int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs, 65 int64_t bucketSizeNs, bool conditionSliced, bool fullLink, 66 const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers) 67 : mConfigKey(key), 68 mTrackerId(id), 69 mEventKey(eventKey), 70 mWizard(wizard), 71 mConditionTrackerIndex(conditionIndex), 72 mBucketSizeNs(bucketSizeNs), 73 mDimensionInCondition(dimensionInCondition), 74 mNested(nesting), 75 mCurrentBucketStartTimeNs(currentBucketStartNs), 76 mDuration(0), 77 mDurationFullBucket(0), 78 mCurrentBucketNum(currentBucketNum), 79 mStartTimeNs(startTimeNs), 80 mConditionSliced(conditionSliced), 81 mHasLinksToAllConditionDimensionsInTracker(fullLink), 82 mAnomalyTrackers(anomalyTrackers){}; 83 ~DurationTracker()84 virtual ~DurationTracker(){}; 85 86 virtual unique_ptr<DurationTracker> clone(const int64_t eventTime) = 0; 87 88 virtual void noteStart(const HashableDimensionKey& key, bool condition, 89 const int64_t eventTime, const ConditionKey& conditionKey) = 0; 90 virtual void noteStop(const HashableDimensionKey& key, const int64_t eventTime, 91 const bool stopAll) = 0; 92 virtual void noteStopAll(const int64_t eventTime) = 0; 93 94 virtual void onSlicedConditionMayChange(bool overallCondition, const int64_t timestamp) = 0; 95 virtual void onConditionChanged(bool condition, const int64_t timestamp) = 0; 96 97 // Flush stale buckets if needed, and return true if the tracker has no on-going duration 98 // events, so that the owner can safely remove the tracker. 99 virtual bool flushIfNeeded( 100 int64_t timestampNs, 101 std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) = 0; 102 103 // Should only be called during an app upgrade or from this tracker's flushIfNeeded. If from 104 // an app upgrade, we assume that we're trying to form a partial bucket. 105 virtual bool flushCurrentBucket( 106 const int64_t& eventTimeNs, 107 std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) = 0; 108 109 // Predict the anomaly timestamp given the current status. 110 virtual int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker, 111 const int64_t currentTimestamp) const = 0; 112 // Dump internal states for debugging 113 virtual void dumpStates(FILE* out, bool verbose) const = 0; 114 setEventKey(const MetricDimensionKey & eventKey)115 void setEventKey(const MetricDimensionKey& eventKey) { 116 mEventKey = eventKey; 117 } 118 119 protected: getCurrentBucketEndTimeNs()120 int64_t getCurrentBucketEndTimeNs() const { 121 return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs; 122 } 123 124 // Starts the anomaly alarm. startAnomalyAlarm(const int64_t eventTime)125 void startAnomalyAlarm(const int64_t eventTime) { 126 for (auto& anomalyTracker : mAnomalyTrackers) { 127 if (anomalyTracker != nullptr) { 128 const int64_t alarmTimestampNs = 129 predictAnomalyTimestampNs(*anomalyTracker, eventTime); 130 if (alarmTimestampNs > 0) { 131 anomalyTracker->startAlarm(mEventKey, alarmTimestampNs); 132 } 133 } 134 } 135 } 136 137 // Stops the anomaly alarm. If it should have already fired, declare the anomaly now. stopAnomalyAlarm(const int64_t timestamp)138 void stopAnomalyAlarm(const int64_t timestamp) { 139 for (auto& anomalyTracker : mAnomalyTrackers) { 140 if (anomalyTracker != nullptr) { 141 anomalyTracker->stopAlarm(mEventKey, timestamp); 142 } 143 } 144 } 145 addPastBucketToAnomalyTrackers(const int64_t & bucketValue,const int64_t & bucketNum)146 void addPastBucketToAnomalyTrackers(const int64_t& bucketValue, const int64_t& bucketNum) { 147 for (auto& anomalyTracker : mAnomalyTrackers) { 148 if (anomalyTracker != nullptr) { 149 anomalyTracker->addPastBucket(mEventKey, bucketValue, bucketNum); 150 } 151 } 152 } 153 detectAndDeclareAnomaly(const int64_t & timestamp,const int64_t & currBucketNum,const int64_t & currentBucketValue)154 void detectAndDeclareAnomaly(const int64_t& timestamp, const int64_t& currBucketNum, 155 const int64_t& currentBucketValue) { 156 for (auto& anomalyTracker : mAnomalyTrackers) { 157 if (anomalyTracker != nullptr) { 158 anomalyTracker->detectAndDeclareAnomaly(timestamp, currBucketNum, mTrackerId, 159 mEventKey, currentBucketValue); 160 } 161 } 162 } 163 164 // Convenience to compute the current bucket's end time, which is always aligned with the 165 // start time of the metric. getCurrentBucketEndTimeNs()166 int64_t getCurrentBucketEndTimeNs() { 167 return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs; 168 } 169 170 // A reference to the DurationMetricProducer's config key. 171 const ConfigKey& mConfigKey; 172 173 const int64_t mTrackerId; 174 175 MetricDimensionKey mEventKey; 176 177 sp<ConditionWizard> mWizard; 178 179 const int mConditionTrackerIndex; 180 181 const int64_t mBucketSizeNs; 182 183 const std::vector<Matcher>& mDimensionInCondition; 184 185 const bool mNested; 186 187 int64_t mCurrentBucketStartTimeNs; 188 189 int64_t mDuration; // current recorded duration result (for partial bucket) 190 191 int64_t mDurationFullBucket; // Sum of past partial buckets in current full bucket. 192 193 int64_t mCurrentBucketNum; 194 195 const int64_t mStartTimeNs; 196 197 const bool mConditionSliced; 198 199 bool mSameConditionDimensionsInTracker; 200 bool mHasLinksToAllConditionDimensionsInTracker; 201 202 std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers; 203 204 FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp); 205 FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm); 206 FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm); 207 }; 208 209 } // namespace statsd 210 } // namespace os 211 } // namespace android 212 213 #endif // DURATION_TRACKER_H 214