Home | History | Annotate | Download | only in anomaly
      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
     18 #include "Log.h"
     19 
     20 #include "anomaly/AlarmMonitor.h"
     21 #include "guardrail/StatsdStats.h"
     22 
     23 namespace android {
     24 namespace os {
     25 namespace statsd {
     26 
     27 AlarmMonitor::AlarmMonitor(
     28         uint32_t minDiffToUpdateRegisteredAlarmTimeSec,
     29         const std::function<void(const sp<IStatsCompanionService>&, int64_t)>& updateAlarm,
     30         const std::function<void(const sp<IStatsCompanionService>&)>& cancelAlarm)
     31     : mRegisteredAlarmTimeSec(0), mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec),
     32       mUpdateAlarm(updateAlarm),
     33       mCancelAlarm(cancelAlarm) {}
     34 
     35 AlarmMonitor::~AlarmMonitor() {}
     36 
     37 void AlarmMonitor::setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService) {
     38     std::lock_guard<std::mutex> lock(mLock);
     39     sp<IStatsCompanionService> tmpForLock = mStatsCompanionService;
     40     mStatsCompanionService = statsCompanionService;
     41     if (statsCompanionService == nullptr) {
     42         VLOG("Erasing link to statsCompanionService");
     43         return;
     44     }
     45     VLOG("Creating link to statsCompanionService");
     46     const sp<const InternalAlarm> top = mPq.top();
     47     if (top != nullptr) {
     48         updateRegisteredAlarmTime_l(top->timestampSec);
     49     }
     50 }
     51 
     52 void AlarmMonitor::add(sp<const InternalAlarm> alarm) {
     53     std::lock_guard<std::mutex> lock(mLock);
     54     if (alarm == nullptr) {
     55         ALOGW("Asked to add a null alarm.");
     56         return;
     57     }
     58     if (alarm->timestampSec < 1) {
     59         // forbidden since a timestamp 0 is used to indicate no alarm registered
     60         ALOGW("Asked to add a 0-time alarm.");
     61         return;
     62     }
     63     // TODO: Ensure that refractory period is respected.
     64     VLOG("Adding alarm with time %u", alarm->timestampSec);
     65     mPq.push(alarm);
     66     if (mRegisteredAlarmTimeSec < 1 ||
     67         alarm->timestampSec + mMinUpdateTimeSec < mRegisteredAlarmTimeSec) {
     68         updateRegisteredAlarmTime_l(alarm->timestampSec);
     69     }
     70 }
     71 
     72 void AlarmMonitor::remove(sp<const InternalAlarm> alarm) {
     73     std::lock_guard<std::mutex> lock(mLock);
     74     if (alarm == nullptr) {
     75         ALOGW("Asked to remove a null alarm.");
     76         return;
     77     }
     78     VLOG("Removing alarm with time %u", alarm->timestampSec);
     79     bool wasPresent = mPq.remove(alarm);
     80     if (!wasPresent) return;
     81     if (mPq.empty()) {
     82         VLOG("Queue is empty. Cancel any alarm.");
     83         cancelRegisteredAlarmTime_l();
     84         return;
     85     }
     86     uint32_t soonestAlarmTimeSec = mPq.top()->timestampSec;
     87     VLOG("Soonest alarm is %u", soonestAlarmTimeSec);
     88     if (soonestAlarmTimeSec > mRegisteredAlarmTimeSec + mMinUpdateTimeSec) {
     89         updateRegisteredAlarmTime_l(soonestAlarmTimeSec);
     90     }
     91 }
     92 
     93 // More efficient than repeatedly calling remove(mPq.top()) since it batches the
     94 // updates to the registered alarm.
     95 unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> AlarmMonitor::popSoonerThan(
     96         uint32_t timestampSec) {
     97     VLOG("Removing alarms with time <= %u", timestampSec);
     98     unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> oldAlarms;
     99     std::lock_guard<std::mutex> lock(mLock);
    100 
    101     for (sp<const InternalAlarm> t = mPq.top(); t != nullptr && t->timestampSec <= timestampSec;
    102         t = mPq.top()) {
    103         oldAlarms.insert(t);
    104         mPq.pop();  // remove t
    105     }
    106     // Always update registered alarm time (if anything has changed).
    107     if (!oldAlarms.empty()) {
    108         if (mPq.empty()) {
    109             VLOG("Queue is empty. Cancel any alarm.");
    110             cancelRegisteredAlarmTime_l();
    111         } else {
    112             // Always update the registered alarm in this case (unlike remove()).
    113             updateRegisteredAlarmTime_l(mPq.top()->timestampSec);
    114         }
    115     }
    116     return oldAlarms;
    117 }
    118 
    119 void AlarmMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) {
    120     VLOG("Updating reg alarm time to %u", timestampSec);
    121     mRegisteredAlarmTimeSec = timestampSec;
    122     mUpdateAlarm(mStatsCompanionService, secToMs(mRegisteredAlarmTimeSec));
    123 }
    124 
    125 void AlarmMonitor::cancelRegisteredAlarmTime_l() {
    126     VLOG("Cancelling reg alarm.");
    127     mRegisteredAlarmTimeSec = 0;
    128     mCancelAlarm(mStatsCompanionService);
    129 }
    130 
    131 int64_t AlarmMonitor::secToMs(uint32_t timeSec) {
    132     return ((int64_t)timeSec) * 1000;
    133 }
    134 
    135 }  // namespace statsd
    136 }  // namespace os
    137 }  // namespace android
    138