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 
AlarmMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec,const std::function<void (const sp<IStatsCompanionService> &,int64_t)> & updateAlarm,const std::function<void (const sp<IStatsCompanionService> &)> & cancelAlarm)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 
~AlarmMonitor()35 AlarmMonitor::~AlarmMonitor() {}
36 
setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService)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 
add(sp<const InternalAlarm> alarm)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(b/110563466): 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 
remove(sp<const InternalAlarm> alarm)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.
popSoonerThan(uint32_t timestampSec)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 
updateRegisteredAlarmTime_l(uint32_t timestampSec)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 
cancelRegisteredAlarmTime_l()125 void AlarmMonitor::cancelRegisteredAlarmTime_l() {
126     VLOG("Cancelling reg alarm.");
127     mRegisteredAlarmTimeSec = 0;
128     mCancelAlarm(mStatsCompanionService);
129 }
130 
secToMs(uint32_t timeSec)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