blob: 4190769077ab1eeefedca42fcc8cdabf4bb96ba7 [file] [log] [blame]
Hridya Valsarajud3e3d722017-12-11 17:31:00 -08001/*
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
Yifan Hong50c9e252019-10-03 16:26:13 -070017#define LOG_TAG "HealthLoop"
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080018#define KLOG_LEVEL 6
19
Yifan Hong50c9e252019-10-03 16:26:13 -070020#include <health/HealthLoop.h>
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080021
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080022#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>
Yifan Hong50c9e252019-10-03 16:26:13 -070030
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>
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080036#include <utils/Errors.h>
37
Yifan Hong50c9e252019-10-03 16:26:13 -070038#include <health/utils.h>
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080039
40using namespace android;
Yifan Hong50c9e252019-10-03 16:26:13 -070041using namespace std::chrono_literals;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080042
Yifan Hong50c9e252019-10-03 16:26:13 -070043namespace android {
44namespace hardware {
45namespace health {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080046
Yifan Hong50c9e252019-10-03 16:26:13 -070047HealthLoop::HealthLoop() {
48 InitHealthdConfig(&healthd_config_);
49 awake_poll_interval_ = -1;
50 wakealarm_wake_interval_ = healthd_config_.periodic_chores_interval_fast;
51}
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080052
Yifan Hong50c9e252019-10-03 16:26:13 -070053HealthLoop::~HealthLoop() {
54 LOG(FATAL) << "HealthLoop cannot be destroyed";
55}
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080056
Yifan Hong50c9e252019-10-03 16:26:13 -070057int HealthLoop::RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) {
58 CHECK(!reject_event_register_);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080059
Yifan Hong50c9e252019-10-03 16:26:13 -070060 auto* event_handler =
61 event_handlers_
62 .emplace_back(std::make_unique<EventHandler>(EventHandler{this, fd, func}))
63 .get();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080064
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080065 struct epoll_event ev;
66
67 ev.events = EPOLLIN;
68
69 if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
70
Yifan Hong50c9e252019-10-03 16:26:13 -070071 ev.data.ptr = reinterpret_cast<void*>(event_handler);
72
73 if (epoll_ctl(epollfd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080074 KLOG_ERROR(LOG_TAG, "epoll_ctl failed; errno=%d\n", errno);
75 return -1;
76 }
77
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080078 return 0;
79}
80
Yifan Hong50c9e252019-10-03 16:26:13 -070081void HealthLoop::WakeAlarmSetInterval(int interval) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080082 struct itimerspec itval;
83
Yifan Hong50c9e252019-10-03 16:26:13 -070084 if (wakealarm_fd_ == -1) return;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080085
Yifan Hong50c9e252019-10-03 16:26:13 -070086 wakealarm_wake_interval_ = interval;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080087
88 if (interval == -1) interval = 0;
89
90 itval.it_interval.tv_sec = interval;
91 itval.it_interval.tv_nsec = 0;
92 itval.it_value.tv_sec = interval;
93 itval.it_value.tv_nsec = 0;
94
Yifan Hong50c9e252019-10-03 16:26:13 -070095 if (timerfd_settime(wakealarm_fd_, 0, &itval, NULL) == -1)
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080096 KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
97}
98
Yifan Hong50c9e252019-10-03 16:26:13 -070099void HealthLoop::AdjustWakealarmPeriods(bool charger_online) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800100 // Fast wake interval when on charger (watch for overheat);
101 // slow wake interval when on battery (watch for drained battery).
102
Yifan Hong50c9e252019-10-03 16:26:13 -0700103 int new_wake_interval = charger_online ? healthd_config_.periodic_chores_interval_fast
104 : healthd_config_.periodic_chores_interval_slow;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800105
Yifan Hong50c9e252019-10-03 16:26:13 -0700106 if (new_wake_interval != wakealarm_wake_interval_) WakeAlarmSetInterval(new_wake_interval);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800107
108 // During awake periods poll at fast rate. If wake alarm is set at fast
109 // rate then just use the alarm; if wake alarm is set at slow rate then
110 // poll at fast rate while awake and let alarm wake up at slow rate when
111 // asleep.
112
Yifan Hong50c9e252019-10-03 16:26:13 -0700113 if (healthd_config_.periodic_chores_interval_fast == -1)
114 awake_poll_interval_ = -1;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800115 else
Yifan Hong50c9e252019-10-03 16:26:13 -0700116 awake_poll_interval_ = new_wake_interval == healthd_config_.periodic_chores_interval_fast
117 ? -1
118 : healthd_config_.periodic_chores_interval_fast * 1000;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800119}
120
Yifan Hong50c9e252019-10-03 16:26:13 -0700121void HealthLoop::PeriodicChores() {
122 ScheduleBatteryUpdate();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800123}
124
Yifan Hong50c9e252019-10-03 16:26:13 -0700125// TODO(b/140330870): Use BPF instead.
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800126#define UEVENT_MSG_LEN 2048
Yifan Hong50c9e252019-10-03 16:26:13 -0700127void HealthLoop::UeventEvent(uint32_t /*epevents*/) {
128 // No need to lock because uevent_fd_ is guaranteed to be initialized.
129
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800130 char msg[UEVENT_MSG_LEN + 2];
131 char* cp;
132 int n;
133
Yifan Hong50c9e252019-10-03 16:26:13 -0700134 n = uevent_kernel_multicast_recv(uevent_fd_, msg, UEVENT_MSG_LEN);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800135 if (n <= 0) return;
136 if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
137 return;
138
139 msg[n] = '\0';
140 msg[n + 1] = '\0';
141 cp = msg;
142
143 while (*cp) {
Bart Van Asscheac9f9cb2021-10-19 11:55:53 -0700144 if (!strcmp(cp, "SUBSYSTEM=power_supply")) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700145 ScheduleBatteryUpdate();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800146 break;
147 }
148
149 /* advance to after the next \0 */
150 while (*cp++)
151 ;
152 }
153}
154
Yifan Hong50c9e252019-10-03 16:26:13 -0700155void HealthLoop::UeventInit(void) {
156 uevent_fd_.reset(uevent_open_socket(64 * 1024, true));
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800157
Yifan Hong50c9e252019-10-03 16:26:13 -0700158 if (uevent_fd_ < 0) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800159 KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
160 return;
161 }
162
Yifan Hong50c9e252019-10-03 16:26:13 -0700163 fcntl(uevent_fd_, F_SETFL, O_NONBLOCK);
164 if (RegisterEvent(uevent_fd_, &HealthLoop::UeventEvent, EVENT_WAKEUP_FD))
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800165 KLOG_ERROR(LOG_TAG, "register for uevent events failed\n");
166}
167
Yifan Hong50c9e252019-10-03 16:26:13 -0700168void HealthLoop::WakeAlarmEvent(uint32_t /*epevents*/) {
169 // No need to lock because wakealarm_fd_ is guaranteed to be initialized.
170
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800171 unsigned long long wakeups;
172
Yifan Hong50c9e252019-10-03 16:26:13 -0700173 if (read(wakealarm_fd_, &wakeups, sizeof(wakeups)) == -1) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800174 KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
175 return;
176 }
177
Yifan Hong50c9e252019-10-03 16:26:13 -0700178 PeriodicChores();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800179}
180
Yifan Hong50c9e252019-10-03 16:26:13 -0700181void HealthLoop::WakeAlarmInit(void) {
182 wakealarm_fd_.reset(timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK));
183 if (wakealarm_fd_ == -1) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800184 KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
185 return;
186 }
187
Yifan Hong50c9e252019-10-03 16:26:13 -0700188 if (RegisterEvent(wakealarm_fd_, &HealthLoop::WakeAlarmEvent, EVENT_WAKEUP_FD))
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800189 KLOG_ERROR(LOG_TAG, "Registration of wakealarm event failed\n");
190
Yifan Hong50c9e252019-10-03 16:26:13 -0700191 WakeAlarmSetInterval(healthd_config_.periodic_chores_interval_fast);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800192}
193
Yifan Hong50c9e252019-10-03 16:26:13 -0700194void HealthLoop::MainLoop(void) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800195 int nevents = 0;
196 while (1) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700197 reject_event_register_ = true;
198 size_t eventct = event_handlers_.size();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800199 struct epoll_event events[eventct];
Yifan Hong50c9e252019-10-03 16:26:13 -0700200 int timeout = awake_poll_interval_;
201
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800202 int mode_timeout;
203
204 /* Don't wait for first timer timeout to run periodic chores */
Yifan Hong50c9e252019-10-03 16:26:13 -0700205 if (!nevents) PeriodicChores();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800206
Yifan Hong50c9e252019-10-03 16:26:13 -0700207 Heartbeat();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800208
Yifan Hong50c9e252019-10-03 16:26:13 -0700209 mode_timeout = PrepareToWait();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800210 if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) timeout = mode_timeout;
Yifan Hong50c9e252019-10-03 16:26:13 -0700211 nevents = epoll_wait(epollfd_, events, eventct, timeout);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800212 if (nevents == -1) {
213 if (errno == EINTR) continue;
214 KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
215 break;
216 }
217
218 for (int n = 0; n < nevents; ++n) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700219 if (events[n].data.ptr) {
220 auto* event_handler = reinterpret_cast<EventHandler*>(events[n].data.ptr);
221 event_handler->func(event_handler->object, events[n].events);
222 }
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800223 }
224 }
225
226 return;
227}
228
Yifan Hong50c9e252019-10-03 16:26:13 -0700229int HealthLoop::InitInternal() {
230 epollfd_.reset(epoll_create1(EPOLL_CLOEXEC));
231 if (epollfd_ == -1) {
Nick Kralevich8c038f22018-12-15 11:36:47 -0800232 KLOG_ERROR(LOG_TAG, "epoll_create1 failed; errno=%d\n", errno);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800233 return -1;
234 }
235
Yifan Hong50c9e252019-10-03 16:26:13 -0700236 // Call subclass's init for any additional init steps.
237 // Note that healthd_config_ is initialized before wakealarm_fd_; see
238 // AdjustUeventWakealarmPeriods().
239 Init(&healthd_config_);
240
241 WakeAlarmInit();
242 UeventInit();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800243
244 return 0;
245}
246
Yifan Hong50c9e252019-10-03 16:26:13 -0700247int HealthLoop::StartLoop() {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800248 int ret;
249
250 klog_set_level(KLOG_LEVEL);
251
Yifan Hong50c9e252019-10-03 16:26:13 -0700252 ret = InitInternal();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800253 if (ret) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700254 KLOG_ERROR(LOG_TAG, "Initialization failed, exiting\n");
255 return 2;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800256 }
257
Yifan Hong50c9e252019-10-03 16:26:13 -0700258 MainLoop();
259 KLOG_ERROR(LOG_TAG, "Main loop terminated, exiting\n");
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800260 return 3;
261}
Yifan Hong50c9e252019-10-03 16:26:13 -0700262
263} // namespace health
264} // namespace hardware
265} // namespace android