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