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 <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::BatteryChargingPolicy;
59 using aidl::android::hardware::health::BatteryChargingState;
60 using aidl::android::hardware::health::BatteryHealth;
61 using aidl::android::hardware::health::BatteryHealthData;
62 using aidl::android::hardware::health::BatteryStatus;
63 using aidl::android::hardware::health::HealthInfo;
64
65 namespace {
66
67 // Translate from AIDL back to HIDL definition for getHealthInfo_*_* calls.
68 // Skips storageInfo and diskStats.
translateToHidl(const::aidl::android::hardware::health::HealthInfo & in,::android::hardware::health::V1_0::HealthInfo * out)69 void translateToHidl(const ::aidl::android::hardware::health::HealthInfo& in,
70 ::android::hardware::health::V1_0::HealthInfo* out) {
71 out->chargerAcOnline = in.chargerAcOnline;
72 out->chargerUsbOnline = in.chargerUsbOnline;
73 out->chargerWirelessOnline = in.chargerWirelessOnline;
74 out->maxChargingCurrent = in.maxChargingCurrentMicroamps;
75 out->maxChargingVoltage = in.maxChargingVoltageMicrovolts;
76 out->batteryStatus =
77 static_cast<::android::hardware::health::V1_0::BatteryStatus>(in.batteryStatus);
78 out->batteryHealth =
79 static_cast<::android::hardware::health::V1_0::BatteryHealth>(in.batteryHealth);
80 out->batteryPresent = in.batteryPresent;
81 out->batteryLevel = in.batteryLevel;
82 out->batteryVoltage = in.batteryVoltageMillivolts;
83 out->batteryTemperature = in.batteryTemperatureTenthsCelsius;
84 out->batteryCurrent = in.batteryCurrentMicroamps;
85 out->batteryCycleCount = in.batteryCycleCount;
86 out->batteryFullCharge = in.batteryFullChargeUah;
87 out->batteryChargeCounter = in.batteryChargeCounterUah;
88 out->batteryTechnology = in.batteryTechnology;
89 }
90
translateToHidl(const::aidl::android::hardware::health::HealthInfo & in,::android::hardware::health::V2_0::HealthInfo * out)91 void translateToHidl(const ::aidl::android::hardware::health::HealthInfo& in,
92 ::android::hardware::health::V2_0::HealthInfo* out) {
93 translateToHidl(in, &out->legacy);
94 out->batteryCurrentAverage = in.batteryCurrentAverageMicroamps;
95 // Skip storageInfo and diskStats
96 }
97
translateToHidl(const::aidl::android::hardware::health::HealthInfo & in,::android::hardware::health::V2_1::HealthInfo * out)98 void translateToHidl(const ::aidl::android::hardware::health::HealthInfo& in,
99 ::android::hardware::health::V2_1::HealthInfo* out) {
100 translateToHidl(in, &out->legacy);
101 out->batteryCapacityLevel = static_cast<android::hardware::health::V2_1::BatteryCapacityLevel>(
102 in.batteryCapacityLevel);
103 out->batteryChargeTimeToFullNowSeconds = in.batteryChargeTimeToFullNowSeconds;
104 out->batteryFullChargeDesignCapacityUah = in.batteryFullChargeDesignCapacityUah;
105 }
106
107 } // namespace
108
109 namespace android {
110
111 template <typename T>
112 struct SysfsStringEnumMap {
113 const char* s;
114 T val;
115 };
116
117 template <typename T>
mapSysfsString(const char * str,SysfsStringEnumMap<T> map[])118 static std::optional<T> mapSysfsString(const char* str, SysfsStringEnumMap<T> map[]) {
119 for (int i = 0; map[i].s; i++)
120 if (!strcmp(str, map[i].s))
121 return map[i].val;
122
123 return std::nullopt;
124 }
125
initHealthInfo(HealthInfo * health_info)126 static void initHealthInfo(HealthInfo* health_info) {
127 *health_info = {
128 .batteryCapacityLevel = BatteryCapacityLevel::UNSUPPORTED,
129 .batteryChargeTimeToFullNowSeconds =
130 (int64_t)HealthInfo::BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED,
131 .batteryStatus = BatteryStatus::UNKNOWN,
132 .batteryHealth = BatteryHealth::UNKNOWN,
133 };
134 }
135
BatteryMonitor()136 BatteryMonitor::BatteryMonitor()
137 : mHealthdConfig(nullptr),
138 mBatteryDevicePresent(false),
139 mBatteryFixedCapacity(0),
140 mBatteryFixedTemperature(0),
141 mBatteryHealthStatus(BatteryMonitor::BH_UNKNOWN),
142 mHealthInfo(std::make_unique<HealthInfo>()) {
143 initHealthInfo(mHealthInfo.get());
144 }
145
~BatteryMonitor()146 BatteryMonitor::~BatteryMonitor() {}
147
getHealthInfo_1_0() const148 HealthInfo_1_0 BatteryMonitor::getHealthInfo_1_0() const {
149 HealthInfo_1_0 health_info_1_0;
150 translateToHidl(*mHealthInfo, &health_info_1_0);
151 return health_info_1_0;
152 }
153
getHealthInfo_2_0() const154 HealthInfo_2_0 BatteryMonitor::getHealthInfo_2_0() const {
155 HealthInfo_2_0 health_info_2_0;
156 translateToHidl(*mHealthInfo, &health_info_2_0);
157 return health_info_2_0;
158 }
159
getHealthInfo_2_1() const160 HealthInfo_2_1 BatteryMonitor::getHealthInfo_2_1() const {
161 HealthInfo_2_1 health_info_2_1;
162 translateToHidl(*mHealthInfo, &health_info_2_1);
163 return health_info_2_1;
164 }
165
getHealthInfo() const166 const HealthInfo& BatteryMonitor::getHealthInfo() const {
167 return *mHealthInfo;
168 }
169
getBatteryStatus(const char * status)170 BatteryStatus getBatteryStatus(const char* status) {
171 static SysfsStringEnumMap<BatteryStatus> batteryStatusMap[] = {
172 {"Unknown", BatteryStatus::UNKNOWN},
173 {"Charging", BatteryStatus::CHARGING},
174 {"Discharging", BatteryStatus::DISCHARGING},
175 {"Not charging", BatteryStatus::NOT_CHARGING},
176 {"Full", BatteryStatus::FULL},
177 {NULL, BatteryStatus::UNKNOWN},
178 };
179
180 auto ret = mapSysfsString(status, batteryStatusMap);
181 if (!ret) {
182 KLOG_WARNING(LOG_TAG, "Unknown battery status '%s'\n", status);
183 *ret = BatteryStatus::UNKNOWN;
184 }
185
186 return *ret;
187 }
188
getBatteryCapacityLevel(const char * capacityLevel)189 BatteryCapacityLevel getBatteryCapacityLevel(const char* capacityLevel) {
190 static SysfsStringEnumMap<BatteryCapacityLevel> batteryCapacityLevelMap[] = {
191 {"Unknown", BatteryCapacityLevel::UNKNOWN},
192 {"Critical", BatteryCapacityLevel::CRITICAL},
193 {"Low", BatteryCapacityLevel::LOW},
194 {"Normal", BatteryCapacityLevel::NORMAL},
195 {"High", BatteryCapacityLevel::HIGH},
196 {"Full", BatteryCapacityLevel::FULL},
197 {NULL, BatteryCapacityLevel::UNSUPPORTED},
198 };
199
200 auto ret = mapSysfsString(capacityLevel, batteryCapacityLevelMap);
201 if (!ret) {
202 KLOG_WARNING(LOG_TAG, "Unsupported battery capacity level '%s'\n", capacityLevel);
203 *ret = BatteryCapacityLevel::UNSUPPORTED;
204 }
205
206 return *ret;
207 }
208
getBatteryHealth(const char * status)209 BatteryHealth getBatteryHealth(const char* status) {
210 static SysfsStringEnumMap<BatteryHealth> batteryHealthMap[] = {
211 {"Unknown", BatteryHealth::UNKNOWN},
212 {"Good", BatteryHealth::GOOD},
213 {"Overheat", BatteryHealth::OVERHEAT},
214 {"Dead", BatteryHealth::DEAD},
215 {"Over voltage", BatteryHealth::OVER_VOLTAGE},
216 {"Unspecified failure", BatteryHealth::UNSPECIFIED_FAILURE},
217 {"Cold", BatteryHealth::COLD},
218 // battery health values from JEITA spec
219 {"Warm", BatteryHealth::GOOD},
220 {"Cool", BatteryHealth::GOOD},
221 {"Hot", BatteryHealth::OVERHEAT},
222 {NULL, BatteryHealth::UNKNOWN},
223 };
224
225 auto ret = mapSysfsString(status, batteryHealthMap);
226 if (!ret) {
227 KLOG_WARNING(LOG_TAG, "Unknown battery health '%s'\n", status);
228 *ret = BatteryHealth::UNKNOWN;
229 }
230
231 return *ret;
232 }
233
getBatteryHealthStatus(int status)234 BatteryHealth getBatteryHealthStatus(int status) {
235 BatteryHealth value;
236
237 if (status == BatteryMonitor::BH_NOMINAL)
238 value = BatteryHealth::GOOD;
239 else if (status == BatteryMonitor::BH_MARGINAL)
240 value = BatteryHealth::FAIR;
241 else if (status == BatteryMonitor::BH_NEEDS_REPLACEMENT)
242 value = BatteryHealth::DEAD;
243 else if (status == BatteryMonitor::BH_FAILED)
244 value = BatteryHealth::UNSPECIFIED_FAILURE;
245 else if (status == BatteryMonitor::BH_NOT_AVAILABLE)
246 value = BatteryHealth::NOT_AVAILABLE;
247 else if (status == BatteryMonitor::BH_INCONSISTENT)
248 value = BatteryHealth::INCONSISTENT;
249 else
250 value = BatteryHealth::UNKNOWN;
251
252 return value;
253 }
254
getBatteryChargingPolicy(const char * chargingPolicy)255 BatteryChargingPolicy getBatteryChargingPolicy(const char* chargingPolicy) {
256 static SysfsStringEnumMap<BatteryChargingPolicy> batteryChargingPolicyMap[] = {
257 {"0", BatteryChargingPolicy::INVALID}, {"1", BatteryChargingPolicy::DEFAULT},
258 {"2", BatteryChargingPolicy::LONG_LIFE}, {"3", BatteryChargingPolicy::ADAPTIVE},
259 {NULL, BatteryChargingPolicy::DEFAULT},
260 };
261
262 auto ret = mapSysfsString(chargingPolicy, batteryChargingPolicyMap);
263 if (!ret) {
264 *ret = BatteryChargingPolicy::DEFAULT;
265 }
266
267 return *ret;
268 }
269
getBatteryChargingState(const char * chargingState)270 BatteryChargingState getBatteryChargingState(const char* chargingState) {
271 static SysfsStringEnumMap<BatteryChargingState> batteryChargingStateMap[] = {
272 {"0", BatteryChargingState::INVALID}, {"1", BatteryChargingState::NORMAL},
273 {"2", BatteryChargingState::TOO_COLD}, {"3", BatteryChargingState::TOO_HOT},
274 {"4", BatteryChargingState::LONG_LIFE}, {"5", BatteryChargingState::ADAPTIVE},
275 {NULL, BatteryChargingState::NORMAL},
276 };
277
278 auto ret = mapSysfsString(chargingState, batteryChargingStateMap);
279 if (!ret) {
280 *ret = BatteryChargingState::NORMAL;
281 }
282
283 return *ret;
284 }
285
readFromFile(const String8 & path,std::string * buf)286 static int readFromFile(const String8& path, std::string* buf) {
287 buf->clear();
288 if (android::base::ReadFileToString(path.c_str(), buf)) {
289 *buf = android::base::Trim(*buf);
290 }
291 return buf->length();
292 }
293
writeToFile(const String8 & path,int32_t in_value)294 static bool writeToFile(const String8& path, int32_t in_value) {
295 return android::base::WriteStringToFile(std::to_string(in_value), path.c_str());
296 }
297
readPowerSupplyType(const String8 & path)298 static BatteryMonitor::PowerSupplyType readPowerSupplyType(const String8& path) {
299 static SysfsStringEnumMap<int> supplyTypeMap[] = {
300 {"Unknown", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_UNKNOWN},
301 {"Battery", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_BATTERY},
302 {"UPS", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
303 {"Mains", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
304 {"USB", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_USB},
305 {"USB_DCP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
306 {"USB_HVDCP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
307 {"USB_CDP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
308 {"USB_ACA", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
309 {"USB_C", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
310 {"USB_PD", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
311 {"USB_PD_DRP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_USB},
312 {"Wireless", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_WIRELESS},
313 {"Dock", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_DOCK},
314 {NULL, 0},
315 };
316 std::string buf;
317
318 if (readFromFile(path, &buf) <= 0) {
319 return BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
320 }
321
322 auto ret = mapSysfsString(buf.c_str(), supplyTypeMap);
323 if (!ret) {
324 KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str());
325 *ret = BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
326 }
327
328 return static_cast<BatteryMonitor::PowerSupplyType>(*ret);
329 }
330
getBooleanField(const String8 & path)331 static bool getBooleanField(const String8& path) {
332 std::string buf;
333 bool value = false;
334
335 if (readFromFile(path, &buf) > 0)
336 if (buf[0] != '0')
337 value = true;
338
339 return value;
340 }
341
getIntField(const String8 & path)342 static int getIntField(const String8& path) {
343 std::string buf;
344 int value = 0;
345
346 if (readFromFile(path, &buf) > 0)
347 android::base::ParseInt(buf, &value);
348
349 return value;
350 }
351
isScopedPowerSupply(const char * name)352 static bool isScopedPowerSupply(const char* name) {
353 constexpr char kScopeDevice[] = "Device";
354
355 String8 path;
356 path.appendFormat("%s/%s/scope", POWER_SUPPLY_SYSFS_PATH, name);
357 std::string scope;
358 return (readFromFile(path, &scope) > 0 && scope == kScopeDevice);
359 }
360
updateValues(void)361 void BatteryMonitor::updateValues(void) {
362 initHealthInfo(mHealthInfo.get());
363
364 if (!mHealthdConfig->batteryPresentPath.isEmpty())
365 mHealthInfo->batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
366 else
367 mHealthInfo->batteryPresent = mBatteryDevicePresent;
368
369 mHealthInfo->batteryLevel = mBatteryFixedCapacity
370 ? mBatteryFixedCapacity
371 : getIntField(mHealthdConfig->batteryCapacityPath);
372 mHealthInfo->batteryVoltageMillivolts = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
373
374 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
375 mHealthInfo->batteryCurrentMicroamps = getIntField(mHealthdConfig->batteryCurrentNowPath);
376
377 if (!mHealthdConfig->batteryFullChargePath.isEmpty())
378 mHealthInfo->batteryFullChargeUah = getIntField(mHealthdConfig->batteryFullChargePath);
379
380 if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
381 mHealthInfo->batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
382
383 if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
384 mHealthInfo->batteryChargeCounterUah =
385 getIntField(mHealthdConfig->batteryChargeCounterPath);
386
387 if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty())
388 mHealthInfo->batteryCurrentAverageMicroamps =
389 getIntField(mHealthdConfig->batteryCurrentAvgPath);
390
391 if (!mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
392 mHealthInfo->batteryChargeTimeToFullNowSeconds =
393 getIntField(mHealthdConfig->batteryChargeTimeToFullNowPath);
394
395 if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
396 mHealthInfo->batteryFullChargeDesignCapacityUah =
397 getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath);
398
399 if (!mHealthdConfig->batteryHealthStatusPath.isEmpty())
400 mBatteryHealthStatus = getIntField(mHealthdConfig->batteryHealthStatusPath);
401
402 if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty())
403 mHealthInfo->batteryHealthData->batteryStateOfHealth =
404 getIntField(mHealthdConfig->batteryStateOfHealthPath);
405
406 if (!mHealthdConfig->batteryManufacturingDatePath.isEmpty())
407 mHealthInfo->batteryHealthData->batteryManufacturingDateSeconds =
408 getIntField(mHealthdConfig->batteryManufacturingDatePath);
409
410 if (!mHealthdConfig->batteryFirstUsageDatePath.isEmpty())
411 mHealthInfo->batteryHealthData->batteryFirstUsageSeconds =
412 getIntField(mHealthdConfig->batteryFirstUsageDatePath);
413
414 mHealthInfo->batteryTemperatureTenthsCelsius =
415 mBatteryFixedTemperature ? mBatteryFixedTemperature
416 : getIntField(mHealthdConfig->batteryTemperaturePath);
417
418 std::string buf;
419
420 if (readFromFile(mHealthdConfig->batteryCapacityLevelPath, &buf) > 0)
421 mHealthInfo->batteryCapacityLevel = getBatteryCapacityLevel(buf.c_str());
422
423 if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
424 mHealthInfo->batteryStatus = getBatteryStatus(buf.c_str());
425
426 // Backward compatible with android.hardware.health V1
427 if (mBatteryHealthStatus < BatteryMonitor::BH_MARGINAL) {
428 if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
429 mHealthInfo->batteryHealth = getBatteryHealth(buf.c_str());
430 } else {
431 mHealthInfo->batteryHealth = getBatteryHealthStatus(mBatteryHealthStatus);
432 }
433
434 if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0)
435 mHealthInfo->batteryTechnology = String8(buf.c_str());
436
437 if (readFromFile(mHealthdConfig->chargingPolicyPath, &buf) > 0)
438 mHealthInfo->chargingPolicy = getBatteryChargingPolicy(buf.c_str());
439
440 if (readFromFile(mHealthdConfig->chargingStatePath, &buf) > 0)
441 mHealthInfo->chargingState = getBatteryChargingState(buf.c_str());
442
443 double MaxPower = 0;
444
445 for (size_t i = 0; i < mChargerNames.size(); i++) {
446 String8 path;
447 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
448 mChargerNames[i].string());
449 if (getIntField(path)) {
450 path.clear();
451 path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
452 mChargerNames[i].string());
453 switch(readPowerSupplyType(path)) {
454 case ANDROID_POWER_SUPPLY_TYPE_AC:
455 mHealthInfo->chargerAcOnline = true;
456 break;
457 case ANDROID_POWER_SUPPLY_TYPE_USB:
458 mHealthInfo->chargerUsbOnline = true;
459 break;
460 case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
461 mHealthInfo->chargerWirelessOnline = true;
462 break;
463 case ANDROID_POWER_SUPPLY_TYPE_DOCK:
464 mHealthInfo->chargerDockOnline = true;
465 break;
466 default:
467 path.clear();
468 path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH,
469 mChargerNames[i].string());
470 if (access(path.string(), R_OK) == 0)
471 mHealthInfo->chargerDockOnline = true;
472 else
473 KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
474 mChargerNames[i].string());
475 }
476 path.clear();
477 path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
478 mChargerNames[i].string());
479 int ChargingCurrent =
480 (access(path.string(), R_OK) == 0) ? getIntField(path) : 0;
481
482 path.clear();
483 path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
484 mChargerNames[i].string());
485
486 int ChargingVoltage =
487 (access(path.string(), R_OK) == 0) ? getIntField(path) :
488 DEFAULT_VBUS_VOLTAGE;
489
490 double power = ((double)ChargingCurrent / MILLION) *
491 ((double)ChargingVoltage / MILLION);
492 if (MaxPower < power) {
493 mHealthInfo->maxChargingCurrentMicroamps = ChargingCurrent;
494 mHealthInfo->maxChargingVoltageMicrovolts = ChargingVoltage;
495 MaxPower = power;
496 }
497 }
498 }
499 }
500
doLogValues(const HealthInfo & props,const struct healthd_config & healthd_config)501 static void doLogValues(const HealthInfo& props, const struct healthd_config& healthd_config) {
502 char dmesgline[256];
503 size_t len;
504 if (props.batteryPresent) {
505 snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
506 props.batteryLevel, props.batteryVoltageMillivolts,
507 props.batteryTemperatureTenthsCelsius < 0 ? "-" : "",
508 abs(props.batteryTemperatureTenthsCelsius / 10),
509 abs(props.batteryTemperatureTenthsCelsius % 10), props.batteryHealth,
510 props.batteryStatus);
511
512 len = strlen(dmesgline);
513 if (!healthd_config.batteryCurrentNowPath.isEmpty()) {
514 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d",
515 props.batteryCurrentMicroamps);
516 }
517
518 if (!healthd_config.batteryFullChargePath.isEmpty()) {
519 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d",
520 props.batteryFullChargeUah);
521 }
522
523 if (!healthd_config.batteryCycleCountPath.isEmpty()) {
524 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " cc=%d",
525 props.batteryCycleCount);
526 }
527 } else {
528 len = snprintf(dmesgline, sizeof(dmesgline), "battery none");
529 }
530
531 snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s%s",
532 props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "",
533 props.chargerWirelessOnline ? "w" : "", props.chargerDockOnline ? "d" : "");
534
535 KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
536 }
537
logValues(const HealthInfo_2_1 & health_info,const struct healthd_config & healthd_config)538 void BatteryMonitor::logValues(const HealthInfo_2_1& health_info,
539 const struct healthd_config& healthd_config) {
540 HealthInfo aidl_health_info;
541 (void)android::h2a::translate(health_info, &aidl_health_info);
542 doLogValues(aidl_health_info, healthd_config);
543 }
544
logValues(void)545 void BatteryMonitor::logValues(void) {
546 doLogValues(*mHealthInfo, *mHealthdConfig);
547 }
548
isChargerOnline()549 bool BatteryMonitor::isChargerOnline() {
550 const HealthInfo& props = *mHealthInfo;
551 return props.chargerAcOnline | props.chargerUsbOnline | props.chargerWirelessOnline |
552 props.chargerDockOnline;
553 }
554
getChargeStatus()555 int BatteryMonitor::getChargeStatus() {
556 BatteryStatus result = BatteryStatus::UNKNOWN;
557 if (!mHealthdConfig->batteryStatusPath.isEmpty()) {
558 std::string buf;
559 if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
560 result = getBatteryStatus(buf.c_str());
561 }
562 return static_cast<int>(result);
563 }
564
setChargingPolicy(int value)565 status_t BatteryMonitor::setChargingPolicy(int value) {
566 status_t ret = NAME_NOT_FOUND;
567 bool result;
568 if (!mHealthdConfig->chargingPolicyPath.isEmpty()) {
569 result = writeToFile(mHealthdConfig->chargingPolicyPath, value);
570 if (!result) {
571 KLOG_WARNING(LOG_TAG, "setChargingPolicy fail\n");
572 ret = BAD_VALUE;
573 } else {
574 ret = OK;
575 }
576 }
577 return ret;
578 }
579
getChargingPolicy()580 int BatteryMonitor::getChargingPolicy() {
581 BatteryChargingPolicy result = BatteryChargingPolicy::DEFAULT;
582 if (!mHealthdConfig->chargingPolicyPath.isEmpty()) {
583 std::string buf;
584 if (readFromFile(mHealthdConfig->chargingPolicyPath, &buf) > 0)
585 result = getBatteryChargingPolicy(buf.c_str());
586 }
587 return static_cast<int>(result);
588 }
589
getBatteryHealthData(int id)590 int BatteryMonitor::getBatteryHealthData(int id) {
591 if (id == BATTERY_PROP_MANUFACTURING_DATE) {
592 if (!mHealthdConfig->batteryManufacturingDatePath.isEmpty())
593 return getIntField(mHealthdConfig->batteryManufacturingDatePath);
594 }
595 if (id == BATTERY_PROP_FIRST_USAGE_DATE) {
596 if (!mHealthdConfig->batteryFirstUsageDatePath.isEmpty())
597 return getIntField(mHealthdConfig->batteryFirstUsageDatePath);
598 }
599 if (id == BATTERY_PROP_STATE_OF_HEALTH) {
600 if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty())
601 return getIntField(mHealthdConfig->batteryStateOfHealthPath);
602 }
603 return 0;
604 }
605
getProperty(int id,struct BatteryProperty * val)606 status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
607 status_t ret = BAD_VALUE;
608 std::string buf;
609
610 val->valueInt64 = LONG_MIN;
611
612 switch(id) {
613 case BATTERY_PROP_CHARGE_COUNTER:
614 if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
615 val->valueInt64 =
616 getIntField(mHealthdConfig->batteryChargeCounterPath);
617 ret = OK;
618 } else {
619 ret = NAME_NOT_FOUND;
620 }
621 break;
622
623 case BATTERY_PROP_CURRENT_NOW:
624 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
625 val->valueInt64 =
626 getIntField(mHealthdConfig->batteryCurrentNowPath);
627 ret = OK;
628 } else {
629 ret = NAME_NOT_FOUND;
630 }
631 break;
632
633 case BATTERY_PROP_CURRENT_AVG:
634 if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
635 val->valueInt64 =
636 getIntField(mHealthdConfig->batteryCurrentAvgPath);
637 ret = OK;
638 } else {
639 ret = NAME_NOT_FOUND;
640 }
641 break;
642
643 case BATTERY_PROP_CAPACITY:
644 if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
645 val->valueInt64 =
646 getIntField(mHealthdConfig->batteryCapacityPath);
647 ret = OK;
648 } else {
649 ret = NAME_NOT_FOUND;
650 }
651 break;
652
653 case BATTERY_PROP_ENERGY_COUNTER:
654 if (mHealthdConfig->energyCounter) {
655 ret = mHealthdConfig->energyCounter(&val->valueInt64);
656 } else {
657 ret = NAME_NOT_FOUND;
658 }
659 break;
660
661 case BATTERY_PROP_BATTERY_STATUS:
662 val->valueInt64 = getChargeStatus();
663 ret = OK;
664 break;
665
666 case BATTERY_PROP_CHARGING_POLICY:
667 val->valueInt64 = getChargingPolicy();
668 ret = OK;
669 break;
670
671 case BATTERY_PROP_MANUFACTURING_DATE:
672 val->valueInt64 = getBatteryHealthData(BATTERY_PROP_MANUFACTURING_DATE);
673 ret = OK;
674 break;
675
676 case BATTERY_PROP_FIRST_USAGE_DATE:
677 val->valueInt64 = getBatteryHealthData(BATTERY_PROP_FIRST_USAGE_DATE);
678 ret = OK;
679 break;
680
681 case BATTERY_PROP_STATE_OF_HEALTH:
682 val->valueInt64 = getBatteryHealthData(BATTERY_PROP_STATE_OF_HEALTH);
683 ret = OK;
684 break;
685
686 default:
687 break;
688 }
689
690 return ret;
691 }
692
dumpState(int fd)693 void BatteryMonitor::dumpState(int fd) {
694 int v;
695 char vs[128];
696 const HealthInfo& props = *mHealthInfo;
697
698 snprintf(vs, sizeof(vs),
699 "ac: %d usb: %d wireless: %d dock: %d current_max: %d voltage_max: %d\n",
700 props.chargerAcOnline, props.chargerUsbOnline, props.chargerWirelessOnline,
701 props.chargerDockOnline, props.maxChargingCurrentMicroamps,
702 props.maxChargingVoltageMicrovolts);
703 write(fd, vs, strlen(vs));
704 snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
705 props.batteryStatus, props.batteryHealth, props.batteryPresent);
706 write(fd, vs, strlen(vs));
707 snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n", props.batteryLevel,
708 props.batteryVoltageMillivolts, props.batteryTemperatureTenthsCelsius);
709 write(fd, vs, strlen(vs));
710
711 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
712 v = getIntField(mHealthdConfig->batteryCurrentNowPath);
713 snprintf(vs, sizeof(vs), "current now: %d\n", v);
714 write(fd, vs, strlen(vs));
715 }
716
717 if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
718 v = getIntField(mHealthdConfig->batteryCurrentAvgPath);
719 snprintf(vs, sizeof(vs), "current avg: %d\n", v);
720 write(fd, vs, strlen(vs));
721 }
722
723 if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
724 v = getIntField(mHealthdConfig->batteryChargeCounterPath);
725 snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
726 write(fd, vs, strlen(vs));
727 }
728
729 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
730 snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrentMicroamps);
731 write(fd, vs, strlen(vs));
732 }
733
734 if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
735 snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount);
736 write(fd, vs, strlen(vs));
737 }
738
739 if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
740 snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullChargeUah);
741 write(fd, vs, strlen(vs));
742 }
743 }
744
init(struct healthd_config * hc)745 void BatteryMonitor::init(struct healthd_config *hc) {
746 String8 path;
747 char pval[PROPERTY_VALUE_MAX];
748
749 mHealthdConfig = hc;
750 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir);
751 if (dir == NULL) {
752 KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
753 } else {
754 struct dirent* entry;
755
756 while ((entry = readdir(dir.get()))) {
757 const char* name = entry->d_name;
758
759 if (!strcmp(name, ".") || !strcmp(name, ".."))
760 continue;
761
762 std::vector<String8>::iterator itIgnoreName =
763 find(hc->ignorePowerSupplyNames.begin(), hc->ignorePowerSupplyNames.end(),
764 String8(name));
765 if (itIgnoreName != hc->ignorePowerSupplyNames.end())
766 continue;
767
768 // Look for "type" file in each subdirectory
769 path.clear();
770 path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
771 switch(readPowerSupplyType(path)) {
772 case ANDROID_POWER_SUPPLY_TYPE_AC:
773 case ANDROID_POWER_SUPPLY_TYPE_USB:
774 case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
775 case ANDROID_POWER_SUPPLY_TYPE_DOCK:
776 path.clear();
777 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
778 if (access(path.string(), R_OK) == 0)
779 mChargerNames.add(String8(name));
780 break;
781
782 case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
783 // Some devices expose the battery status of sub-component like
784 // stylus. Such a device-scoped battery info needs to be skipped
785 // in BatteryMonitor, which is intended to report the status of
786 // the battery supplying the power to the whole system.
787 if (isScopedPowerSupply(name)) continue;
788 mBatteryDevicePresent = true;
789
790 if (mHealthdConfig->batteryStatusPath.isEmpty()) {
791 path.clear();
792 path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
793 name);
794 if (access(path, R_OK) == 0)
795 mHealthdConfig->batteryStatusPath = path;
796 }
797
798 if (mHealthdConfig->batteryHealthPath.isEmpty()) {
799 path.clear();
800 path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
801 name);
802 if (access(path, R_OK) == 0)
803 mHealthdConfig->batteryHealthPath = path;
804 }
805
806 if (mHealthdConfig->batteryPresentPath.isEmpty()) {
807 path.clear();
808 path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
809 name);
810 if (access(path, R_OK) == 0)
811 mHealthdConfig->batteryPresentPath = path;
812 }
813
814 if (mHealthdConfig->batteryCapacityPath.isEmpty()) {
815 path.clear();
816 path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
817 name);
818 if (access(path, R_OK) == 0)
819 mHealthdConfig->batteryCapacityPath = path;
820 }
821
822 if (mHealthdConfig->batteryVoltagePath.isEmpty()) {
823 path.clear();
824 path.appendFormat("%s/%s/voltage_now",
825 POWER_SUPPLY_SYSFS_PATH, name);
826 if (access(path, R_OK) == 0) {
827 mHealthdConfig->batteryVoltagePath = path;
828 }
829 }
830
831 if (mHealthdConfig->batteryFullChargePath.isEmpty()) {
832 path.clear();
833 path.appendFormat("%s/%s/charge_full",
834 POWER_SUPPLY_SYSFS_PATH, name);
835 if (access(path, R_OK) == 0)
836 mHealthdConfig->batteryFullChargePath = path;
837 }
838
839 if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
840 path.clear();
841 path.appendFormat("%s/%s/current_now",
842 POWER_SUPPLY_SYSFS_PATH, name);
843 if (access(path, R_OK) == 0)
844 mHealthdConfig->batteryCurrentNowPath = path;
845 }
846
847 if (mHealthdConfig->batteryCycleCountPath.isEmpty()) {
848 path.clear();
849 path.appendFormat("%s/%s/cycle_count",
850 POWER_SUPPLY_SYSFS_PATH, name);
851 if (access(path, R_OK) == 0)
852 mHealthdConfig->batteryCycleCountPath = path;
853 }
854
855 if (mHealthdConfig->batteryCapacityLevelPath.isEmpty()) {
856 path.clear();
857 path.appendFormat("%s/%s/capacity_level", POWER_SUPPLY_SYSFS_PATH, name);
858 if (access(path, R_OK) == 0) mHealthdConfig->batteryCapacityLevelPath = path;
859 }
860
861 if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty()) {
862 path.clear();
863 path.appendFormat("%s/%s/time_to_full_now", POWER_SUPPLY_SYSFS_PATH, name);
864 if (access(path, R_OK) == 0)
865 mHealthdConfig->batteryChargeTimeToFullNowPath = path;
866 }
867
868 if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty()) {
869 path.clear();
870 path.appendFormat("%s/%s/charge_full_design", POWER_SUPPLY_SYSFS_PATH, name);
871 if (access(path, R_OK) == 0)
872 mHealthdConfig->batteryFullChargeDesignCapacityUahPath = path;
873 }
874
875 if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
876 path.clear();
877 path.appendFormat("%s/%s/current_avg",
878 POWER_SUPPLY_SYSFS_PATH, name);
879 if (access(path, R_OK) == 0)
880 mHealthdConfig->batteryCurrentAvgPath = path;
881 }
882
883 if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
884 path.clear();
885 path.appendFormat("%s/%s/charge_counter",
886 POWER_SUPPLY_SYSFS_PATH, name);
887 if (access(path, R_OK) == 0)
888 mHealthdConfig->batteryChargeCounterPath = path;
889 }
890
891 if (mHealthdConfig->batteryTemperaturePath.isEmpty()) {
892 path.clear();
893 path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,
894 name);
895 if (access(path, R_OK) == 0) {
896 mHealthdConfig->batteryTemperaturePath = path;
897 }
898 }
899
900 if (mHealthdConfig->batteryTechnologyPath.isEmpty()) {
901 path.clear();
902 path.appendFormat("%s/%s/technology",
903 POWER_SUPPLY_SYSFS_PATH, name);
904 if (access(path, R_OK) == 0)
905 mHealthdConfig->batteryTechnologyPath = path;
906 }
907
908 if (mHealthdConfig->batteryStateOfHealthPath.isEmpty()) {
909 path.clear();
910 path.appendFormat("%s/%s/state_of_health", POWER_SUPPLY_SYSFS_PATH, name);
911 if (access(path, R_OK) == 0) {
912 mHealthdConfig->batteryStateOfHealthPath = path;
913 } else {
914 path.clear();
915 path.appendFormat("%s/%s/health_index", POWER_SUPPLY_SYSFS_PATH, name);
916 if (access(path, R_OK) == 0)
917 mHealthdConfig->batteryStateOfHealthPath = path;
918 }
919 }
920
921 if (mHealthdConfig->batteryHealthStatusPath.isEmpty()) {
922 path.clear();
923 path.appendFormat("%s/%s/health_status", POWER_SUPPLY_SYSFS_PATH, name);
924 if (access(path, R_OK) == 0) mHealthdConfig->batteryHealthStatusPath = path;
925 }
926
927 if (mHealthdConfig->batteryManufacturingDatePath.isEmpty()) {
928 path.clear();
929 path.appendFormat("%s/%s/manufacturing_date", POWER_SUPPLY_SYSFS_PATH, name);
930 if (access(path, R_OK) == 0)
931 mHealthdConfig->batteryManufacturingDatePath = path;
932 }
933
934 if (mHealthdConfig->batteryFirstUsageDatePath.isEmpty()) {
935 path.clear();
936 path.appendFormat("%s/%s/first_usage_date", POWER_SUPPLY_SYSFS_PATH, name);
937 if (access(path, R_OK) == 0) mHealthdConfig->batteryFirstUsageDatePath = path;
938 }
939
940 if (mHealthdConfig->chargingStatePath.isEmpty()) {
941 path.clear();
942 path.appendFormat("%s/%s/charging_state", POWER_SUPPLY_SYSFS_PATH, name);
943 if (access(path, R_OK) == 0) mHealthdConfig->chargingStatePath = path;
944 }
945
946 if (mHealthdConfig->chargingPolicyPath.isEmpty()) {
947 path.clear();
948 path.appendFormat("%s/%s/charging_policy", POWER_SUPPLY_SYSFS_PATH, name);
949 if (access(path, R_OK) == 0) mHealthdConfig->chargingPolicyPath = path;
950 }
951
952 break;
953
954 case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
955 break;
956 }
957
958 // Look for "is_dock" file
959 path.clear();
960 path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH, name);
961 if (access(path.string(), R_OK) == 0) {
962 path.clear();
963 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
964 if (access(path.string(), R_OK) == 0)
965 mChargerNames.add(String8(name));
966
967 }
968 }
969 }
970
971 // Typically the case for devices which do not have a battery and
972 // and are always plugged into AC mains.
973 if (!mBatteryDevicePresent) {
974 KLOG_WARNING(LOG_TAG, "No battery devices found\n");
975 hc->periodic_chores_interval_fast = -1;
976 hc->periodic_chores_interval_slow = -1;
977 } else {
978 if (mHealthdConfig->batteryStatusPath.isEmpty())
979 KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
980 if (mHealthdConfig->batteryHealthPath.isEmpty())
981 KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
982 if (mHealthdConfig->batteryPresentPath.isEmpty())
983 KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
984 if (mHealthdConfig->batteryCapacityPath.isEmpty())
985 KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
986 if (mHealthdConfig->batteryVoltagePath.isEmpty())
987 KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
988 if (mHealthdConfig->batteryTemperaturePath.isEmpty())
989 KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
990 if (mHealthdConfig->batteryTechnologyPath.isEmpty())
991 KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
992 if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
993 KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
994 if (mHealthdConfig->batteryFullChargePath.isEmpty())
995 KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
996 if (mHealthdConfig->batteryCycleCountPath.isEmpty())
997 KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n");
998 if (mHealthdConfig->batteryCapacityLevelPath.isEmpty())
999 KLOG_WARNING(LOG_TAG, "batteryCapacityLevelPath not found\n");
1000 if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
1001 KLOG_WARNING(LOG_TAG, "batteryChargeTimeToFullNowPath. not found\n");
1002 if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
1003 KLOG_WARNING(LOG_TAG, "batteryFullChargeDesignCapacityUahPath. not found\n");
1004 if (mHealthdConfig->batteryStateOfHealthPath.isEmpty())
1005 KLOG_WARNING(LOG_TAG, "batteryStateOfHealthPath not found\n");
1006 if (mHealthdConfig->batteryHealthStatusPath.isEmpty())
1007 KLOG_WARNING(LOG_TAG, "batteryHealthStatusPath not found\n");
1008 if (mHealthdConfig->batteryManufacturingDatePath.isEmpty())
1009 KLOG_WARNING(LOG_TAG, "batteryManufacturingDatePath not found\n");
1010 if (mHealthdConfig->batteryFirstUsageDatePath.isEmpty())
1011 KLOG_WARNING(LOG_TAG, "batteryFirstUsageDatePath not found\n");
1012 if (mHealthdConfig->chargingStatePath.isEmpty())
1013 KLOG_WARNING(LOG_TAG, "chargingStatePath not found\n");
1014 if (mHealthdConfig->chargingPolicyPath.isEmpty())
1015 KLOG_WARNING(LOG_TAG, "chargingPolicyPath not found\n");
1016 }
1017
1018 if (property_get("ro.boot.fake_battery", pval, NULL) > 0
1019 && strtol(pval, NULL, 10) != 0) {
1020 mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY;
1021 mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
1022 }
1023 }
1024
1025 }; // namespace android
1026