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 
19 #include <healthd/healthd.h>
20 #include <healthd/BatteryMonitor.h>
21 
22 #include <dirent.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 
30 #include <algorithm>
31 #include <memory>
32 #include <optional>
33 
34 #include <android-base/file.h>
35 #include <android-base/parseint.h>
36 #include <android-base/strings.h>
37 #include <android/hardware/health/2.1/types.h>
38 #include <batteryservice/BatteryService.h>
39 #include <cutils/klog.h>
40 #include <cutils/properties.h>
41 #include <utils/Errors.h>
42 #include <utils/String8.h>
43 #include <utils/Vector.h>
44 
45 #define POWER_SUPPLY_SUBSYSTEM "power_supply"
46 #define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
47 #define FAKE_BATTERY_CAPACITY 42
48 #define FAKE_BATTERY_TEMPERATURE 424
49 #define MILLION 1.0e6
50 #define DEFAULT_VBUS_VOLTAGE 5000000
51 
52 using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
53 using HealthInfo_2_0 = android::hardware::health::V2_0::HealthInfo;
54 using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
55 using android::hardware::health::V1_0::BatteryHealth;
56 using android::hardware::health::V1_0::BatteryStatus;
57 using android::hardware::health::V2_1::BatteryCapacityLevel;
58 using android::hardware::health::V2_1::Constants;
59 
60 namespace android {
61 
62 template <typename T>
63 struct SysfsStringEnumMap {
64     const char* s;
65     T val;
66 };
67 
68 template <typename T>
mapSysfsString(const char * str,SysfsStringEnumMap<T> map[])69 static std::optional<T> mapSysfsString(const char* str, SysfsStringEnumMap<T> map[]) {
70     for (int i = 0; map[i].s; i++)
71         if (!strcmp(str, map[i].s))
72             return map[i].val;
73 
74     return std::nullopt;
75 }
76 
initHealthInfo(HealthInfo_2_1 * health_info_2_1)77 static void initHealthInfo(HealthInfo_2_1* health_info_2_1) {
78     *health_info_2_1 = HealthInfo_2_1{};
79 
80     // HIDL enum values are zero initialized, so they need to be initialized
81     // properly.
82     health_info_2_1->batteryCapacityLevel = BatteryCapacityLevel::UNKNOWN;
83     health_info_2_1->batteryChargeTimeToFullNowSeconds =
84             (int64_t)Constants::BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED;
85     auto* props = &health_info_2_1->legacy.legacy;
86     props->batteryStatus = BatteryStatus::UNKNOWN;
87     props->batteryHealth = BatteryHealth::UNKNOWN;
88 }
89 
BatteryMonitor()90 BatteryMonitor::BatteryMonitor()
91     : mHealthdConfig(nullptr),
92       mBatteryDevicePresent(false),
93       mBatteryFixedCapacity(0),
94       mBatteryFixedTemperature(0),
95       mHealthInfo(std::make_unique<HealthInfo_2_1>()) {
96     initHealthInfo(mHealthInfo.get());
97 }
98 
~BatteryMonitor()99 BatteryMonitor::~BatteryMonitor() {}
100 
getHealthInfo_1_0() const101 const HealthInfo_1_0& BatteryMonitor::getHealthInfo_1_0() const {
102     return getHealthInfo_2_0().legacy;
103 }
104 
getHealthInfo_2_0() const105 const HealthInfo_2_0& BatteryMonitor::getHealthInfo_2_0() const {
106     return getHealthInfo_2_1().legacy;
107 }
108 
getHealthInfo_2_1() const109 const HealthInfo_2_1& BatteryMonitor::getHealthInfo_2_1() const {
110     return *mHealthInfo;
111 }
112 
getBatteryStatus(const char * status)113 BatteryStatus getBatteryStatus(const char* status) {
114     static SysfsStringEnumMap<BatteryStatus> batteryStatusMap[] = {
115             {"Unknown", BatteryStatus::UNKNOWN},
116             {"Charging", BatteryStatus::CHARGING},
117             {"Discharging", BatteryStatus::DISCHARGING},
118             {"Not charging", BatteryStatus::NOT_CHARGING},
119             {"Full", BatteryStatus::FULL},
120             {NULL, BatteryStatus::UNKNOWN},
121     };
122 
123     auto ret = mapSysfsString(status, batteryStatusMap);
124     if (!ret) {
125         KLOG_WARNING(LOG_TAG, "Unknown battery status '%s'\n", status);
126         *ret = BatteryStatus::UNKNOWN;
127     }
128 
129     return *ret;
130 }
131 
getBatteryCapacityLevel(const char * capacityLevel)132 BatteryCapacityLevel getBatteryCapacityLevel(const char* capacityLevel) {
133     static SysfsStringEnumMap<BatteryCapacityLevel> batteryCapacityLevelMap[] = {
134             {"Unknown", BatteryCapacityLevel::UNKNOWN},
135             {"Critical", BatteryCapacityLevel::CRITICAL},
136             {"Low", BatteryCapacityLevel::LOW},
137             {"Normal", BatteryCapacityLevel::NORMAL},
138             {"High", BatteryCapacityLevel::HIGH},
139             {"Full", BatteryCapacityLevel::FULL},
140             {NULL, BatteryCapacityLevel::UNSUPPORTED},
141     };
142 
143     auto ret = mapSysfsString(capacityLevel, batteryCapacityLevelMap);
144     if (!ret) {
145         KLOG_WARNING(LOG_TAG, "Unsupported battery capacity level '%s'\n", capacityLevel);
146         *ret = BatteryCapacityLevel::UNSUPPORTED;
147     }
148 
149     return *ret;
150 }
151 
getBatteryHealth(const char * status)152 BatteryHealth getBatteryHealth(const char* status) {
153     static SysfsStringEnumMap<BatteryHealth> batteryHealthMap[] = {
154             {"Unknown", BatteryHealth::UNKNOWN},
155             {"Good", BatteryHealth::GOOD},
156             {"Overheat", BatteryHealth::OVERHEAT},
157             {"Dead", BatteryHealth::DEAD},
158             {"Over voltage", BatteryHealth::OVER_VOLTAGE},
159             {"Unspecified failure", BatteryHealth::UNSPECIFIED_FAILURE},
160             {"Cold", BatteryHealth::COLD},
161             // battery health values from JEITA spec
162             {"Warm", BatteryHealth::GOOD},
163             {"Cool", BatteryHealth::GOOD},
164             {"Hot", BatteryHealth::OVERHEAT},
165             {NULL, BatteryHealth::UNKNOWN},
166     };
167 
168     auto ret = mapSysfsString(status, batteryHealthMap);
169     if (!ret) {
170         KLOG_WARNING(LOG_TAG, "Unknown battery health '%s'\n", status);
171         *ret = BatteryHealth::UNKNOWN;
172     }
173 
174     return *ret;
175 }
176 
readFromFile(const String8 & path,std::string * buf)177 int BatteryMonitor::readFromFile(const String8& path, std::string* buf) {
178     if (android::base::ReadFileToString(path.c_str(), buf)) {
179         *buf = android::base::Trim(*buf);
180     }
181     return buf->length();
182 }
183 
readPowerSupplyType(const String8 & path)184 BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String8& path) {
185     static SysfsStringEnumMap<int> supplyTypeMap[] = {
186             {"Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN},
187             {"Battery", ANDROID_POWER_SUPPLY_TYPE_BATTERY},
188             {"UPS", ANDROID_POWER_SUPPLY_TYPE_AC},
189             {"Mains", ANDROID_POWER_SUPPLY_TYPE_AC},
190             {"USB", ANDROID_POWER_SUPPLY_TYPE_USB},
191             {"USB_DCP", ANDROID_POWER_SUPPLY_TYPE_AC},
192             {"USB_HVDCP", ANDROID_POWER_SUPPLY_TYPE_AC},
193             {"USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC},
194             {"USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC},
195             {"USB_C", ANDROID_POWER_SUPPLY_TYPE_AC},
196             {"USB_PD", ANDROID_POWER_SUPPLY_TYPE_AC},
197             {"USB_PD_DRP", ANDROID_POWER_SUPPLY_TYPE_USB},
198             {"Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS},
199             {NULL, 0},
200     };
201     std::string buf;
202 
203     if (readFromFile(path, &buf) <= 0)
204         return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
205 
206     auto ret = mapSysfsString(buf.c_str(), supplyTypeMap);
207     if (!ret) {
208         KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str());
209         *ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
210     }
211 
212     return static_cast<BatteryMonitor::PowerSupplyType>(*ret);
213 }
214 
getBooleanField(const String8 & path)215 bool BatteryMonitor::getBooleanField(const String8& path) {
216     std::string buf;
217     bool value = false;
218 
219     if (readFromFile(path, &buf) > 0)
220         if (buf[0] != '0')
221             value = true;
222 
223     return value;
224 }
225 
getIntField(const String8 & path)226 int BatteryMonitor::getIntField(const String8& path) {
227     std::string buf;
228     int value = 0;
229 
230     if (readFromFile(path, &buf) > 0)
231         android::base::ParseInt(buf, &value);
232 
233     return value;
234 }
235 
isScopedPowerSupply(const char * name)236 bool BatteryMonitor::isScopedPowerSupply(const char* name) {
237     constexpr char kScopeDevice[] = "Device";
238 
239     String8 path;
240     path.appendFormat("%s/%s/scope", POWER_SUPPLY_SYSFS_PATH, name);
241     std::string scope;
242     return (readFromFile(path, &scope) > 0 && scope == kScopeDevice);
243 }
244 
updateValues(void)245 void BatteryMonitor::updateValues(void) {
246     initHealthInfo(mHealthInfo.get());
247 
248     HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
249 
250     if (!mHealthdConfig->batteryPresentPath.isEmpty())
251         props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
252     else
253         props.batteryPresent = mBatteryDevicePresent;
254 
255     props.batteryLevel = mBatteryFixedCapacity ?
256         mBatteryFixedCapacity :
257         getIntField(mHealthdConfig->batteryCapacityPath);
258     props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
259 
260     if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
261         props.batteryCurrent = getIntField(mHealthdConfig->batteryCurrentNowPath);
262 
263     if (!mHealthdConfig->batteryFullChargePath.isEmpty())
264         props.batteryFullCharge = getIntField(mHealthdConfig->batteryFullChargePath);
265 
266     if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
267         props.batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
268 
269     if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
270         props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);
271 
272     if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty())
273         mHealthInfo->legacy.batteryCurrentAverage =
274                 getIntField(mHealthdConfig->batteryCurrentAvgPath);
275 
276     if (!mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
277         mHealthInfo->batteryChargeTimeToFullNowSeconds =
278                 getIntField(mHealthdConfig->batteryChargeTimeToFullNowPath);
279 
280     if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
281         mHealthInfo->batteryFullChargeDesignCapacityUah =
282                 getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath);
283 
284     props.batteryTemperature = mBatteryFixedTemperature ?
285         mBatteryFixedTemperature :
286         getIntField(mHealthdConfig->batteryTemperaturePath);
287 
288     std::string buf;
289 
290     if (readFromFile(mHealthdConfig->batteryCapacityLevelPath, &buf) > 0)
291         mHealthInfo->batteryCapacityLevel = getBatteryCapacityLevel(buf.c_str());
292 
293     if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
294         props.batteryStatus = getBatteryStatus(buf.c_str());
295 
296     if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
297         props.batteryHealth = getBatteryHealth(buf.c_str());
298 
299     if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0)
300         props.batteryTechnology = String8(buf.c_str());
301 
302     double MaxPower = 0;
303 
304     for (size_t i = 0; i < mChargerNames.size(); i++) {
305         String8 path;
306         path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
307                           mChargerNames[i].string());
308         if (getIntField(path)) {
309             path.clear();
310             path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
311                               mChargerNames[i].string());
312             switch(readPowerSupplyType(path)) {
313             case ANDROID_POWER_SUPPLY_TYPE_AC:
314                 props.chargerAcOnline = true;
315                 break;
316             case ANDROID_POWER_SUPPLY_TYPE_USB:
317                 props.chargerUsbOnline = true;
318                 break;
319             case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
320                 props.chargerWirelessOnline = true;
321                 break;
322             default:
323                 KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
324                              mChargerNames[i].string());
325             }
326             path.clear();
327             path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
328                               mChargerNames[i].string());
329             int ChargingCurrent =
330                     (access(path.string(), R_OK) == 0) ? getIntField(path) : 0;
331 
332             path.clear();
333             path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
334                               mChargerNames[i].string());
335 
336             int ChargingVoltage =
337                 (access(path.string(), R_OK) == 0) ? getIntField(path) :
338                 DEFAULT_VBUS_VOLTAGE;
339 
340             double power = ((double)ChargingCurrent / MILLION) *
341                            ((double)ChargingVoltage / MILLION);
342             if (MaxPower < power) {
343                 props.maxChargingCurrent = ChargingCurrent;
344                 props.maxChargingVoltage = ChargingVoltage;
345                 MaxPower = power;
346             }
347         }
348     }
349 }
350 
logValues(void)351 void BatteryMonitor::logValues(void) {
352     char dmesgline[256];
353     size_t len;
354     const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
355     if (props.batteryPresent) {
356         snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
357                  props.batteryLevel, props.batteryVoltage, props.batteryTemperature < 0 ? "-" : "",
358                  abs(props.batteryTemperature / 10), abs(props.batteryTemperature % 10),
359                  props.batteryHealth, props.batteryStatus);
360 
361         len = strlen(dmesgline);
362         if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
363             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d",
364                             props.batteryCurrent);
365         }
366 
367         if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
368             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d",
369                             props.batteryFullCharge);
370         }
371 
372         if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
373             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " cc=%d",
374                             props.batteryCycleCount);
375         }
376     } else {
377         len = snprintf(dmesgline, sizeof(dmesgline), "battery none");
378     }
379 
380     snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
381              props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "",
382              props.chargerWirelessOnline ? "w" : "");
383 
384     KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
385 }
386 
isChargerOnline()387 bool BatteryMonitor::isChargerOnline() {
388     const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
389     return props.chargerAcOnline | props.chargerUsbOnline |
390             props.chargerWirelessOnline;
391 }
392 
getChargeStatus()393 int BatteryMonitor::getChargeStatus() {
394     BatteryStatus result = BatteryStatus::UNKNOWN;
395     if (!mHealthdConfig->batteryStatusPath.isEmpty()) {
396         std::string buf;
397         if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
398             result = getBatteryStatus(buf.c_str());
399     }
400     return static_cast<int>(result);
401 }
402 
getProperty(int id,struct BatteryProperty * val)403 status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
404     status_t ret = BAD_VALUE;
405     std::string buf;
406 
407     val->valueInt64 = LONG_MIN;
408 
409     switch(id) {
410     case BATTERY_PROP_CHARGE_COUNTER:
411         if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
412             val->valueInt64 =
413                 getIntField(mHealthdConfig->batteryChargeCounterPath);
414             ret = OK;
415         } else {
416             ret = NAME_NOT_FOUND;
417         }
418         break;
419 
420     case BATTERY_PROP_CURRENT_NOW:
421         if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
422             val->valueInt64 =
423                 getIntField(mHealthdConfig->batteryCurrentNowPath);
424             ret = OK;
425         } else {
426             ret = NAME_NOT_FOUND;
427         }
428         break;
429 
430     case BATTERY_PROP_CURRENT_AVG:
431         if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
432             val->valueInt64 =
433                 getIntField(mHealthdConfig->batteryCurrentAvgPath);
434             ret = OK;
435         } else {
436             ret = NAME_NOT_FOUND;
437         }
438         break;
439 
440     case BATTERY_PROP_CAPACITY:
441         if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
442             val->valueInt64 =
443                 getIntField(mHealthdConfig->batteryCapacityPath);
444             ret = OK;
445         } else {
446             ret = NAME_NOT_FOUND;
447         }
448         break;
449 
450     case BATTERY_PROP_ENERGY_COUNTER:
451         if (mHealthdConfig->energyCounter) {
452             ret = mHealthdConfig->energyCounter(&val->valueInt64);
453         } else {
454             ret = NAME_NOT_FOUND;
455         }
456         break;
457 
458     case BATTERY_PROP_BATTERY_STATUS:
459         val->valueInt64 = getChargeStatus();
460         ret = OK;
461         break;
462 
463     default:
464         break;
465     }
466 
467     return ret;
468 }
469 
dumpState(int fd)470 void BatteryMonitor::dumpState(int fd) {
471     int v;
472     char vs[128];
473     const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
474 
475     snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d current_max: %d voltage_max: %d\n",
476              props.chargerAcOnline, props.chargerUsbOnline,
477              props.chargerWirelessOnline, props.maxChargingCurrent,
478              props.maxChargingVoltage);
479     write(fd, vs, strlen(vs));
480     snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
481              props.batteryStatus, props.batteryHealth, props.batteryPresent);
482     write(fd, vs, strlen(vs));
483     snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n",
484              props.batteryLevel, props.batteryVoltage,
485              props.batteryTemperature);
486     write(fd, vs, strlen(vs));
487 
488     if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
489         v = getIntField(mHealthdConfig->batteryCurrentNowPath);
490         snprintf(vs, sizeof(vs), "current now: %d\n", v);
491         write(fd, vs, strlen(vs));
492     }
493 
494     if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
495         v = getIntField(mHealthdConfig->batteryCurrentAvgPath);
496         snprintf(vs, sizeof(vs), "current avg: %d\n", v);
497         write(fd, vs, strlen(vs));
498     }
499 
500     if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
501         v = getIntField(mHealthdConfig->batteryChargeCounterPath);
502         snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
503         write(fd, vs, strlen(vs));
504     }
505 
506     if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
507         snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrent);
508         write(fd, vs, strlen(vs));
509     }
510 
511     if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
512         snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount);
513         write(fd, vs, strlen(vs));
514     }
515 
516     if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
517         snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullCharge);
518         write(fd, vs, strlen(vs));
519     }
520 }
521 
init(struct healthd_config * hc)522 void BatteryMonitor::init(struct healthd_config *hc) {
523     String8 path;
524     char pval[PROPERTY_VALUE_MAX];
525 
526     mHealthdConfig = hc;
527     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir);
528     if (dir == NULL) {
529         KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
530     } else {
531         struct dirent* entry;
532 
533         while ((entry = readdir(dir.get()))) {
534             const char* name = entry->d_name;
535             std::vector<String8>::iterator itIgnoreName;
536 
537             if (!strcmp(name, ".") || !strcmp(name, ".."))
538                 continue;
539 
540             itIgnoreName = find(hc->ignorePowerSupplyNames.begin(),
541                                 hc->ignorePowerSupplyNames.end(), String8(name));
542             if (itIgnoreName != hc->ignorePowerSupplyNames.end())
543                 continue;
544 
545             // Look for "type" file in each subdirectory
546             path.clear();
547             path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
548             switch(readPowerSupplyType(path)) {
549             case ANDROID_POWER_SUPPLY_TYPE_AC:
550             case ANDROID_POWER_SUPPLY_TYPE_USB:
551             case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
552                 path.clear();
553                 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
554                 if (access(path.string(), R_OK) == 0)
555                     mChargerNames.add(String8(name));
556                 break;
557 
558             case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
559                 // Some devices expose the battery status of sub-component like
560                 // stylus. Such a device-scoped battery info needs to be skipped
561                 // in BatteryMonitor, which is intended to report the status of
562                 // the battery supplying the power to the whole system.
563                 if (isScopedPowerSupply(name)) continue;
564                 mBatteryDevicePresent = true;
565 
566                 if (mHealthdConfig->batteryStatusPath.isEmpty()) {
567                     path.clear();
568                     path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
569                                       name);
570                     if (access(path, R_OK) == 0)
571                         mHealthdConfig->batteryStatusPath = path;
572                 }
573 
574                 if (mHealthdConfig->batteryHealthPath.isEmpty()) {
575                     path.clear();
576                     path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
577                                       name);
578                     if (access(path, R_OK) == 0)
579                         mHealthdConfig->batteryHealthPath = path;
580                 }
581 
582                 if (mHealthdConfig->batteryPresentPath.isEmpty()) {
583                     path.clear();
584                     path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
585                                       name);
586                     if (access(path, R_OK) == 0)
587                         mHealthdConfig->batteryPresentPath = path;
588                 }
589 
590                 if (mHealthdConfig->batteryCapacityPath.isEmpty()) {
591                     path.clear();
592                     path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
593                                       name);
594                     if (access(path, R_OK) == 0)
595                         mHealthdConfig->batteryCapacityPath = path;
596                 }
597 
598                 if (mHealthdConfig->batteryVoltagePath.isEmpty()) {
599                     path.clear();
600                     path.appendFormat("%s/%s/voltage_now",
601                                       POWER_SUPPLY_SYSFS_PATH, name);
602                     if (access(path, R_OK) == 0) {
603                         mHealthdConfig->batteryVoltagePath = path;
604                     }
605                 }
606 
607                 if (mHealthdConfig->batteryFullChargePath.isEmpty()) {
608                     path.clear();
609                     path.appendFormat("%s/%s/charge_full",
610                                       POWER_SUPPLY_SYSFS_PATH, name);
611                     if (access(path, R_OK) == 0)
612                         mHealthdConfig->batteryFullChargePath = path;
613                 }
614 
615                 if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
616                     path.clear();
617                     path.appendFormat("%s/%s/current_now",
618                                       POWER_SUPPLY_SYSFS_PATH, name);
619                     if (access(path, R_OK) == 0)
620                         mHealthdConfig->batteryCurrentNowPath = path;
621                 }
622 
623                 if (mHealthdConfig->batteryCycleCountPath.isEmpty()) {
624                     path.clear();
625                     path.appendFormat("%s/%s/cycle_count",
626                                       POWER_SUPPLY_SYSFS_PATH, name);
627                     if (access(path, R_OK) == 0)
628                         mHealthdConfig->batteryCycleCountPath = path;
629                 }
630 
631                 if (mHealthdConfig->batteryCapacityLevelPath.isEmpty()) {
632                     path.clear();
633                     path.appendFormat("%s/%s/capacity_level", POWER_SUPPLY_SYSFS_PATH, name);
634                     if (access(path, R_OK) == 0) mHealthdConfig->batteryCapacityLevelPath = path;
635                 }
636 
637                 if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty()) {
638                     path.clear();
639                     path.appendFormat("%s/%s/time_to_full_now", POWER_SUPPLY_SYSFS_PATH, name);
640                     if (access(path, R_OK) == 0)
641                         mHealthdConfig->batteryChargeTimeToFullNowPath = path;
642                 }
643 
644                 if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty()) {
645                     path.clear();
646                     path.appendFormat("%s/%s/charge_full_design", POWER_SUPPLY_SYSFS_PATH, name);
647                     if (access(path, R_OK) == 0)
648                         mHealthdConfig->batteryFullChargeDesignCapacityUahPath = path;
649                 }
650 
651                 if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
652                     path.clear();
653                     path.appendFormat("%s/%s/current_avg",
654                                       POWER_SUPPLY_SYSFS_PATH, name);
655                     if (access(path, R_OK) == 0)
656                         mHealthdConfig->batteryCurrentAvgPath = path;
657                 }
658 
659                 if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
660                     path.clear();
661                     path.appendFormat("%s/%s/charge_counter",
662                                       POWER_SUPPLY_SYSFS_PATH, name);
663                     if (access(path, R_OK) == 0)
664                         mHealthdConfig->batteryChargeCounterPath = path;
665                 }
666 
667                 if (mHealthdConfig->batteryTemperaturePath.isEmpty()) {
668                     path.clear();
669                     path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,
670                                       name);
671                     if (access(path, R_OK) == 0) {
672                         mHealthdConfig->batteryTemperaturePath = path;
673                     }
674                 }
675 
676                 if (mHealthdConfig->batteryTechnologyPath.isEmpty()) {
677                     path.clear();
678                     path.appendFormat("%s/%s/technology",
679                                       POWER_SUPPLY_SYSFS_PATH, name);
680                     if (access(path, R_OK) == 0)
681                         mHealthdConfig->batteryTechnologyPath = path;
682                 }
683 
684                 break;
685 
686             case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
687                 break;
688             }
689         }
690     }
691 
692     // Typically the case for devices which do not have a battery and
693     // and are always plugged into AC mains.
694     if (!mBatteryDevicePresent) {
695         KLOG_WARNING(LOG_TAG, "No battery devices found\n");
696         hc->periodic_chores_interval_fast = -1;
697         hc->periodic_chores_interval_slow = -1;
698     } else {
699         if (mHealthdConfig->batteryStatusPath.isEmpty())
700             KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
701         if (mHealthdConfig->batteryHealthPath.isEmpty())
702             KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
703         if (mHealthdConfig->batteryPresentPath.isEmpty())
704             KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
705         if (mHealthdConfig->batteryCapacityPath.isEmpty())
706             KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
707         if (mHealthdConfig->batteryVoltagePath.isEmpty())
708             KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
709         if (mHealthdConfig->batteryTemperaturePath.isEmpty())
710             KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
711         if (mHealthdConfig->batteryTechnologyPath.isEmpty())
712             KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
713         if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
714             KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
715         if (mHealthdConfig->batteryFullChargePath.isEmpty())
716             KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
717         if (mHealthdConfig->batteryCycleCountPath.isEmpty())
718             KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n");
719         if (mHealthdConfig->batteryCapacityLevelPath.isEmpty())
720             KLOG_WARNING(LOG_TAG, "batteryCapacityLevelPath not found\n");
721         if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
722             KLOG_WARNING(LOG_TAG, "batteryChargeTimeToFullNowPath. not found\n");
723         if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
724             KLOG_WARNING(LOG_TAG, "batteryFullChargeDesignCapacityUahPath. not found\n");
725     }
726 
727     if (property_get("ro.boot.fake_battery", pval, NULL) > 0
728                                                && strtol(pval, NULL, 10) != 0) {
729         mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY;
730         mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
731     }
732 }
733 
734 }; // namespace android
735