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#define DEBUG false // STOPSHIP if true 18#include "Log.h" 19 20#include "DurationAnomalyTracker.h" 21#include "guardrail/StatsdStats.h" 22 23namespace android { 24namespace os { 25namespace statsd { 26 27DurationAnomalyTracker::DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey, 28 const sp<AlarmMonitor>& alarmMonitor) 29 : AnomalyTracker(alert, configKey), mAlarmMonitor(alarmMonitor) { 30 VLOG("DurationAnomalyTracker() called"); 31} 32 33DurationAnomalyTracker::~DurationAnomalyTracker() { 34 VLOG("~DurationAnomalyTracker() called"); 35 cancelAllAlarms(); 36} 37 38void DurationAnomalyTracker::startAlarm(const MetricDimensionKey& dimensionKey, 39 const int64_t& timestampNs) { 40 // Alarms are stored in secs. Must round up, since if it fires early, it is ignored completely. 41 uint32_t timestampSec = static_cast<uint32_t>((timestampNs -1) / NS_PER_SEC) + 1; // round up 42 if (isInRefractoryPeriod(timestampNs, dimensionKey)) { 43 VLOG("Not setting anomaly alarm since it would fall in the refractory period."); 44 return; 45 } 46 47 auto itr = mAlarms.find(dimensionKey); 48 if (itr != mAlarms.end() && mAlarmMonitor != nullptr) { 49 mAlarmMonitor->remove(itr->second); 50 } 51 52 sp<const InternalAlarm> alarm = new InternalAlarm{timestampSec}; 53 mAlarms[dimensionKey] = alarm; 54 if (mAlarmMonitor != nullptr) { 55 mAlarmMonitor->add(alarm); 56 } 57} 58 59void DurationAnomalyTracker::stopAlarm(const MetricDimensionKey& dimensionKey, 60 const int64_t& timestampNs) { 61 const auto itr = mAlarms.find(dimensionKey); 62 if (itr == mAlarms.end()) { 63 return; 64 } 65 66 // If the alarm is set in the past but hasn't fired yet (due to lag), catch it now. 67 if (itr->second != nullptr && timestampNs >= (int64_t)NS_PER_SEC * itr->second->timestampSec) { 68 declareAnomaly(timestampNs, dimensionKey); 69 } 70 if (mAlarmMonitor != nullptr) { 71 mAlarmMonitor->remove(itr->second); 72 } 73 mAlarms.erase(dimensionKey); 74} 75 76void DurationAnomalyTracker::cancelAllAlarms() { 77 if (mAlarmMonitor != nullptr) { 78 for (const auto& itr : mAlarms) { 79 mAlarmMonitor->remove(itr.second); 80 } 81 } 82 mAlarms.clear(); 83} 84 85void DurationAnomalyTracker::informAlarmsFired(const int64_t& timestampNs, 86 unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) { 87 88 if (firedAlarms.empty() || mAlarms.empty()) return; 89 // Find the intersection of firedAlarms and mAlarms. 90 // The for loop is inefficient, since it loops over all keys, but that's okay since it is very 91 // seldomly called. The alternative would be having InternalAlarms store information about the 92 // DurationAnomalyTracker and key, but that's a lot of data overhead to speed up something that 93 // is rarely ever called. 94 unordered_map<MetricDimensionKey, sp<const InternalAlarm>> matchedAlarms; 95 for (const auto& kv : mAlarms) { 96 if (firedAlarms.count(kv.second) > 0) { 97 matchedAlarms.insert({kv.first, kv.second}); 98 } 99 } 100 101 // Now declare each of these alarms to have fired. 102 for (const auto& kv : matchedAlarms) { 103 declareAnomaly(timestampNs, kv.first); 104 mAlarms.erase(kv.first); 105 firedAlarms.erase(kv.second); // No one else can also own it, so we're done with it. 106 } 107} 108 109} // namespace statsd 110} // namespace os 111} // namespace android 112