Commit 9af3ef99 authored by Bailey Berro's avatar Bailey Berro Committed by Commit Bot

Add BatteryHealthObserver to SystemDataProvider

Allows clients to implement the BatteryHealthObserver interface and
register themselves as an observer in order to receive periodic updates
about the battery health.

Bug: 1128204
Change-Id: Ib4ffc60ec5fd30bda37c255bd17b669eaa4b9f74
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2438474
Commit-Queue: Bailey Berro <baileyberro@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarZentaro Kavanagh <zentaro@chromium.org>
Cr-Commit-Position: refs/heads/master@{#812822}
parent a1c2aee1
...@@ -29,7 +29,9 @@ using PhysicalCpuInfos = std::vector<healthd::PhysicalCpuInfoPtr>; ...@@ -29,7 +29,9 @@ using PhysicalCpuInfos = std::vector<healthd::PhysicalCpuInfoPtr>;
using PowerSupplyProperties = power_manager::PowerSupplyProperties; using PowerSupplyProperties = power_manager::PowerSupplyProperties;
using ProbeCategories = healthd::ProbeCategoryEnum; using ProbeCategories = healthd::ProbeCategoryEnum;
constexpr int kBatteryHealthRefreshIntervalInSeconds = 60;
constexpr int kChargeStatusRefreshIntervalInSeconds = 15; constexpr int kChargeStatusRefreshIntervalInSeconds = 15;
constexpr int kMilliampsInAnAmp = 1000;
void PopulateBoardName(const healthd::SystemInfo& system_info, void PopulateBoardName(const healthd::SystemInfo& system_info,
mojom::SystemInfo& out_system_info) { mojom::SystemInfo& out_system_info) {
...@@ -86,9 +88,8 @@ void PopulateDeviceCapabilities(const healthd::TelemetryInfo& telemetry_info, ...@@ -86,9 +88,8 @@ void PopulateDeviceCapabilities(const healthd::TelemetryInfo& telemetry_info,
void PopulateBatteryInfo(const healthd::BatteryInfo& battery_info, void PopulateBatteryInfo(const healthd::BatteryInfo& battery_info,
mojom::BatteryInfo& out_battery_info) { mojom::BatteryInfo& out_battery_info) {
out_battery_info.manufacturer = battery_info.vendor; out_battery_info.manufacturer = battery_info.vendor;
// Multiply by 1000 to convert amps to milliamps.
out_battery_info.charge_full_design_milliamp_hours = out_battery_info.charge_full_design_milliamp_hours =
battery_info.charge_full_design * 1000; battery_info.charge_full_design * kMilliampsInAnAmp;
} }
void PopulatePowerInfo(const PowerSupplyProperties& power_supply_properties, void PopulatePowerInfo(const PowerSupplyProperties& power_supply_properties,
...@@ -109,15 +110,29 @@ void PopulateBatteryChargeStatus( ...@@ -109,15 +110,29 @@ void PopulateBatteryChargeStatus(
mojom::BatteryChargeStatus& out_charge_status) { mojom::BatteryChargeStatus& out_charge_status) {
PopulatePowerInfo(power_supply_properties, out_charge_status); PopulatePowerInfo(power_supply_properties, out_charge_status);
// Multiply by 1000 to convert amps to milliamps. out_charge_status.current_now_milliamps =
out_charge_status.current_now_milliamps = battery_info.current_now * 1000; battery_info.current_now * kMilliampsInAnAmp;
out_charge_status.charge_now_milliamp_hours = battery_info.charge_now * 1000; out_charge_status.charge_now_milliamp_hours =
battery_info.charge_now * kMilliampsInAnAmp;
}
void PopulateBatteryHealth(const healthd::BatteryInfo& battery_info,
mojom::BatteryHealth& out_battery_health) {
out_battery_health.charge_full_now_milliamp_hours =
battery_info.charge_full * kMilliampsInAnAmp;
out_battery_health.charge_full_design_milliamp_hours =
battery_info.charge_full_design * kMilliampsInAnAmp;
out_battery_health.cycle_count = battery_info.cycle_count;
out_battery_health.battery_wear_percentage =
out_battery_health.charge_full_now_milliamp_hours /
out_battery_health.charge_full_design_milliamp_hours;
} }
} // namespace } // namespace
SystemDataProvider::SystemDataProvider() { SystemDataProvider::SystemDataProvider() {
battery_charge_status_timer_ = std::make_unique<base::RepeatingTimer>(); battery_charge_status_timer_ = std::make_unique<base::RepeatingTimer>();
battery_health_timer_ = std::make_unique<base::RepeatingTimer>();
PowerManagerClient::Get()->AddObserver(this); PowerManagerClient::Get()->AddObserver(this);
} }
...@@ -158,6 +173,20 @@ void SystemDataProvider::ObserveBatteryChargeStatus( ...@@ -158,6 +173,20 @@ void SystemDataProvider::ObserveBatteryChargeStatus(
UpdateBatteryChargeStatus(); UpdateBatteryChargeStatus();
} }
void SystemDataProvider::ObserveBatteryHealth(
mojo::PendingRemote<mojom::BatteryHealthObserver> observer) {
battery_health_observers_.Add(std::move(observer));
if (!battery_health_timer_->IsRunning()) {
battery_health_timer_->Start(
FROM_HERE,
base::TimeDelta::FromSeconds(kBatteryHealthRefreshIntervalInSeconds),
base::BindRepeating(&SystemDataProvider::UpdateBatteryHealth,
base::Unretained(this)));
}
UpdateBatteryHealth();
}
void SystemDataProvider::PowerChanged( void SystemDataProvider::PowerChanged(
const power_manager::PowerSupplyProperties& proto) { const power_manager::PowerSupplyProperties& proto) {
if (battery_charge_status_observers_.empty()) { if (battery_charge_status_observers_.empty()) {
...@@ -177,6 +206,11 @@ void SystemDataProvider::SetBatteryChargeStatusTimerForTesting( ...@@ -177,6 +206,11 @@ void SystemDataProvider::SetBatteryChargeStatusTimerForTesting(
battery_charge_status_timer_ = std::move(timer); battery_charge_status_timer_ = std::move(timer);
} }
void SystemDataProvider::SetBatteryHealthTimerForTesting(
std::unique_ptr<base::RepeatingTimer> timer) {
battery_health_timer_ = std::move(timer);
}
void SystemDataProvider::OnSystemInfoProbeResponse( void SystemDataProvider::OnSystemInfoProbeResponse(
GetSystemInfoCallback callback, GetSystemInfoCallback callback,
healthd::TelemetryInfoPtr info_ptr) { healthd::TelemetryInfoPtr info_ptr) {
...@@ -258,6 +292,15 @@ void SystemDataProvider::UpdateBatteryChargeStatus() { ...@@ -258,6 +292,15 @@ void SystemDataProvider::UpdateBatteryChargeStatus() {
base::Unretained(this), properties)); base::Unretained(this), properties));
} }
void SystemDataProvider::UpdateBatteryHealth() {
BindCrosHealthdProbeServiceIfNeccessary();
probe_service_->ProbeTelemetryInfo(
{ProbeCategories::kBattery},
base::BindOnce(&SystemDataProvider::OnBatteryHealthUpdated,
base::Unretained(this)));
}
void SystemDataProvider::OnBatteryChargeStatusUpdated( void SystemDataProvider::OnBatteryChargeStatusUpdated(
const base::Optional<PowerSupplyProperties>& power_supply_properties, const base::Optional<PowerSupplyProperties>& power_supply_properties,
healthd::TelemetryInfoPtr info_ptr) { healthd::TelemetryInfoPtr info_ptr) {
...@@ -294,6 +337,28 @@ void SystemDataProvider::OnBatteryChargeStatusUpdated( ...@@ -294,6 +337,28 @@ void SystemDataProvider::OnBatteryChargeStatusUpdated(
NotifyBatteryChargeStatusObservers(battery_charge_status); NotifyBatteryChargeStatusObservers(battery_charge_status);
} }
void SystemDataProvider::OnBatteryHealthUpdated(
healthd::TelemetryInfoPtr info_ptr) {
mojom::BatteryHealthPtr battery_health = mojom::BatteryHealth::New();
if (info_ptr.is_null()) {
LOG(ERROR) << "Null response from croshealthd::ProbeTelemetryInfo.";
NotifyBatteryHealthObservers(battery_health);
battery_health_timer_.reset();
return;
}
if (!DoesDeviceHaveBattery(*info_ptr)) {
NotifyBatteryHealthObservers(battery_health);
battery_health_timer_.reset();
return;
}
PopulateBatteryHealth(*diagnostics::GetBatteryInfo(*info_ptr),
*battery_health.get());
NotifyBatteryHealthObservers(battery_health);
}
void SystemDataProvider::NotifyBatteryChargeStatusObservers( void SystemDataProvider::NotifyBatteryChargeStatusObservers(
const mojom::BatteryChargeStatusPtr& battery_charge_status) { const mojom::BatteryChargeStatusPtr& battery_charge_status) {
for (auto& observer : battery_charge_status_observers_) { for (auto& observer : battery_charge_status_observers_) {
...@@ -301,6 +366,13 @@ void SystemDataProvider::NotifyBatteryChargeStatusObservers( ...@@ -301,6 +366,13 @@ void SystemDataProvider::NotifyBatteryChargeStatusObservers(
} }
} }
void SystemDataProvider::NotifyBatteryHealthObservers(
const mojom::BatteryHealthPtr& battery_health) {
for (auto& observer : battery_health_observers_) {
observer->OnBatteryHealthUpdated(battery_health.Clone());
}
}
void SystemDataProvider::BindCrosHealthdProbeServiceIfNeccessary() { void SystemDataProvider::BindCrosHealthdProbeServiceIfNeccessary() {
if (!probe_service_ || !probe_service_.is_connected()) { if (!probe_service_ || !probe_service_.is_connected()) {
cros_healthd::ServiceConnection::GetInstance()->GetProbeService( cros_healthd::ServiceConnection::GetInstance()->GetProbeService(
......
...@@ -37,6 +37,8 @@ class SystemDataProvider : public mojom::SystemDataProvider, ...@@ -37,6 +37,8 @@ class SystemDataProvider : public mojom::SystemDataProvider,
void ObserveBatteryChargeStatus( void ObserveBatteryChargeStatus(
mojo::PendingRemote<mojom::BatteryChargeStatusObserver> observer) mojo::PendingRemote<mojom::BatteryChargeStatusObserver> observer)
override; override;
void ObserveBatteryHealth(
mojo::PendingRemote<mojom::BatteryHealthObserver> observer) override;
// PowerManagerClient::Observer: // PowerManagerClient::Observer:
void PowerChanged(const power_manager::PowerSupplyProperties& proto) override; void PowerChanged(const power_manager::PowerSupplyProperties& proto) override;
...@@ -44,6 +46,9 @@ class SystemDataProvider : public mojom::SystemDataProvider, ...@@ -44,6 +46,9 @@ class SystemDataProvider : public mojom::SystemDataProvider,
void SetBatteryChargeStatusTimerForTesting( void SetBatteryChargeStatusTimerForTesting(
std::unique_ptr<base::RepeatingTimer> timer); std::unique_ptr<base::RepeatingTimer> timer);
void SetBatteryHealthTimerForTesting(
std::unique_ptr<base::RepeatingTimer> timer);
private: private:
void BindCrosHealthdProbeServiceIfNeccessary(); void BindCrosHealthdProbeServiceIfNeccessary();
...@@ -59,19 +64,28 @@ class SystemDataProvider : public mojom::SystemDataProvider, ...@@ -59,19 +64,28 @@ class SystemDataProvider : public mojom::SystemDataProvider,
void UpdateBatteryChargeStatus(); void UpdateBatteryChargeStatus();
void UpdateBatteryHealth();
void NotifyBatteryChargeStatusObservers( void NotifyBatteryChargeStatusObservers(
const mojom::BatteryChargeStatusPtr& battery_charge_status); const mojom::BatteryChargeStatusPtr& battery_charge_status);
void NotifyBatteryHealthObservers(
const mojom::BatteryHealthPtr& battery_health);
void OnBatteryChargeStatusUpdated( void OnBatteryChargeStatusUpdated(
const base::Optional<power_manager::PowerSupplyProperties>& const base::Optional<power_manager::PowerSupplyProperties>&
power_supply_properties, power_supply_properties,
cros_healthd::mojom::TelemetryInfoPtr info_ptr); cros_healthd::mojom::TelemetryInfoPtr info_ptr);
void OnBatteryHealthUpdated(cros_healthd::mojom::TelemetryInfoPtr info_ptr);
mojo::Remote<cros_healthd::mojom::CrosHealthdProbeService> probe_service_; mojo::Remote<cros_healthd::mojom::CrosHealthdProbeService> probe_service_;
mojo::RemoteSet<mojom::BatteryChargeStatusObserver> mojo::RemoteSet<mojom::BatteryChargeStatusObserver>
battery_charge_status_observers_; battery_charge_status_observers_;
mojo::RemoteSet<mojom::BatteryHealthObserver> battery_health_observers_;
std::unique_ptr<base::RepeatingTimer> battery_charge_status_timer_; std::unique_ptr<base::RepeatingTimer> battery_charge_status_timer_;
std::unique_ptr<base::RepeatingTimer> battery_health_timer_;
}; };
} // namespace diagnostics } // namespace diagnostics
......
...@@ -156,6 +156,27 @@ CreateCrosHealthdBatteryChargeStatusResponse(double charge_now, ...@@ -156,6 +156,27 @@ CreateCrosHealthdBatteryChargeStatusResponse(double charge_now,
/*temperature=*/0); /*temperature=*/0);
} }
cros_healthd::mojom::BatteryInfoPtr CreateCrosHealthdBatteryHealthResponse(
double charge_full_now,
double charge_full_design,
int32_t cycle_count) {
return CreateCrosHealthdBatteryInfoResponse(
/*cycle_count=*/cycle_count,
/*voltage_now=*/0,
/*vendor=*/"",
/*serial_number=*/"",
/*charge_full_design=*/charge_full_design,
/*charge_full=*/charge_full_now,
/*voltage_min_design=*/0,
/*model_name=*/"",
/*charge_now=*/0,
/*current_now=*/0,
/*technology=*/"",
/*status=*/"",
/*manufacture_date=*/base::nullopt,
/*temperature=*/0);
}
void SetCrosHealthdBatteryInfoResponse(const std::string& vendor, void SetCrosHealthdBatteryInfoResponse(const std::string& vendor,
double charge_full_design) { double charge_full_design) {
cros_healthd::mojom::BatteryInfoPtr battery_info = cros_healthd::mojom::BatteryInfoPtr battery_info =
...@@ -174,6 +195,17 @@ void SetCrosHealthdBatteryChargeStatusResponse(double charge_now, ...@@ -174,6 +195,17 @@ void SetCrosHealthdBatteryChargeStatusResponse(double charge_now,
/*memory_info=*/nullptr); /*memory_info=*/nullptr);
} }
void SetCrosHealthdBatteryHealthResponse(double charge_full_now,
double charge_full_design,
int32_t cycle_count) {
cros_healthd::mojom::BatteryInfoPtr battery_info =
CreateCrosHealthdBatteryHealthResponse(charge_full_now,
charge_full_design, cycle_count);
SetProbeTelemetryInfoResponse(std::move(battery_info), /*cpu_info=*/nullptr,
/*memory_info=*/nullptr,
/*memory_info=*/nullptr);
}
bool AreValidPowerTimes(int64_t time_to_full, int64_t time_to_empty) { bool AreValidPowerTimes(int64_t time_to_full, int64_t time_to_empty) {
// Exactly one of |time_to_full| or |time_to_empty| must be zero. The other // Exactly one of |time_to_full| or |time_to_empty| must be zero. The other
// can be a positive integer to represent the time to charge/discharge or -1 // can be a positive integer to represent the time to charge/discharge or -1
...@@ -209,9 +241,9 @@ power_manager::PowerSupplyProperties ConstructPowerSupplyProperties( ...@@ -209,9 +241,9 @@ power_manager::PowerSupplyProperties ConstructPowerSupplyProperties(
// Sets the PowerSupplyProperties on FakePowerManagerClient. Calling this // Sets the PowerSupplyProperties on FakePowerManagerClient. Calling this
// method immediately notifies PowerManagerClient observers. One of // method immediately notifies PowerManagerClient observers. One of
// |time_to_full| or |time_to_empty| must be either -1 or a positive number. The // |time_to_full| or |time_to_empty| must be either -1 or a positive number.
// other must be 0. If |battery_state| is NOT_PRESENT, both |time_to_full| and // The other must be 0. If |battery_state| is NOT_PRESENT, both |time_to_full|
// |time_to_empty| will be left unset. // and |time_to_empty| will be left unset.
void SetPowerManagerProperties( void SetPowerManagerProperties(
power_manager::PowerSupplyProperties::ExternalPower power_source, power_manager::PowerSupplyProperties::ExternalPower power_source,
power_manager::PowerSupplyProperties::BatteryState battery_state, power_manager::PowerSupplyProperties::BatteryState battery_state,
...@@ -263,6 +295,26 @@ void VerifyChargeStatusResult( ...@@ -263,6 +295,26 @@ void VerifyChargeStatusResult(
EXPECT_EQ(expected_power_time, update->power_time); EXPECT_EQ(expected_power_time, update->power_time);
} }
void VerifyHealthResult(const mojom::BatteryHealthPtr& update,
double charge_full_now,
double charge_full_design,
int32_t expected_cycle_count) {
const int32_t expected_charge_full_now_milliamp_hours =
charge_full_now * 1000;
const int32_t expected_charge_full_design_milliamp_hours =
charge_full_design * 1000;
const int8_t expected_battery_wear_percentage =
expected_charge_full_now_milliamp_hours /
expected_charge_full_design_milliamp_hours;
EXPECT_EQ(expected_charge_full_now_milliamp_hours,
update->charge_full_now_milliamp_hours);
EXPECT_EQ(expected_charge_full_design_milliamp_hours,
update->charge_full_design_milliamp_hours);
EXPECT_EQ(expected_cycle_count, update->cycle_count);
EXPECT_EQ(expected_battery_wear_percentage, update->battery_wear_percentage);
}
} // namespace } // namespace
struct FakeBatteryChargeStatusObserver struct FakeBatteryChargeStatusObserver
...@@ -280,6 +332,19 @@ struct FakeBatteryChargeStatusObserver ...@@ -280,6 +332,19 @@ struct FakeBatteryChargeStatusObserver
mojo::Receiver<mojom::BatteryChargeStatusObserver> receiver{this}; mojo::Receiver<mojom::BatteryChargeStatusObserver> receiver{this};
}; };
struct FakeBatteryHealthObserver : public mojom::BatteryHealthObserver {
// mojom::BatteryHealthObserver
void OnBatteryHealthUpdated(mojom::BatteryHealthPtr status_ptr) override {
updates.emplace_back(std::move(status_ptr));
}
// Tracks calls to OnBatteryHealthUpdated. Each call adds an element to
// the vector.
std::vector<mojom::BatteryHealthPtr> updates;
mojo::Receiver<mojom::BatteryHealthObserver> receiver{this};
};
class SystemDataProviderTest : public testing::Test { class SystemDataProviderTest : public testing::Test {
public: public:
SystemDataProviderTest() { SystemDataProviderTest() {
...@@ -446,5 +511,53 @@ TEST_F(SystemDataProviderTest, BatteryChargeStatusObserver) { ...@@ -446,5 +511,53 @@ TEST_F(SystemDataProviderTest, BatteryChargeStatusObserver) {
new_time_to_full_secs, time_to_empty_secs); new_time_to_full_secs, time_to_empty_secs);
} }
TEST_F(SystemDataProviderTest, BatteryHealthObserver) {
// Setup Timer
auto timer = std::make_unique<base::MockRepeatingTimer>();
auto* timer_ptr = timer.get();
system_data_provider_->SetBatteryHealthTimerForTesting(std::move(timer));
// Setup initial data
const double charge_full_now = 20;
const double charge_full_design = 26;
const int32_t cycle_count = 500;
SetCrosHealthdBatteryHealthResponse(charge_full_now, charge_full_design,
cycle_count);
// Registering as an observer should trigger one update.
FakeBatteryHealthObserver health_observer;
system_data_provider_->ObserveBatteryHealth(
health_observer.receiver.BindNewPipeAndPassRemote());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, health_observer.updates.size());
VerifyHealthResult(health_observer.updates[0], charge_full_now,
charge_full_design, cycle_count);
// Firing the timer should trigger another.
timer_ptr->Fire();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2u, health_observer.updates.size());
VerifyHealthResult(health_observer.updates[1], charge_full_now,
charge_full_design, cycle_count);
// Updating the information in Croshealthd does not trigger an update until
// the timer fires
const int32_t new_cycle_count = cycle_count + 1;
SetCrosHealthdBatteryHealthResponse(charge_full_now, charge_full_design,
new_cycle_count);
EXPECT_EQ(2u, health_observer.updates.size());
timer_ptr->Fire();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(3u, health_observer.updates.size());
VerifyHealthResult(health_observer.updates[2], charge_full_now,
charge_full_design, new_cycle_count);
}
} // namespace diagnostics } // namespace diagnostics
} // namespace chromeos } // namespace chromeos
...@@ -55,6 +55,14 @@ struct BatteryChargeStatus { ...@@ -55,6 +55,14 @@ struct BatteryChargeStatus {
ExternalPowerSource power_adapter_status; ExternalPowerSource power_adapter_status;
}; };
// Contains information about the health of the battery.
struct BatteryHealth {
int32 charge_full_now_milliamp_hours;
int32 charge_full_design_milliamp_hours;
int32 cycle_count;
int8 battery_wear_percentage;
};
// Implemented by clients that wish to be updated periodically about changes to // Implemented by clients that wish to be updated periodically about changes to
// the battery charge status. // the battery charge status.
interface BatteryChargeStatusObserver { interface BatteryChargeStatusObserver {
...@@ -65,6 +73,15 @@ interface BatteryChargeStatusObserver { ...@@ -65,6 +73,15 @@ interface BatteryChargeStatusObserver {
OnBatteryChargeStatusUpdated(BatteryChargeStatus battery_charge_status); OnBatteryChargeStatusUpdated(BatteryChargeStatus battery_charge_status);
}; };
// Implemented by clients that wish to be updated periodically about the health
// of the device battery.
interface BatteryHealthObserver {
// OnBatteryHealthUpdated calls can be triggered by either of 2 conditions:
// 1) A BatteryHealthObserver is registered with SystemDataProvider
// 2) A periodic update is sent by SystemDataProvider
OnBatteryHealthUpdated(BatteryHealth battery_health);
};
// Provides telemetric information about the system. This API is exposed to the // Provides telemetric information about the system. This API is exposed to the
// Diagnostics SWA. // Diagnostics SWA.
interface SystemDataProvider { interface SystemDataProvider {
...@@ -80,4 +97,7 @@ interface SystemDataProvider { ...@@ -80,4 +97,7 @@ interface SystemDataProvider {
// Registers an observer of BatteryChargeStatus information. // Registers an observer of BatteryChargeStatus information.
ObserveBatteryChargeStatus( ObserveBatteryChargeStatus(
pending_remote<BatteryChargeStatusObserver> observer); pending_remote<BatteryChargeStatusObserver> observer);
// Registers an observer of BatteryHealth inforamation.
ObserveBatteryHealth(pending_remote<BatteryHealthObserver> observer);
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment