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