Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: device/battery/battery_status_manager_mac.cc

Issue 2818673003: [DeviceService] Expose battery monitoring solely via the Device Service (Closed)
Patch Set: Java file format change Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
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 "device/battery/battery_status_manager.h"
6
7 #include <CoreFoundation/CoreFoundation.h>
8 #include <IOKit/ps/IOPSKeys.h>
9 #include <IOKit/ps/IOPowerSources.h>
10
11 #include <memory>
12 #include <vector>
13
14 #include "base/mac/foundation_util.h"
15 #include "base/mac/scoped_cftyperef.h"
16 #include "base/macros.h"
17 #include "base/metrics/histogram_macros.h"
18 #include "base/time/time.h"
19
20 namespace device {
21
22 namespace {
23
24 typedef BatteryStatusService::BatteryUpdateCallback BatteryCallback;
25
26 // Returns the value corresponding to |key| in the dictionary |description|.
27 // Returns |default_value| if the dictionary does not contain |key|, the
28 // corresponding value is NULL or it could not be converted to SInt64.
29 SInt64 GetValueAsSInt64(CFDictionaryRef description,
30 CFStringRef key,
31 SInt64 default_value) {
32 CFNumberRef number =
33 base::mac::GetValueFromDictionary<CFNumberRef>(description, key);
34 SInt64 value;
35
36 if (number && CFNumberGetValue(number, kCFNumberSInt64Type, &value))
37 return value;
38
39 return default_value;
40 }
41
42 bool GetValueAsBoolean(CFDictionaryRef description,
43 CFStringRef key,
44 bool default_value) {
45 CFBooleanRef boolean =
46 base::mac::GetValueFromDictionary<CFBooleanRef>(description, key);
47
48 return boolean ? CFBooleanGetValue(boolean) : default_value;
49 }
50
51 bool CFStringsAreEqual(CFStringRef string1, CFStringRef string2) {
52 if (!string1 || !string2)
53 return false;
54 return CFStringCompare(string1, string2, 0) == kCFCompareEqualTo;
55 }
56
57 void UpdateNumberBatteriesHistogram(int count) {
58 UMA_HISTOGRAM_CUSTOM_COUNTS(
59 "BatteryStatus.NumberBatteriesMac", count, 1, 5, 6);
60 }
61
62 void FetchBatteryStatus(CFDictionaryRef description,
63 mojom::BatteryStatus* status) {
64 CFStringRef current_state =
65 base::mac::GetValueFromDictionary<CFStringRef>(description,
66 CFSTR(kIOPSPowerSourceStateKey));
67
68 bool on_battery_power =
69 CFStringsAreEqual(current_state, CFSTR(kIOPSBatteryPowerValue));
70 bool is_charging =
71 GetValueAsBoolean(description, CFSTR(kIOPSIsChargingKey), true);
72 bool is_charged =
73 GetValueAsBoolean(description, CFSTR(kIOPSIsChargedKey), false);
74
75 status->charging = !on_battery_power || is_charging;
76
77 SInt64 current_capacity =
78 GetValueAsSInt64(description, CFSTR(kIOPSCurrentCapacityKey), -1);
79 SInt64 max_capacity =
80 GetValueAsSInt64(description, CFSTR(kIOPSMaxCapacityKey), -1);
81
82 // Set level if it is available and valid. Otherwise leave the default value,
83 // which is 1.
84 if (current_capacity != -1 && max_capacity != -1 &&
85 current_capacity <= max_capacity && max_capacity != 0) {
86 status->level = current_capacity / static_cast<double>(max_capacity);
87 }
88
89 if (is_charging) {
90 SInt64 charging_time =
91 GetValueAsSInt64(description, CFSTR(kIOPSTimeToFullChargeKey), -1);
92
93 // Battery is charging: set the charging time if it's available, otherwise
94 // set to +infinity.
95 status->charging_time = charging_time != -1
96 ? base::TimeDelta::FromMinutes(charging_time).InSeconds()
97 : std::numeric_limits<double>::infinity();
98 } else {
99 // Battery is not charging.
100 // Set chargingTime to +infinity if the battery is not charged. Otherwise
101 // leave the default value, which is 0.
102 if (!is_charged)
103 status->charging_time = std::numeric_limits<double>::infinity();
104
105 // Set dischargingTime if it's available and valid, i.e. when on battery
106 // power. Otherwise leave the default value, which is +infinity.
107 if (on_battery_power) {
108 SInt64 discharging_time =
109 GetValueAsSInt64(description, CFSTR(kIOPSTimeToEmptyKey), -1);
110 if (discharging_time != -1) {
111 status->discharging_time =
112 base::TimeDelta::FromMinutes(discharging_time).InSeconds();
113 }
114 }
115 }
116 }
117
118 std::vector<mojom::BatteryStatus> GetInternalBatteriesStates() {
119 std::vector<mojom::BatteryStatus> internal_sources;
120
121 base::ScopedCFTypeRef<CFTypeRef> info(IOPSCopyPowerSourcesInfo());
122 base::ScopedCFTypeRef<CFArrayRef> power_sources_list(
123 IOPSCopyPowerSourcesList(info));
124 CFIndex count = CFArrayGetCount(power_sources_list);
125
126 for (CFIndex i = 0; i < count; ++i) {
127 CFDictionaryRef description = IOPSGetPowerSourceDescription(info,
128 CFArrayGetValueAtIndex(power_sources_list, i));
129
130 if (!description)
131 continue;
132
133 CFStringRef transport_type =
134 base::mac::GetValueFromDictionary<CFStringRef>(description,
135 CFSTR(kIOPSTransportTypeKey));
136
137 bool internal_source =
138 CFStringsAreEqual(transport_type, CFSTR(kIOPSInternalType));
139 bool source_present =
140 GetValueAsBoolean(description, CFSTR(kIOPSIsPresentKey), false);
141
142 if (internal_source && source_present) {
143 mojom::BatteryStatus status;
144 FetchBatteryStatus(description, &status);
145 internal_sources.push_back(status);
146 }
147 }
148
149 return internal_sources;
150 }
151
152 void OnBatteryStatusChanged(const BatteryCallback& callback) {
153 std::vector<mojom::BatteryStatus> batteries(GetInternalBatteriesStates());
154
155 if (batteries.empty()) {
156 callback.Run(mojom::BatteryStatus());
157 return;
158 }
159
160 // TODO(timvolodine): implement the case when there are multiple internal
161 // sources, e.g. when multiple batteries are present. Currently this will
162 // fail a DCHECK.
163 DCHECK(batteries.size() == 1);
164 callback.Run(batteries.front());
165 }
166
167 class BatteryStatusObserver {
168 public:
169 explicit BatteryStatusObserver(const BatteryCallback& callback)
170 : callback_(callback) {}
171
172 ~BatteryStatusObserver() { DCHECK(!notifier_run_loop_source_); }
173
174 void Start() {
175 if (notifier_run_loop_source_)
176 return;
177
178 notifier_run_loop_source_.reset(
179 IOPSNotificationCreateRunLoopSource(CallOnBatteryStatusChanged,
180 static_cast<void*>(&callback_)));
181 if (!notifier_run_loop_source_) {
182 LOG(ERROR) << "Failed to create battery status notification run loop";
183 // Make sure to execute to callback with the default values.
184 callback_.Run(mojom::BatteryStatus());
185 return;
186 }
187
188 CallOnBatteryStatusChanged(static_cast<void*>(&callback_));
189 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifier_run_loop_source_,
190 kCFRunLoopDefaultMode);
191 UpdateNumberBatteriesHistogram(GetInternalBatteriesStates().size());
192 }
193
194 void Stop() {
195 if (!notifier_run_loop_source_)
196 return;
197
198 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), notifier_run_loop_source_,
199 kCFRunLoopDefaultMode);
200 notifier_run_loop_source_.reset();
201 }
202
203 private:
204 static void CallOnBatteryStatusChanged(void* callback) {
205 OnBatteryStatusChanged(*static_cast<BatteryCallback*>(callback));
206 }
207
208 BatteryCallback callback_;
209 base::ScopedCFTypeRef<CFRunLoopSourceRef> notifier_run_loop_source_;
210
211 DISALLOW_COPY_AND_ASSIGN(BatteryStatusObserver);
212 };
213
214 class BatteryStatusManagerMac : public BatteryStatusManager {
215 public:
216 explicit BatteryStatusManagerMac(const BatteryCallback& callback)
217 : notifier_(new BatteryStatusObserver(callback)) {}
218
219 ~BatteryStatusManagerMac() override { notifier_->Stop(); }
220
221 // BatteryStatusManager:
222 bool StartListeningBatteryChange() override {
223 notifier_->Start();
224 return true;
225 }
226
227 void StopListeningBatteryChange() override {
228 notifier_->Stop();
229 }
230
231 private:
232 std::unique_ptr<BatteryStatusObserver> notifier_;
233
234 DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerMac);
235 };
236
237 } // end namespace
238
239 // static
240 std::unique_ptr<BatteryStatusManager> BatteryStatusManager::Create(
241 const BatteryStatusService::BatteryUpdateCallback& callback) {
242 return std::unique_ptr<BatteryStatusManager>(
243 new BatteryStatusManagerMac(callback));
244 }
245
246 } // namespace device
OLDNEW
« no previous file with comments | « device/battery/battery_status_manager_linux_unittest.cc ('k') | device/battery/battery_status_manager_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698