blob: cf4b4cf978d85cc4f6972064666bbdc1fa3daca7 [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>
Bart Van Assche70878582024-08-04 07:14:29 -070023#include <sys/epoll.h> // epoll_create1(), epoll_ctl(), epoll_wait()
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080024#include <sys/timerfd.h>
Bart Van Assche70878582024-08-04 07:14:29 -070025#include <unistd.h> // read()
Yifan Hong50c9e252019-10-03 16:26:13 -070026
27#include <android-base/logging.h>
28#include <batteryservice/BatteryService.h>
Bart Van Assche70878582024-08-04 07:14:29 -070029#include <cutils/klog.h> // KLOG_*()
Yifan Hong50c9e252019-10-03 16:26:13 -070030#include <cutils/uevent.h>
31#include <healthd/healthd.h>
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080032
Yifan Hong50c9e252019-10-03 16:26:13 -070033#include <health/utils.h>
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080034
35using namespace android;
Yifan Hong50c9e252019-10-03 16:26:13 -070036using namespace std::chrono_literals;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080037
Yifan Hong50c9e252019-10-03 16:26:13 -070038namespace android {
39namespace hardware {
40namespace health {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080041
Yifan Hong50c9e252019-10-03 16:26:13 -070042HealthLoop::HealthLoop() {
43 InitHealthdConfig(&healthd_config_);
44 awake_poll_interval_ = -1;
45 wakealarm_wake_interval_ = healthd_config_.periodic_chores_interval_fast;
46}
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080047
Yifan Hong50c9e252019-10-03 16:26:13 -070048HealthLoop::~HealthLoop() {
49 LOG(FATAL) << "HealthLoop cannot be destroyed";
50}
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080051
Yifan Hong50c9e252019-10-03 16:26:13 -070052int HealthLoop::RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) {
53 CHECK(!reject_event_register_);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080054
Yifan Hong50c9e252019-10-03 16:26:13 -070055 auto* event_handler =
56 event_handlers_
57 .emplace_back(std::make_unique<EventHandler>(EventHandler{this, fd, func}))
58 .get();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080059
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080060 struct epoll_event ev;
61
62 ev.events = EPOLLIN;
63
64 if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
65
Yifan Hong50c9e252019-10-03 16:26:13 -070066 ev.data.ptr = reinterpret_cast<void*>(event_handler);
67
68 if (epoll_ctl(epollfd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080069 KLOG_ERROR(LOG_TAG, "epoll_ctl failed; errno=%d\n", errno);
70 return -1;
71 }
72
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080073 return 0;
74}
75
Yifan Hong50c9e252019-10-03 16:26:13 -070076void HealthLoop::WakeAlarmSetInterval(int interval) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080077 struct itimerspec itval;
78
Yifan Hong50c9e252019-10-03 16:26:13 -070079 if (wakealarm_fd_ == -1) return;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080080
Yifan Hong50c9e252019-10-03 16:26:13 -070081 wakealarm_wake_interval_ = interval;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080082
83 if (interval == -1) interval = 0;
84
85 itval.it_interval.tv_sec = interval;
86 itval.it_interval.tv_nsec = 0;
87 itval.it_value.tv_sec = interval;
88 itval.it_value.tv_nsec = 0;
89
Yifan Hong50c9e252019-10-03 16:26:13 -070090 if (timerfd_settime(wakealarm_fd_, 0, &itval, NULL) == -1)
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080091 KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
92}
93
Yifan Hong50c9e252019-10-03 16:26:13 -070094void HealthLoop::AdjustWakealarmPeriods(bool charger_online) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080095 // Fast wake interval when on charger (watch for overheat);
96 // slow wake interval when on battery (watch for drained battery).
97
Yifan Hong50c9e252019-10-03 16:26:13 -070098 int new_wake_interval = charger_online ? healthd_config_.periodic_chores_interval_fast
99 : healthd_config_.periodic_chores_interval_slow;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800100
Yifan Hong50c9e252019-10-03 16:26:13 -0700101 if (new_wake_interval != wakealarm_wake_interval_) WakeAlarmSetInterval(new_wake_interval);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800102
103 // During awake periods poll at fast rate. If wake alarm is set at fast
104 // rate then just use the alarm; if wake alarm is set at slow rate then
105 // poll at fast rate while awake and let alarm wake up at slow rate when
106 // asleep.
107
Yifan Hong50c9e252019-10-03 16:26:13 -0700108 if (healthd_config_.periodic_chores_interval_fast == -1)
109 awake_poll_interval_ = -1;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800110 else
Yifan Hong50c9e252019-10-03 16:26:13 -0700111 awake_poll_interval_ = new_wake_interval == healthd_config_.periodic_chores_interval_fast
112 ? -1
113 : healthd_config_.periodic_chores_interval_fast * 1000;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800114}
115
Yifan Hong50c9e252019-10-03 16:26:13 -0700116void HealthLoop::PeriodicChores() {
117 ScheduleBatteryUpdate();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800118}
119
Yifan Hong50c9e252019-10-03 16:26:13 -0700120// TODO(b/140330870): Use BPF instead.
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800121#define UEVENT_MSG_LEN 2048
Yifan Hong50c9e252019-10-03 16:26:13 -0700122void HealthLoop::UeventEvent(uint32_t /*epevents*/) {
123 // No need to lock because uevent_fd_ is guaranteed to be initialized.
124
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800125 char msg[UEVENT_MSG_LEN + 2];
126 char* cp;
127 int n;
128
Yifan Hong50c9e252019-10-03 16:26:13 -0700129 n = uevent_kernel_multicast_recv(uevent_fd_, msg, UEVENT_MSG_LEN);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800130 if (n <= 0) return;
131 if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
132 return;
133
134 msg[n] = '\0';
135 msg[n + 1] = '\0';
136 cp = msg;
137
138 while (*cp) {
Bart Van Asscheac9f9cb2021-10-19 11:55:53 -0700139 if (!strcmp(cp, "SUBSYSTEM=power_supply")) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700140 ScheduleBatteryUpdate();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800141 break;
142 }
143
144 /* advance to after the next \0 */
145 while (*cp++)
146 ;
147 }
148}
149
Yifan Hong50c9e252019-10-03 16:26:13 -0700150void HealthLoop::UeventInit(void) {
151 uevent_fd_.reset(uevent_open_socket(64 * 1024, true));
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800152
Yifan Hong50c9e252019-10-03 16:26:13 -0700153 if (uevent_fd_ < 0) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800154 KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
155 return;
156 }
157
Yifan Hong50c9e252019-10-03 16:26:13 -0700158 fcntl(uevent_fd_, F_SETFL, O_NONBLOCK);
159 if (RegisterEvent(uevent_fd_, &HealthLoop::UeventEvent, EVENT_WAKEUP_FD))
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800160 KLOG_ERROR(LOG_TAG, "register for uevent events failed\n");
161}
162
Yifan Hong50c9e252019-10-03 16:26:13 -0700163void HealthLoop::WakeAlarmEvent(uint32_t /*epevents*/) {
164 // No need to lock because wakealarm_fd_ is guaranteed to be initialized.
165
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800166 unsigned long long wakeups;
167
Yifan Hong50c9e252019-10-03 16:26:13 -0700168 if (read(wakealarm_fd_, &wakeups, sizeof(wakeups)) == -1) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800169 KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
170 return;
171 }
172
Yifan Hong50c9e252019-10-03 16:26:13 -0700173 PeriodicChores();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800174}
175
Yifan Hong50c9e252019-10-03 16:26:13 -0700176void HealthLoop::WakeAlarmInit(void) {
177 wakealarm_fd_.reset(timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK));
178 if (wakealarm_fd_ == -1) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800179 KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
180 return;
181 }
182
Yifan Hong50c9e252019-10-03 16:26:13 -0700183 if (RegisterEvent(wakealarm_fd_, &HealthLoop::WakeAlarmEvent, EVENT_WAKEUP_FD))
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800184 KLOG_ERROR(LOG_TAG, "Registration of wakealarm event failed\n");
185
Yifan Hong50c9e252019-10-03 16:26:13 -0700186 WakeAlarmSetInterval(healthd_config_.periodic_chores_interval_fast);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800187}
188
Yifan Hong50c9e252019-10-03 16:26:13 -0700189void HealthLoop::MainLoop(void) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800190 int nevents = 0;
191 while (1) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700192 reject_event_register_ = true;
193 size_t eventct = event_handlers_.size();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800194 struct epoll_event events[eventct];
Yifan Hong50c9e252019-10-03 16:26:13 -0700195 int timeout = awake_poll_interval_;
196
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800197 int mode_timeout;
198
199 /* Don't wait for first timer timeout to run periodic chores */
Yifan Hong50c9e252019-10-03 16:26:13 -0700200 if (!nevents) PeriodicChores();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800201
Yifan Hong50c9e252019-10-03 16:26:13 -0700202 Heartbeat();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800203
Yifan Hong50c9e252019-10-03 16:26:13 -0700204 mode_timeout = PrepareToWait();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800205 if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) timeout = mode_timeout;
Yifan Hong50c9e252019-10-03 16:26:13 -0700206 nevents = epoll_wait(epollfd_, events, eventct, timeout);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800207 if (nevents == -1) {
208 if (errno == EINTR) continue;
209 KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
210 break;
211 }
212
213 for (int n = 0; n < nevents; ++n) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700214 if (events[n].data.ptr) {
215 auto* event_handler = reinterpret_cast<EventHandler*>(events[n].data.ptr);
216 event_handler->func(event_handler->object, events[n].events);
217 }
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800218 }
219 }
220
221 return;
222}
223
Yifan Hong50c9e252019-10-03 16:26:13 -0700224int HealthLoop::InitInternal() {
225 epollfd_.reset(epoll_create1(EPOLL_CLOEXEC));
226 if (epollfd_ == -1) {
Nick Kralevich8c038f22018-12-15 11:36:47 -0800227 KLOG_ERROR(LOG_TAG, "epoll_create1 failed; errno=%d\n", errno);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800228 return -1;
229 }
230
Yifan Hong50c9e252019-10-03 16:26:13 -0700231 // Call subclass's init for any additional init steps.
232 // Note that healthd_config_ is initialized before wakealarm_fd_; see
233 // AdjustUeventWakealarmPeriods().
234 Init(&healthd_config_);
235
236 WakeAlarmInit();
237 UeventInit();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800238
239 return 0;
240}
241
Yifan Hong50c9e252019-10-03 16:26:13 -0700242int HealthLoop::StartLoop() {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800243 int ret;
244
245 klog_set_level(KLOG_LEVEL);
246
Yifan Hong50c9e252019-10-03 16:26:13 -0700247 ret = InitInternal();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800248 if (ret) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700249 KLOG_ERROR(LOG_TAG, "Initialization failed, exiting\n");
250 return 2;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800251 }
252
Yifan Hong50c9e252019-10-03 16:26:13 -0700253 MainLoop();
254 KLOG_ERROR(LOG_TAG, "Main loop terminated, exiting\n");
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800255 return 3;
256}
Yifan Hong50c9e252019-10-03 16:26:13 -0700257
258} // namespace health
259} // namespace hardware
260} // namespace android