Refactor battery info querying functions into librecovery_utils.

Bug: 134560109
Test: Run recovery_unit_test.
Change-Id: Ibbcdcfd507fa23657ee7ff677208b0003ec382ba
This commit is contained in:
Tao Bao 2019-09-27 23:32:00 -07:00
parent c6fb9f9df5
commit 832c9cd24f
6 changed files with 191 additions and 91 deletions

View file

@ -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: [

View file

@ -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()) {

View file

@ -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",
],

View 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 };
}
}

View 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();

View 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);
}