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