charger: separate UI and HAL access.

Abstract all the HIDL-ness from charger so an AIDL HAL
can later replace the HIDL HAL.

Created libhealthd_charger_ui that is responsible for
UI stuff in charger. Then libhealthd_charger is now the
charger library backed by HIDL HAL.

Bug: 170338625
Bug: 203246116

Test: charger_test

Change-Id: I193bb76afa18b3367f24796ac53b1760650e8683
This commit is contained in:
Yifan Hong 2021-10-20 17:15:32 -07:00
parent 132f2341f9
commit b5d7033dcc
8 changed files with 254 additions and 97 deletions

View file

@ -120,21 +120,22 @@ cc_library_static {
}
cc_library_static {
name: "libhealthd_charger",
local_include_dirs: ["include"],
export_include_dirs: [".", "include"],
name: "libhealthd_charger_ui",
export_include_dirs: [
"include",
"include_charger",
],
static_libs: [
"android.hardware.health@1.0-convert",
"android.hardware.health-V1-ndk",
"android.hardware.health-translate-ndk",
"libcharger_sysprop",
"libhealthd_draw",
"libhealthloop",
"libhealth2impl",
"libminui",
],
shared_libs: [
"android.hardware.health@2.1",
"libbase",
"libcutils",
"liblog",
@ -143,14 +144,51 @@ cc_library_static {
"libutils",
],
header_libs: [
"libhealthd_headers",
],
export_static_lib_headers: [
"android.hardware.health-V1-ndk",
],
srcs: [
"healthd_mode_charger.cpp",
"AnimationParser.cpp",
],
}
cc_library_static {
name: "libhealthd_charger",
export_include_dirs: [
"include",
"include_charger",
],
static_libs: [
"android.hardware.health@1.0-convert",
"libhealth2impl",
"libhealthd_charger_ui",
],
shared_libs: [
"android.hardware.health@2.1",
"libbase",
"libcutils",
"liblog",
"libutils",
],
srcs: [
"healthd_mode_charger_hidl.cpp",
],
}
cc_defaults {
name: "charger_defaults",
local_include_dirs: [
"include_charger",
],
cflags: [
"-Wall",
@ -174,6 +212,7 @@ cc_defaults {
static_libs: [
// common
"android.hardware.health@1.0-convert",
"android.hardware.health-V1-ndk",
"libbatterymonitor",
"libcharger_sysprop",
"libhealthd_charger_nops",
@ -183,6 +222,7 @@ cc_defaults {
// system charger only
"libhealthd_draw",
"libhealthd_charger",
"libhealthd_charger_ui",
"libminui",
"libsuspend",
],
@ -209,6 +249,7 @@ cc_binary {
exclude_static_libs: [
"libhealthd_draw",
"libhealthd_charger",
"libhealthd_charger_ui",
"libminui",
"libsuspend",
],

View file

@ -15,9 +15,9 @@
*/
#include <android-base/logging.h>
#include <charger.sysprop.h>
#include "charger.sysprop.h"
#include "healthd_mode_charger.h"
#include "healthd_mode_charger_hidl.h"
#include "healthd_mode_charger_nops.h"
#ifndef CHARGER_FORCE_NO_UI

View file

@ -31,7 +31,7 @@
#include <health/utils.h>
#include <health2impl/Health.h>
#include "healthd_mode_charger.h"
#include "healthd_mode_charger_hidl.h"
using android::hardware::health::InitHealthdConfig;
using android::hardware::health::V2_1::HealthInfo;
@ -153,7 +153,7 @@ int main(int /*argc*/, char** /*argv*/) {
sp<IHealth> passthrough = new TestHealth(std::move(config));
std::thread bgThread([=] {
android::Charger charger(passthrough);
android::ChargerHidl charger(passthrough);
charger.StartLoop();
});

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
#include "healthd_mode_charger.h"
#include <charger/healthd_mode_charger.h>
#include <dirent.h>
#include <errno.h>
@ -51,26 +51,16 @@
#include "AnimationParser.h"
#include "charger.sysprop.h"
#include "charger_utils.h"
#include "healthd_draw.h"
#include <android/hardware/health/2.0/IHealthInfoCallback.h>
#include <health/utils.h>
#include <health2impl/HalHealthLoop.h>
#include <health2impl/Health.h>
#include <aidl/android/hardware/health/BatteryStatus.h>
#include <health/HealthLoop.h>
#include <healthd/healthd.h>
using std::string_literals::operator""s;
using namespace android;
using android::hardware::Return;
using android::hardware::health::GetHealthServiceOrDefault;
using aidl::android::hardware::health::BatteryStatus;
using android::hardware::health::HealthLoop;
using android::hardware::health::V1_0::BatteryStatus;
using android::hardware::health::V2_0::Result;
using android::hardware::health::V2_1::IHealth;
using IHealth_2_0 = android::hardware::health::V2_0::IHealth;
using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
// main healthd loop
extern int healthd_main(void);
@ -199,8 +189,8 @@ void Charger::InitDefaultAnimationFrames() {
};
}
Charger::Charger(const sp<IHealth>& service)
: HalHealthLoop("charger", service), batt_anim_(BASE_ANIMATION) {}
Charger::Charger(ChargerConfigurationInterface* configuration)
: batt_anim_(BASE_ANIMATION), configuration_(configuration) {}
Charger::~Charger() {}
@ -291,7 +281,7 @@ void Charger::UpdateScreenState(int64_t now) {
if (!batt_anim_.run || now < next_screen_transition_) return;
// If battery level is not ready, keep checking in the defined time
if (health_info_.batteryLevel == 0 && health_info_.batteryStatus == BatteryStatus::UNKNOWN) {
if (health_info_.battery_level == 0 && health_info_.battery_status == BatteryStatus::UNKNOWN) {
if (wait_batt_level_timestamp_ == 0) {
// Set max delay time and skip drawing screen
wait_batt_level_timestamp_ = now + MAX_BATT_LEVEL_WAIT_TIME;
@ -305,18 +295,15 @@ void Charger::UpdateScreenState(int64_t now) {
}
if (healthd_draw_ == nullptr) {
std::optional<bool> out_screen_on;
service()->shouldKeepScreenOn([&](Result res, bool screen_on) {
if (res == Result::SUCCESS) {
*out_screen_on = screen_on;
}
});
std::optional<bool> out_screen_on = configuration_->ChargerShouldKeepScreenOn();
if (out_screen_on.has_value()) {
if (!*out_screen_on) {
LOGV("[%" PRId64 "] leave screen off\n", now);
batt_anim_.run = false;
next_screen_transition_ = -1;
if (charger_online()) request_suspend(true);
if (configuration_->ChargerIsOnline()) {
request_suspend(true);
}
return;
}
}
@ -337,7 +324,9 @@ void Charger::UpdateScreenState(int64_t now) {
healthd_draw_->blank_screen(true);
screen_blanked_ = true;
LOGV("[%" PRId64 "] animation done\n", now);
if (charger_online()) request_suspend(true);
if (configuration_->ChargerIsOnline()) {
request_suspend(true);
}
return;
}
@ -351,9 +340,9 @@ void Charger::UpdateScreenState(int64_t now) {
/* animation starting, set up the animation */
if (batt_anim_.cur_frame == 0) {
LOGV("[%" PRId64 "] animation starting\n", now);
batt_anim_.cur_level = health_info_.batteryLevel;
batt_anim_.cur_status = (int)health_info_.batteryStatus;
if (health_info_.batteryLevel >= 0 && batt_anim_.num_frames != 0) {
batt_anim_.cur_level = health_info_.battery_level;
batt_anim_.cur_status = (int)health_info_.battery_status;
if (health_info_.battery_level >= 0 && batt_anim_.num_frames != 0) {
/* find first frame given current battery level */
for (int i = 0; i < batt_anim_.num_frames; i++) {
if (batt_anim_.cur_level >= batt_anim_.frames[i].min_level &&
@ -363,7 +352,7 @@ void Charger::UpdateScreenState(int64_t now) {
}
}
if (charger_online()) {
if (configuration_->ChargerIsOnline()) {
// repeat the first frame first_frame_repeats times
disp_time = batt_anim_.frames[batt_anim_.cur_frame].disp_time *
batt_anim_.first_frame_repeats;
@ -394,7 +383,7 @@ void Charger::UpdateScreenState(int64_t now) {
/* advance frame cntr to the next valid frame only if we are charging
* if necessary, advance cycle cntr, and reset frame cntr
*/
if (charger_online()) {
if (configuration_->ChargerIsOnline()) {
batt_anim_.cur_frame++;
while (batt_anim_.cur_frame < batt_anim_.num_frames &&
@ -516,7 +505,7 @@ void Charger::HandlePowerSupplyState(int64_t now) {
int timer_shutdown = UNPLUGGED_SHUTDOWN_TIME;
if (!have_battery_state_) return;
if (!charger_online()) {
if (!configuration_->ChargerIsOnline()) {
request_suspend(false);
if (next_pwr_check_ == -1) {
/* Last cycle would have stopped at the extreme top of battery-icon
@ -557,7 +546,7 @@ void Charger::HandlePowerSupplyState(int64_t now) {
}
}
void Charger::Heartbeat() {
void Charger::OnHeartbeat() {
// charger* charger = &charger_state;
int64_t now = curr_time_ms();
@ -570,9 +559,7 @@ void Charger::Heartbeat() {
UpdateScreenState(now);
}
void Charger::OnHealthInfoChanged(const HealthInfo_2_1& health_info) {
set_charger_online(health_info);
void Charger::OnHealthInfoChanged(const ChargerHealthInfo& health_info) {
if (!have_battery_state_) {
have_battery_state_ = true;
next_screen_transition_ = curr_time_ms() - 1;
@ -580,12 +567,10 @@ void Charger::OnHealthInfoChanged(const HealthInfo_2_1& health_info) {
reset_animation(&batt_anim_);
kick_animation(&batt_anim_);
}
health_info_ = health_info.legacy.legacy;
AdjustWakealarmPeriods(charger_online());
health_info_ = health_info;
}
int Charger::PrepareToWait(void) {
int Charger::OnPrepareToWait(void) {
int64_t now = curr_time_ms();
int64_t next_event = INT64_MAX;
int64_t timeout;
@ -672,7 +657,7 @@ void Charger::InitAnimation() {
}
}
void Charger::Init(struct healthd_config* config) {
void Charger::OnInit(struct healthd_config* config) {
int ret;
int i;
int epollfd;
@ -685,7 +670,7 @@ void Charger::Init(struct healthd_config* config) {
std::bind(&Charger::InputCallback, this, std::placeholders::_1, std::placeholders::_2));
if (!ret) {
epollfd = ev_get_epollfd();
RegisterEvent(epollfd, &charger_event_handler, EVENT_WAKEUP_FD);
configuration_->ChargerRegisterEvent(epollfd, &charger_event_handler, EVENT_WAKEUP_FD);
}
InitAnimation();
@ -730,7 +715,7 @@ void Charger::Init(struct healthd_config* config) {
wait_batt_level_timestamp_ = 0;
// Retrieve healthd_config from the existing health HAL.
HalHealthLoop::Init(config);
configuration_->ChargerInitConfig(config);
boot_min_cap_ = config->boot_min_cap;
}
@ -773,25 +758,3 @@ void animation::set_resource_root(const std::string& root, const std::string& ba
}
} // namespace android
int healthd_charger_main(int argc, char** argv) {
int ch;
while ((ch = getopt(argc, argv, "cr")) != -1) {
switch (ch) {
case 'c':
// -c is now a noop
break;
case 'r':
// -r is now a noop
break;
case '?':
default:
LOGE("Unrecognized charger option: %c\n", optopt);
exit(1);
}
}
Charger charger(GetHealthServiceOrDefault());
return charger.StartLoop();
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (C) 2021 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 "healthd_mode_charger_hidl.h"
#include <android/hardware/health/2.0/types.h>
#include <cutils/klog.h>
#include "charger_utils.h"
using android::hardware::health::GetHealthServiceOrDefault;
using android::hardware::health::V2_0::Result;
namespace android {
ChargerHidl::ChargerHidl(const sp<android::hardware::health::V2_1::IHealth>& service)
: HalHealthLoop("charger", service), charger_(std::make_unique<Charger>(this)) {}
void ChargerHidl::OnHealthInfoChanged(const HealthInfo_2_1& health_info) {
set_charger_online(health_info);
charger_->OnHealthInfoChanged(ChargerHealthInfo{
.battery_level = health_info.legacy.legacy.batteryLevel,
.battery_status = static_cast<::aidl::android::hardware::health::BatteryStatus>(
health_info.legacy.legacy.batteryStatus),
});
AdjustWakealarmPeriods(charger_online());
}
std::optional<bool> ChargerHidl::ChargerShouldKeepScreenOn() {
std::optional<bool> out_screen_on;
service()->shouldKeepScreenOn([&](Result res, bool screen_on) {
if (res == Result::SUCCESS) {
*out_screen_on = screen_on;
}
});
return out_screen_on;
}
} // namespace android
int healthd_charger_main(int argc, char** argv) {
int ch;
while ((ch = getopt(argc, argv, "cr")) != -1) {
switch (ch) {
case 'c':
// -c is now a noop
break;
case 'r':
// -r is now a noop
break;
case '?':
default:
KLOG_ERROR("charger", "Unrecognized charger option: %c\n", optopt);
exit(1);
}
}
android::ChargerHidl charger(GetHealthServiceOrDefault());
return charger.StartLoop();
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (C) 2021 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 <health2impl/HalHealthLoop.h>
#include <charger/healthd_mode_charger.h>
namespace android {
// An implementation of Charger backed by HIDL implementation. Uses HIDL health
// HAL's HalHealthLoop.
class ChargerHidl : public ::android::ChargerConfigurationInterface,
public ::android::hardware::health::V2_1::implementation::HalHealthLoop {
using HalHealthLoop = ::android::hardware::health::V2_1::implementation::HalHealthLoop;
using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
public:
explicit ChargerHidl(const sp<android::hardware::health::V2_1::IHealth>& service);
std::optional<bool> ChargerShouldKeepScreenOn() override;
bool ChargerIsOnline() override { return HalHealthLoop::charger_online(); }
void ChargerInitConfig(healthd_config* config) override { return HalHealthLoop::Init(config); }
int ChargerRegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) override {
return HalHealthLoop::RegisterEvent(fd, func, wakeup);
}
// HealthLoop overrides
void Heartbeat() override { charger_->OnHeartbeat(); }
int PrepareToWait() override { return charger_->OnPrepareToWait(); }
void Init(struct healthd_config* config) override { charger_->OnInit(config); }
// HalHealthLoop overrides
void OnHealthInfoChanged(const HealthInfo_2_1& health_info) override;
private:
sp<android::hardware::health::V2_1::IHealth> service_;
std::unique_ptr<Charger> charger_;
};
} // namespace android
int healthd_charger_main(int argc, char** argv);

View file

@ -23,11 +23,12 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
#include <android/hardware/health/2.1/IHealth.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <health/utils.h>
#include "healthd_mode_charger.h"
#include "healthd_mode_charger_hidl.h"
using android::hardware::Return;
using android::hardware::health::InitHealthdConfig;
@ -102,12 +103,12 @@ class MockHealth : public android::hardware::health::V2_1::IHealth {
MOCK_METHOD(Return<void>, shouldKeepScreenOn, (shouldKeepScreenOn_cb _hidl_cb));
};
class TestCharger : public Charger {
class TestCharger : public ChargerHidl {
public:
// Inherit constructor.
using Charger::Charger;
using ChargerHidl::ChargerHidl;
// Expose protected functions to be used in tests.
void Init(struct healthd_config* config) override { Charger::Init(config); }
void Init(struct healthd_config* config) override { ChargerHidl::Init(config); }
MOCK_METHOD(int, CreateDisplaySurface, (const std::string& name, GRSurface** surface));
MOCK_METHOD(int, CreateMultiDisplaySurface,
(const std::string& name, int* frames, int* fps, GRSurface*** surface));

View file

@ -19,11 +19,12 @@
#include <linux/input.h>
#include <memory>
#include <optional>
#include <vector>
#include <android/hardware/health/2.0/IHealthInfoCallback.h>
#include <android/hardware/health/2.1/IHealth.h>
#include <health2impl/HalHealthLoop.h>
#include <aidl/android/hardware/health/BatteryStatus.h>
#include <health/HealthLoop.h>
#include <healthd/healthd.h>
#include "animation.h"
@ -37,22 +38,43 @@ struct key_state {
int64_t timestamp;
};
class Charger : public ::android::hardware::health::V2_1::implementation::HalHealthLoop {
public:
using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
// Health info that interests charger
struct ChargerHealthInfo {
int32_t battery_level;
aidl::android::hardware::health::BatteryStatus battery_status;
};
Charger(const sp<android::hardware::health::V2_1::IHealth>& service);
~Charger();
// Configuration interface for charger. This includes:
// - HalHealthLoop APIs that interests charger.
// - configuration values that used to be provided by sysprops
class ChargerConfigurationInterface {
public:
virtual ~ChargerConfigurationInterface() = default;
// HalHealthLoop related APIs
virtual std::optional<bool> ChargerShouldKeepScreenOn() = 0;
virtual bool ChargerIsOnline() = 0;
virtual void ChargerInitConfig(healthd_config* config) = 0;
using BoundFunction =
std::function<void(android::hardware::health::HealthLoop*, uint32_t /* epevents */)>;
virtual int ChargerRegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) = 0;
// Other configuration values
};
// charger UI
class Charger {
public:
explicit Charger(ChargerConfigurationInterface* configuration);
virtual ~Charger();
// Hooks for ChargerConfigurationInterface
void OnHeartbeat();
int OnPrepareToWait();
// |cookie| is passed to ChargerConfigurationInterface::ChargerInitConfig
void OnInit(struct healthd_config* config);
void OnHealthInfoChanged(const ChargerHealthInfo& health_info);
protected:
// HealthLoop overrides.
void Heartbeat() override;
int PrepareToWait() override;
void Init(struct healthd_config* config) override;
// HalHealthLoop overrides
void OnHealthInfoChanged(const HealthInfo_2_1& health_info) override;
// Allowed to be mocked for testing.
virtual int CreateDisplaySurface(const std::string& name, GRSurface** surface);
virtual int CreateMultiDisplaySurface(const std::string& name, int* frames, int* fps,
@ -83,10 +105,10 @@ class Charger : public ::android::hardware::health::V2_1::implementation::HalHea
GRSurface* surf_unknown_ = nullptr;
int boot_min_cap_ = 0;
HealthInfo_1_0 health_info_ = {};
ChargerHealthInfo health_info_ = {};
std::unique_ptr<HealthdDraw> healthd_draw_;
std::vector<animation::frame> owned_frames_;
ChargerConfigurationInterface* configuration_;
};
} // namespace android
int healthd_charger_main(int argc, char** argv);