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