xref: /aosp_15_r20/bootable/recovery/recovery_utils/battery_utils.cpp (revision e7c364b630b241adcb6c7726a21055250b91fdac)
1*e7c364b6SAndroid Build Coastguard Worker /*
2*e7c364b6SAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*e7c364b6SAndroid Build Coastguard Worker  *
4*e7c364b6SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*e7c364b6SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*e7c364b6SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*e7c364b6SAndroid Build Coastguard Worker  *
8*e7c364b6SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*e7c364b6SAndroid Build Coastguard Worker  *
10*e7c364b6SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*e7c364b6SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*e7c364b6SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e7c364b6SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*e7c364b6SAndroid Build Coastguard Worker  * limitations under the License.
15*e7c364b6SAndroid Build Coastguard Worker  */
16*e7c364b6SAndroid Build Coastguard Worker 
17*e7c364b6SAndroid Build Coastguard Worker #include "recovery_utils/battery_utils.h"
18*e7c364b6SAndroid Build Coastguard Worker 
19*e7c364b6SAndroid Build Coastguard Worker #include <stdint.h>
20*e7c364b6SAndroid Build Coastguard Worker #include <unistd.h>
21*e7c364b6SAndroid Build Coastguard Worker 
22*e7c364b6SAndroid Build Coastguard Worker #include <android-base/logging.h>
23*e7c364b6SAndroid Build Coastguard Worker #include <android/binder_manager.h>
24*e7c364b6SAndroid Build Coastguard Worker #include <health-shim/shim.h>
25*e7c364b6SAndroid Build Coastguard Worker #include <healthhalutils/HealthHalUtils.h>
26*e7c364b6SAndroid Build Coastguard Worker 
GetBatteryInfo()27*e7c364b6SAndroid Build Coastguard Worker BatteryInfo GetBatteryInfo() {
28*e7c364b6SAndroid Build Coastguard Worker   using android::hardware::health::V2_0::get_health_service;
29*e7c364b6SAndroid Build Coastguard Worker   using HidlHealth = android::hardware::health::V2_0::IHealth;
30*e7c364b6SAndroid Build Coastguard Worker   using aidl::android::hardware::health::BatteryStatus;
31*e7c364b6SAndroid Build Coastguard Worker   using aidl::android::hardware::health::HealthShim;
32*e7c364b6SAndroid Build Coastguard Worker   using aidl::android::hardware::health::IHealth;
33*e7c364b6SAndroid Build Coastguard Worker   using aidl::android::hardware::health::toString;
34*e7c364b6SAndroid Build Coastguard Worker   using std::string_literals::operator""s;
35*e7c364b6SAndroid Build Coastguard Worker 
36*e7c364b6SAndroid Build Coastguard Worker   auto service_name = IHealth::descriptor + "/default"s;
37*e7c364b6SAndroid Build Coastguard Worker   std::shared_ptr<IHealth> health;
38*e7c364b6SAndroid Build Coastguard Worker   if (AServiceManager_isDeclared(service_name.c_str())) {
39*e7c364b6SAndroid Build Coastguard Worker     ndk::SpAIBinder binder(AServiceManager_waitForService(service_name.c_str()));
40*e7c364b6SAndroid Build Coastguard Worker     health = IHealth::fromBinder(binder);
41*e7c364b6SAndroid Build Coastguard Worker   }
42*e7c364b6SAndroid Build Coastguard Worker   if (health == nullptr) {
43*e7c364b6SAndroid Build Coastguard Worker     LOG(INFO) << "Unable to get AIDL health service, trying HIDL...";
44*e7c364b6SAndroid Build Coastguard Worker     android::sp<HidlHealth> hidl_health = get_health_service();
45*e7c364b6SAndroid Build Coastguard Worker     if (hidl_health != nullptr) {
46*e7c364b6SAndroid Build Coastguard Worker       health = ndk::SharedRefBase::make<HealthShim>(hidl_health);
47*e7c364b6SAndroid Build Coastguard Worker     }
48*e7c364b6SAndroid Build Coastguard Worker   }
49*e7c364b6SAndroid Build Coastguard Worker   if (health == nullptr) {
50*e7c364b6SAndroid Build Coastguard Worker     LOG(WARNING) << "No health implementation is found; assuming defaults";
51*e7c364b6SAndroid Build Coastguard Worker   }
52*e7c364b6SAndroid Build Coastguard Worker 
53*e7c364b6SAndroid Build Coastguard Worker   int wait_second = 0;
54*e7c364b6SAndroid Build Coastguard Worker   while (true) {
55*e7c364b6SAndroid Build Coastguard Worker     auto charge_status = BatteryStatus::UNKNOWN;
56*e7c364b6SAndroid Build Coastguard Worker     if (health != nullptr) {
57*e7c364b6SAndroid Build Coastguard Worker       auto res = health->getChargeStatus(&charge_status);
58*e7c364b6SAndroid Build Coastguard Worker       if (!res.isOk()) {
59*e7c364b6SAndroid Build Coastguard Worker         LOG(WARNING) << "Unable to call getChargeStatus: " << res.getDescription();
60*e7c364b6SAndroid Build Coastguard Worker         charge_status = BatteryStatus::UNKNOWN;
61*e7c364b6SAndroid Build Coastguard Worker       }
62*e7c364b6SAndroid Build Coastguard Worker     }
63*e7c364b6SAndroid Build Coastguard Worker 
64*e7c364b6SAndroid Build Coastguard Worker     // Treat unknown status as on charger. See hardware/interfaces/health/aidl/BatteryStatus.aidl
65*e7c364b6SAndroid Build Coastguard Worker     // for the meaning of the return values.
66*e7c364b6SAndroid Build Coastguard Worker     bool charging = (charge_status != BatteryStatus::DISCHARGING &&
67*e7c364b6SAndroid Build Coastguard Worker                      charge_status != BatteryStatus::NOT_CHARGING);
68*e7c364b6SAndroid Build Coastguard Worker 
69*e7c364b6SAndroid Build Coastguard Worker     int32_t capacity = INT32_MIN;
70*e7c364b6SAndroid Build Coastguard Worker     if (health != nullptr) {
71*e7c364b6SAndroid Build Coastguard Worker       auto res = health->getCapacity(&capacity);
72*e7c364b6SAndroid Build Coastguard Worker       if (!res.isOk()) {
73*e7c364b6SAndroid Build Coastguard Worker         LOG(WARNING) << "Unable to call getCapacity: " << res.getDescription();
74*e7c364b6SAndroid Build Coastguard Worker         capacity = INT32_MIN;
75*e7c364b6SAndroid Build Coastguard Worker       }
76*e7c364b6SAndroid Build Coastguard Worker     }
77*e7c364b6SAndroid Build Coastguard Worker 
78*e7c364b6SAndroid Build Coastguard Worker     LOG(INFO) << "charge_status " << toString(charge_status) << ", charging " << charging
79*e7c364b6SAndroid Build Coastguard Worker               << ", capacity " << capacity;
80*e7c364b6SAndroid Build Coastguard Worker 
81*e7c364b6SAndroid Build Coastguard Worker     constexpr int BATTERY_READ_TIMEOUT_IN_SEC = 10;
82*e7c364b6SAndroid Build Coastguard Worker     // At startup, the battery drivers in devices like N5X/N6P take some time to load
83*e7c364b6SAndroid Build Coastguard Worker     // the battery profile. Before the load finishes, it reports value 50 as a fake
84*e7c364b6SAndroid Build Coastguard Worker     // capacity. BATTERY_READ_TIMEOUT_IN_SEC is set that the battery drivers are expected
85*e7c364b6SAndroid Build Coastguard Worker     // to finish loading the battery profile earlier than 10 seconds after kernel startup.
86*e7c364b6SAndroid Build Coastguard Worker     if (capacity == 50) {
87*e7c364b6SAndroid Build Coastguard Worker       if (wait_second < BATTERY_READ_TIMEOUT_IN_SEC) {
88*e7c364b6SAndroid Build Coastguard Worker         LOG(INFO) << "Battery capacity == 50, waiting "
89*e7c364b6SAndroid Build Coastguard Worker                   << (BATTERY_READ_TIMEOUT_IN_SEC - wait_second)
90*e7c364b6SAndroid Build Coastguard Worker                   << " seconds to ensure this is not a fake value...";
91*e7c364b6SAndroid Build Coastguard Worker         sleep(1);
92*e7c364b6SAndroid Build Coastguard Worker         wait_second++;
93*e7c364b6SAndroid Build Coastguard Worker         continue;
94*e7c364b6SAndroid Build Coastguard Worker       }
95*e7c364b6SAndroid Build Coastguard Worker     }
96*e7c364b6SAndroid Build Coastguard Worker     // If we can't read battery percentage, it may be a device without battery. In this
97*e7c364b6SAndroid Build Coastguard Worker     // situation, use 100 as a fake battery percentage.
98*e7c364b6SAndroid Build Coastguard Worker     if (capacity == INT32_MIN) {
99*e7c364b6SAndroid Build Coastguard Worker       LOG(WARNING) << "Using fake battery capacity 100.";
100*e7c364b6SAndroid Build Coastguard Worker       capacity = 100;
101*e7c364b6SAndroid Build Coastguard Worker     }
102*e7c364b6SAndroid Build Coastguard Worker 
103*e7c364b6SAndroid Build Coastguard Worker     LOG(INFO) << "GetBatteryInfo() reporting charging " << charging << ", capacity " << capacity;
104*e7c364b6SAndroid Build Coastguard Worker     return BatteryInfo{ charging, capacity };
105*e7c364b6SAndroid Build Coastguard Worker   }
106*e7c364b6SAndroid Build Coastguard Worker }
107