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