Refactor battery info querying functions into librecovery_utils.
Bug: 134560109 Test: Run recovery_unit_test. Change-Id: Ibbcdcfd507fa23657ee7ff677208b0003ec382ba
This commit is contained in:
parent
c6fb9f9df5
commit
832c9cd24f
6 changed files with 191 additions and 91 deletions
|
@ -58,7 +58,6 @@ cc_defaults {
|
|||
],
|
||||
|
||||
shared_libs: [
|
||||
"android.hardware.health@2.0",
|
||||
"libbase",
|
||||
"libbootloader_message",
|
||||
"libcrypto",
|
||||
|
@ -74,9 +73,6 @@ cc_defaults {
|
|||
"libminui",
|
||||
"librecovery_utils",
|
||||
"libotautil",
|
||||
|
||||
// external dependencies
|
||||
"libhealthhalutils",
|
||||
],
|
||||
}
|
||||
|
||||
|
@ -105,6 +101,7 @@ cc_binary {
|
|||
defaults: [
|
||||
"libinstall_defaults",
|
||||
"librecovery_defaults",
|
||||
"librecovery_utils_defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
|
|
85
recovery.cpp
85
recovery.cpp
|
@ -42,7 +42,6 @@
|
|||
#include <android-base/strings.h>
|
||||
#include <cutils/properties.h> /* for property_list */
|
||||
#include <fs_mgr/roots.h>
|
||||
#include <healthhalutils/HealthHalUtils.h>
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
#include "bootloader_message/bootloader_message.h"
|
||||
|
@ -59,6 +58,7 @@
|
|||
#include "otautil/sysutil.h"
|
||||
#include "recovery_ui/screen_ui.h"
|
||||
#include "recovery_ui/ui.h"
|
||||
#include "recovery_utils/battery_utils.h"
|
||||
#include "recovery_utils/logging.h"
|
||||
#include "recovery_utils/roots.h"
|
||||
|
||||
|
@ -453,74 +453,17 @@ static void print_property(const char* key, const char* name, void* /* cookie */
|
|||
printf("%s=%s\n", key, name);
|
||||
}
|
||||
|
||||
static bool is_battery_ok(int* required_battery_level) {
|
||||
using android::hardware::health::V1_0::BatteryStatus;
|
||||
using android::hardware::health::V2_0::get_health_service;
|
||||
using android::hardware::health::V2_0::IHealth;
|
||||
using android::hardware::health::V2_0::Result;
|
||||
using android::hardware::health::V2_0::toString;
|
||||
static bool IsBatteryOk(int* required_battery_level) {
|
||||
// GmsCore enters recovery mode to install package when having enough battery percentage.
|
||||
// Normally, the threshold is 40% without charger and 20% with charger. So we check the battery
|
||||
// level against a slightly lower limit.
|
||||
constexpr int BATTERY_OK_PERCENTAGE = 20;
|
||||
constexpr int BATTERY_WITH_CHARGER_OK_PERCENTAGE = 15;
|
||||
|
||||
android::sp<IHealth> health = get_health_service();
|
||||
|
||||
static constexpr int BATTERY_READ_TIMEOUT_IN_SEC = 10;
|
||||
int wait_second = 0;
|
||||
while (true) {
|
||||
auto charge_status = BatteryStatus::UNKNOWN;
|
||||
|
||||
if (health == nullptr) {
|
||||
LOG(WARNING) << "no health implementation is found, assuming defaults";
|
||||
} else {
|
||||
health
|
||||
->getChargeStatus([&charge_status](auto res, auto out_status) {
|
||||
if (res == Result::SUCCESS) {
|
||||
charge_status = out_status;
|
||||
}
|
||||
})
|
||||
.isOk(); // should not have transport error
|
||||
}
|
||||
|
||||
// Treat unknown status as charged.
|
||||
bool charged = (charge_status != BatteryStatus::DISCHARGING &&
|
||||
charge_status != BatteryStatus::NOT_CHARGING);
|
||||
|
||||
Result res = Result::UNKNOWN;
|
||||
int32_t capacity = INT32_MIN;
|
||||
if (health != nullptr) {
|
||||
health
|
||||
->getCapacity([&res, &capacity](auto out_res, auto out_capacity) {
|
||||
res = out_res;
|
||||
capacity = out_capacity;
|
||||
})
|
||||
.isOk(); // should not have transport error
|
||||
}
|
||||
|
||||
LOG(INFO) << "charge_status " << toString(charge_status) << ", charged " << charged
|
||||
<< ", status " << toString(res) << ", capacity " << capacity;
|
||||
// At startup, the battery drivers in devices like N5X/N6P take some time to load
|
||||
// the battery profile. Before the load finishes, it reports value 50 as a fake
|
||||
// capacity. BATTERY_READ_TIMEOUT_IN_SEC is set that the battery drivers are expected
|
||||
// to finish loading the battery profile earlier than 10 seconds after kernel startup.
|
||||
if (res == Result::SUCCESS && capacity == 50) {
|
||||
if (wait_second < BATTERY_READ_TIMEOUT_IN_SEC) {
|
||||
sleep(1);
|
||||
wait_second++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// If we can't read battery percentage, it may be a device without battery. In this
|
||||
// situation, use 100 as a fake battery percentage.
|
||||
if (res != Result::SUCCESS) {
|
||||
capacity = 100;
|
||||
}
|
||||
|
||||
// GmsCore enters recovery mode to install package when having enough battery percentage.
|
||||
// Normally, the threshold is 40% without charger and 20% with charger. So we should check
|
||||
// battery with a slightly lower limitation.
|
||||
static constexpr int BATTERY_OK_PERCENTAGE = 20;
|
||||
static constexpr int BATTERY_WITH_CHARGER_OK_PERCENTAGE = 15;
|
||||
*required_battery_level = charged ? BATTERY_WITH_CHARGER_OK_PERCENTAGE : BATTERY_OK_PERCENTAGE;
|
||||
return capacity >= *required_battery_level;
|
||||
}
|
||||
auto battery_info = GetBatteryInfo();
|
||||
*required_battery_level =
|
||||
battery_info.charging ? BATTERY_WITH_CHARGER_OK_PERCENTAGE : BATTERY_OK_PERCENTAGE;
|
||||
return battery_info.capacity >= *required_battery_level;
|
||||
}
|
||||
|
||||
// Set the retry count to |retry_count| in BCB.
|
||||
|
@ -713,12 +656,10 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri
|
|||
// to log the update attempt since update_package is non-NULL.
|
||||
save_current_log = true;
|
||||
|
||||
int required_battery_level;
|
||||
if (retry_count == 0 && !is_battery_ok(&required_battery_level)) {
|
||||
if (int required_battery_level; retry_count == 0 && !IsBatteryOk(&required_battery_level)) {
|
||||
ui->Print("battery capacity is not enough for installing package: %d%% needed\n",
|
||||
required_battery_level);
|
||||
// Log the error code to last_install when installation skips due to
|
||||
// low battery.
|
||||
// Log the error code to last_install when installation skips due to low battery.
|
||||
log_failure_code(kLowBattery, update_package);
|
||||
status = INSTALL_SKIPPED;
|
||||
} else if (retry_count == 0 && bootreason_in_blacklist()) {
|
||||
|
|
|
@ -12,6 +12,32 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
cc_defaults {
|
||||
name: "librecovery_utils_defaults",
|
||||
|
||||
defaults: [
|
||||
"recovery_defaults",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"android.hardware.health@2.0",
|
||||
"libbase",
|
||||
"libext4_utils",
|
||||
"libfs_mgr",
|
||||
"libhidlbase",
|
||||
"libselinux",
|
||||
"libutils",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"libotautil",
|
||||
|
||||
// External dependencies.
|
||||
"libfstab",
|
||||
"libhealthhalutils",
|
||||
],
|
||||
}
|
||||
|
||||
// A utility lib that's local to recovery (in contrast, libotautil is exposed to device-specific
|
||||
// recovery_ui lib as well as device-specific updater).
|
||||
cc_library_static {
|
||||
|
@ -20,23 +46,17 @@ cc_library_static {
|
|||
recovery_available: true,
|
||||
|
||||
defaults: [
|
||||
"recovery_defaults",
|
||||
"librecovery_utils_defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"battery_utils.cpp",
|
||||
"logging.cpp",
|
||||
"parse_install_logs.cpp",
|
||||
"roots.cpp",
|
||||
"thermalutil.cpp",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libext4_utils",
|
||||
"libfs_mgr",
|
||||
"libselinux",
|
||||
],
|
||||
|
||||
export_include_dirs: [
|
||||
"include",
|
||||
],
|
||||
|
@ -45,13 +65,6 @@ cc_library_static {
|
|||
"system/vold",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"libotautil",
|
||||
|
||||
// external dependency
|
||||
"libfstab",
|
||||
],
|
||||
|
||||
export_static_lib_headers: [
|
||||
"libfstab",
|
||||
],
|
||||
|
|
89
recovery_utils/battery_utils.cpp
Normal file
89
recovery_utils/battery_utils.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "recovery_utils/battery_utils.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <healthhalutils/HealthHalUtils.h>
|
||||
|
||||
BatteryInfo GetBatteryInfo() {
|
||||
using android::hardware::health::V1_0::BatteryStatus;
|
||||
using android::hardware::health::V2_0::get_health_service;
|
||||
using android::hardware::health::V2_0::IHealth;
|
||||
using android::hardware::health::V2_0::Result;
|
||||
using android::hardware::health::V2_0::toString;
|
||||
|
||||
android::sp<IHealth> health = get_health_service();
|
||||
|
||||
int wait_second = 0;
|
||||
while (true) {
|
||||
auto charge_status = BatteryStatus::UNKNOWN;
|
||||
|
||||
if (health == nullptr) {
|
||||
LOG(WARNING) << "No health implementation is found; assuming defaults";
|
||||
} else {
|
||||
health
|
||||
->getChargeStatus([&charge_status](auto res, auto out_status) {
|
||||
if (res == Result::SUCCESS) {
|
||||
charge_status = out_status;
|
||||
}
|
||||
})
|
||||
.isOk(); // should not have transport error
|
||||
}
|
||||
|
||||
// Treat unknown status as on charger. See hardware/interfaces/health/1.0/types.hal for the
|
||||
// meaning of the return values.
|
||||
bool charging = (charge_status != BatteryStatus::DISCHARGING &&
|
||||
charge_status != BatteryStatus::NOT_CHARGING);
|
||||
|
||||
Result res = Result::UNKNOWN;
|
||||
int32_t capacity = INT32_MIN;
|
||||
if (health != nullptr) {
|
||||
health
|
||||
->getCapacity([&res, &capacity](auto out_res, auto out_capacity) {
|
||||
res = out_res;
|
||||
capacity = out_capacity;
|
||||
})
|
||||
.isOk(); // should not have transport error
|
||||
}
|
||||
|
||||
LOG(INFO) << "charge_status " << toString(charge_status) << ", charging " << charging
|
||||
<< ", status " << toString(res) << ", capacity " << capacity;
|
||||
|
||||
constexpr int BATTERY_READ_TIMEOUT_IN_SEC = 10;
|
||||
// At startup, the battery drivers in devices like N5X/N6P take some time to load
|
||||
// the battery profile. Before the load finishes, it reports value 50 as a fake
|
||||
// capacity. BATTERY_READ_TIMEOUT_IN_SEC is set that the battery drivers are expected
|
||||
// to finish loading the battery profile earlier than 10 seconds after kernel startup.
|
||||
if (res == Result::SUCCESS && capacity == 50) {
|
||||
if (wait_second < BATTERY_READ_TIMEOUT_IN_SEC) {
|
||||
sleep(1);
|
||||
wait_second++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// If we can't read battery percentage, it may be a device without battery. In this
|
||||
// situation, use 100 as a fake battery percentage.
|
||||
if (res != Result::SUCCESS) {
|
||||
capacity = 100;
|
||||
}
|
||||
|
||||
return BatteryInfo{ charging, capacity };
|
||||
}
|
||||
}
|
33
recovery_utils/include/recovery_utils/battery_utils.h
Normal file
33
recovery_utils/include/recovery_utils/battery_utils.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct BatteryInfo {
|
||||
// Whether the device is on charger. Note that the value will be `true` if the battery status is
|
||||
// unknown (BATTERY_STATUS_UNKNOWN).
|
||||
bool charging;
|
||||
|
||||
// The remaining battery capacity percentage (i.e. between 0 and 100). See getCapacity in
|
||||
// hardware/interfaces/health/2.0/IHealth.hal. Returns 100 in case it fails to read a value from
|
||||
// the health HAL.
|
||||
int32_t capacity;
|
||||
};
|
||||
|
||||
// Returns the battery status for OTA installation purpose.
|
||||
BatteryInfo GetBatteryInfo();
|
27
tests/unit/battery_utils_test.cpp
Normal file
27
tests/unit/battery_utils_test.cpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agree to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "recovery_utils/battery_utils.h"
|
||||
|
||||
TEST(BatteryInfoTest, GetBatteryInfo) {
|
||||
auto info = GetBatteryInfo();
|
||||
// 0 <= capacity <= 100
|
||||
ASSERT_LE(0, info.capacity);
|
||||
ASSERT_LE(info.capacity, 100);
|
||||
}
|
Loading…
Reference in a new issue