| Index: trunk/src/content/browser/battery_status/battery_status_manager_linux.cc
|
| ===================================================================
|
| --- trunk/src/content/browser/battery_status/battery_status_manager_linux.cc (revision 289378)
|
| +++ trunk/src/content/browser/battery_status/battery_status_manager_linux.cc (working copy)
|
| @@ -1,374 +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 "content/browser/battery_status/battery_status_manager_linux.h"
|
| -
|
| -#include "base/macros.h"
|
| -#include "base/threading/thread.h"
|
| -#include "base/values.h"
|
| -#include "content/browser/battery_status/battery_status_manager.h"
|
| -#include "content/public/browser/browser_thread.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"
|
| -
|
| -namespace content {
|
| -
|
| -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,
|
| -};
|
| -
|
| -typedef std::vector<dbus::ObjectPath> PathsVector;
|
| -
|
| -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;
|
| -}
|
| -
|
| -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;
|
| -}
|
| -
|
| -scoped_ptr<base::DictionaryValue> GetPropertiesAsDictionary(
|
| - dbus::ObjectProxy* proxy) {
|
| - dbus::MethodCall method_call(dbus::kPropertiesInterface,
|
| - dbus::kPropertiesGetAll);
|
| - dbus::MessageWriter builder(&method_call);
|
| - builder.AppendString(kUPowerDeviceName);
|
| -
|
| - scoped_ptr<dbus::Response> response(
|
| - proxy->CallMethodAndBlock(&method_call,
|
| - dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
|
| - if (response) {
|
| - dbus::MessageReader reader(response.get());
|
| - scoped_ptr<base::Value> value(dbus::PopDataAsValue(&reader));
|
| - base::DictionaryValue* dictionary_value = NULL;
|
| - if (value && value->GetAsDictionary(&dictionary_value)) {
|
| - ignore_result(value.release());
|
| - return scoped_ptr<base::DictionaryValue>(dictionary_value);
|
| - }
|
| - }
|
| - return scoped_ptr<base::DictionaryValue>();
|
| -}
|
| -
|
| -scoped_ptr<PathsVector> GetPowerSourcesPaths(dbus::ObjectProxy* proxy) {
|
| - scoped_ptr<PathsVector> paths(new PathsVector());
|
| - if (!proxy)
|
| - return paths.Pass();
|
| -
|
| - dbus::MethodCall method_call(kUPowerServiceName, kUPowerEnumerateDevices);
|
| - scoped_ptr<dbus::Response> response(
|
| - proxy->CallMethodAndBlock(&method_call,
|
| - dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
|
| -
|
| - if (response) {
|
| - dbus::MessageReader reader(response.get());
|
| - reader.PopArrayOfObjectPaths(paths.get());
|
| - }
|
| - return paths.Pass();;
|
| -}
|
| -
|
| -// Class that represents a dedicated thread which communicates with DBus to
|
| -// obtain battery information and receives battery change notifications.
|
| -class BatteryStatusNotificationThread : public base::Thread {
|
| - public:
|
| - BatteryStatusNotificationThread(
|
| - const BatteryStatusService::BatteryUpdateCallback& callback)
|
| - : base::Thread(kBatteryNotifierThreadName),
|
| - callback_(callback),
|
| - battery_proxy_(NULL) {}
|
| -
|
| - virtual ~BatteryStatusNotificationThread() {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| -
|
| - // 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()->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 (system_bus_)
|
| - return;
|
| -
|
| - InitDBus();
|
| - dbus::ObjectProxy* power_proxy =
|
| - system_bus_->GetObjectProxy(kUPowerServiceName,
|
| - dbus::ObjectPath(kUPowerPath));
|
| - scoped_ptr<PathsVector> device_paths = GetPowerSourcesPaths(power_proxy);
|
| -
|
| - 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);
|
| - scoped_ptr<base::DictionaryValue> dictionary =
|
| - GetPropertiesAsDictionary(device_proxy);
|
| -
|
| - if (!dictionary)
|
| - continue;
|
| -
|
| - bool is_present = GetPropertyAsBoolean(*dictionary, "IsPresent", false);
|
| - uint32 type = static_cast<uint32>(
|
| - 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).
|
| - // TODO(timvolodine): add UMA logging for this case.
|
| - LOG(WARNING) << "multiple batteries found, "
|
| - << "using status data of the first battery only.";
|
| - } else {
|
| - battery_proxy_ = device_proxy;
|
| - }
|
| - }
|
| -
|
| - if (!battery_proxy_) {
|
| - callback_.Run(blink::WebBatteryStatus());
|
| - return;
|
| - }
|
| -
|
| - battery_proxy_->ConnectToSignal(
|
| - kUPowerDeviceName,
|
| - kUPowerDeviceSignalChanged,
|
| - base::Bind(&BatteryStatusNotificationThread::BatteryChanged,
|
| - base::Unretained(this)),
|
| - base::Bind(&BatteryStatusNotificationThread::OnSignalConnected,
|
| - base::Unretained(this)));
|
| - }
|
| -
|
| - void StopListening() {
|
| - DCHECK(OnWatcherThread());
|
| - ShutdownDBusConnection();
|
| - }
|
| -
|
| - 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);
|
| - }
|
| -
|
| - void ShutdownDBusConnection() {
|
| - DCHECK(OnWatcherThread());
|
| -
|
| - if (!system_bus_)
|
| - return;
|
| -
|
| - // 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());
|
| -
|
| - if (interface_name != kUPowerDeviceName ||
|
| - signal_name != kUPowerDeviceSignalChanged) {
|
| - return;
|
| - }
|
| -
|
| - if (!system_bus_)
|
| - return;
|
| -
|
| - if (success) {
|
| - BatteryChanged(NULL);
|
| - } else {
|
| - // Failed to register for "Changed" signal, execute callback with the
|
| - // default values.
|
| - callback_.Run(blink::WebBatteryStatus());
|
| - }
|
| - }
|
| -
|
| - void BatteryChanged(dbus::Signal* signal /* unsused */) {
|
| - DCHECK(OnWatcherThread());
|
| -
|
| - if (!system_bus_)
|
| - return;
|
| -
|
| - scoped_ptr<base::DictionaryValue> dictionary =
|
| - GetPropertiesAsDictionary(battery_proxy_);
|
| - if (dictionary)
|
| - callback_.Run(ComputeWebBatteryStatus(*dictionary));
|
| - else
|
| - callback_.Run(blink::WebBatteryStatus());
|
| - }
|
| -
|
| - BatteryStatusService::BatteryUpdateCallback callback_;
|
| - scoped_refptr<dbus::Bus> system_bus_;
|
| - dbus::ObjectProxy* battery_proxy_; // owned by the bus
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(BatteryStatusNotificationThread);
|
| -};
|
| -
|
| -// Runs on IO thread and creates a notification thread and delegates Start/Stop
|
| -// calls to it.
|
| -class BatteryStatusManagerLinux : public BatteryStatusManager {
|
| - public:
|
| - explicit BatteryStatusManagerLinux(
|
| - const BatteryStatusService::BatteryUpdateCallback& callback)
|
| - : callback_(callback) {}
|
| -
|
| - virtual ~BatteryStatusManagerLinux() {}
|
| -
|
| - private:
|
| - // BatteryStatusManager:
|
| - virtual bool StartListeningBatteryChange() OVERRIDE {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| -
|
| - if (!StartNotifierThreadIfNecessary())
|
| - return false;
|
| -
|
| - notifier_thread_->message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&BatteryStatusNotificationThread::StartListening,
|
| - base::Unretained(notifier_thread_.get())));
|
| - return true;
|
| - }
|
| -
|
| - virtual void StopListeningBatteryChange() OVERRIDE {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| -
|
| - if (!notifier_thread_)
|
| - return;
|
| -
|
| - 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;
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - BatteryStatusService::BatteryUpdateCallback callback_;
|
| - scoped_ptr<BatteryStatusNotificationThread> notifier_thread_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerLinux);
|
| -};
|
| -
|
| -} // namespace
|
| -
|
| -blink::WebBatteryStatus ComputeWebBatteryStatus(
|
| - const base::DictionaryValue& dictionary) {
|
| - blink::WebBatteryStatus status;
|
| - if (!dictionary.HasKey("State"))
|
| - return status;
|
| -
|
| - uint32 state = static_cast<uint32>(
|
| - 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;
|
| -
|
| - switch (state) {
|
| - case UPOWER_DEVICE_STATE_CHARGING : {
|
| - double time_to_full = GetPropertyAsDouble(dictionary, "TimeToFull", 0);
|
| - status.chargingTime =
|
| - (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.dischargingTime = time_to_empty;
|
| - status.chargingTime = std::numeric_limits<double>::infinity();
|
| - break;
|
| - }
|
| - case UPOWER_DEVICE_STATE_FULL : {
|
| - break;
|
| - }
|
| - default: {
|
| - status.chargingTime = std::numeric_limits<double>::infinity();
|
| - }
|
| - }
|
| - return status;
|
| -}
|
| -
|
| -// static
|
| -scoped_ptr<BatteryStatusManager> BatteryStatusManager::Create(
|
| - const BatteryStatusService::BatteryUpdateCallback& callback) {
|
| - return scoped_ptr<BatteryStatusManager>(
|
| - new BatteryStatusManagerLinux(callback));
|
| -}
|
| -
|
| -} // namespace content
|
|
|