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