blob: d43c2d51ce37a919ba41e2e517b4d1c12dcba3e6 [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
Bart Van Assche5c604b92024-07-29 14:22:31 -070033#include <BpfSyscallWrappers.h>
Yifan Hong50c9e252019-10-03 16:26:13 -070034#include <health/utils.h>
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080035
Bart Van Assche5c604b92024-07-29 14:22:31 -070036using android::base::ErrnoError;
37using android::base::Result;
38using android::base::unique_fd;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080039using namespace android;
Yifan Hong50c9e252019-10-03 16:26:13 -070040using namespace std::chrono_literals;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080041
Yifan Hong50c9e252019-10-03 16:26:13 -070042namespace android {
43namespace hardware {
44namespace health {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080045
Yifan Hong50c9e252019-10-03 16:26:13 -070046HealthLoop::HealthLoop() {
47 InitHealthdConfig(&healthd_config_);
48 awake_poll_interval_ = -1;
49 wakealarm_wake_interval_ = healthd_config_.periodic_chores_interval_fast;
50}
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080051
Yifan Hong50c9e252019-10-03 16:26:13 -070052HealthLoop::~HealthLoop() {
53 LOG(FATAL) << "HealthLoop cannot be destroyed";
54}
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080055
Yifan Hong50c9e252019-10-03 16:26:13 -070056int HealthLoop::RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) {
57 CHECK(!reject_event_register_);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080058
Bart Van Assche6fe36182024-08-05 15:43:27 -070059 auto* event_handler = event_handlers_
60 .emplace_back(std::make_unique<EventHandler>(
61 EventHandler{this, fd, std::move(func)}))
62 .get();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080063
Bart Van Assche185589b2024-08-27 10:32:47 +000064 struct epoll_event ev;
65
66 ev.events = EPOLLIN;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080067
68 if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
69
Bart Van Assche185589b2024-08-27 10:32:47 +000070 ev.data.ptr = reinterpret_cast<void*>(event_handler);
71
Yifan Hong50c9e252019-10-03 16:26:13 -070072 if (epoll_ctl(epollfd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080073 KLOG_ERROR(LOG_TAG, "epoll_ctl failed; errno=%d\n", errno);
74 return -1;
75 }
76
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080077 return 0;
78}
79
Yifan Hong50c9e252019-10-03 16:26:13 -070080void HealthLoop::WakeAlarmSetInterval(int interval) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080081 struct itimerspec itval;
82
Yifan Hong50c9e252019-10-03 16:26:13 -070083 if (wakealarm_fd_ == -1) return;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080084
Yifan Hong50c9e252019-10-03 16:26:13 -070085 wakealarm_wake_interval_ = interval;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080086
87 if (interval == -1) interval = 0;
88
89 itval.it_interval.tv_sec = interval;
90 itval.it_interval.tv_nsec = 0;
91 itval.it_value.tv_sec = interval;
92 itval.it_value.tv_nsec = 0;
93
Yifan Hong50c9e252019-10-03 16:26:13 -070094 if (timerfd_settime(wakealarm_fd_, 0, &itval, NULL) == -1)
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080095 KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
96}
97
Yifan Hong50c9e252019-10-03 16:26:13 -070098void HealthLoop::AdjustWakealarmPeriods(bool charger_online) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080099 // Fast wake interval when on charger (watch for overheat);
100 // slow wake interval when on battery (watch for drained battery).
101
Yifan Hong50c9e252019-10-03 16:26:13 -0700102 int new_wake_interval = charger_online ? healthd_config_.periodic_chores_interval_fast
103 : healthd_config_.periodic_chores_interval_slow;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800104
Yifan Hong50c9e252019-10-03 16:26:13 -0700105 if (new_wake_interval != wakealarm_wake_interval_) WakeAlarmSetInterval(new_wake_interval);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800106
107 // During awake periods poll at fast rate. If wake alarm is set at fast
108 // rate then just use the alarm; if wake alarm is set at slow rate then
109 // poll at fast rate while awake and let alarm wake up at slow rate when
110 // asleep.
111
Yifan Hong50c9e252019-10-03 16:26:13 -0700112 if (healthd_config_.periodic_chores_interval_fast == -1)
113 awake_poll_interval_ = -1;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800114 else
Yifan Hong50c9e252019-10-03 16:26:13 -0700115 awake_poll_interval_ = new_wake_interval == healthd_config_.periodic_chores_interval_fast
116 ? -1
117 : healthd_config_.periodic_chores_interval_fast * 1000;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800118}
119
Yifan Hong50c9e252019-10-03 16:26:13 -0700120void HealthLoop::PeriodicChores() {
121 ScheduleBatteryUpdate();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800122}
123
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800124#define UEVENT_MSG_LEN 2048
Bart Van Assche185589b2024-08-27 10:32:47 +0000125void HealthLoop::UeventEvent(uint32_t /*epevents*/) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700126 // No need to lock because uevent_fd_ is guaranteed to be initialized.
127
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800128 char msg[UEVENT_MSG_LEN + 2];
129 char* cp;
130 int n;
131
Yifan Hong50c9e252019-10-03 16:26:13 -0700132 n = uevent_kernel_multicast_recv(uevent_fd_, msg, UEVENT_MSG_LEN);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800133 if (n <= 0) return;
134 if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
135 return;
136
137 msg[n] = '\0';
138 msg[n + 1] = '\0';
139 cp = msg;
140
141 while (*cp) {
Bart Van Asscheac9f9cb2021-10-19 11:55:53 -0700142 if (!strcmp(cp, "SUBSYSTEM=power_supply")) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700143 ScheduleBatteryUpdate();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800144 break;
145 }
146
147 /* advance to after the next \0 */
148 while (*cp++)
149 ;
150 }
151}
152
Bart Van Assche5c604b92024-07-29 14:22:31 -0700153// Attach a BPF filter to the @uevent_fd file descriptor. This fails in recovery mode because BPF is
154// not supported in recovery mode. This fails for kernel versions 5.4 and before because the BPF
155// program is rejected by the BPF verifier of older kernels.
156Result<void> HealthLoop::AttachFilter(int uevent_fd) {
157 static const char prg[] =
158 "/sys/fs/bpf/vendor/prog_filterPowerSupplyEvents_skfilter_power_supply";
159 int filter_fd(bpf::retrieveProgram(prg));
160 if (filter_fd < 0) {
161 return ErrnoError() << "failed to load BPF program " << prg;
162 }
163 if (setsockopt(uevent_fd, SOL_SOCKET, SO_ATTACH_BPF, &filter_fd, sizeof(filter_fd)) < 0) {
164 close(filter_fd);
165 return ErrnoError() << "failed to attach BPF program";
166 }
167 close(filter_fd);
168 return {};
169}
170
Yifan Hong50c9e252019-10-03 16:26:13 -0700171void HealthLoop::UeventInit(void) {
Bart Van Assche5c604b92024-07-29 14:22:31 -0700172 uevent_fd_.reset(uevent_create_socket(64 * 1024, true));
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800173
Yifan Hong50c9e252019-10-03 16:26:13 -0700174 if (uevent_fd_ < 0) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800175 KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
176 return;
177 }
178
Yifan Hong50c9e252019-10-03 16:26:13 -0700179 fcntl(uevent_fd_, F_SETFL, O_NONBLOCK);
Bart Van Assche5c604b92024-07-29 14:22:31 -0700180
181 Result<void> attach_result = AttachFilter(uevent_fd_);
182 if (!attach_result.ok()) {
183 std::string error_msg = attach_result.error().message();
184 error_msg +=
185 ". This is expected in recovery mode and also for kernel versions before 5.10.";
186 KLOG_WARNING(LOG_TAG, "%s", error_msg.c_str());
187 } else {
188 KLOG_INFO(LOG_TAG, "Successfully attached the BPF filter to the uevent socket");
189 }
190
Yifan Hong50c9e252019-10-03 16:26:13 -0700191 if (RegisterEvent(uevent_fd_, &HealthLoop::UeventEvent, EVENT_WAKEUP_FD))
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800192 KLOG_ERROR(LOG_TAG, "register for uevent events failed\n");
Bart Van Assche5c604b92024-07-29 14:22:31 -0700193
194 if (uevent_bind(uevent_fd_.get()) < 0) {
195 uevent_fd_.reset();
196 KLOG_ERROR(LOG_TAG, "uevent_init: binding socket failed\n");
197 return;
198 }
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800199}
200
Yifan Hong50c9e252019-10-03 16:26:13 -0700201void HealthLoop::WakeAlarmEvent(uint32_t /*epevents*/) {
202 // No need to lock because wakealarm_fd_ is guaranteed to be initialized.
203
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800204 unsigned long long wakeups;
205
Yifan Hong50c9e252019-10-03 16:26:13 -0700206 if (read(wakealarm_fd_, &wakeups, sizeof(wakeups)) == -1) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800207 KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
208 return;
209 }
210
Yifan Hong50c9e252019-10-03 16:26:13 -0700211 PeriodicChores();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800212}
213
Yifan Hong50c9e252019-10-03 16:26:13 -0700214void HealthLoop::WakeAlarmInit(void) {
215 wakealarm_fd_.reset(timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK));
216 if (wakealarm_fd_ == -1) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800217 KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
218 return;
219 }
220
Yifan Hong50c9e252019-10-03 16:26:13 -0700221 if (RegisterEvent(wakealarm_fd_, &HealthLoop::WakeAlarmEvent, EVENT_WAKEUP_FD))
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800222 KLOG_ERROR(LOG_TAG, "Registration of wakealarm event failed\n");
223
Yifan Hong50c9e252019-10-03 16:26:13 -0700224 WakeAlarmSetInterval(healthd_config_.periodic_chores_interval_fast);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800225}
226
Yifan Hong50c9e252019-10-03 16:26:13 -0700227void HealthLoop::MainLoop(void) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800228 int nevents = 0;
229 while (1) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700230 reject_event_register_ = true;
231 size_t eventct = event_handlers_.size();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800232 struct epoll_event events[eventct];
Yifan Hong50c9e252019-10-03 16:26:13 -0700233 int timeout = awake_poll_interval_;
234
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800235 int mode_timeout;
236
237 /* Don't wait for first timer timeout to run periodic chores */
Yifan Hong50c9e252019-10-03 16:26:13 -0700238 if (!nevents) PeriodicChores();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800239
Yifan Hong50c9e252019-10-03 16:26:13 -0700240 Heartbeat();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800241
Yifan Hong50c9e252019-10-03 16:26:13 -0700242 mode_timeout = PrepareToWait();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800243 if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) timeout = mode_timeout;
Yifan Hong50c9e252019-10-03 16:26:13 -0700244 nevents = epoll_wait(epollfd_, events, eventct, timeout);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800245 if (nevents == -1) {
246 if (errno == EINTR) continue;
247 KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
248 break;
249 }
250
251 for (int n = 0; n < nevents; ++n) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700252 if (events[n].data.ptr) {
253 auto* event_handler = reinterpret_cast<EventHandler*>(events[n].data.ptr);
254 event_handler->func(event_handler->object, events[n].events);
255 }
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800256 }
257 }
258
259 return;
260}
261
Yifan Hong50c9e252019-10-03 16:26:13 -0700262int HealthLoop::InitInternal() {
263 epollfd_.reset(epoll_create1(EPOLL_CLOEXEC));
264 if (epollfd_ == -1) {
Nick Kralevich8c038f22018-12-15 11:36:47 -0800265 KLOG_ERROR(LOG_TAG, "epoll_create1 failed; errno=%d\n", errno);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800266 return -1;
267 }
268
Yifan Hong50c9e252019-10-03 16:26:13 -0700269 // Call subclass's init for any additional init steps.
270 // Note that healthd_config_ is initialized before wakealarm_fd_; see
271 // AdjustUeventWakealarmPeriods().
272 Init(&healthd_config_);
273
274 WakeAlarmInit();
275 UeventInit();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800276
277 return 0;
278}
279
Yifan Hong50c9e252019-10-03 16:26:13 -0700280int HealthLoop::StartLoop() {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800281 int ret;
282
283 klog_set_level(KLOG_LEVEL);
284
Yifan Hong50c9e252019-10-03 16:26:13 -0700285 ret = InitInternal();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800286 if (ret) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700287 KLOG_ERROR(LOG_TAG, "Initialization failed, exiting\n");
288 return 2;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800289 }
290
Yifan Hong50c9e252019-10-03 16:26:13 -0700291 MainLoop();
292 KLOG_ERROR(LOG_TAG, "Main loop terminated, exiting\n");
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800293 return 3;
294}
Yifan Hong50c9e252019-10-03 16:26:13 -0700295
296} // namespace health
297} // namespace hardware
298} // namespace android