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 "healthd-common" 18 #define KLOG_LEVEL 6 19 20 #include <healthd/healthd.h> 21 #include <healthd/BatteryMonitor.h> 22 23 #include <errno.h> 24 #include <libgen.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 #include <batteryservice/BatteryService.h> 30 #include <cutils/klog.h> 31 #include <cutils/uevent.h> 32 #include <sys/epoll.h> 33 #include <sys/timerfd.h> 34 #include <utils/Errors.h> 35 36 using namespace android; 37 38 #ifndef BOARD_PERIODIC_CHORES_INTERVAL_FAST 39 // Periodic chores fast interval in seconds 40 #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1) 41 #else 42 #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (BOARD_PERIODIC_CHORES_INTERVAL_FAST) 43 #endif 44 45 #ifndef BOARD_PERIODIC_CHORES_INTERVAL_SLOW 46 // Periodic chores fast interval in seconds 47 #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10) 48 #else 49 #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (BOARD_PERIODIC_CHORES_INTERVAL_SLOW) 50 #endif 51 52 static struct healthd_config healthd_config = { 53 .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST, 54 .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW, 55 .batteryStatusPath = String8(String8::kEmptyString), 56 .batteryHealthPath = String8(String8::kEmptyString), 57 .batteryPresentPath = String8(String8::kEmptyString), 58 .batteryCapacityPath = String8(String8::kEmptyString), 59 .batteryVoltagePath = String8(String8::kEmptyString), 60 .batteryTemperaturePath = String8(String8::kEmptyString), 61 .batteryTechnologyPath = String8(String8::kEmptyString), 62 .batteryCurrentNowPath = String8(String8::kEmptyString), 63 .batteryCurrentAvgPath = String8(String8::kEmptyString), 64 .batteryChargeCounterPath = String8(String8::kEmptyString), 65 .batteryFullChargePath = String8(String8::kEmptyString), 66 .batteryCycleCountPath = String8(String8::kEmptyString), 67 .energyCounter = NULL, 68 .boot_min_cap = 0, 69 .screen_on = NULL, 70 }; 71 72 static int eventct; 73 static int epollfd; 74 75 #define POWER_SUPPLY_SUBSYSTEM "power_supply" 76 77 // epoll_create() parameter is actually unused 78 #define MAX_EPOLL_EVENTS 40 79 static int uevent_fd; 80 static int wakealarm_fd; 81 82 // -1 for no epoll timeout 83 static int awake_poll_interval = -1; 84 85 static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST; 86 87 static BatteryMonitor* gBatteryMonitor; 88 89 struct healthd_mode_ops *healthd_mode_ops; 90 91 int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) { 92 struct epoll_event ev; 93 94 ev.events = EPOLLIN; 95 96 if (wakeup == EVENT_WAKEUP_FD) 97 ev.events |= EPOLLWAKEUP; 98 99 ev.data.ptr = (void *)handler; 100 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) { 101 KLOG_ERROR(LOG_TAG, 102 "epoll_ctl failed; errno=%d\n", errno); 103 return -1; 104 } 105 106 eventct++; 107 return 0; 108 } 109 110 static void wakealarm_set_interval(int interval) { 111 struct itimerspec itval; 112 113 if (wakealarm_fd == -1) 114 return; 115 116 wakealarm_wake_interval = interval; 117 118 if (interval == -1) 119 interval = 0; 120 121 itval.it_interval.tv_sec = interval; 122 itval.it_interval.tv_nsec = 0; 123 itval.it_value.tv_sec = interval; 124 itval.it_value.tv_nsec = 0; 125 126 if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1) 127 KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n"); 128 } 129 130 status_t healthd_get_property(int id, struct BatteryProperty *val) { 131 return gBatteryMonitor->getProperty(id, val); 132 } 133 134 void healthd_battery_update(void) { 135 // Fast wake interval when on charger (watch for overheat); 136 // slow wake interval when on battery (watch for drained battery). 137 138 int new_wake_interval = gBatteryMonitor->update() ? 139 healthd_config.periodic_chores_interval_fast : 140 healthd_config.periodic_chores_interval_slow; 141 142 if (new_wake_interval != wakealarm_wake_interval) 143 wakealarm_set_interval(new_wake_interval); 144 145 // During awake periods poll at fast rate. If wake alarm is set at fast 146 // rate then just use the alarm; if wake alarm is set at slow rate then 147 // poll at fast rate while awake and let alarm wake up at slow rate when 148 // asleep. 149 150 if (healthd_config.periodic_chores_interval_fast == -1) 151 awake_poll_interval = -1; 152 else 153 awake_poll_interval = 154 new_wake_interval == healthd_config.periodic_chores_interval_fast ? 155 -1 : healthd_config.periodic_chores_interval_fast * 1000; 156 } 157 158 void healthd_dump_battery_state(int fd) { 159 gBatteryMonitor->dumpState(fd); 160 fsync(fd); 161 } 162 163 static void periodic_chores() { 164 healthd_battery_update(); 165 } 166 167 #define UEVENT_MSG_LEN 2048 168 static void uevent_event(uint32_t /*epevents*/) { 169 char msg[UEVENT_MSG_LEN+2]; 170 char *cp; 171 int n; 172 173 n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN); 174 if (n <= 0) 175 return; 176 if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ 177 return; 178 179 msg[n] = '\0'; 180 msg[n+1] = '\0'; 181 cp = msg; 182 183 while (*cp) { 184 if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) { 185 healthd_battery_update(); 186 break; 187 } 188 189 /* advance to after the next \0 */ 190 while (*cp++) 191 ; 192 } 193 } 194 195 static void uevent_init(void) { 196 uevent_fd = uevent_open_socket(64*1024, true); 197 198 if (uevent_fd < 0) { 199 KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n"); 200 return; 201 } 202 203 fcntl(uevent_fd, F_SETFL, O_NONBLOCK); 204 if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD)) 205 KLOG_ERROR(LOG_TAG, 206 "register for uevent events failed\n"); 207 } 208 209 static void wakealarm_event(uint32_t /*epevents*/) { 210 unsigned long long wakeups; 211 212 if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) { 213 KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n"); 214 return; 215 } 216 217 periodic_chores(); 218 } 219 220 static void wakealarm_init(void) { 221 wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK); 222 if (wakealarm_fd == -1) { 223 KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n"); 224 return; 225 } 226 227 if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD)) 228 KLOG_ERROR(LOG_TAG, 229 "Registration of wakealarm event failed\n"); 230 231 wakealarm_set_interval(healthd_config.periodic_chores_interval_fast); 232 } 233 234 static void healthd_mainloop(void) { 235 int nevents = 0; 236 while (1) { 237 struct epoll_event events[eventct]; 238 int timeout = awake_poll_interval; 239 int mode_timeout; 240 241 /* Don't wait for first timer timeout to run periodic chores */ 242 if (!nevents) 243 periodic_chores(); 244 245 healthd_mode_ops->heartbeat(); 246 247 mode_timeout = healthd_mode_ops->preparetowait(); 248 if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) 249 timeout = mode_timeout; 250 nevents = epoll_wait(epollfd, events, eventct, timeout); 251 if (nevents == -1) { 252 if (errno == EINTR) 253 continue; 254 KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n"); 255 break; 256 } 257 258 for (int n = 0; n < nevents; ++n) { 259 if (events[n].data.ptr) 260 (*(void (*)(int))events[n].data.ptr)(events[n].events); 261 } 262 } 263 264 return; 265 } 266 267 static int healthd_init() { 268 epollfd = epoll_create(MAX_EPOLL_EVENTS); 269 if (epollfd == -1) { 270 KLOG_ERROR(LOG_TAG, 271 "epoll_create failed; errno=%d\n", 272 errno); 273 return -1; 274 } 275 276 healthd_board_init(&healthd_config); 277 healthd_mode_ops->init(&healthd_config); 278 wakealarm_init(); 279 uevent_init(); 280 gBatteryMonitor = new BatteryMonitor(); 281 gBatteryMonitor->init(&healthd_config); 282 return 0; 283 } 284 285 int healthd_main() { 286 int ret; 287 288 klog_set_level(KLOG_LEVEL); 289 290 if (!healthd_mode_ops) { 291 KLOG_ERROR("healthd ops not set, exiting\n"); 292 exit(1); 293 } 294 295 ret = healthd_init(); 296 if (ret) { 297 KLOG_ERROR("Initialization failed, exiting\n"); 298 exit(2); 299 } 300 301 healthd_mainloop(); 302 KLOG_ERROR("Main loop terminated, exiting\n"); 303 return 3; 304 } 305