1 /*
2 * Copyright (C) 2013 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 LOG_TAG "HealthLoop"
18 #define KLOG_LEVEL 6
19
20 #include <health/HealthLoop.h>
21
22 #include <errno.h>
23 #include <libgen.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/epoll.h>
28 #include <sys/timerfd.h>
29 #include <unistd.h>
30
31 #include <android-base/logging.h>
32 #include <batteryservice/BatteryService.h>
33 #include <cutils/klog.h>
34 #include <cutils/uevent.h>
35 #include <healthd/healthd.h>
36 #include <utils/Errors.h>
37
38 #include <health/utils.h>
39
40 using namespace android;
41 using namespace std::chrono_literals;
42
43 #define POWER_SUPPLY_SUBSYSTEM "power_supply"
44
45 namespace android {
46 namespace hardware {
47 namespace health {
48
HealthLoop()49 HealthLoop::HealthLoop() {
50 InitHealthdConfig(&healthd_config_);
51 awake_poll_interval_ = -1;
52 wakealarm_wake_interval_ = healthd_config_.periodic_chores_interval_fast;
53 }
54
~HealthLoop()55 HealthLoop::~HealthLoop() {
56 LOG(FATAL) << "HealthLoop cannot be destroyed";
57 }
58
RegisterEvent(int fd,BoundFunction func,EventWakeup wakeup)59 int HealthLoop::RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) {
60 CHECK(!reject_event_register_);
61
62 auto* event_handler =
63 event_handlers_
64 .emplace_back(std::make_unique<EventHandler>(EventHandler{this, fd, func}))
65 .get();
66
67 struct epoll_event ev;
68
69 ev.events = EPOLLIN;
70
71 if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
72
73 ev.data.ptr = reinterpret_cast<void*>(event_handler);
74
75 if (epoll_ctl(epollfd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
76 KLOG_ERROR(LOG_TAG, "epoll_ctl failed; errno=%d\n", errno);
77 return -1;
78 }
79
80 return 0;
81 }
82
WakeAlarmSetInterval(int interval)83 void HealthLoop::WakeAlarmSetInterval(int interval) {
84 struct itimerspec itval;
85
86 if (wakealarm_fd_ == -1) return;
87
88 wakealarm_wake_interval_ = interval;
89
90 if (interval == -1) interval = 0;
91
92 itval.it_interval.tv_sec = interval;
93 itval.it_interval.tv_nsec = 0;
94 itval.it_value.tv_sec = interval;
95 itval.it_value.tv_nsec = 0;
96
97 if (timerfd_settime(wakealarm_fd_, 0, &itval, NULL) == -1)
98 KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
99 }
100
AdjustWakealarmPeriods(bool charger_online)101 void HealthLoop::AdjustWakealarmPeriods(bool charger_online) {
102 // Fast wake interval when on charger (watch for overheat);
103 // slow wake interval when on battery (watch for drained battery).
104
105 int new_wake_interval = charger_online ? healthd_config_.periodic_chores_interval_fast
106 : healthd_config_.periodic_chores_interval_slow;
107
108 if (new_wake_interval != wakealarm_wake_interval_) WakeAlarmSetInterval(new_wake_interval);
109
110 // During awake periods poll at fast rate. If wake alarm is set at fast
111 // rate then just use the alarm; if wake alarm is set at slow rate then
112 // poll at fast rate while awake and let alarm wake up at slow rate when
113 // asleep.
114
115 if (healthd_config_.periodic_chores_interval_fast == -1)
116 awake_poll_interval_ = -1;
117 else
118 awake_poll_interval_ = new_wake_interval == healthd_config_.periodic_chores_interval_fast
119 ? -1
120 : healthd_config_.periodic_chores_interval_fast * 1000;
121 }
122
PeriodicChores()123 void HealthLoop::PeriodicChores() {
124 ScheduleBatteryUpdate();
125 }
126
127 // TODO(b/140330870): Use BPF instead.
128 #define UEVENT_MSG_LEN 2048
UeventEvent(uint32_t)129 void HealthLoop::UeventEvent(uint32_t /*epevents*/) {
130 // No need to lock because uevent_fd_ is guaranteed to be initialized.
131
132 char msg[UEVENT_MSG_LEN + 2];
133 char* cp;
134 int n;
135
136 n = uevent_kernel_multicast_recv(uevent_fd_, msg, UEVENT_MSG_LEN);
137 if (n <= 0) return;
138 if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
139 return;
140
141 msg[n] = '\0';
142 msg[n + 1] = '\0';
143 cp = msg;
144
145 while (*cp) {
146 if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
147 ScheduleBatteryUpdate();
148 break;
149 }
150
151 /* advance to after the next \0 */
152 while (*cp++)
153 ;
154 }
155 }
156
UeventInit(void)157 void HealthLoop::UeventInit(void) {
158 uevent_fd_.reset(uevent_open_socket(64 * 1024, true));
159
160 if (uevent_fd_ < 0) {
161 KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
162 return;
163 }
164
165 fcntl(uevent_fd_, F_SETFL, O_NONBLOCK);
166 if (RegisterEvent(uevent_fd_, &HealthLoop::UeventEvent, EVENT_WAKEUP_FD))
167 KLOG_ERROR(LOG_TAG, "register for uevent events failed\n");
168 }
169
WakeAlarmEvent(uint32_t)170 void HealthLoop::WakeAlarmEvent(uint32_t /*epevents*/) {
171 // No need to lock because wakealarm_fd_ is guaranteed to be initialized.
172
173 unsigned long long wakeups;
174
175 if (read(wakealarm_fd_, &wakeups, sizeof(wakeups)) == -1) {
176 KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
177 return;
178 }
179
180 PeriodicChores();
181 }
182
WakeAlarmInit(void)183 void HealthLoop::WakeAlarmInit(void) {
184 wakealarm_fd_.reset(timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK));
185 if (wakealarm_fd_ == -1) {
186 KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
187 return;
188 }
189
190 if (RegisterEvent(wakealarm_fd_, &HealthLoop::WakeAlarmEvent, EVENT_WAKEUP_FD))
191 KLOG_ERROR(LOG_TAG, "Registration of wakealarm event failed\n");
192
193 WakeAlarmSetInterval(healthd_config_.periodic_chores_interval_fast);
194 }
195
MainLoop(void)196 void HealthLoop::MainLoop(void) {
197 int nevents = 0;
198 while (1) {
199 reject_event_register_ = true;
200 size_t eventct = event_handlers_.size();
201 struct epoll_event events[eventct];
202 int timeout = awake_poll_interval_;
203
204 int mode_timeout;
205
206 /* Don't wait for first timer timeout to run periodic chores */
207 if (!nevents) PeriodicChores();
208
209 Heartbeat();
210
211 mode_timeout = PrepareToWait();
212 if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) timeout = mode_timeout;
213 nevents = epoll_wait(epollfd_, events, eventct, timeout);
214 if (nevents == -1) {
215 if (errno == EINTR) continue;
216 KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
217 break;
218 }
219
220 for (int n = 0; n < nevents; ++n) {
221 if (events[n].data.ptr) {
222 auto* event_handler = reinterpret_cast<EventHandler*>(events[n].data.ptr);
223 event_handler->func(event_handler->object, events[n].events);
224 }
225 }
226 }
227
228 return;
229 }
230
InitInternal()231 int HealthLoop::InitInternal() {
232 epollfd_.reset(epoll_create1(EPOLL_CLOEXEC));
233 if (epollfd_ == -1) {
234 KLOG_ERROR(LOG_TAG, "epoll_create1 failed; errno=%d\n", errno);
235 return -1;
236 }
237
238 // Call subclass's init for any additional init steps.
239 // Note that healthd_config_ is initialized before wakealarm_fd_; see
240 // AdjustUeventWakealarmPeriods().
241 Init(&healthd_config_);
242
243 WakeAlarmInit();
244 UeventInit();
245
246 return 0;
247 }
248
StartLoop()249 int HealthLoop::StartLoop() {
250 int ret;
251
252 klog_set_level(KLOG_LEVEL);
253
254 ret = InitInternal();
255 if (ret) {
256 KLOG_ERROR(LOG_TAG, "Initialization failed, exiting\n");
257 return 2;
258 }
259
260 MainLoop();
261 KLOG_ERROR(LOG_TAG, "Main loop terminated, exiting\n");
262 return 3;
263 }
264
265 } // namespace health
266 } // namespace hardware
267 } // namespace android
268