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

Unified Diff: device/battery/battery_status_manager_linux.cc

Issue 2818673003: [DeviceService] Expose battery monitoring solely via the Device Service (Closed)
Patch Set: Java file format change Created 3 years, 8 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « device/battery/battery_status_manager_linux.h ('k') | device/battery/battery_status_manager_linux-inl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: device/battery/battery_status_manager_linux.cc
diff --git a/device/battery/battery_status_manager_linux.cc b/device/battery/battery_status_manager_linux.cc
deleted file mode 100644
index 0fd085949b680e801f3831580cebe9443a009cc3..0000000000000000000000000000000000000000
--- a/device/battery/battery_status_manager_linux.cc
+++ /dev/null
@@ -1,622 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "device/battery/battery_status_manager_linux.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <limits>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread.h"
-#include "base/values.h"
-#include "base/version.h"
-#include "dbus/bus.h"
-#include "dbus/message.h"
-#include "dbus/object_path.h"
-#include "dbus/object_proxy.h"
-#include "dbus/property.h"
-#include "dbus/values_util.h"
-#include "device/battery/battery_status_manager_linux-inl.h"
-
-namespace device {
-namespace {
-const char kBatteryNotifierThreadName[] = "BatteryStatusNotifier";
-
-class UPowerProperties : public dbus::PropertySet {
- public:
- UPowerProperties(dbus::ObjectProxy* object_proxy,
- const PropertyChangedCallback callback);
- ~UPowerProperties() override;
-
- base::Version daemon_version();
-
- private:
- dbus::Property<std::string> daemon_version_;
-
- DISALLOW_COPY_AND_ASSIGN(UPowerProperties);
-};
-
-UPowerProperties::UPowerProperties(dbus::ObjectProxy* object_proxy,
- const PropertyChangedCallback callback)
- : dbus::PropertySet(object_proxy, kUPowerInterfaceName, callback) {
- RegisterProperty(kUPowerPropertyDaemonVersion, &daemon_version_);
-}
-
-UPowerProperties::~UPowerProperties() {}
-
-base::Version UPowerProperties::daemon_version() {
- return (daemon_version_.is_valid() || daemon_version_.GetAndBlock())
- ? base::Version(daemon_version_.value())
- : base::Version();
-}
-
-class UPowerObject {
- public:
- using PropertyChangedCallback = dbus::PropertySet::PropertyChangedCallback;
-
- UPowerObject(dbus::Bus* dbus,
- const PropertyChangedCallback property_changed_callback);
- ~UPowerObject();
-
- std::vector<dbus::ObjectPath> EnumerateDevices();
- dbus::ObjectPath GetDisplayDevice();
-
- dbus::ObjectProxy* proxy() { return proxy_; }
- UPowerProperties* properties() { return properties_.get(); }
-
- private:
- dbus::Bus* dbus_; // Owned by the BatteryStatusNotificationThread.
- dbus::ObjectProxy* proxy_; // Owned by the dbus.
- std::unique_ptr<UPowerProperties> properties_;
-
- DISALLOW_COPY_AND_ASSIGN(UPowerObject);
-};
-
-UPowerObject::UPowerObject(
- dbus::Bus* dbus,
- const PropertyChangedCallback property_changed_callback)
- : dbus_(dbus),
- proxy_(dbus_->GetObjectProxy(kUPowerServiceName,
- dbus::ObjectPath(kUPowerPath))),
- properties_(new UPowerProperties(proxy_, property_changed_callback)) {}
-
-UPowerObject::~UPowerObject() {
- properties_.reset(); // before the proxy is deleted.
- dbus_->RemoveObjectProxy(kUPowerServiceName, proxy_->object_path(),
- base::Bind(&base::DoNothing));
-}
-
-std::vector<dbus::ObjectPath> UPowerObject::EnumerateDevices() {
- std::vector<dbus::ObjectPath> paths;
- dbus::MethodCall method_call(kUPowerServiceName,
- kUPowerMethodEnumerateDevices);
- std::unique_ptr<dbus::Response> response(proxy_->CallMethodAndBlock(
- &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
-
- if (response) {
- dbus::MessageReader reader(response.get());
- reader.PopArrayOfObjectPaths(&paths);
- }
- return paths;
-}
-
-dbus::ObjectPath UPowerObject::GetDisplayDevice() {
- dbus::ObjectPath display_device_path;
- if (!proxy_)
- return display_device_path;
-
- dbus::MethodCall method_call(kUPowerServiceName,
- kUPowerMethodGetDisplayDevice);
- std::unique_ptr<dbus::Response> response(proxy_->CallMethodAndBlock(
- &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
-
- if (response) {
- dbus::MessageReader reader(response.get());
- reader.PopObjectPath(&display_device_path);
- }
- return display_device_path;
-}
-
-void UpdateNumberBatteriesHistogram(int count) {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "BatteryStatus.NumberBatteriesLinux", count, 1, 5, 6);
-}
-
-class BatteryProperties : public dbus::PropertySet {
- public:
- BatteryProperties(dbus::ObjectProxy* object_proxy,
- const PropertyChangedCallback callback);
- ~BatteryProperties() override;
-
- void ConnectSignals() override;
-
- void Invalidate();
-
- bool is_present(bool default_value = false);
- double percentage(double default_value = 100);
- uint32_t state(uint32_t default_value = UPOWER_DEVICE_STATE_UNKNOWN);
- int64_t time_to_empty(int64_t default_value = 0);
- int64_t time_to_full(int64_t default_value = 0);
- uint32_t type(uint32_t default_value = UPOWER_DEVICE_TYPE_UNKNOWN);
-
- private:
- bool connected_ = false;
- dbus::Property<bool> is_present_;
- dbus::Property<double> percentage_;
- dbus::Property<uint32_t> state_;
- dbus::Property<int64_t> time_to_empty_;
- dbus::Property<int64_t> time_to_full_;
- dbus::Property<uint32_t> type_;
-
- DISALLOW_COPY_AND_ASSIGN(BatteryProperties);
-};
-
-BatteryProperties::BatteryProperties(dbus::ObjectProxy* object_proxy,
- const PropertyChangedCallback callback)
- : dbus::PropertySet(object_proxy, kUPowerDeviceInterfaceName, callback) {
- RegisterProperty(kUPowerDevicePropertyIsPresent, &is_present_);
- RegisterProperty(kUPowerDevicePropertyPercentage, &percentage_);
- RegisterProperty(kUPowerDevicePropertyState, &state_);
- RegisterProperty(kUPowerDevicePropertyTimeToEmpty, &time_to_empty_);
- RegisterProperty(kUPowerDevicePropertyTimeToFull, &time_to_full_);
- RegisterProperty(kUPowerDevicePropertyType, &type_);
-}
-
-BatteryProperties::~BatteryProperties() {}
-
-void BatteryProperties::ConnectSignals() {
- if (!connected_) {
- connected_ = true;
- dbus::PropertySet::ConnectSignals();
- }
-}
-
-void BatteryProperties::Invalidate() {
- is_present_.set_valid(false);
- percentage_.set_valid(false);
- state_.set_valid(false);
- time_to_empty_.set_valid(false);
- time_to_full_.set_valid(false);
- type_.set_valid(false);
-}
-
-bool BatteryProperties::is_present(bool default_value) {
- return (is_present_.is_valid() || is_present_.GetAndBlock())
- ? is_present_.value()
- : default_value;
-}
-
-double BatteryProperties::percentage(double default_value) {
- return (percentage_.is_valid() || percentage_.GetAndBlock())
- ? percentage_.value()
- : default_value;
-}
-
-uint32_t BatteryProperties::state(uint32_t default_value) {
- return (state_.is_valid() || state_.GetAndBlock()) ? state_.value()
- : default_value;
-}
-
-int64_t BatteryProperties::time_to_empty(int64_t default_value) {
- return (time_to_empty_.is_valid() || time_to_empty_.GetAndBlock())
- ? time_to_empty_.value()
- : default_value;
-}
-
-int64_t BatteryProperties::time_to_full(int64_t default_value) {
- return (time_to_full_.is_valid() || time_to_full_.GetAndBlock())
- ? time_to_full_.value()
- : default_value;
-}
-
-uint32_t BatteryProperties::type(uint32_t default_value) {
- return (type_.is_valid() || type_.GetAndBlock()) ? type_.value()
- : default_value;
-}
-
-class BatteryObject {
- public:
- using PropertyChangedCallback = dbus::PropertySet::PropertyChangedCallback;
-
- BatteryObject(dbus::Bus* dbus,
- const dbus::ObjectPath& device_path,
- const PropertyChangedCallback& property_changed_callback);
- ~BatteryObject();
-
- bool IsValid();
-
- dbus::ObjectProxy* proxy() { return proxy_; }
- BatteryProperties* properties() { return properties_.get(); }
-
- private:
- dbus::Bus* dbus_; // Owned by the BatteryStatusNotificationThread,
- dbus::ObjectProxy* proxy_; // Owned by the dbus.
- std::unique_ptr<BatteryProperties> properties_;
-
- DISALLOW_COPY_AND_ASSIGN(BatteryObject);
-};
-
-BatteryObject::BatteryObject(
- dbus::Bus* dbus,
- const dbus::ObjectPath& device_path,
- const PropertyChangedCallback& property_changed_callback)
- : dbus_(dbus),
- proxy_(dbus_->GetObjectProxy(kUPowerServiceName, device_path)),
- properties_(new BatteryProperties(proxy_, property_changed_callback)) {}
-
-BatteryObject::~BatteryObject() {
- properties_.reset(); // before the proxy is deleted.
- dbus_->RemoveObjectProxy(kUPowerServiceName, proxy_->object_path(),
- base::Bind(&base::DoNothing));
-}
-
-bool BatteryObject::IsValid() {
- return properties_->is_present() &&
- properties_->type() == UPOWER_DEVICE_TYPE_BATTERY;
-}
-
-mojom::BatteryStatus ComputeWebBatteryStatus(BatteryProperties* properties) {
- mojom::BatteryStatus status;
- uint32_t state = properties->state();
- status.charging = state != UPOWER_DEVICE_STATE_DISCHARGING &&
- state != UPOWER_DEVICE_STATE_EMPTY;
- // Convert percentage to a value between 0 and 1 with 2 digits of precision.
- // This is to bring it in line with other platforms like Mac and Android where
- // we report level with 1% granularity. It also serves the purpose of reducing
- // the possibility of fingerprinting and triggers less level change events on
- // the blink side.
- // TODO(timvolodine): consider moving this rounding to the blink side.
- status.level = round(properties->percentage()) / 100.f;
-
- switch (state) {
- case UPOWER_DEVICE_STATE_CHARGING: {
- int64_t time_to_full = properties->time_to_full();
- status.charging_time = (time_to_full > 0)
- ? time_to_full
- : std::numeric_limits<double>::infinity();
- break;
- }
- case UPOWER_DEVICE_STATE_DISCHARGING: {
- int64_t time_to_empty = properties->time_to_empty();
- // Set dischargingTime if it's available. Otherwise leave the default
- // value which is +infinity.
- if (time_to_empty > 0)
- status.discharging_time = time_to_empty;
- status.charging_time = std::numeric_limits<double>::infinity();
- break;
- }
- case UPOWER_DEVICE_STATE_FULL: {
- break;
- }
- default: { status.charging_time = std::numeric_limits<double>::infinity(); }
- }
- return status;
-}
-
-} // namespace
-
-// Class that represents a dedicated thread which communicates with DBus to
-// obtain battery information and receives battery change notifications.
-class BatteryStatusManagerLinux::BatteryStatusNotificationThread
- : public base::Thread {
- public:
- BatteryStatusNotificationThread(
- const BatteryStatusService::BatteryUpdateCallback& callback)
- : base::Thread(kBatteryNotifierThreadName), callback_(callback) {}
-
- ~BatteryStatusNotificationThread() override {
- // Make sure to shutdown the dbus connection if it is still open in the very
- // end. It needs to happen on the BatteryStatusNotificationThread.
- message_loop()->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&BatteryStatusNotificationThread::ShutdownDBusConnection,
- base::Unretained(this)));
-
- // Drain the message queue of the BatteryStatusNotificationThread and stop.
- Stop();
- }
-
- void StartListening() {
- DCHECK(OnWatcherThread());
-
- if (upower_)
- return;
-
- if (!system_bus_)
- InitDBus();
-
- upower_ = base::MakeUnique<UPowerObject>(
- system_bus_.get(), UPowerObject::PropertyChangedCallback());
- upower_->proxy()->ConnectToSignal(
- kUPowerServiceName, kUPowerSignalDeviceAdded,
- base::Bind(&BatteryStatusNotificationThread::DeviceAdded,
- base::Unretained(this)),
- base::Bind(&BatteryStatusNotificationThread::OnSignalConnected,
- base::Unretained(this)));
- upower_->proxy()->ConnectToSignal(
- kUPowerServiceName, kUPowerSignalDeviceRemoved,
- base::Bind(&BatteryStatusNotificationThread::DeviceRemoved,
- base::Unretained(this)),
- base::Bind(&BatteryStatusNotificationThread::OnSignalConnected,
- base::Unretained(this)));
-
- FindBatteryDevice();
- }
-
- void StopListening() {
- DCHECK(OnWatcherThread());
- ShutdownDBusConnection();
- }
-
- void SetDBusForTesting(dbus::Bus* bus) { system_bus_ = bus; }
-
- private:
- bool OnWatcherThread() {
- return task_runner()->BelongsToCurrentThread();
- }
-
- void InitDBus() {
- DCHECK(OnWatcherThread());
-
- dbus::Bus::Options options;
- options.bus_type = dbus::Bus::SYSTEM;
- options.connection_type = dbus::Bus::PRIVATE;
- system_bus_ = new dbus::Bus(options);
- }
-
- bool IsDaemonVersionBelow_0_99() {
- base::Version daemon_version = upower_->properties()->daemon_version();
- return daemon_version.IsValid() &&
- daemon_version.CompareTo(base::Version("0.99")) < 0;
- }
-
- void FindBatteryDevice() {
- // Move the currently watched battery_ device to a stack-local variable such
- // that we can enumerate all devices (once more):
- // first testing the display device, then testing all devices from
- // EnumerateDevices. We will monitor the first battery device we find.
- // - That may be the same device we did monitor on entering this method;
- // then we'll use the same BatteryObject instance, that was moved to
- // current - see UseCurrentOrCreateBattery().
- // - Or it may be a new device; then the previously monitored BatteryObject
- // instance (if any) is released on leaving this function.
- // - Or we may not find a battery device; then on leaving this function
- // battery_ will be nullptr and the previously monitored BatteryObject
- // instance (if any) is no longer a battery and will be released.
- std::unique_ptr<BatteryObject> current = std::move(battery_);
- auto UseCurrentOrCreateBattery =
- [&current, this](const dbus::ObjectPath& device_path) {
- if (current && current->proxy()->object_path() == device_path)
- return std::move(current);
- return CreateBattery(device_path);
- };
-
- dbus::ObjectPath display_device_path;
- if (!IsDaemonVersionBelow_0_99())
- display_device_path = upower_->GetDisplayDevice();
- if (display_device_path.IsValid()) {
- auto battery = UseCurrentOrCreateBattery(display_device_path);
- if (battery->IsValid())
- battery_ = std::move(battery);
- }
-
- if (!battery_) {
- int num_batteries = 0;
- for (const auto& device_path : upower_->EnumerateDevices()) {
- auto battery = UseCurrentOrCreateBattery(device_path);
- if (!battery->IsValid())
- continue;
-
- if (battery_) {
- // TODO(timvolodine): add support for multiple batteries. Currently we
- // only collect information from the first battery we encounter
- // (crbug.com/400780).
- LOG(WARNING) << "multiple batteries found, "
- << "using status data of the first battery only.";
- } else {
- battery_ = std::move(battery);
- }
- num_batteries++;
- }
-
- UpdateNumberBatteriesHistogram(num_batteries);
- }
-
- if (!battery_) {
- callback_.Run(mojom::BatteryStatus());
- return;
- }
-
- battery_->properties()->ConnectSignals();
- NotifyBatteryStatus();
-
- if (IsDaemonVersionBelow_0_99()) {
- // UPower Version 0.99 replaced the Changed signal with the
- // PropertyChanged signal. For older versions we need to listen
- // to the Changed signal.
- battery_->proxy()->ConnectToSignal(
- kUPowerDeviceInterfaceName, kUPowerDeviceSignalChanged,
- base::Bind(&BatteryStatusNotificationThread::BatteryChanged,
- base::Unretained(this)),
- base::Bind(&BatteryStatusNotificationThread::OnSignalConnected,
- base::Unretained(this)));
- }
- }
-
- void ShutdownDBusConnection() {
- DCHECK(OnWatcherThread());
-
- if (!system_bus_.get())
- return;
-
- battery_.reset(); // before the system_bus_ is shut down.
- upower_.reset();
-
- // Shutdown DBus connection later because there may be pending tasks on
- // this thread.
- message_loop()->task_runner()->PostTask(
- FROM_HERE, base::Bind(&dbus::Bus::ShutdownAndBlock, system_bus_));
- system_bus_ = NULL;
- }
-
- void OnSignalConnected(const std::string& interface_name,
- const std::string& signal_name,
- bool success) {}
-
- std::unique_ptr<BatteryObject> CreateBattery(
- const dbus::ObjectPath& device_path) {
- return base::MakeUnique<BatteryObject>(
- system_bus_.get(), device_path,
- base::Bind(&BatteryStatusNotificationThread::BatteryPropertyChanged,
- base::Unretained(this)));
- }
-
- void DeviceAdded(dbus::Signal* signal /* unused */) {
- // Re-iterate all devices to see if we need to monitor the added battery
- // instead of the currently monitored battery.
- FindBatteryDevice();
- }
-
- void DeviceRemoved(dbus::Signal* signal) {
- if (!battery_)
- return;
-
- // UPower specifies that the DeviceRemoved signal has an object-path as
- // argument, however IRL that signal was observed with a string argument,
- // so cover both cases (argument as string, as object-path and neither of
- // these) and call FindBatteryDevice() if either we couldn't get the
- // argument or the removed device-path is the battery_.
- dbus::MessageReader reader(signal);
- dbus::ObjectPath removed_device_path;
- switch (reader.GetDataType()) {
- case dbus::Message::DataType::STRING: {
- std::string removed_device_path_string;
- if (reader.PopString(&removed_device_path_string))
- removed_device_path = dbus::ObjectPath(removed_device_path_string);
- break;
- }
-
- case dbus::Message::DataType::OBJECT_PATH:
- reader.PopObjectPath(&removed_device_path);
- break;
-
- default:
- break;
- }
-
- if (!removed_device_path.IsValid() ||
- battery_->proxy()->object_path() == removed_device_path)
- FindBatteryDevice();
- }
-
- void BatteryPropertyChanged(const std::string& property_name) {
- NotifyBatteryStatus();
- }
-
- void BatteryChanged(dbus::Signal* signal /* unsused */) {
- DCHECK(battery_);
- battery_->properties()->Invalidate();
- NotifyBatteryStatus();
- }
-
- void NotifyBatteryStatus() {
- DCHECK(OnWatcherThread());
-
- if (!system_bus_.get() || !battery_ || notifying_battery_status_)
- return;
-
- // If the system uses a UPower daemon older than version 0.99
- // (see IsDaemonVersionBelow_0_99), then we are notified about changed
- // battery_ properties through the 'Changed' signal of the battery_
- // device (see BatteryChanged()). That is implemented to invalidate all
- // battery_ properties (so they are re-fetched from the dbus). Getting
- // the new property-value triggers a callback to BatteryPropertyChanged().
- // notifying_battery_status_ is set to avoid recursion and computing the
- // status too often.
- notifying_battery_status_ = true;
- callback_.Run(ComputeWebBatteryStatus(battery_->properties()));
- notifying_battery_status_ = false;
- }
-
- BatteryStatusService::BatteryUpdateCallback callback_;
- scoped_refptr<dbus::Bus> system_bus_;
- std::unique_ptr<UPowerObject> upower_;
- std::unique_ptr<BatteryObject> battery_;
- bool notifying_battery_status_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(BatteryStatusNotificationThread);
-};
-
-BatteryStatusManagerLinux::BatteryStatusManagerLinux(
- const BatteryStatusService::BatteryUpdateCallback& callback)
- : callback_(callback) {}
-
-BatteryStatusManagerLinux::~BatteryStatusManagerLinux() {}
-
-bool BatteryStatusManagerLinux::StartListeningBatteryChange() {
- if (!StartNotifierThreadIfNecessary())
- return false;
-
- notifier_thread_->task_runner()->PostTask(
- FROM_HERE, base::Bind(&BatteryStatusNotificationThread::StartListening,
- base::Unretained(notifier_thread_.get())));
- return true;
-}
-
-void BatteryStatusManagerLinux::StopListeningBatteryChange() {
- if (!notifier_thread_)
- return;
-
- notifier_thread_->task_runner()->PostTask(
- FROM_HERE, base::Bind(&BatteryStatusNotificationThread::StopListening,
- base::Unretained(notifier_thread_.get())));
-}
-
-bool BatteryStatusManagerLinux::StartNotifierThreadIfNecessary() {
- if (notifier_thread_)
- return true;
-
- base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
- auto notifier_thread =
- base::MakeUnique<BatteryStatusNotificationThread>(callback_);
- if (!notifier_thread->StartWithOptions(thread_options)) {
- LOG(ERROR) << "Could not start the " << kBatteryNotifierThreadName
- << " thread";
- return false;
- }
- notifier_thread_ = std::move(notifier_thread);
- return true;
-}
-
-base::Thread* BatteryStatusManagerLinux::GetNotifierThreadForTesting() {
- return notifier_thread_.get();
-}
-
-// static
-std::unique_ptr<BatteryStatusManagerLinux>
-BatteryStatusManagerLinux::CreateForTesting(
- const BatteryStatusService::BatteryUpdateCallback& callback,
- dbus::Bus* bus) {
- auto manager = base::MakeUnique<BatteryStatusManagerLinux>(callback);
- if (!manager->StartNotifierThreadIfNecessary())
- return nullptr;
- manager->notifier_thread_->SetDBusForTesting(bus);
- return manager;
-}
-
-// static
-std::unique_ptr<BatteryStatusManager> BatteryStatusManager::Create(
- const BatteryStatusService::BatteryUpdateCallback& callback) {
- return base::MakeUnique<BatteryStatusManagerLinux>(callback);
-}
-
-} // namespace device
« no previous file with comments | « device/battery/battery_status_manager_linux.h ('k') | device/battery/battery_status_manager_linux-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698