• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <batteryservice/BatteryService.h>
31 #include <cutils/klog.h>
32 #include <cutils/properties.h>
33 #include <utils/Errors.h>
34 #include <utils/String8.h>
35 #include <utils/Vector.h>
36 
37 #define POWER_SUPPLY_SUBSYSTEM "power_supply"
38 #define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
39 #define FAKE_BATTERY_CAPACITY 42
40 #define FAKE_BATTERY_TEMPERATURE 424
41 #define ALWAYS_PLUGGED_CAPACITY 100
42 #define MILLION 1.0e6
43 #define DEFAULT_VBUS_VOLTAGE 5000000
44 
45 namespace android {
46 
47 struct sysfsStringEnumMap {
48     const char* s;
49     int val;
50 };
51 
mapSysfsString(const char * str,struct sysfsStringEnumMap map[])52 static int mapSysfsString(const char* str,
53                           struct sysfsStringEnumMap map[]) {
54     for (int i = 0; map[i].s; i++)
55         if (!strcmp(str, map[i].s))
56             return map[i].val;
57 
58     return -1;
59 }
60 
initBatteryProperties(BatteryProperties * props)61 static void initBatteryProperties(BatteryProperties* props) {
62     props->chargerAcOnline = false;
63     props->chargerUsbOnline = false;
64     props->chargerWirelessOnline = false;
65     props->maxChargingCurrent = 0;
66     props->maxChargingVoltage = 0;
67     props->batteryStatus = BATTERY_STATUS_UNKNOWN;
68     props->batteryHealth = BATTERY_HEALTH_UNKNOWN;
69     props->batteryPresent = false;
70     props->batteryLevel = 0;
71     props->batteryVoltage = 0;
72     props->batteryTemperature = 0;
73     props->batteryCurrent = 0;
74     props->batteryCycleCount = 0;
75     props->batteryFullCharge = 0;
76     props->batteryChargeCounter = 0;
77     props->batteryTechnology.clear();
78 }
79 
BatteryMonitor()80 BatteryMonitor::BatteryMonitor() : mHealthdConfig(nullptr), mBatteryDevicePresent(false),
81     mAlwaysPluggedDevice(false), mBatteryFixedCapacity(0), mBatteryFixedTemperature(0) {
82     initBatteryProperties(&props);
83 }
84 
getBatteryStatus(const char * status)85 int BatteryMonitor::getBatteryStatus(const char* status) {
86     int ret;
87     struct sysfsStringEnumMap batteryStatusMap[] = {
88         { "Unknown", BATTERY_STATUS_UNKNOWN },
89         { "Charging", BATTERY_STATUS_CHARGING },
90         { "Discharging", BATTERY_STATUS_DISCHARGING },
91         { "Not charging", BATTERY_STATUS_NOT_CHARGING },
92         { "Full", BATTERY_STATUS_FULL },
93         { NULL, 0 },
94     };
95 
96     ret = mapSysfsString(status, batteryStatusMap);
97     if (ret < 0) {
98         KLOG_WARNING(LOG_TAG, "Unknown battery status '%s'\n", status);
99         ret = BATTERY_STATUS_UNKNOWN;
100     }
101 
102     return ret;
103 }
104 
getBatteryHealth(const char * status)105 int BatteryMonitor::getBatteryHealth(const char* status) {
106     int ret;
107     struct sysfsStringEnumMap batteryHealthMap[] = {
108         { "Unknown", BATTERY_HEALTH_UNKNOWN },
109         { "Good", BATTERY_HEALTH_GOOD },
110         { "Overheat", BATTERY_HEALTH_OVERHEAT },
111         { "Dead", BATTERY_HEALTH_DEAD },
112         { "Over voltage", BATTERY_HEALTH_OVER_VOLTAGE },
113         { "Unspecified failure", BATTERY_HEALTH_UNSPECIFIED_FAILURE },
114         { "Cold", BATTERY_HEALTH_COLD },
115         { NULL, 0 },
116     };
117 
118     ret = mapSysfsString(status, batteryHealthMap);
119     if (ret < 0) {
120         KLOG_WARNING(LOG_TAG, "Unknown battery health '%s'\n", status);
121         ret = BATTERY_HEALTH_UNKNOWN;
122     }
123 
124     return ret;
125 }
126 
readFromFile(const String8 & path,char * buf,size_t size)127 int BatteryMonitor::readFromFile(const String8& path, char* buf, size_t size) {
128     char *cp = NULL;
129 
130     if (path.isEmpty())
131         return -1;
132     int fd = open(path.string(), O_RDONLY, 0);
133     if (fd == -1) {
134         KLOG_ERROR(LOG_TAG, "Could not open '%s'\n", path.string());
135         return -1;
136     }
137 
138     ssize_t count = TEMP_FAILURE_RETRY(read(fd, buf, size));
139     if (count > 0)
140             cp = (char *)memrchr(buf, '\n', count);
141 
142     if (cp)
143         *cp = '\0';
144     else
145         buf[0] = '\0';
146 
147     close(fd);
148     return count;
149 }
150 
readPowerSupplyType(const String8 & path)151 BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String8& path) {
152     const int SIZE = 128;
153     char buf[SIZE];
154     int length = readFromFile(path, buf, SIZE);
155     BatteryMonitor::PowerSupplyType ret;
156     struct sysfsStringEnumMap supplyTypeMap[] = {
157             { "Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN },
158             { "Battery", ANDROID_POWER_SUPPLY_TYPE_BATTERY },
159             { "UPS", ANDROID_POWER_SUPPLY_TYPE_AC },
160             { "Mains", ANDROID_POWER_SUPPLY_TYPE_AC },
161             { "USB", ANDROID_POWER_SUPPLY_TYPE_USB },
162             { "USB_DCP", ANDROID_POWER_SUPPLY_TYPE_AC },
163             { "USB_HVDCP", ANDROID_POWER_SUPPLY_TYPE_AC },
164             { "USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC },
165             { "USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC },
166             { "USB_C", ANDROID_POWER_SUPPLY_TYPE_AC },
167             { "USB_PD", ANDROID_POWER_SUPPLY_TYPE_AC },
168             { "USB_PD_DRP", ANDROID_POWER_SUPPLY_TYPE_USB },
169             { "Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS },
170             { NULL, 0 },
171     };
172 
173     if (length <= 0)
174         return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
175 
176     ret = (BatteryMonitor::PowerSupplyType)mapSysfsString(buf, supplyTypeMap);
177     if (ret < 0) {
178         KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf);
179         ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
180     }
181 
182     return ret;
183 }
184 
getBooleanField(const String8 & path)185 bool BatteryMonitor::getBooleanField(const String8& path) {
186     const int SIZE = 16;
187     char buf[SIZE];
188 
189     bool value = false;
190     if (readFromFile(path, buf, SIZE) > 0) {
191         if (buf[0] != '0') {
192             value = true;
193         }
194     }
195 
196     return value;
197 }
198 
getIntField(const String8 & path)199 int BatteryMonitor::getIntField(const String8& path) {
200     const int SIZE = 128;
201     char buf[SIZE];
202 
203     int value = 0;
204     if (readFromFile(path, buf, SIZE) > 0) {
205         value = strtol(buf, NULL, 0);
206     }
207     return value;
208 }
209 
update(void)210 bool BatteryMonitor::update(void) {
211     bool logthis;
212 
213     initBatteryProperties(&props);
214 
215     if (!mHealthdConfig->batteryPresentPath.isEmpty())
216         props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
217     else
218         props.batteryPresent = mBatteryDevicePresent;
219 
220     props.batteryLevel = mBatteryFixedCapacity ?
221         mBatteryFixedCapacity :
222         getIntField(mHealthdConfig->batteryCapacityPath);
223     props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
224 
225     if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
226         props.batteryCurrent = getIntField(mHealthdConfig->batteryCurrentNowPath) / 1000;
227 
228     if (!mHealthdConfig->batteryFullChargePath.isEmpty())
229         props.batteryFullCharge = getIntField(mHealthdConfig->batteryFullChargePath);
230 
231     if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
232         props.batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
233 
234     if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
235         props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);
236 
237     props.batteryTemperature = mBatteryFixedTemperature ?
238         mBatteryFixedTemperature :
239         getIntField(mHealthdConfig->batteryTemperaturePath);
240 
241     // For devices which do not have battery and are always plugged
242     // into power souce.
243     if (mAlwaysPluggedDevice) {
244         props.chargerAcOnline = true;
245         props.batteryPresent = true;
246         props.batteryStatus = BATTERY_STATUS_CHARGING;
247         props.batteryHealth = BATTERY_HEALTH_GOOD;
248     }
249 
250     const int SIZE = 128;
251     char buf[SIZE];
252     String8 btech;
253 
254     if (readFromFile(mHealthdConfig->batteryStatusPath, buf, SIZE) > 0)
255         props.batteryStatus = getBatteryStatus(buf);
256 
257     if (readFromFile(mHealthdConfig->batteryHealthPath, buf, SIZE) > 0)
258         props.batteryHealth = getBatteryHealth(buf);
259 
260     if (readFromFile(mHealthdConfig->batteryTechnologyPath, buf, SIZE) > 0)
261         props.batteryTechnology = String8(buf);
262 
263     unsigned int i;
264     double MaxPower = 0;
265 
266     for (i = 0; i < mChargerNames.size(); i++) {
267         String8 path;
268         path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
269                           mChargerNames[i].string());
270 
271         if (readFromFile(path, buf, SIZE) > 0) {
272             if (buf[0] != '0') {
273                 path.clear();
274                 path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
275                                   mChargerNames[i].string());
276                 switch(readPowerSupplyType(path)) {
277                 case ANDROID_POWER_SUPPLY_TYPE_AC:
278                     props.chargerAcOnline = true;
279                     break;
280                 case ANDROID_POWER_SUPPLY_TYPE_USB:
281                     props.chargerUsbOnline = true;
282                     break;
283                 case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
284                     props.chargerWirelessOnline = true;
285                     break;
286                 default:
287                     KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
288                                  mChargerNames[i].string());
289                 }
290                 path.clear();
291                 path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
292                                   mChargerNames[i].string());
293                 int ChargingCurrent =
294                     (access(path.string(), R_OK) == 0) ? getIntField(path) : 0;
295 
296                 path.clear();
297                 path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
298                                   mChargerNames[i].string());
299 
300                 int ChargingVoltage =
301                     (access(path.string(), R_OK) == 0) ? getIntField(path) :
302                     DEFAULT_VBUS_VOLTAGE;
303 
304                 double power = ((double)ChargingCurrent / MILLION) *
305                         ((double)ChargingVoltage / MILLION);
306                 if (MaxPower < power) {
307                     props.maxChargingCurrent = ChargingCurrent;
308                     props.maxChargingVoltage = ChargingVoltage;
309                     MaxPower = power;
310                 }
311             }
312         }
313     }
314 
315     logthis = !healthd_board_battery_update(&props);
316 
317     if (logthis) {
318         char dmesgline[256];
319         size_t len;
320         if (props.batteryPresent) {
321             snprintf(dmesgline, sizeof(dmesgline),
322                  "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
323                  props.batteryLevel, props.batteryVoltage,
324                  props.batteryTemperature < 0 ? "-" : "",
325                  abs(props.batteryTemperature / 10),
326                  abs(props.batteryTemperature % 10), props.batteryHealth,
327                  props.batteryStatus);
328 
329             len = strlen(dmesgline);
330             if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
331                 len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
332                                 " c=%d", props.batteryCurrent);
333             }
334 
335             if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
336                 len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
337                                 " fc=%d", props.batteryFullCharge);
338             }
339 
340             if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
341                 len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
342                                 " cc=%d", props.batteryCycleCount);
343             }
344         } else {
345             snprintf(dmesgline, sizeof(dmesgline),
346                  "battery none");
347         }
348 
349         len = strlen(dmesgline);
350         snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
351                  props.chargerAcOnline ? "a" : "",
352                  props.chargerUsbOnline ? "u" : "",
353                  props.chargerWirelessOnline ? "w" : "");
354 
355         KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
356     }
357 
358     healthd_mode_ops->battery_update(&props);
359     return props.chargerAcOnline | props.chargerUsbOnline |
360             props.chargerWirelessOnline;
361 }
362 
getChargeStatus()363 int BatteryMonitor::getChargeStatus() {
364     int result = BATTERY_STATUS_UNKNOWN;
365     if (!mHealthdConfig->batteryStatusPath.isEmpty()) {
366         char buf[128];
367         if (readFromFile(mHealthdConfig->batteryStatusPath, buf, sizeof(buf)) > 0) {
368             result = getBatteryStatus(buf);
369         }
370     }
371     return result;
372 }
373 
getProperty(int id,struct BatteryProperty * val)374 status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
375     status_t ret = BAD_VALUE;
376 
377     val->valueInt64 = LONG_MIN;
378 
379     switch(id) {
380     case BATTERY_PROP_CHARGE_COUNTER:
381         if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
382             val->valueInt64 =
383                 getIntField(mHealthdConfig->batteryChargeCounterPath);
384             ret = NO_ERROR;
385         } else {
386             ret = NAME_NOT_FOUND;
387         }
388         break;
389 
390     case BATTERY_PROP_CURRENT_NOW:
391         if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
392             val->valueInt64 =
393                 getIntField(mHealthdConfig->batteryCurrentNowPath);
394             ret = NO_ERROR;
395         } else {
396             ret = NAME_NOT_FOUND;
397         }
398         break;
399 
400     case BATTERY_PROP_CURRENT_AVG:
401         if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
402             val->valueInt64 =
403                 getIntField(mHealthdConfig->batteryCurrentAvgPath);
404             ret = NO_ERROR;
405         } else {
406             ret = NAME_NOT_FOUND;
407         }
408         break;
409 
410     case BATTERY_PROP_CAPACITY:
411         if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
412             val->valueInt64 =
413                 getIntField(mHealthdConfig->batteryCapacityPath);
414             ret = NO_ERROR;
415         } else {
416             ret = NAME_NOT_FOUND;
417         }
418         break;
419 
420     case BATTERY_PROP_ENERGY_COUNTER:
421         if (mHealthdConfig->energyCounter) {
422             ret = mHealthdConfig->energyCounter(&val->valueInt64);
423         } else {
424             ret = NAME_NOT_FOUND;
425         }
426         break;
427 
428     default:
429         break;
430     }
431 
432     return ret;
433 }
434 
dumpState(int fd)435 void BatteryMonitor::dumpState(int fd) {
436     int v;
437     char vs[128];
438 
439     snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d current_max: %d voltage_max: %d\n",
440              props.chargerAcOnline, props.chargerUsbOnline,
441              props.chargerWirelessOnline, props.maxChargingCurrent,
442              props.maxChargingVoltage);
443     write(fd, vs, strlen(vs));
444     snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
445              props.batteryStatus, props.batteryHealth, props.batteryPresent);
446     write(fd, vs, strlen(vs));
447     snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n",
448              props.batteryLevel, props.batteryVoltage,
449              props.batteryTemperature);
450     write(fd, vs, strlen(vs));
451 
452     if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
453         v = getIntField(mHealthdConfig->batteryCurrentNowPath);
454         snprintf(vs, sizeof(vs), "current now: %d\n", v);
455         write(fd, vs, strlen(vs));
456     }
457 
458     if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
459         v = getIntField(mHealthdConfig->batteryCurrentAvgPath);
460         snprintf(vs, sizeof(vs), "current avg: %d\n", v);
461         write(fd, vs, strlen(vs));
462     }
463 
464     if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
465         v = getIntField(mHealthdConfig->batteryChargeCounterPath);
466         snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
467         write(fd, vs, strlen(vs));
468     }
469 
470     if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
471         snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrent);
472         write(fd, vs, strlen(vs));
473     }
474 
475     if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
476         snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount);
477         write(fd, vs, strlen(vs));
478     }
479 
480     if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
481         snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullCharge);
482         write(fd, vs, strlen(vs));
483     }
484 }
485 
init(struct healthd_config * hc)486 void BatteryMonitor::init(struct healthd_config *hc) {
487     String8 path;
488     char pval[PROPERTY_VALUE_MAX];
489 
490     mHealthdConfig = hc;
491     DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);
492     if (dir == NULL) {
493         KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
494     } else {
495         struct dirent* entry;
496 
497         while ((entry = readdir(dir))) {
498             const char* name = entry->d_name;
499 
500             if (!strcmp(name, ".") || !strcmp(name, ".."))
501                 continue;
502 
503             // Look for "type" file in each subdirectory
504             path.clear();
505             path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
506             switch(readPowerSupplyType(path)) {
507             case ANDROID_POWER_SUPPLY_TYPE_AC:
508             case ANDROID_POWER_SUPPLY_TYPE_USB:
509             case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
510                 path.clear();
511                 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
512                 if (access(path.string(), R_OK) == 0)
513                     mChargerNames.add(String8(name));
514                 break;
515 
516             case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
517                 mBatteryDevicePresent = true;
518 
519                 if (mHealthdConfig->batteryStatusPath.isEmpty()) {
520                     path.clear();
521                     path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
522                                       name);
523                     if (access(path, R_OK) == 0)
524                         mHealthdConfig->batteryStatusPath = path;
525                 }
526 
527                 if (mHealthdConfig->batteryHealthPath.isEmpty()) {
528                     path.clear();
529                     path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
530                                       name);
531                     if (access(path, R_OK) == 0)
532                         mHealthdConfig->batteryHealthPath = path;
533                 }
534 
535                 if (mHealthdConfig->batteryPresentPath.isEmpty()) {
536                     path.clear();
537                     path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
538                                       name);
539                     if (access(path, R_OK) == 0)
540                         mHealthdConfig->batteryPresentPath = path;
541                 }
542 
543                 if (mHealthdConfig->batteryCapacityPath.isEmpty()) {
544                     path.clear();
545                     path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
546                                       name);
547                     if (access(path, R_OK) == 0)
548                         mHealthdConfig->batteryCapacityPath = path;
549                 }
550 
551                 if (mHealthdConfig->batteryVoltagePath.isEmpty()) {
552                     path.clear();
553                     path.appendFormat("%s/%s/voltage_now",
554                                       POWER_SUPPLY_SYSFS_PATH, name);
555                     if (access(path, R_OK) == 0) {
556                         mHealthdConfig->batteryVoltagePath = path;
557                     } else {
558                         path.clear();
559                         path.appendFormat("%s/%s/batt_vol",
560                                           POWER_SUPPLY_SYSFS_PATH, name);
561                         if (access(path, R_OK) == 0)
562                             mHealthdConfig->batteryVoltagePath = path;
563                     }
564                 }
565 
566                 if (mHealthdConfig->batteryFullChargePath.isEmpty()) {
567                     path.clear();
568                     path.appendFormat("%s/%s/charge_full",
569                                       POWER_SUPPLY_SYSFS_PATH, name);
570                     if (access(path, R_OK) == 0)
571                         mHealthdConfig->batteryFullChargePath = path;
572                 }
573 
574                 if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
575                     path.clear();
576                     path.appendFormat("%s/%s/current_now",
577                                       POWER_SUPPLY_SYSFS_PATH, name);
578                     if (access(path, R_OK) == 0)
579                         mHealthdConfig->batteryCurrentNowPath = path;
580                 }
581 
582                 if (mHealthdConfig->batteryCycleCountPath.isEmpty()) {
583                     path.clear();
584                     path.appendFormat("%s/%s/cycle_count",
585                                       POWER_SUPPLY_SYSFS_PATH, name);
586                     if (access(path, R_OK) == 0)
587                         mHealthdConfig->batteryCycleCountPath = path;
588                 }
589 
590                 if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
591                     path.clear();
592                     path.appendFormat("%s/%s/current_avg",
593                                       POWER_SUPPLY_SYSFS_PATH, name);
594                     if (access(path, R_OK) == 0)
595                         mHealthdConfig->batteryCurrentAvgPath = path;
596                 }
597 
598                 if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
599                     path.clear();
600                     path.appendFormat("%s/%s/charge_counter",
601                                       POWER_SUPPLY_SYSFS_PATH, name);
602                     if (access(path, R_OK) == 0)
603                         mHealthdConfig->batteryChargeCounterPath = path;
604                 }
605 
606                 if (mHealthdConfig->batteryTemperaturePath.isEmpty()) {
607                     path.clear();
608                     path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,
609                                       name);
610                     if (access(path, R_OK) == 0) {
611                         mHealthdConfig->batteryTemperaturePath = path;
612                     } else {
613                         path.clear();
614                         path.appendFormat("%s/%s/batt_temp",
615                                           POWER_SUPPLY_SYSFS_PATH, name);
616                         if (access(path, R_OK) == 0)
617                             mHealthdConfig->batteryTemperaturePath = path;
618                     }
619                 }
620 
621                 if (mHealthdConfig->batteryTechnologyPath.isEmpty()) {
622                     path.clear();
623                     path.appendFormat("%s/%s/technology",
624                                       POWER_SUPPLY_SYSFS_PATH, name);
625                     if (access(path, R_OK) == 0)
626                         mHealthdConfig->batteryTechnologyPath = path;
627                 }
628 
629                 break;
630 
631             case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
632                 break;
633             }
634         }
635         closedir(dir);
636     }
637 
638     // Typically the case for devices which do not have a battery and
639     // and are always plugged into AC mains.
640     if (!mBatteryDevicePresent) {
641         KLOG_WARNING(LOG_TAG, "No battery devices found\n");
642         hc->periodic_chores_interval_fast = -1;
643         hc->periodic_chores_interval_slow = -1;
644         mBatteryFixedCapacity = ALWAYS_PLUGGED_CAPACITY;
645         mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
646         mAlwaysPluggedDevice = true;
647     } else {
648         if (mHealthdConfig->batteryStatusPath.isEmpty())
649             KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
650         if (mHealthdConfig->batteryHealthPath.isEmpty())
651             KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
652         if (mHealthdConfig->batteryPresentPath.isEmpty())
653             KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
654         if (mHealthdConfig->batteryCapacityPath.isEmpty())
655             KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
656         if (mHealthdConfig->batteryVoltagePath.isEmpty())
657             KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
658         if (mHealthdConfig->batteryTemperaturePath.isEmpty())
659             KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
660         if (mHealthdConfig->batteryTechnologyPath.isEmpty())
661             KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
662         if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
663             KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
664         if (mHealthdConfig->batteryFullChargePath.isEmpty())
665             KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
666         if (mHealthdConfig->batteryCycleCountPath.isEmpty())
667             KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n");
668     }
669 
670     if (property_get("ro.boot.fake_battery", pval, NULL) > 0
671                                                && strtol(pval, NULL, 10) != 0) {
672         mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY;
673         mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
674     }
675 }
676 
677 }; // namespace android
678