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