1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/power_monitor/battery_state_sampler.h"
6
7 #include "base/power_monitor/power_monitor_buildflags.h"
8
9 #if !BUILDFLAG(IS_MAC)
10 #include "base/power_monitor/timer_sampling_event_source.h"
11 #endif
12
13 namespace base {
14
15 namespace {
16
17 // Singleton instance of the BatteryStateSampler.
18 BatteryStateSampler* g_battery_state_sampler = nullptr;
19 bool g_test_instance_installed = false;
20
21 } // namespace
22
BatteryStateSampler(std::unique_ptr<SamplingEventSource> sampling_event_source,std::unique_ptr<BatteryLevelProvider> battery_level_provider)23 BatteryStateSampler::BatteryStateSampler(
24 std::unique_ptr<SamplingEventSource> sampling_event_source,
25 std::unique_ptr<BatteryLevelProvider> battery_level_provider)
26 : sampling_event_source_(std::move(sampling_event_source)),
27 battery_level_provider_(std::move(battery_level_provider)) {
28 DCHECK(sampling_event_source_);
29 DCHECK(battery_level_provider_);
30
31 DCHECK(!g_battery_state_sampler);
32 g_battery_state_sampler = this;
33
34 // Get an initial sample.
35 battery_level_provider_->GetBatteryState(
36 base::BindOnce(&BatteryStateSampler::OnInitialBatteryStateSampled,
37 base::Unretained(this)));
38
39 // Start the periodic sampling.
40 sampling_event_source_->Start(base::BindRepeating(
41 &BatteryStateSampler::OnSamplingEvent, base::Unretained(this)));
42 }
43
~BatteryStateSampler()44 BatteryStateSampler::~BatteryStateSampler() {
45 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
46 DCHECK_EQ(g_battery_state_sampler, this);
47 g_battery_state_sampler = nullptr;
48 g_test_instance_installed = false;
49 }
50
51 // static
Get()52 BatteryStateSampler* BatteryStateSampler::Get() {
53 // On a platform with a BatteryLevelProvider implementation, the global
54 // instance must be created before accessing it.
55 // TODO(crbug.com/1373560): ChromeOS currently doesn't define
56 // `HAS_BATTERY_LEVEL_PROVIDER_IMPL` but it should once the locations of the
57 // providers and sampling sources are consolidated.
58 #if BUILDFLAG(HAS_BATTERY_LEVEL_PROVIDER_IMPL) || BUILDFLAG(IS_CHROMEOS_ASH)
59 DCHECK(g_battery_state_sampler);
60 #endif
61 return g_battery_state_sampler;
62 }
63
AddObserver(Observer * observer)64 void BatteryStateSampler::AddObserver(Observer* observer) {
65 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
66
67 observer_list_.AddObserver(observer);
68
69 // Send the last sample available.
70 if (has_last_battery_state_)
71 observer->OnBatteryStateSampled(last_battery_state_);
72 }
73
RemoveObserver(Observer * observer)74 void BatteryStateSampler::RemoveObserver(Observer* observer) {
75 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
76 observer_list_.RemoveObserver(observer);
77 }
78
Shutdown()79 void BatteryStateSampler::Shutdown() {
80 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
81 sampling_event_source_.reset();
82 battery_level_provider_.reset();
83 }
84
85 // static
86 std::unique_ptr<base::BatteryStateSampler>
CreateInstanceForTesting(std::unique_ptr<SamplingEventSource> sampling_event_source,std::unique_ptr<BatteryLevelProvider> battery_level_provider)87 BatteryStateSampler::CreateInstanceForTesting(
88 std::unique_ptr<SamplingEventSource> sampling_event_source,
89 std::unique_ptr<BatteryLevelProvider> battery_level_provider) {
90 g_test_instance_installed = true;
91 return std::make_unique<BatteryStateSampler>(
92 std::move(sampling_event_source), std::move(battery_level_provider));
93 }
94
95 // static
HasTestingInstance()96 bool BatteryStateSampler::HasTestingInstance() {
97 return g_test_instance_installed;
98 }
99
100 #if !BUILDFLAG(IS_MAC)
101 // static
102 std::unique_ptr<SamplingEventSource>
CreateSamplingEventSource()103 BatteryStateSampler::CreateSamplingEventSource() {
104 // On platforms where the OS does not provide a notification when an updated
105 // battery level is available, simply sample on a regular 1 minute interval.
106 return std::make_unique<TimerSamplingEventSource>(Minutes(1));
107 }
108 #endif // !BUILDFLAG(IS_MAC)
109
OnInitialBatteryStateSampled(const std::optional<BatteryLevelProvider::BatteryState> & battery_state)110 void BatteryStateSampler::OnInitialBatteryStateSampled(
111 const std::optional<BatteryLevelProvider::BatteryState>& battery_state) {
112 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
113
114 DCHECK(!has_last_battery_state_);
115 has_last_battery_state_ = true;
116 last_battery_state_ = battery_state;
117
118 for (auto& observer : observer_list_)
119 observer.OnBatteryStateSampled(battery_state);
120 }
121
OnSamplingEvent()122 void BatteryStateSampler::OnSamplingEvent() {
123 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
124 DCHECK(battery_level_provider_);
125
126 battery_level_provider_->GetBatteryState(base::BindOnce(
127 &BatteryStateSampler::OnBatteryStateSampled, base::Unretained(this)));
128 }
129
OnBatteryStateSampled(const std::optional<BatteryLevelProvider::BatteryState> & battery_state)130 void BatteryStateSampler::OnBatteryStateSampled(
131 const std::optional<BatteryLevelProvider::BatteryState>& battery_state) {
132 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
133
134 DCHECK(has_last_battery_state_);
135 last_battery_state_ = battery_state;
136
137 for (auto& observer : observer_list_)
138 observer.OnBatteryStateSampled(battery_state);
139 }
140
141 } // namespace base
142