blob: 3f4b5bc596323d1a5fd0358d29c88ee20fd6c1de [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
43#define POWER_SUPPLY_SUBSYSTEM "power_supply"
44
Yifan Hong50c9e252019-10-03 16:26:13 -070045namespace android {
46namespace hardware {
47namespace health {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080048
Yifan Hong50c9e252019-10-03 16:26:13 -070049HealthLoop::HealthLoop() {
50 InitHealthdConfig(&healthd_config_);
51 awake_poll_interval_ = -1;
52 wakealarm_wake_interval_ = healthd_config_.periodic_chores_interval_fast;
53}
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080054
Yifan Hong50c9e252019-10-03 16:26:13 -070055HealthLoop::~HealthLoop() {
56 LOG(FATAL) << "HealthLoop cannot be destroyed";
57}
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080058
Yifan Hong50c9e252019-10-03 16:26:13 -070059int HealthLoop::RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) {
60 CHECK(!reject_event_register_);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080061
Yifan Hong50c9e252019-10-03 16:26:13 -070062 auto* event_handler =
63 event_handlers_
64 .emplace_back(std::make_unique<EventHandler>(EventHandler{this, fd, func}))
65 .get();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080066
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080067 struct epoll_event ev;
68
69 ev.events = EPOLLIN;
70
71 if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
72
Yifan Hong50c9e252019-10-03 16:26:13 -070073 ev.data.ptr = reinterpret_cast<void*>(event_handler);
74
75 if (epoll_ctl(epollfd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080076 KLOG_ERROR(LOG_TAG, "epoll_ctl failed; errno=%d\n", errno);
77 return -1;
78 }
79
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080080 return 0;
81}
82
Yifan Hong50c9e252019-10-03 16:26:13 -070083void HealthLoop::WakeAlarmSetInterval(int interval) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080084 struct itimerspec itval;
85
Yifan Hong50c9e252019-10-03 16:26:13 -070086 if (wakealarm_fd_ == -1) return;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080087
Yifan Hong50c9e252019-10-03 16:26:13 -070088 wakealarm_wake_interval_ = interval;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080089
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
Yifan Hong50c9e252019-10-03 16:26:13 -070097 if (timerfd_settime(wakealarm_fd_, 0, &itval, NULL) == -1)
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080098 KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
99}
100
Yifan Hong50c9e252019-10-03 16:26:13 -0700101void HealthLoop::AdjustWakealarmPeriods(bool charger_online) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800102 // Fast wake interval when on charger (watch for overheat);
103 // slow wake interval when on battery (watch for drained battery).
104
Yifan Hong50c9e252019-10-03 16:26:13 -0700105 int new_wake_interval = charger_online ? healthd_config_.periodic_chores_interval_fast
106 : healthd_config_.periodic_chores_interval_slow;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800107
Yifan Hong50c9e252019-10-03 16:26:13 -0700108 if (new_wake_interval != wakealarm_wake_interval_) WakeAlarmSetInterval(new_wake_interval);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800109
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
Yifan Hong50c9e252019-10-03 16:26:13 -0700115 if (healthd_config_.periodic_chores_interval_fast == -1)
116 awake_poll_interval_ = -1;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800117 else
Yifan Hong50c9e252019-10-03 16:26:13 -0700118 awake_poll_interval_ = new_wake_interval == healthd_config_.periodic_chores_interval_fast
119 ? -1
120 : healthd_config_.periodic_chores_interval_fast * 1000;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800121}
122
Yifan Hong50c9e252019-10-03 16:26:13 -0700123void HealthLoop::PeriodicChores() {
124 ScheduleBatteryUpdate();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800125}
126
Yifan Hong50c9e252019-10-03 16:26:13 -0700127// TODO(b/140330870): Use BPF instead.
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800128#define UEVENT_MSG_LEN 2048
Yifan Hong50c9e252019-10-03 16:26:13 -0700129void HealthLoop::UeventEvent(uint32_t /*epevents*/) {
130 // No need to lock because uevent_fd_ is guaranteed to be initialized.
131
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800132 char msg[UEVENT_MSG_LEN + 2];
133 char* cp;
134 int n;
135
Yifan Hong50c9e252019-10-03 16:26:13 -0700136 n = uevent_kernel_multicast_recv(uevent_fd_, msg, UEVENT_MSG_LEN);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800137 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)) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700147 ScheduleBatteryUpdate();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800148 break;
149 }
150
151 /* advance to after the next \0 */
152 while (*cp++)
153 ;
154 }
155}
156
Yifan Hong50c9e252019-10-03 16:26:13 -0700157void HealthLoop::UeventInit(void) {
158 uevent_fd_.reset(uevent_open_socket(64 * 1024, true));
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800159
Yifan Hong50c9e252019-10-03 16:26:13 -0700160 if (uevent_fd_ < 0) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800161 KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
162 return;
163 }
164
Yifan Hong50c9e252019-10-03 16:26:13 -0700165 fcntl(uevent_fd_, F_SETFL, O_NONBLOCK);
166 if (RegisterEvent(uevent_fd_, &HealthLoop::UeventEvent, EVENT_WAKEUP_FD))
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800167 KLOG_ERROR(LOG_TAG, "register for uevent events failed\n");
168}
169
Yifan Hong50c9e252019-10-03 16:26:13 -0700170void HealthLoop::WakeAlarmEvent(uint32_t /*epevents*/) {
171 // No need to lock because wakealarm_fd_ is guaranteed to be initialized.
172
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800173 unsigned long long wakeups;
174
Yifan Hong50c9e252019-10-03 16:26:13 -0700175 if (read(wakealarm_fd_, &wakeups, sizeof(wakeups)) == -1) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800176 KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
177 return;
178 }
179
Yifan Hong50c9e252019-10-03 16:26:13 -0700180 PeriodicChores();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800181}
182
Yifan Hong50c9e252019-10-03 16:26:13 -0700183void HealthLoop::WakeAlarmInit(void) {
184 wakealarm_fd_.reset(timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK));
185 if (wakealarm_fd_ == -1) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800186 KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
187 return;
188 }
189
Yifan Hong50c9e252019-10-03 16:26:13 -0700190 if (RegisterEvent(wakealarm_fd_, &HealthLoop::WakeAlarmEvent, EVENT_WAKEUP_FD))
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800191 KLOG_ERROR(LOG_TAG, "Registration of wakealarm event failed\n");
192
Yifan Hong50c9e252019-10-03 16:26:13 -0700193 WakeAlarmSetInterval(healthd_config_.periodic_chores_interval_fast);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800194}
195
Yifan Hong50c9e252019-10-03 16:26:13 -0700196void HealthLoop::MainLoop(void) {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800197 int nevents = 0;
198 while (1) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700199 reject_event_register_ = true;
200 size_t eventct = event_handlers_.size();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800201 struct epoll_event events[eventct];
Yifan Hong50c9e252019-10-03 16:26:13 -0700202 int timeout = awake_poll_interval_;
203
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800204 int mode_timeout;
205
206 /* Don't wait for first timer timeout to run periodic chores */
Yifan Hong50c9e252019-10-03 16:26:13 -0700207 if (!nevents) PeriodicChores();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800208
Yifan Hong50c9e252019-10-03 16:26:13 -0700209 Heartbeat();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800210
Yifan Hong50c9e252019-10-03 16:26:13 -0700211 mode_timeout = PrepareToWait();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800212 if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) timeout = mode_timeout;
Yifan Hong50c9e252019-10-03 16:26:13 -0700213 nevents = epoll_wait(epollfd_, events, eventct, timeout);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800214 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) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700221 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 }
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800225 }
226 }
227
228 return;
229}
230
Yifan Hong50c9e252019-10-03 16:26:13 -0700231int HealthLoop::InitInternal() {
232 epollfd_.reset(epoll_create1(EPOLL_CLOEXEC));
233 if (epollfd_ == -1) {
Nick Kralevich8c038f22018-12-15 11:36:47 -0800234 KLOG_ERROR(LOG_TAG, "epoll_create1 failed; errno=%d\n", errno);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800235 return -1;
236 }
237
Yifan Hong50c9e252019-10-03 16:26:13 -0700238 // 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();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800245
246 return 0;
247}
248
Yifan Hong50c9e252019-10-03 16:26:13 -0700249int HealthLoop::StartLoop() {
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800250 int ret;
251
252 klog_set_level(KLOG_LEVEL);
253
Yifan Hong50c9e252019-10-03 16:26:13 -0700254 ret = InitInternal();
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800255 if (ret) {
Yifan Hong50c9e252019-10-03 16:26:13 -0700256 KLOG_ERROR(LOG_TAG, "Initialization failed, exiting\n");
257 return 2;
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800258 }
259
Yifan Hong50c9e252019-10-03 16:26:13 -0700260 MainLoop();
261 KLOG_ERROR(LOG_TAG, "Main loop terminated, exiting\n");
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800262 return 3;
263}
Yifan Hong50c9e252019-10-03 16:26:13 -0700264
265} // namespace health
266} // namespace hardware
267} // namespace android