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" 18#define KLOG_LEVEL 6 19 20#include "healthd.h" 21#include "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 36using namespace android; 37 38// Periodic chores intervals in seconds 39#define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1) 40#define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10) 41 42static struct healthd_config healthd_config = { 43 .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST, 44 .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW, 45 .batteryStatusPath = String8(String8::kEmptyString), 46 .batteryHealthPath = String8(String8::kEmptyString), 47 .batteryPresentPath = String8(String8::kEmptyString), 48 .batteryCapacityPath = String8(String8::kEmptyString), 49 .batteryVoltagePath = String8(String8::kEmptyString), 50 .batteryTemperaturePath = String8(String8::kEmptyString), 51 .batteryTechnologyPath = String8(String8::kEmptyString), 52 .batteryCurrentNowPath = String8(String8::kEmptyString), 53 .batteryCurrentAvgPath = String8(String8::kEmptyString), 54 .batteryChargeCounterPath = String8(String8::kEmptyString), 55 .energyCounter = NULL, 56 .boot_min_cap = 0, 57 .screen_on = NULL, 58}; 59 60static int eventct; 61static int epollfd; 62 63#define POWER_SUPPLY_SUBSYSTEM "power_supply" 64 65// epoll_create() parameter is actually unused 66#define MAX_EPOLL_EVENTS 40 67static int uevent_fd; 68static int wakealarm_fd; 69 70// -1 for no epoll timeout 71static int awake_poll_interval = -1; 72 73static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST; 74 75static BatteryMonitor* gBatteryMonitor; 76 77struct healthd_mode_ops *healthd_mode_ops; 78 79// Android mode 80 81extern void healthd_mode_android_init(struct healthd_config *config); 82extern int healthd_mode_android_preparetowait(void); 83extern void healthd_mode_android_battery_update( 84 struct android::BatteryProperties *props); 85 86// Charger mode 87 88extern void healthd_mode_charger_init(struct healthd_config *config); 89extern int healthd_mode_charger_preparetowait(void); 90extern void healthd_mode_charger_heartbeat(void); 91extern void healthd_mode_charger_battery_update( 92 struct android::BatteryProperties *props); 93 94// NOPs for modes that need no special action 95 96static void healthd_mode_nop_init(struct healthd_config *config); 97static int healthd_mode_nop_preparetowait(void); 98static void healthd_mode_nop_heartbeat(void); 99static void healthd_mode_nop_battery_update( 100 struct android::BatteryProperties *props); 101 102static struct healthd_mode_ops android_ops = { 103 .init = healthd_mode_android_init, 104 .preparetowait = healthd_mode_android_preparetowait, 105 .heartbeat = healthd_mode_nop_heartbeat, 106 .battery_update = healthd_mode_android_battery_update, 107}; 108 109static struct healthd_mode_ops charger_ops = { 110 .init = healthd_mode_charger_init, 111 .preparetowait = healthd_mode_charger_preparetowait, 112 .heartbeat = healthd_mode_charger_heartbeat, 113 .battery_update = healthd_mode_charger_battery_update, 114}; 115 116static struct healthd_mode_ops recovery_ops = { 117 .init = healthd_mode_nop_init, 118 .preparetowait = healthd_mode_nop_preparetowait, 119 .heartbeat = healthd_mode_nop_heartbeat, 120 .battery_update = healthd_mode_nop_battery_update, 121}; 122 123static void healthd_mode_nop_init(struct healthd_config* /*config*/) { 124} 125 126static int healthd_mode_nop_preparetowait(void) { 127 return -1; 128} 129 130static void healthd_mode_nop_heartbeat(void) { 131} 132 133static void healthd_mode_nop_battery_update( 134 struct android::BatteryProperties* /*props*/) { 135} 136 137int healthd_register_event(int fd, void (*handler)(uint32_t)) { 138 struct epoll_event ev; 139 140 ev.events = EPOLLIN | EPOLLWAKEUP; 141 ev.data.ptr = (void *)handler; 142 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) { 143 KLOG_ERROR(LOG_TAG, 144 "epoll_ctl failed; errno=%d\n", errno); 145 return -1; 146 } 147 148 eventct++; 149 return 0; 150} 151 152static void wakealarm_set_interval(int interval) { 153 struct itimerspec itval; 154 155 if (wakealarm_fd == -1) 156 return; 157 158 wakealarm_wake_interval = interval; 159 160 if (interval == -1) 161 interval = 0; 162 163 itval.it_interval.tv_sec = interval; 164 itval.it_interval.tv_nsec = 0; 165 itval.it_value.tv_sec = interval; 166 itval.it_value.tv_nsec = 0; 167 168 if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1) 169 KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n"); 170} 171 172status_t healthd_get_property(int id, struct BatteryProperty *val) { 173 return gBatteryMonitor->getProperty(id, val); 174} 175 176void healthd_battery_update(void) { 177 // Fast wake interval when on charger (watch for overheat); 178 // slow wake interval when on battery (watch for drained battery). 179 180 int new_wake_interval = gBatteryMonitor->update() ? 181 healthd_config.periodic_chores_interval_fast : 182 healthd_config.periodic_chores_interval_slow; 183 184 if (new_wake_interval != wakealarm_wake_interval) 185 wakealarm_set_interval(new_wake_interval); 186 187 // During awake periods poll at fast rate. If wake alarm is set at fast 188 // rate then just use the alarm; if wake alarm is set at slow rate then 189 // poll at fast rate while awake and let alarm wake up at slow rate when 190 // asleep. 191 192 if (healthd_config.periodic_chores_interval_fast == -1) 193 awake_poll_interval = -1; 194 else 195 awake_poll_interval = 196 new_wake_interval == healthd_config.periodic_chores_interval_fast ? 197 -1 : healthd_config.periodic_chores_interval_fast * 1000; 198} 199 200void healthd_dump_battery_state(int fd) { 201 gBatteryMonitor->dumpState(fd); 202 fsync(fd); 203} 204 205static void periodic_chores() { 206 healthd_battery_update(); 207} 208 209#define UEVENT_MSG_LEN 2048 210static void uevent_event(uint32_t /*epevents*/) { 211 char msg[UEVENT_MSG_LEN+2]; 212 char *cp; 213 int n; 214 215 n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN); 216 if (n <= 0) 217 return; 218 if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ 219 return; 220 221 msg[n] = '\0'; 222 msg[n+1] = '\0'; 223 cp = msg; 224 225 while (*cp) { 226 if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) { 227 healthd_battery_update(); 228 break; 229 } 230 231 /* advance to after the next \0 */ 232 while (*cp++) 233 ; 234 } 235} 236 237static void uevent_init(void) { 238 uevent_fd = uevent_open_socket(64*1024, true); 239 240 if (uevent_fd < 0) { 241 KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n"); 242 return; 243 } 244 245 fcntl(uevent_fd, F_SETFL, O_NONBLOCK); 246 if (healthd_register_event(uevent_fd, uevent_event)) 247 KLOG_ERROR(LOG_TAG, 248 "register for uevent events failed\n"); 249} 250 251static void wakealarm_event(uint32_t /*epevents*/) { 252 unsigned long long wakeups; 253 254 if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) { 255 KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n"); 256 return; 257 } 258 259 periodic_chores(); 260} 261 262static void wakealarm_init(void) { 263 wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK); 264 if (wakealarm_fd == -1) { 265 KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n"); 266 return; 267 } 268 269 if (healthd_register_event(wakealarm_fd, wakealarm_event)) 270 KLOG_ERROR(LOG_TAG, 271 "Registration of wakealarm event failed\n"); 272 273 wakealarm_set_interval(healthd_config.periodic_chores_interval_fast); 274} 275 276static void healthd_mainloop(void) { 277 while (1) { 278 struct epoll_event events[eventct]; 279 int nevents; 280 int timeout = awake_poll_interval; 281 int mode_timeout; 282 283 mode_timeout = healthd_mode_ops->preparetowait(); 284 if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) 285 timeout = mode_timeout; 286 nevents = epoll_wait(epollfd, events, eventct, timeout); 287 288 if (nevents == -1) { 289 if (errno == EINTR) 290 continue; 291 KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n"); 292 break; 293 } 294 295 for (int n = 0; n < nevents; ++n) { 296 if (events[n].data.ptr) 297 (*(void (*)(int))events[n].data.ptr)(events[n].events); 298 } 299 300 if (!nevents) 301 periodic_chores(); 302 303 healthd_mode_ops->heartbeat(); 304 } 305 306 return; 307} 308 309static int healthd_init() { 310 epollfd = epoll_create(MAX_EPOLL_EVENTS); 311 if (epollfd == -1) { 312 KLOG_ERROR(LOG_TAG, 313 "epoll_create failed; errno=%d\n", 314 errno); 315 return -1; 316 } 317 318 healthd_board_init(&healthd_config); 319 healthd_mode_ops->init(&healthd_config); 320 wakealarm_init(); 321 uevent_init(); 322 gBatteryMonitor = new BatteryMonitor(); 323 gBatteryMonitor->init(&healthd_config); 324 return 0; 325} 326 327int main(int argc, char **argv) { 328 int ch; 329 int ret; 330 331 klog_set_level(KLOG_LEVEL); 332 healthd_mode_ops = &android_ops; 333 334 if (!strcmp(basename(argv[0]), "charger")) { 335 healthd_mode_ops = &charger_ops; 336 } else { 337 while ((ch = getopt(argc, argv, "cr")) != -1) { 338 switch (ch) { 339 case 'c': 340 healthd_mode_ops = &charger_ops; 341 break; 342 case 'r': 343 healthd_mode_ops = &recovery_ops; 344 break; 345 case '?': 346 default: 347 KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n", 348 optopt); 349 exit(1); 350 } 351 } 352 } 353 354 ret = healthd_init(); 355 if (ret) { 356 KLOG_ERROR("Initialization failed, exiting\n"); 357 exit(2); 358 } 359 360 healthd_mainloop(); 361 KLOG_ERROR("Main loop terminated, exiting\n"); 362 return 3; 363} 364