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

Unified Diff: device/battery/battery_status_manager_linux.cc

Issue 2066503002: Implement device::BatteryStatus support for UPower daemon 0.99.x (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Implement device::BatteryStatus support for UPower daemon 0.99.x (rebased) Created 4 years, 4 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
index f708b8c49f23227a474567b8ec9ad2d9d8d10581..ec96544d775387d66dc1750c5ccb59bb3187c6b0 100644
--- a/device/battery/battery_status_manager_linux.cc
+++ b/device/battery/battery_status_manager_linux.cc
@@ -7,96 +7,122 @@
#include <stddef.h>
#include <stdint.h>
+#include <limits>
#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
#include "base/macros.h"
#include "base/metrics/histogram.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.h"
+#include "device/battery/battery_status_manager_linux-inl.h"
namespace device {
-
namespace {
-
-const char kUPowerServiceName[] = "org.freedesktop.UPower";
-const char kUPowerDeviceName[] = "org.freedesktop.UPower.Device";
-const char kUPowerPath[] = "/org/freedesktop/UPower";
-const char kUPowerDeviceSignalChanged[] = "Changed";
-const char kUPowerEnumerateDevices[] = "EnumerateDevices";
const char kBatteryNotifierThreadName[] = "BatteryStatusNotifier";
-// UPowerDeviceType reflects the possible UPower.Device.Type values,
-// see upower.freedesktop.org/docs/Device.html#Device:Type.
-enum UPowerDeviceType {
- UPOWER_DEVICE_TYPE_UNKNOWN = 0,
- UPOWER_DEVICE_TYPE_LINE_POWER = 1,
- UPOWER_DEVICE_TYPE_BATTERY = 2,
- UPOWER_DEVICE_TYPE_UPS = 3,
- UPOWER_DEVICE_TYPE_MONITOR = 4,
- UPOWER_DEVICE_TYPE_MOUSE = 5,
- UPOWER_DEVICE_TYPE_KEYBOARD = 6,
- UPOWER_DEVICE_TYPE_PDA = 7,
- UPOWER_DEVICE_TYPE_PHONE = 8,
-};
+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_;
-typedef std::vector<dbus::ObjectPath> PathsVector;
+ DISALLOW_COPY_AND_ASSIGN(UPowerProperties);
+};
-double GetPropertyAsDouble(const base::DictionaryValue& dictionary,
- const std::string& property_name,
- double default_value) {
- double value = default_value;
- return dictionary.GetDouble(property_name, &value) ? value : default_value;
+UPowerProperties::UPowerProperties(dbus::ObjectProxy* object_proxy,
+ const PropertyChangedCallback callback)
+ : dbus::PropertySet(object_proxy, kUPowerInterfaceName, callback) {
+ RegisterProperty(kUPowerPropertyDaemonVersion, &daemon_version_);
}
-bool GetPropertyAsBoolean(const base::DictionaryValue& dictionary,
- const std::string& property_name,
- bool default_value) {
- bool value = default_value;
- return dictionary.GetBoolean(property_name, &value) ? value : default_value;
+UPowerProperties::~UPowerProperties() {}
+
+base::Version UPowerProperties::daemon_version() {
+ return (daemon_version_.is_valid() || daemon_version_.GetAndBlock())
+ ? base::Version(daemon_version_.value())
+ : base::Version();
}
-std::unique_ptr<base::DictionaryValue> GetPropertiesAsDictionary(
- dbus::ObjectProxy* proxy) {
- dbus::MethodCall method_call(dbus::kPropertiesInterface,
- dbus::kPropertiesGetAll);
- dbus::MessageWriter builder(&method_call);
- builder.AppendString(kUPowerDeviceName);
+class UPowerObject {
+ public:
+ typedef dbus::PropertySet::PropertyChangedCallback PropertyChangedCallback;
+
+ UPowerObject(dbus::Bus* dbus,
+ const PropertyChangedCallback property_changed_callback);
+ ~UPowerObject();
+
+ std::vector<dbus::ObjectPath> EnumerateDevices();
+ dbus::ObjectPath GetDisplayDevice();
- std::unique_ptr<dbus::Response> response(proxy->CallMethodAndBlock(
+ 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());
- std::unique_ptr<base::Value> value(dbus::PopDataAsValue(&reader));
- base::DictionaryValue* dictionary_value = NULL;
- if (value && value->GetAsDictionary(&dictionary_value)) {
- ignore_result(value.release());
- return std::unique_ptr<base::DictionaryValue>(dictionary_value);
- }
+ reader.PopArrayOfObjectPaths(&paths);
}
- return std::unique_ptr<base::DictionaryValue>();
+ return paths;
}
-std::unique_ptr<PathsVector> GetPowerSourcesPaths(dbus::ObjectProxy* proxy) {
- std::unique_ptr<PathsVector> paths(new PathsVector());
- if (!proxy)
- return paths;
+dbus::ObjectPath UPowerObject::GetDisplayDevice() {
+ dbus::ObjectPath display_device_path;
+ if (!proxy_)
+ return display_device_path;
- dbus::MethodCall method_call(kUPowerServiceName, kUPowerEnumerateDevices);
- std::unique_ptr<dbus::Response> response(proxy->CallMethodAndBlock(
+ 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.PopArrayOfObjectPaths(paths.get());
+ reader.PopObjectPath(&display_device_path);
}
- return paths;
+ return display_device_path;
}
void UpdateNumberBatteriesHistogram(int count) {
@@ -104,15 +130,187 @@ void UpdateNumberBatteriesHistogram(int count) {
"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:
+ typedef dbus::PropertySet::PropertyChangedCallback 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;
+}
+
+BatteryStatus ComputeWebBatteryStatus(BatteryProperties* properties) {
+ 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 BatteryStatusNotificationThread : public base::Thread {
+class BatteryStatusManagerLinux::BatteryStatusNotificationThread
+ : public base::Thread {
public:
BatteryStatusNotificationThread(
const BatteryStatusService::BatteryUpdateCallback& callback)
- : base::Thread(kBatteryNotifierThreadName),
- callback_(callback),
- battery_proxy_(NULL) {}
+ : base::Thread(kBatteryNotifierThreadName), callback_(callback) {}
~BatteryStatusNotificationThread() override {
// Make sure to shutdown the dbus connection if it is still open in the very
@@ -129,64 +327,28 @@ class BatteryStatusNotificationThread : public base::Thread {
void StartListening() {
DCHECK(OnWatcherThread());
- if (system_bus_.get())
+ if (upower_)
return;
- InitDBus();
- dbus::ObjectProxy* power_proxy =
- system_bus_->GetObjectProxy(kUPowerServiceName,
- dbus::ObjectPath(kUPowerPath));
- std::unique_ptr<PathsVector> device_paths =
- GetPowerSourcesPaths(power_proxy);
- int num_batteries = 0;
-
- for (size_t i = 0; i < device_paths->size(); ++i) {
- const dbus::ObjectPath& device_path = device_paths->at(i);
- dbus::ObjectProxy* device_proxy = system_bus_->GetObjectProxy(
- kUPowerServiceName, device_path);
- std::unique_ptr<base::DictionaryValue> dictionary =
- GetPropertiesAsDictionary(device_proxy);
-
- if (!dictionary)
- continue;
-
- bool is_present = GetPropertyAsBoolean(*dictionary, "IsPresent", false);
- uint32_t type = static_cast<uint32_t>(
- GetPropertyAsDouble(*dictionary, "Type", UPOWER_DEVICE_TYPE_UNKNOWN));
-
- if (!is_present || type != UPOWER_DEVICE_TYPE_BATTERY) {
- system_bus_->RemoveObjectProxy(kUPowerServiceName,
- device_path,
- base::Bind(&base::DoNothing));
- continue;
- }
-
- if (battery_proxy_) {
- // 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_proxy_ = device_proxy;
- }
- num_batteries++;
- }
-
- UpdateNumberBatteriesHistogram(num_batteries);
-
- if (!battery_proxy_) {
- callback_.Run(BatteryStatus());
- return;
- }
+ if (!system_bus_)
+ InitDBus();
- battery_proxy_->ConnectToSignal(
- kUPowerDeviceName,
- kUPowerDeviceSignalChanged,
- base::Bind(&BatteryStatusNotificationThread::BatteryChanged,
+ upower_.reset(new 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() {
@@ -194,6 +356,8 @@ class BatteryStatusNotificationThread : public base::Thread {
ShutdownDBusConnection();
}
+ void SetDBusForTesting(dbus::Bus* bus) { system_bus_ = bus; }
+
private:
bool OnWatcherThread() {
return task_runner()->BelongsToCurrentThread();
@@ -208,164 +372,249 @@ class BatteryStatusNotificationThread : public base::Thread {
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);
+ else
+ return CreateBattery(device_path);
+ };
+
+ dbus::ObjectPath display_device_path = upower_->GetDisplayDevice();
+ if (display_device_path.IsValid()) {
+ std::unique_ptr<BatteryObject> 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()) {
+ std::unique_ptr<BatteryObject> 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_) {
+ battery_->properties()->ConnectSignals();
+ NotifyBatteryStatus();
+ } else {
+ callback_.Run(BatteryStatus());
+ return;
+ }
+
+ 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()->PostTask(FROM_HERE,
base::Bind(&dbus::Bus::ShutdownAndBlock,
system_bus_));
system_bus_ = NULL;
- battery_proxy_ = NULL;
}
void OnSignalConnected(const std::string& interface_name,
const std::string& signal_name,
- bool success) {
- DCHECK(OnWatcherThread());
+ bool success) {}
+
+ std::unique_ptr<BatteryObject> CreateBattery(
+ const dbus::ObjectPath& device_path) {
+ std::unique_ptr<BatteryObject> battery(new BatteryObject(
+ system_bus_.get(), device_path,
+ base::Bind(&BatteryStatusNotificationThread::BatteryPropertyChanged,
+ base::Unretained(this))));
+ return battery;
+ }
- if (interface_name != kUPowerDeviceName ||
- signal_name != kUPowerDeviceSignalChanged) {
- return;
- }
+ 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();
+ }
- if (!system_bus_.get())
+ void DeviceRemoved(dbus::Signal* signal) {
+ if (!battery_)
return;
- if (success) {
- BatteryChanged(NULL);
- } else {
- // Failed to register for "Changed" signal, execute callback with the
- // default values.
- callback_.Run(BatteryStatus());
+ // 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())
+ if (!system_bus_.get() || !battery_ || notifying_battery_status_)
return;
- std::unique_ptr<base::DictionaryValue> dictionary =
- GetPropertiesAsDictionary(battery_proxy_);
- if (dictionary)
- callback_.Run(ComputeWebBatteryStatus(*dictionary));
- else
- callback_.Run(BatteryStatus());
+ // 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_;
- dbus::ObjectProxy* battery_proxy_; // owned by the bus
+ std::unique_ptr<UPowerObject> upower_;
+ std::unique_ptr<BatteryObject> battery_;
+ bool notifying_battery_status_ = false;
DISALLOW_COPY_AND_ASSIGN(BatteryStatusNotificationThread);
};
-// Creates a notification thread and delegates Start/Stop calls to it.
-class BatteryStatusManagerLinux : public BatteryStatusManager {
- public:
- explicit BatteryStatusManagerLinux(
- const BatteryStatusService::BatteryUpdateCallback& callback)
- : callback_(callback) {}
+BatteryStatusManagerLinux::BatteryStatusManagerLinux(
+ const BatteryStatusService::BatteryUpdateCallback& callback)
+ : callback_(callback) {}
- ~BatteryStatusManagerLinux() override {}
+BatteryStatusManagerLinux::~BatteryStatusManagerLinux() {}
- private:
- // BatteryStatusManager:
- bool StartListeningBatteryChange() override {
- if (!StartNotifierThreadIfNecessary())
- return false;
+bool BatteryStatusManagerLinux::StartListeningBatteryChange() {
+ if (!StartNotifierThreadIfNecessary())
+ return false;
- notifier_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&BatteryStatusNotificationThread::StartListening,
- base::Unretained(notifier_thread_.get())));
- return true;
- }
+ notifier_thread_->message_loop()->PostTask(
+ FROM_HERE, base::Bind(&BatteryStatusNotificationThread::StartListening,
+ base::Unretained(notifier_thread_.get())));
+ return true;
+}
- void StopListeningBatteryChange() override {
- if (!notifier_thread_)
- return;
+void BatteryStatusManagerLinux::StopListeningBatteryChange() {
+ if (!notifier_thread_)
+ return;
- notifier_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&BatteryStatusNotificationThread::StopListening,
- base::Unretained(notifier_thread_.get())));
- }
+ notifier_thread_->message_loop()->PostTask(
+ FROM_HERE, base::Bind(&BatteryStatusNotificationThread::StopListening,
+ base::Unretained(notifier_thread_.get())));
+}
- // Starts the notifier thread if not already started and returns true on
- // success.
- bool StartNotifierThreadIfNecessary() {
- if (notifier_thread_)
- return true;
-
- base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
- notifier_thread_.reset(new BatteryStatusNotificationThread(callback_));
- if (!notifier_thread_->StartWithOptions(thread_options)) {
- notifier_thread_.reset();
- LOG(ERROR) << "Could not start the " << kBatteryNotifierThreadName
- << " thread";
- return false;
- }
+bool BatteryStatusManagerLinux::StartNotifierThreadIfNecessary() {
+ if (notifier_thread_)
return true;
- }
-
- BatteryStatusService::BatteryUpdateCallback callback_;
- std::unique_ptr<BatteryStatusNotificationThread> notifier_thread_;
-
- DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerLinux);
-};
-} // namespace
-
-BatteryStatus ComputeWebBatteryStatus(const base::DictionaryValue& dictionary) {
- BatteryStatus status;
- if (!dictionary.HasKey("State"))
- return status;
+ base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
+ notifier_thread_.reset(new BatteryStatusNotificationThread(callback_));
+ if (!notifier_thread_->StartWithOptions(thread_options)) {
+ notifier_thread_.reset();
+ LOG(ERROR) << "Could not start the " << kBatteryNotifierThreadName
+ << " thread";
+ return false;
+ }
+ return true;
+}
- uint32_t state = static_cast<uint32_t>(
- GetPropertyAsDouble(dictionary, "State", UPOWER_DEVICE_STATE_UNKNOWN));
- status.charging = state != UPOWER_DEVICE_STATE_DISCHARGING &&
- state != UPOWER_DEVICE_STATE_EMPTY;
- double percentage = GetPropertyAsDouble(dictionary, "Percentage", 100);
- // 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(percentage) / 100.f;
+base::Thread* BatteryStatusManagerLinux::GetNotifierThreadForTesting() {
+ return notifier_thread_.get();
+}
- switch (state) {
- case UPOWER_DEVICE_STATE_CHARGING : {
- double time_to_full = GetPropertyAsDouble(dictionary, "TimeToFull", 0);
- status.charging_time =
- (time_to_full > 0) ? time_to_full
- : std::numeric_limits<double>::infinity();
- break;
- }
- case UPOWER_DEVICE_STATE_DISCHARGING : {
- double time_to_empty = GetPropertyAsDouble(dictionary, "TimeToEmpty", 0);
- // 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;
+// static
+std::unique_ptr<BatteryStatusManagerLinux>
+BatteryStatusManagerLinux::CreateForTesting(
+ const BatteryStatusService::BatteryUpdateCallback& callback,
+ dbus::Bus* bus) {
+ std::unique_ptr<BatteryStatusManagerLinux> manager(
+ new BatteryStatusManagerLinux(callback));
+ if (manager->StartNotifierThreadIfNecessary())
+ manager->notifier_thread_->SetDBusForTesting(bus);
+ else
+ manager.reset();
+ return manager;
}
// static
« 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