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 struct DurationValues { 60 // Recorded duration for current partial bucket. 61 int64_t mDuration; 62 63 // Sum of past partial bucket durations in current full bucket. 64 // Used for anomaly detection. 65 int64_t mDurationFullBucket; 66 }; 67 68 class DurationTracker { 69 public: DurationTracker(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)70 DurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey, 71 sp<ConditionWizard> wizard, int conditionIndex, bool nesting, 72 int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs, 73 int64_t bucketSizeNs, bool conditionSliced, bool fullLink, 74 const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers) 75 : mConfigKey(key), 76 mTrackerId(id), 77 mEventKey(eventKey), 78 mWizard(wizard), 79 mConditionTrackerIndex(conditionIndex), 80 mBucketSizeNs(bucketSizeNs), 81 mNested(nesting), 82 mCurrentBucketStartTimeNs(currentBucketStartNs), 83 mDuration(0), 84 mCurrentBucketNum(currentBucketNum), 85 mStartTimeNs(startTimeNs), 86 mConditionSliced(conditionSliced), 87 mHasLinksToAllConditionDimensionsInTracker(fullLink), 88 mAnomalyTrackers(anomalyTrackers){}; 89 ~DurationTracker()90 virtual ~DurationTracker(){}; 91 92 virtual void noteStart(const HashableDimensionKey& key, bool condition, const int64_t eventTime, 93 const ConditionKey& conditionKey) = 0; 94 virtual void noteStop(const HashableDimensionKey& key, const int64_t eventTime, 95 const bool stopAll) = 0; 96 virtual void noteStopAll(const int64_t eventTime) = 0; 97 98 virtual void onSlicedConditionMayChange(bool overallCondition, const int64_t timestamp) = 0; 99 virtual void onConditionChanged(bool condition, const int64_t timestamp) = 0; 100 101 virtual void onStateChanged(const int64_t timestamp, const int32_t atomId, 102 const FieldValue& newState) = 0; 103 104 // Flush stale buckets if needed, and return true if the tracker has no on-going duration 105 // events, so that the owner can safely remove the tracker. 106 virtual bool flushIfNeeded( 107 int64_t timestampNs, 108 std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) = 0; 109 110 // Should only be called during an app upgrade or from this tracker's flushIfNeeded. If from 111 // an app upgrade, we assume that we're trying to form a partial bucket. 112 virtual bool flushCurrentBucket( 113 const int64_t& eventTimeNs, 114 std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) = 0; 115 116 // Predict the anomaly timestamp given the current status. 117 virtual int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker, 118 const int64_t currentTimestamp) const = 0; 119 // Dump internal states for debugging 120 virtual void dumpStates(FILE* out, bool verbose) const = 0; 121 122 virtual int64_t getCurrentStateKeyDuration() const = 0; 123 124 virtual int64_t getCurrentStateKeyFullBucketDuration() const = 0; 125 126 // Replace old value with new value for the given state atom. 127 virtual void updateCurrentStateKey(const int32_t atomId, const FieldValue& newState) = 0; 128 129 protected: getCurrentBucketEndTimeNs()130 int64_t getCurrentBucketEndTimeNs() const { 131 return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs; 132 } 133 134 // Starts the anomaly alarm. startAnomalyAlarm(const int64_t eventTime)135 void startAnomalyAlarm(const int64_t eventTime) { 136 for (auto& anomalyTracker : mAnomalyTrackers) { 137 if (anomalyTracker != nullptr) { 138 const int64_t alarmTimestampNs = 139 predictAnomalyTimestampNs(*anomalyTracker, eventTime); 140 if (alarmTimestampNs > 0) { 141 anomalyTracker->startAlarm(mEventKey, alarmTimestampNs); 142 } 143 } 144 } 145 } 146 147 // Stops the anomaly alarm. If it should have already fired, declare the anomaly now. stopAnomalyAlarm(const int64_t timestamp)148 void stopAnomalyAlarm(const int64_t timestamp) { 149 for (auto& anomalyTracker : mAnomalyTrackers) { 150 if (anomalyTracker != nullptr) { 151 anomalyTracker->stopAlarm(mEventKey, timestamp); 152 } 153 } 154 } 155 addPastBucketToAnomalyTrackers(const MetricDimensionKey eventKey,const int64_t & bucketValue,const int64_t & bucketNum)156 void addPastBucketToAnomalyTrackers(const MetricDimensionKey eventKey, 157 const int64_t& bucketValue, const int64_t& bucketNum) { 158 for (auto& anomalyTracker : mAnomalyTrackers) { 159 if (anomalyTracker != nullptr) { 160 anomalyTracker->addPastBucket(eventKey, bucketValue, bucketNum); 161 } 162 } 163 } 164 detectAndDeclareAnomaly(const int64_t & timestamp,const int64_t & currBucketNum,const int64_t & currentBucketValue)165 void detectAndDeclareAnomaly(const int64_t& timestamp, const int64_t& currBucketNum, 166 const int64_t& currentBucketValue) { 167 for (auto& anomalyTracker : mAnomalyTrackers) { 168 if (anomalyTracker != nullptr) { 169 anomalyTracker->detectAndDeclareAnomaly(timestamp, currBucketNum, mTrackerId, 170 mEventKey, currentBucketValue); 171 } 172 } 173 } 174 175 // Convenience to compute the current bucket's end time, which is always aligned with the 176 // start time of the metric. getCurrentBucketEndTimeNs()177 int64_t getCurrentBucketEndTimeNs() { 178 return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs; 179 } 180 setEventKey(const MetricDimensionKey & eventKey)181 void setEventKey(const MetricDimensionKey& eventKey) { 182 mEventKey = eventKey; 183 } 184 185 // A reference to the DurationMetricProducer's config key. 186 const ConfigKey& mConfigKey; 187 188 const int64_t mTrackerId; 189 190 MetricDimensionKey mEventKey; 191 192 sp<ConditionWizard> mWizard; 193 194 const int mConditionTrackerIndex; 195 196 const int64_t mBucketSizeNs; 197 198 const bool mNested; 199 200 int64_t mCurrentBucketStartTimeNs; 201 202 int64_t mDuration; // current recorded duration result (for partial bucket) 203 204 // Recorded duration results for each state key in the current partial bucket. 205 std::unordered_map<HashableDimensionKey, DurationValues> mStateKeyDurationMap; 206 207 int64_t mCurrentBucketNum; 208 209 const int64_t mStartTimeNs; 210 211 const bool mConditionSliced; 212 213 bool mHasLinksToAllConditionDimensionsInTracker; 214 215 std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers; 216 217 FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp); 218 FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm); 219 FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm); 220 }; 221 222 } // namespace statsd 223 } // namespace os 224 } // namespace android 225 226 #endif // DURATION_TRACKER_H 227