int BatteryMonitor::readFromFile(const String8& path, char* buf, size_t size) { char *cp = NULL; if (path.isEmpty()) return -1; int fd = open(path.string(), O_RDONLY, 0); if (fd == -1) { KLOG_ERROR(LOG_TAG, "Could not open '%s'\n", path.string()); return -1; } ssize_t count = TEMP_FAILURE_RETRY(read(fd, buf, size)); if (count > 0) cp = (char *)memrchr(buf, '\n', count); if (cp) *cp = '\0'; else buf[0] = '\0'; close(fd); return count; }
void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) { String8 path; mHealthdConfig = hc; DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH); if (dir == NULL) { KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH); } else { struct dirent* entry; while ((entry = readdir(dir))) { const char* name = entry->d_name; if (!strcmp(name, ".") || !strcmp(name, "..")) continue; char buf[20]; // Look for "type" file in each subdirectory path.clear(); path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name); switch(readPowerSupplyType(path)) { case ANDROID_POWER_SUPPLY_TYPE_AC: case ANDROID_POWER_SUPPLY_TYPE_USB: case ANDROID_POWER_SUPPLY_TYPE_WIRELESS: path.clear(); path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name); if (access(path.string(), R_OK) == 0) mChargerNames.add(String8(name)); break; case ANDROID_POWER_SUPPLY_TYPE_BATTERY: if (mHealthdConfig->batteryStatusPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryStatusPath = path; } if (mHealthdConfig->batteryHealthPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryHealthPath = path; } if (mHealthdConfig->batteryPresentPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryPresentPath = path; } if (mHealthdConfig->batteryCapacityPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryCapacityPath = path; } if (mHealthdConfig->batteryVoltagePath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/voltage_now", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) { mHealthdConfig->batteryVoltagePath = path; } else { path.clear(); path.appendFormat("%s/%s/batt_vol", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryVoltagePath = path; } } if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/current_now", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryCurrentNowPath = path; } if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/charge_counter", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryChargeCounterPath = path; } if (mHealthdConfig->batteryTemperaturePath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) { mHealthdConfig->batteryTemperaturePath = path; } else { path.clear(); path.appendFormat("%s/%s/batt_temp", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryTemperaturePath = path; } } if (mHealthdConfig->batteryTechnologyPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/technology", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryTechnologyPath = path; } break; case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN: break; } } closedir(dir); } if (!mChargerNames.size()) KLOG_ERROR(LOG_TAG, "No charger supplies found\n"); if (mHealthdConfig->batteryStatusPath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n"); if (mHealthdConfig->batteryHealthPath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n"); if (mHealthdConfig->batteryPresentPath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n"); if (mHealthdConfig->batteryCapacityPath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n"); if (mHealthdConfig->batteryVoltagePath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n"); if (mHealthdConfig->batteryTemperaturePath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n"); if (mHealthdConfig->batteryTechnologyPath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n"); if (nosvcmgr == false) { mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(this); mBatteryPropertiesRegistrar->publish(); } }
bool BatteryMonitor::update(void) { bool logthis; props.chargerAcOnline = false; props.chargerUsbOnline = false; props.chargerWirelessOnline = false; props.batteryStatus = BATTERY_STATUS_UNKNOWN; props.batteryHealth = BATTERY_HEALTH_UNKNOWN; if (!mHealthdConfig->batteryPresentPath.isEmpty()) props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath); else props.batteryPresent = mBatteryDevicePresent; props.batteryLevel = mBatteryFixedCapacity ? mBatteryFixedCapacity : getIntField(mHealthdConfig->batteryCapacityPath); props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000; props.batteryTemperature = mBatteryFixedTemperature ? mBatteryFixedTemperature : getIntField(mHealthdConfig->batteryTemperaturePath); const int SIZE = 128; char buf[SIZE]; String8 btech; if (readFromFile(mHealthdConfig->batteryStatusPath, buf, SIZE) > 0) props.batteryStatus = getBatteryStatus(buf); if (readFromFile(mHealthdConfig->batteryHealthPath, buf, SIZE) > 0) props.batteryHealth = getBatteryHealth(buf); if (readFromFile(mHealthdConfig->batteryTechnologyPath, buf, SIZE) > 0) props.batteryTechnology = String8(buf); // reinitialize the mChargerNames vector everytime there is an update String8 path; DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH); if (dir == NULL) { KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH); } else { struct dirent* entry; // reconstruct the charger strings mChargerNames.clear(); while ((entry = readdir(dir))) { const char* name = entry->d_name; if (!strcmp(name, ".") || !strcmp(name, "..")) continue; // Look for "type" file in each subdirectory path.clear(); path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name); switch(readPowerSupplyType(path)) { case ANDROID_POWER_SUPPLY_TYPE_BATTERY: break; default: path.clear(); path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name); if (access(path.string(), R_OK) == 0) { mChargerNames.add(String8(name)); if (readFromFile(path, buf, SIZE) > 0) { if (buf[0] != '0') { path.clear(); path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name); switch(readPowerSupplyType(path)) { case ANDROID_POWER_SUPPLY_TYPE_AC: props.chargerAcOnline = true; break; case ANDROID_POWER_SUPPLY_TYPE_USB: props.chargerUsbOnline = true; break; case ANDROID_POWER_SUPPLY_TYPE_WIRELESS: props.chargerWirelessOnline = true; break; default: KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n", name); } } } } break; } //switch } //while closedir(dir); }//else logthis = !healthd_board_battery_update(&props); if (logthis) { char dmesgline[256]; if (props.batteryPresent) { snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d", props.batteryLevel, props.batteryVoltage, props.batteryTemperature < 0 ? "-" : "", abs(props.batteryTemperature / 10), abs(props.batteryTemperature % 10), props.batteryHealth, props.batteryStatus); if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { int c = getIntField(mHealthdConfig->batteryCurrentNowPath); char b[20]; snprintf(b, sizeof(b), " c=%d", c / 1000); strlcat(dmesgline, b, sizeof(dmesgline)); } } else { snprintf(dmesgline, sizeof(dmesgline), "battery none"); } KLOG_WARNING(LOG_TAG, "%s chg=%s%s%s\n", dmesgline, props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "", props.chargerWirelessOnline ? "w" : ""); } healthd_mode_ops->battery_update(&props); return props.chargerAcOnline | props.chargerUsbOnline | props.chargerWirelessOnline; }
void BatteryMonitor::init(struct healthd_config *hc) { String8 path; char pval[PROPERTY_VALUE_MAX]; mHealthdConfig = hc; DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH); if (dir == NULL) { KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH); } else { struct dirent* entry; while ((entry = readdir(dir))) { const char* name = entry->d_name; if (!strcmp(name, ".") || !strcmp(name, "..")) continue; char buf[20]; // Look for "type" file in each subdirectory path.clear(); path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name); switch(readPowerSupplyType(path)) { case ANDROID_POWER_SUPPLY_TYPE_AC: case ANDROID_POWER_SUPPLY_TYPE_USB: case ANDROID_POWER_SUPPLY_TYPE_WIRELESS: path.clear(); path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name); if (access(path.string(), R_OK) == 0) mChargerNames.add(String8(name)); break; case ANDROID_POWER_SUPPLY_TYPE_BATTERY: mBatteryDevicePresent = true; if (mHealthdConfig->batteryStatusPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryStatusPath = path; } if (mHealthdConfig->batteryHealthPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryHealthPath = path; } if (mHealthdConfig->batteryPresentPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryPresentPath = path; } if (mHealthdConfig->batteryCapacityPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryCapacityPath = path; } if (mHealthdConfig->batteryVoltagePath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/voltage_now", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) { mHealthdConfig->batteryVoltagePath = path; } else { path.clear(); path.appendFormat("%s/%s/batt_vol", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryVoltagePath = path; } } if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/current_now", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryCurrentNowPath = path; } if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/current_avg", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryCurrentAvgPath = path; } if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/charge_counter", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryChargeCounterPath = path; } if (mHealthdConfig->batteryTemperaturePath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) { mHealthdConfig->batteryTemperaturePath = path; } else { path.clear(); path.appendFormat("%s/%s/batt_temp", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryTemperaturePath = path; } } if (mHealthdConfig->batteryTechnologyPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/technology", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryTechnologyPath = path; } break; case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN: break; } } closedir(dir); } if (!mChargerNames.size()) KLOG_ERROR(LOG_TAG, "No charger supplies found\n"); if (!mBatteryDevicePresent) { KLOG_WARNING(LOG_TAG, "No battery devices found\n"); hc->periodic_chores_interval_fast = -1; hc->periodic_chores_interval_slow = -1; } else { if (mHealthdConfig->batteryStatusPath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n"); if (mHealthdConfig->batteryHealthPath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n"); if (mHealthdConfig->batteryPresentPath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n"); if (mHealthdConfig->batteryCapacityPath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n"); if (mHealthdConfig->batteryVoltagePath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n"); if (mHealthdConfig->batteryTemperaturePath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n"); if (mHealthdConfig->batteryTechnologyPath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n"); } if (property_get("ro.boot.fake_battery", pval, NULL) > 0 && strtol(pval, NULL, 10) != 0) { mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY; mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE; } }
int main(int argc, char **argv) { int alarm_time = 5; int count = -1; bool abort_on_failure = false; while (1) { const static struct option long_options[] = { {"abort", no_argument, 0, 'a'}, {"count", required_argument, 0, 'c'}, {"time", required_argument, 0, 't'}, }; int c = getopt_long(argc, argv, "ac:t:", long_options, NULL); if (c < 0) { break; } switch (c) { case 'a': abort_on_failure = true; break; case 'c': count = strtoul(optarg, NULL, 0); break; case 't': alarm_time = strtoul(optarg, NULL, 0); break; case '?': usage(); exit(EXIT_FAILURE); default: abort(); } } klog_init(); klog_set_level(KLOG_INFO_LEVEL); if (optind < argc) { fprintf(stderr, "Unexpected argument: %s\n", argv[optind]); usage(); exit(EXIT_FAILURE); } int fd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0); if (fd < 0) { perror("timerfd_create failed"); exit(EXIT_FAILURE); } struct itimerspec delay = itimerspec(); delay.it_value.tv_sec = alarm_time; int i = 0; int epoll_fd = epoll_create(1); if (epoll_fd < 0) { perror("epoll_create failed"); exit(EXIT_FAILURE); } struct epoll_event ev = epoll_event(); ev.events = EPOLLIN | EPOLLWAKEUP; int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev); if (ret < 0) { perror("epoll_ctl failed"); exit(EXIT_FAILURE); } while (count != 0) { struct timespec expected_time; struct timespec actual_time; uint64_t fired = 0; ret = timerfd_settime(fd, 0, &delay, NULL); if (ret < 0) { perror("timerfd_settime failed"); exit(EXIT_FAILURE); } ret = clock_gettime(CLOCK_BOOTTIME, &expected_time); if (ret < 0) { perror("failed to get time"); exit(EXIT_FAILURE); } expected_time.tv_sec += alarm_time; ret = 0; while (ret != 1) { struct epoll_event out_ev; ret = epoll_wait(epoll_fd, &out_ev, 1, -1); if (ret < 0 && errno != EINTR) { perror("epoll_wait failed"); exit(EXIT_FAILURE); } } ssize_t bytes = read(fd, &fired, sizeof(fired)); if (bytes < 0) { perror("read from timer fd failed"); exit(EXIT_FAILURE); } else if (bytes < (ssize_t)sizeof(fired)) { fprintf(stderr, "unexpected read from timer fd: %zd\n", bytes); } if (fired != 1) { fprintf(stderr, "unexpected timer fd fired count: %" PRIu64 "\n", fired); } ret = clock_gettime(CLOCK_BOOTTIME, &actual_time); if (ret < 0) { perror("failed to get time"); exit(EXIT_FAILURE); } long long diff = timediff_ns(&actual_time, &expected_time); if (llabs(diff) > NSEC_PER_SEC) { fprintf(stderr, "alarm arrived %lld.%03lld seconds %s\n", llabs(diff) / NSEC_PER_SEC, (llabs(diff) / NSEC_PER_MSEC) % MSEC_PER_SEC, diff > 0 ? "late" : "early"); KLOG_ERROR("suspend_stress", "alarm arrived %lld.%03lld seconds %s\n", llabs(diff) / NSEC_PER_SEC, (llabs(diff) / NSEC_PER_MSEC) % MSEC_PER_SEC, diff > 0 ? "late" : "early"); if (abort_on_failure) { exit(EXIT_FAILURE); } } time_t t = time(NULL); i += fired; printf("timer fired: %d at boottime %lld.%.3ld, %s", i, (long long)actual_time.tv_sec, actual_time.tv_nsec / NSEC_PER_MSEC, ctime(&t)); KLOG_INFO("suspend_stress", "timer fired: %d at boottime %lld.%.3ld, %s", i, (long long)actual_time.tv_sec, actual_time.tv_nsec / NSEC_PER_MSEC, ctime(&t)); if (count > 0) count--; } return 0; }