OLD | NEW |
| (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_linux.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <stdint.h> | |
9 | |
10 #include <limits> | |
11 #include <memory> | |
12 #include <string> | |
13 #include <utility> | |
14 #include <vector> | |
15 | |
16 #include "base/macros.h" | |
17 #include "base/metrics/histogram_macros.h" | |
18 #include "base/single_thread_task_runner.h" | |
19 #include "base/threading/thread.h" | |
20 #include "base/values.h" | |
21 #include "base/version.h" | |
22 #include "dbus/bus.h" | |
23 #include "dbus/message.h" | |
24 #include "dbus/object_path.h" | |
25 #include "dbus/object_proxy.h" | |
26 #include "dbus/property.h" | |
27 #include "dbus/values_util.h" | |
28 #include "device/battery/battery_status_manager_linux-inl.h" | |
29 | |
30 namespace device { | |
31 namespace { | |
32 const char kBatteryNotifierThreadName[] = "BatteryStatusNotifier"; | |
33 | |
34 class UPowerProperties : public dbus::PropertySet { | |
35 public: | |
36 UPowerProperties(dbus::ObjectProxy* object_proxy, | |
37 const PropertyChangedCallback callback); | |
38 ~UPowerProperties() override; | |
39 | |
40 base::Version daemon_version(); | |
41 | |
42 private: | |
43 dbus::Property<std::string> daemon_version_; | |
44 | |
45 DISALLOW_COPY_AND_ASSIGN(UPowerProperties); | |
46 }; | |
47 | |
48 UPowerProperties::UPowerProperties(dbus::ObjectProxy* object_proxy, | |
49 const PropertyChangedCallback callback) | |
50 : dbus::PropertySet(object_proxy, kUPowerInterfaceName, callback) { | |
51 RegisterProperty(kUPowerPropertyDaemonVersion, &daemon_version_); | |
52 } | |
53 | |
54 UPowerProperties::~UPowerProperties() {} | |
55 | |
56 base::Version UPowerProperties::daemon_version() { | |
57 return (daemon_version_.is_valid() || daemon_version_.GetAndBlock()) | |
58 ? base::Version(daemon_version_.value()) | |
59 : base::Version(); | |
60 } | |
61 | |
62 class UPowerObject { | |
63 public: | |
64 using PropertyChangedCallback = dbus::PropertySet::PropertyChangedCallback; | |
65 | |
66 UPowerObject(dbus::Bus* dbus, | |
67 const PropertyChangedCallback property_changed_callback); | |
68 ~UPowerObject(); | |
69 | |
70 std::vector<dbus::ObjectPath> EnumerateDevices(); | |
71 dbus::ObjectPath GetDisplayDevice(); | |
72 | |
73 dbus::ObjectProxy* proxy() { return proxy_; } | |
74 UPowerProperties* properties() { return properties_.get(); } | |
75 | |
76 private: | |
77 dbus::Bus* dbus_; // Owned by the BatteryStatusNotificationThread. | |
78 dbus::ObjectProxy* proxy_; // Owned by the dbus. | |
79 std::unique_ptr<UPowerProperties> properties_; | |
80 | |
81 DISALLOW_COPY_AND_ASSIGN(UPowerObject); | |
82 }; | |
83 | |
84 UPowerObject::UPowerObject( | |
85 dbus::Bus* dbus, | |
86 const PropertyChangedCallback property_changed_callback) | |
87 : dbus_(dbus), | |
88 proxy_(dbus_->GetObjectProxy(kUPowerServiceName, | |
89 dbus::ObjectPath(kUPowerPath))), | |
90 properties_(new UPowerProperties(proxy_, property_changed_callback)) {} | |
91 | |
92 UPowerObject::~UPowerObject() { | |
93 properties_.reset(); // before the proxy is deleted. | |
94 dbus_->RemoveObjectProxy(kUPowerServiceName, proxy_->object_path(), | |
95 base::Bind(&base::DoNothing)); | |
96 } | |
97 | |
98 std::vector<dbus::ObjectPath> UPowerObject::EnumerateDevices() { | |
99 std::vector<dbus::ObjectPath> paths; | |
100 dbus::MethodCall method_call(kUPowerServiceName, | |
101 kUPowerMethodEnumerateDevices); | |
102 std::unique_ptr<dbus::Response> response(proxy_->CallMethodAndBlock( | |
103 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); | |
104 | |
105 if (response) { | |
106 dbus::MessageReader reader(response.get()); | |
107 reader.PopArrayOfObjectPaths(&paths); | |
108 } | |
109 return paths; | |
110 } | |
111 | |
112 dbus::ObjectPath UPowerObject::GetDisplayDevice() { | |
113 dbus::ObjectPath display_device_path; | |
114 if (!proxy_) | |
115 return display_device_path; | |
116 | |
117 dbus::MethodCall method_call(kUPowerServiceName, | |
118 kUPowerMethodGetDisplayDevice); | |
119 std::unique_ptr<dbus::Response> response(proxy_->CallMethodAndBlock( | |
120 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); | |
121 | |
122 if (response) { | |
123 dbus::MessageReader reader(response.get()); | |
124 reader.PopObjectPath(&display_device_path); | |
125 } | |
126 return display_device_path; | |
127 } | |
128 | |
129 void UpdateNumberBatteriesHistogram(int count) { | |
130 UMA_HISTOGRAM_CUSTOM_COUNTS( | |
131 "BatteryStatus.NumberBatteriesLinux", count, 1, 5, 6); | |
132 } | |
133 | |
134 class BatteryProperties : public dbus::PropertySet { | |
135 public: | |
136 BatteryProperties(dbus::ObjectProxy* object_proxy, | |
137 const PropertyChangedCallback callback); | |
138 ~BatteryProperties() override; | |
139 | |
140 void ConnectSignals() override; | |
141 | |
142 void Invalidate(); | |
143 | |
144 bool is_present(bool default_value = false); | |
145 double percentage(double default_value = 100); | |
146 uint32_t state(uint32_t default_value = UPOWER_DEVICE_STATE_UNKNOWN); | |
147 int64_t time_to_empty(int64_t default_value = 0); | |
148 int64_t time_to_full(int64_t default_value = 0); | |
149 uint32_t type(uint32_t default_value = UPOWER_DEVICE_TYPE_UNKNOWN); | |
150 | |
151 private: | |
152 bool connected_ = false; | |
153 dbus::Property<bool> is_present_; | |
154 dbus::Property<double> percentage_; | |
155 dbus::Property<uint32_t> state_; | |
156 dbus::Property<int64_t> time_to_empty_; | |
157 dbus::Property<int64_t> time_to_full_; | |
158 dbus::Property<uint32_t> type_; | |
159 | |
160 DISALLOW_COPY_AND_ASSIGN(BatteryProperties); | |
161 }; | |
162 | |
163 BatteryProperties::BatteryProperties(dbus::ObjectProxy* object_proxy, | |
164 const PropertyChangedCallback callback) | |
165 : dbus::PropertySet(object_proxy, kUPowerDeviceInterfaceName, callback) { | |
166 RegisterProperty(kUPowerDevicePropertyIsPresent, &is_present_); | |
167 RegisterProperty(kUPowerDevicePropertyPercentage, &percentage_); | |
168 RegisterProperty(kUPowerDevicePropertyState, &state_); | |
169 RegisterProperty(kUPowerDevicePropertyTimeToEmpty, &time_to_empty_); | |
170 RegisterProperty(kUPowerDevicePropertyTimeToFull, &time_to_full_); | |
171 RegisterProperty(kUPowerDevicePropertyType, &type_); | |
172 } | |
173 | |
174 BatteryProperties::~BatteryProperties() {} | |
175 | |
176 void BatteryProperties::ConnectSignals() { | |
177 if (!connected_) { | |
178 connected_ = true; | |
179 dbus::PropertySet::ConnectSignals(); | |
180 } | |
181 } | |
182 | |
183 void BatteryProperties::Invalidate() { | |
184 is_present_.set_valid(false); | |
185 percentage_.set_valid(false); | |
186 state_.set_valid(false); | |
187 time_to_empty_.set_valid(false); | |
188 time_to_full_.set_valid(false); | |
189 type_.set_valid(false); | |
190 } | |
191 | |
192 bool BatteryProperties::is_present(bool default_value) { | |
193 return (is_present_.is_valid() || is_present_.GetAndBlock()) | |
194 ? is_present_.value() | |
195 : default_value; | |
196 } | |
197 | |
198 double BatteryProperties::percentage(double default_value) { | |
199 return (percentage_.is_valid() || percentage_.GetAndBlock()) | |
200 ? percentage_.value() | |
201 : default_value; | |
202 } | |
203 | |
204 uint32_t BatteryProperties::state(uint32_t default_value) { | |
205 return (state_.is_valid() || state_.GetAndBlock()) ? state_.value() | |
206 : default_value; | |
207 } | |
208 | |
209 int64_t BatteryProperties::time_to_empty(int64_t default_value) { | |
210 return (time_to_empty_.is_valid() || time_to_empty_.GetAndBlock()) | |
211 ? time_to_empty_.value() | |
212 : default_value; | |
213 } | |
214 | |
215 int64_t BatteryProperties::time_to_full(int64_t default_value) { | |
216 return (time_to_full_.is_valid() || time_to_full_.GetAndBlock()) | |
217 ? time_to_full_.value() | |
218 : default_value; | |
219 } | |
220 | |
221 uint32_t BatteryProperties::type(uint32_t default_value) { | |
222 return (type_.is_valid() || type_.GetAndBlock()) ? type_.value() | |
223 : default_value; | |
224 } | |
225 | |
226 class BatteryObject { | |
227 public: | |
228 using PropertyChangedCallback = dbus::PropertySet::PropertyChangedCallback; | |
229 | |
230 BatteryObject(dbus::Bus* dbus, | |
231 const dbus::ObjectPath& device_path, | |
232 const PropertyChangedCallback& property_changed_callback); | |
233 ~BatteryObject(); | |
234 | |
235 bool IsValid(); | |
236 | |
237 dbus::ObjectProxy* proxy() { return proxy_; } | |
238 BatteryProperties* properties() { return properties_.get(); } | |
239 | |
240 private: | |
241 dbus::Bus* dbus_; // Owned by the BatteryStatusNotificationThread, | |
242 dbus::ObjectProxy* proxy_; // Owned by the dbus. | |
243 std::unique_ptr<BatteryProperties> properties_; | |
244 | |
245 DISALLOW_COPY_AND_ASSIGN(BatteryObject); | |
246 }; | |
247 | |
248 BatteryObject::BatteryObject( | |
249 dbus::Bus* dbus, | |
250 const dbus::ObjectPath& device_path, | |
251 const PropertyChangedCallback& property_changed_callback) | |
252 : dbus_(dbus), | |
253 proxy_(dbus_->GetObjectProxy(kUPowerServiceName, device_path)), | |
254 properties_(new BatteryProperties(proxy_, property_changed_callback)) {} | |
255 | |
256 BatteryObject::~BatteryObject() { | |
257 properties_.reset(); // before the proxy is deleted. | |
258 dbus_->RemoveObjectProxy(kUPowerServiceName, proxy_->object_path(), | |
259 base::Bind(&base::DoNothing)); | |
260 } | |
261 | |
262 bool BatteryObject::IsValid() { | |
263 return properties_->is_present() && | |
264 properties_->type() == UPOWER_DEVICE_TYPE_BATTERY; | |
265 } | |
266 | |
267 mojom::BatteryStatus ComputeWebBatteryStatus(BatteryProperties* properties) { | |
268 mojom::BatteryStatus status; | |
269 uint32_t state = properties->state(); | |
270 status.charging = state != UPOWER_DEVICE_STATE_DISCHARGING && | |
271 state != UPOWER_DEVICE_STATE_EMPTY; | |
272 // Convert percentage to a value between 0 and 1 with 2 digits of precision. | |
273 // This is to bring it in line with other platforms like Mac and Android where | |
274 // we report level with 1% granularity. It also serves the purpose of reducing | |
275 // the possibility of fingerprinting and triggers less level change events on | |
276 // the blink side. | |
277 // TODO(timvolodine): consider moving this rounding to the blink side. | |
278 status.level = round(properties->percentage()) / 100.f; | |
279 | |
280 switch (state) { | |
281 case UPOWER_DEVICE_STATE_CHARGING: { | |
282 int64_t time_to_full = properties->time_to_full(); | |
283 status.charging_time = (time_to_full > 0) | |
284 ? time_to_full | |
285 : std::numeric_limits<double>::infinity(); | |
286 break; | |
287 } | |
288 case UPOWER_DEVICE_STATE_DISCHARGING: { | |
289 int64_t time_to_empty = properties->time_to_empty(); | |
290 // Set dischargingTime if it's available. Otherwise leave the default | |
291 // value which is +infinity. | |
292 if (time_to_empty > 0) | |
293 status.discharging_time = time_to_empty; | |
294 status.charging_time = std::numeric_limits<double>::infinity(); | |
295 break; | |
296 } | |
297 case UPOWER_DEVICE_STATE_FULL: { | |
298 break; | |
299 } | |
300 default: { status.charging_time = std::numeric_limits<double>::infinity(); } | |
301 } | |
302 return status; | |
303 } | |
304 | |
305 } // namespace | |
306 | |
307 // Class that represents a dedicated thread which communicates with DBus to | |
308 // obtain battery information and receives battery change notifications. | |
309 class BatteryStatusManagerLinux::BatteryStatusNotificationThread | |
310 : public base::Thread { | |
311 public: | |
312 BatteryStatusNotificationThread( | |
313 const BatteryStatusService::BatteryUpdateCallback& callback) | |
314 : base::Thread(kBatteryNotifierThreadName), callback_(callback) {} | |
315 | |
316 ~BatteryStatusNotificationThread() override { | |
317 // Make sure to shutdown the dbus connection if it is still open in the very | |
318 // end. It needs to happen on the BatteryStatusNotificationThread. | |
319 message_loop()->task_runner()->PostTask( | |
320 FROM_HERE, | |
321 base::Bind(&BatteryStatusNotificationThread::ShutdownDBusConnection, | |
322 base::Unretained(this))); | |
323 | |
324 // Drain the message queue of the BatteryStatusNotificationThread and stop. | |
325 Stop(); | |
326 } | |
327 | |
328 void StartListening() { | |
329 DCHECK(OnWatcherThread()); | |
330 | |
331 if (upower_) | |
332 return; | |
333 | |
334 if (!system_bus_) | |
335 InitDBus(); | |
336 | |
337 upower_ = base::MakeUnique<UPowerObject>( | |
338 system_bus_.get(), UPowerObject::PropertyChangedCallback()); | |
339 upower_->proxy()->ConnectToSignal( | |
340 kUPowerServiceName, kUPowerSignalDeviceAdded, | |
341 base::Bind(&BatteryStatusNotificationThread::DeviceAdded, | |
342 base::Unretained(this)), | |
343 base::Bind(&BatteryStatusNotificationThread::OnSignalConnected, | |
344 base::Unretained(this))); | |
345 upower_->proxy()->ConnectToSignal( | |
346 kUPowerServiceName, kUPowerSignalDeviceRemoved, | |
347 base::Bind(&BatteryStatusNotificationThread::DeviceRemoved, | |
348 base::Unretained(this)), | |
349 base::Bind(&BatteryStatusNotificationThread::OnSignalConnected, | |
350 base::Unretained(this))); | |
351 | |
352 FindBatteryDevice(); | |
353 } | |
354 | |
355 void StopListening() { | |
356 DCHECK(OnWatcherThread()); | |
357 ShutdownDBusConnection(); | |
358 } | |
359 | |
360 void SetDBusForTesting(dbus::Bus* bus) { system_bus_ = bus; } | |
361 | |
362 private: | |
363 bool OnWatcherThread() { | |
364 return task_runner()->BelongsToCurrentThread(); | |
365 } | |
366 | |
367 void InitDBus() { | |
368 DCHECK(OnWatcherThread()); | |
369 | |
370 dbus::Bus::Options options; | |
371 options.bus_type = dbus::Bus::SYSTEM; | |
372 options.connection_type = dbus::Bus::PRIVATE; | |
373 system_bus_ = new dbus::Bus(options); | |
374 } | |
375 | |
376 bool IsDaemonVersionBelow_0_99() { | |
377 base::Version daemon_version = upower_->properties()->daemon_version(); | |
378 return daemon_version.IsValid() && | |
379 daemon_version.CompareTo(base::Version("0.99")) < 0; | |
380 } | |
381 | |
382 void FindBatteryDevice() { | |
383 // Move the currently watched battery_ device to a stack-local variable such | |
384 // that we can enumerate all devices (once more): | |
385 // first testing the display device, then testing all devices from | |
386 // EnumerateDevices. We will monitor the first battery device we find. | |
387 // - That may be the same device we did monitor on entering this method; | |
388 // then we'll use the same BatteryObject instance, that was moved to | |
389 // current - see UseCurrentOrCreateBattery(). | |
390 // - Or it may be a new device; then the previously monitored BatteryObject | |
391 // instance (if any) is released on leaving this function. | |
392 // - Or we may not find a battery device; then on leaving this function | |
393 // battery_ will be nullptr and the previously monitored BatteryObject | |
394 // instance (if any) is no longer a battery and will be released. | |
395 std::unique_ptr<BatteryObject> current = std::move(battery_); | |
396 auto UseCurrentOrCreateBattery = | |
397 [¤t, this](const dbus::ObjectPath& device_path) { | |
398 if (current && current->proxy()->object_path() == device_path) | |
399 return std::move(current); | |
400 return CreateBattery(device_path); | |
401 }; | |
402 | |
403 dbus::ObjectPath display_device_path; | |
404 if (!IsDaemonVersionBelow_0_99()) | |
405 display_device_path = upower_->GetDisplayDevice(); | |
406 if (display_device_path.IsValid()) { | |
407 auto battery = UseCurrentOrCreateBattery(display_device_path); | |
408 if (battery->IsValid()) | |
409 battery_ = std::move(battery); | |
410 } | |
411 | |
412 if (!battery_) { | |
413 int num_batteries = 0; | |
414 for (const auto& device_path : upower_->EnumerateDevices()) { | |
415 auto battery = UseCurrentOrCreateBattery(device_path); | |
416 if (!battery->IsValid()) | |
417 continue; | |
418 | |
419 if (battery_) { | |
420 // TODO(timvolodine): add support for multiple batteries. Currently we | |
421 // only collect information from the first battery we encounter | |
422 // (crbug.com/400780). | |
423 LOG(WARNING) << "multiple batteries found, " | |
424 << "using status data of the first battery only."; | |
425 } else { | |
426 battery_ = std::move(battery); | |
427 } | |
428 num_batteries++; | |
429 } | |
430 | |
431 UpdateNumberBatteriesHistogram(num_batteries); | |
432 } | |
433 | |
434 if (!battery_) { | |
435 callback_.Run(mojom::BatteryStatus()); | |
436 return; | |
437 } | |
438 | |
439 battery_->properties()->ConnectSignals(); | |
440 NotifyBatteryStatus(); | |
441 | |
442 if (IsDaemonVersionBelow_0_99()) { | |
443 // UPower Version 0.99 replaced the Changed signal with the | |
444 // PropertyChanged signal. For older versions we need to listen | |
445 // to the Changed signal. | |
446 battery_->proxy()->ConnectToSignal( | |
447 kUPowerDeviceInterfaceName, kUPowerDeviceSignalChanged, | |
448 base::Bind(&BatteryStatusNotificationThread::BatteryChanged, | |
449 base::Unretained(this)), | |
450 base::Bind(&BatteryStatusNotificationThread::OnSignalConnected, | |
451 base::Unretained(this))); | |
452 } | |
453 } | |
454 | |
455 void ShutdownDBusConnection() { | |
456 DCHECK(OnWatcherThread()); | |
457 | |
458 if (!system_bus_.get()) | |
459 return; | |
460 | |
461 battery_.reset(); // before the system_bus_ is shut down. | |
462 upower_.reset(); | |
463 | |
464 // Shutdown DBus connection later because there may be pending tasks on | |
465 // this thread. | |
466 message_loop()->task_runner()->PostTask( | |
467 FROM_HERE, base::Bind(&dbus::Bus::ShutdownAndBlock, system_bus_)); | |
468 system_bus_ = NULL; | |
469 } | |
470 | |
471 void OnSignalConnected(const std::string& interface_name, | |
472 const std::string& signal_name, | |
473 bool success) {} | |
474 | |
475 std::unique_ptr<BatteryObject> CreateBattery( | |
476 const dbus::ObjectPath& device_path) { | |
477 return base::MakeUnique<BatteryObject>( | |
478 system_bus_.get(), device_path, | |
479 base::Bind(&BatteryStatusNotificationThread::BatteryPropertyChanged, | |
480 base::Unretained(this))); | |
481 } | |
482 | |
483 void DeviceAdded(dbus::Signal* signal /* unused */) { | |
484 // Re-iterate all devices to see if we need to monitor the added battery | |
485 // instead of the currently monitored battery. | |
486 FindBatteryDevice(); | |
487 } | |
488 | |
489 void DeviceRemoved(dbus::Signal* signal) { | |
490 if (!battery_) | |
491 return; | |
492 | |
493 // UPower specifies that the DeviceRemoved signal has an object-path as | |
494 // argument, however IRL that signal was observed with a string argument, | |
495 // so cover both cases (argument as string, as object-path and neither of | |
496 // these) and call FindBatteryDevice() if either we couldn't get the | |
497 // argument or the removed device-path is the battery_. | |
498 dbus::MessageReader reader(signal); | |
499 dbus::ObjectPath removed_device_path; | |
500 switch (reader.GetDataType()) { | |
501 case dbus::Message::DataType::STRING: { | |
502 std::string removed_device_path_string; | |
503 if (reader.PopString(&removed_device_path_string)) | |
504 removed_device_path = dbus::ObjectPath(removed_device_path_string); | |
505 break; | |
506 } | |
507 | |
508 case dbus::Message::DataType::OBJECT_PATH: | |
509 reader.PopObjectPath(&removed_device_path); | |
510 break; | |
511 | |
512 default: | |
513 break; | |
514 } | |
515 | |
516 if (!removed_device_path.IsValid() || | |
517 battery_->proxy()->object_path() == removed_device_path) | |
518 FindBatteryDevice(); | |
519 } | |
520 | |
521 void BatteryPropertyChanged(const std::string& property_name) { | |
522 NotifyBatteryStatus(); | |
523 } | |
524 | |
525 void BatteryChanged(dbus::Signal* signal /* unsused */) { | |
526 DCHECK(battery_); | |
527 battery_->properties()->Invalidate(); | |
528 NotifyBatteryStatus(); | |
529 } | |
530 | |
531 void NotifyBatteryStatus() { | |
532 DCHECK(OnWatcherThread()); | |
533 | |
534 if (!system_bus_.get() || !battery_ || notifying_battery_status_) | |
535 return; | |
536 | |
537 // If the system uses a UPower daemon older than version 0.99 | |
538 // (see IsDaemonVersionBelow_0_99), then we are notified about changed | |
539 // battery_ properties through the 'Changed' signal of the battery_ | |
540 // device (see BatteryChanged()). That is implemented to invalidate all | |
541 // battery_ properties (so they are re-fetched from the dbus). Getting | |
542 // the new property-value triggers a callback to BatteryPropertyChanged(). | |
543 // notifying_battery_status_ is set to avoid recursion and computing the | |
544 // status too often. | |
545 notifying_battery_status_ = true; | |
546 callback_.Run(ComputeWebBatteryStatus(battery_->properties())); | |
547 notifying_battery_status_ = false; | |
548 } | |
549 | |
550 BatteryStatusService::BatteryUpdateCallback callback_; | |
551 scoped_refptr<dbus::Bus> system_bus_; | |
552 std::unique_ptr<UPowerObject> upower_; | |
553 std::unique_ptr<BatteryObject> battery_; | |
554 bool notifying_battery_status_ = false; | |
555 | |
556 DISALLOW_COPY_AND_ASSIGN(BatteryStatusNotificationThread); | |
557 }; | |
558 | |
559 BatteryStatusManagerLinux::BatteryStatusManagerLinux( | |
560 const BatteryStatusService::BatteryUpdateCallback& callback) | |
561 : callback_(callback) {} | |
562 | |
563 BatteryStatusManagerLinux::~BatteryStatusManagerLinux() {} | |
564 | |
565 bool BatteryStatusManagerLinux::StartListeningBatteryChange() { | |
566 if (!StartNotifierThreadIfNecessary()) | |
567 return false; | |
568 | |
569 notifier_thread_->task_runner()->PostTask( | |
570 FROM_HERE, base::Bind(&BatteryStatusNotificationThread::StartListening, | |
571 base::Unretained(notifier_thread_.get()))); | |
572 return true; | |
573 } | |
574 | |
575 void BatteryStatusManagerLinux::StopListeningBatteryChange() { | |
576 if (!notifier_thread_) | |
577 return; | |
578 | |
579 notifier_thread_->task_runner()->PostTask( | |
580 FROM_HERE, base::Bind(&BatteryStatusNotificationThread::StopListening, | |
581 base::Unretained(notifier_thread_.get()))); | |
582 } | |
583 | |
584 bool BatteryStatusManagerLinux::StartNotifierThreadIfNecessary() { | |
585 if (notifier_thread_) | |
586 return true; | |
587 | |
588 base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0); | |
589 auto notifier_thread = | |
590 base::MakeUnique<BatteryStatusNotificationThread>(callback_); | |
591 if (!notifier_thread->StartWithOptions(thread_options)) { | |
592 LOG(ERROR) << "Could not start the " << kBatteryNotifierThreadName | |
593 << " thread"; | |
594 return false; | |
595 } | |
596 notifier_thread_ = std::move(notifier_thread); | |
597 return true; | |
598 } | |
599 | |
600 base::Thread* BatteryStatusManagerLinux::GetNotifierThreadForTesting() { | |
601 return notifier_thread_.get(); | |
602 } | |
603 | |
604 // static | |
605 std::unique_ptr<BatteryStatusManagerLinux> | |
606 BatteryStatusManagerLinux::CreateForTesting( | |
607 const BatteryStatusService::BatteryUpdateCallback& callback, | |
608 dbus::Bus* bus) { | |
609 auto manager = base::MakeUnique<BatteryStatusManagerLinux>(callback); | |
610 if (!manager->StartNotifierThreadIfNecessary()) | |
611 return nullptr; | |
612 manager->notifier_thread_->SetDBusForTesting(bus); | |
613 return manager; | |
614 } | |
615 | |
616 // static | |
617 std::unique_ptr<BatteryStatusManager> BatteryStatusManager::Create( | |
618 const BatteryStatusService::BatteryUpdateCallback& callback) { | |
619 return base::MakeUnique<BatteryStatusManagerLinux>(callback); | |
620 } | |
621 | |
622 } // namespace device | |
OLD | NEW |