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