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

Unified Diff: content/browser/power_save_blocker_linux.cc

Issue 10542089: Power save blocker: switch to new implementation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 6 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
Index: content/browser/power_save_blocker_linux.cc
===================================================================
--- content/browser/power_save_blocker_linux.cc (revision 141311)
+++ content/browser/power_save_blocker_linux.cc (working copy)
@@ -34,483 +34,8 @@
#include "dbus/object_path.h"
#include "dbus/object_proxy.h"
-using content::BrowserThread;
-
namespace {
-// This class is used to inhibit Power Management on Linux systems using D-Bus
-// interfaces. Mainly, there are two interfaces that make this possible.
-// org.freedesktop.PowerManagement[.Inhibit] is considered to be the
-// desktop-agnostic solution. However, it is only used by KDE4 and XFCE.
-//
-// org.gnome.SessionManager is the Power Management interface available on GNOME
-// desktops. Given that there is no generic solution to this problem, this class
-// delegates the task of calling specific D-Bus APIs, to a
-// DBusPowerSaveBlock::Delegate object.
-//
-// This class is a Singleton and the delegate will be instantiated internally,
-// when the singleton instance is created, based on the desktop environment in
-// which the application is running. When the class is instantiated, if it runs
-// under a supported desktop environment it creates the Bus object and the
-// delegate. Otherwise, no object is created and the ApplyBlock method will not
-// do anything.
-class DBusPowerSaveBlocker {
- public:
- // String passed to D-Bus APIs as the reason for which
- // the power management features are temporarily disabled.
- static const char kPowerSaveReason[];
-
- // This delegate interface represents a concrete implementation for a specific
- // D-Bus interface. It is responsible for obtaining specific object proxies,
- // making D-Bus method calls and handling D-Bus responses.
- //
- // When a new DBusPowerBlocker is created, only a specific implementation of
- // the delegate is instantiated. See the DBusPowerSaveBlocker constructor for
- // more details. This is ref_counted to make sure that the callbacks stay
- // alive even after the DBusPowerSaveBlocker object is deleted.
- class Delegate : public base::RefCountedThreadSafe<Delegate> {
- public:
- Delegate() {}
- virtual void ApplyBlock(PowerSaveBlocker::PowerSaveBlockerType type) = 0;
-
- protected:
- virtual ~Delegate() {}
-
- private:
- friend class base::RefCountedThreadSafe<Delegate>;
-
- DISALLOW_COPY_AND_ASSIGN(Delegate);
- };
-
- // Returns a pointer to the sole instance of this class
- static DBusPowerSaveBlocker* GetInstance();
-
- // Forwards a power save block request to the concrete implementation of the
- // Delegate interface. If |delegate_| is NULL, the application runs under an
- // unsupported desktop environment. In this case, the method does nothing.
- void ApplyBlock(PowerSaveBlocker::PowerSaveBlockerType type) {
- if (delegate_)
- delegate_->ApplyBlock(type);
- }
-
- // Getter for the Bus object. Used by the Delegates to obtain object proxies.
- scoped_refptr<dbus::Bus> bus() const { return bus_; }
-
- private:
- DBusPowerSaveBlocker();
- virtual ~DBusPowerSaveBlocker();
-
- // If DPMS is not enabled, then we don't want to try to disable power saving,
- // since on some desktop environments that may enable DPMS with very poor
- // default settings (e.g. turning off the display after only 1 second).
- static bool DPMSEnabled();
-
- // The D-Bus connection.
- scoped_refptr<dbus::Bus> bus_;
-
- // Concrete implementation of the Delegate interface.
- scoped_refptr<Delegate> delegate_;
-
- friend struct DefaultSingletonTraits<DBusPowerSaveBlocker>;
-
- DISALLOW_COPY_AND_ASSIGN(DBusPowerSaveBlocker);
-};
-
-// Delegate implementation for KDE4. It uses the
-// org.freedesktop.PowerManagement interface. It works on XFCE4, too.
-class KDEPowerSaveBlocker : public DBusPowerSaveBlocker::Delegate {
- public:
- KDEPowerSaveBlocker()
- : inhibit_cookie_(0),
- pending_inhibit_call_(false),
- postponed_uninhibit_call_(false) {
- }
-
- virtual void ApplyBlock(
- PowerSaveBlocker::PowerSaveBlockerType type) OVERRIDE {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(pending_inhibit_call_ || !postponed_uninhibit_call_);
-
- // If we have a pending inhibit call, we add a postponed uninhibit
- // request, such that it will be canceled as soon as the response arrives.
- // If we have an active inhibit request and receive a new one,
- // we ignore it since the 'freedesktop' interface has only one Inhibit level
- // and we cannot differentiate between SystemSleep and DisplaySleep,
- // so there's no need to make additional D-Bus method calls.
- if (type == PowerSaveBlocker::kPowerSaveBlockPreventNone) {
- if (pending_inhibit_call_ && postponed_uninhibit_call_) {
- return;
- } else if (pending_inhibit_call_ && !postponed_uninhibit_call_) {
- postponed_uninhibit_call_ = true;
- return;
- } else if (!pending_inhibit_call_ && inhibit_cookie_ == 0) {
- return;
- }
- } else if ((pending_inhibit_call_ && !postponed_uninhibit_call_) ||
- inhibit_cookie_ > 0) {
- return;
- }
-
- scoped_refptr<dbus::ObjectProxy> object_proxy =
- DBusPowerSaveBlocker::GetInstance()->bus()->GetObjectProxy(
- "org.freedesktop.PowerManagement",
- dbus::ObjectPath("/org/freedesktop/PowerManagement/Inhibit"));
- dbus::MethodCall method_call("org.freedesktop.PowerManagement.Inhibit",
- "Inhibit");
- dbus::MessageWriter message_writer(&method_call);
- base::Callback<void(dbus::Response*)> bus_callback;
-
- switch (type) {
- case PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep:
- case PowerSaveBlocker::kPowerSaveBlockPreventSystemSleep:
- // The org.freedesktop.PowerManagement.Inhibit interface offers only one
- // Inhibit() method, that temporarily disables all power management
- // features. We cannot differentiate and disable individual features,
- // like display sleep or system sleep.
- // The first argument of the Inhibit method is the application name.
- // The second argument of the Inhibit method is a string containing
- // the reason of the power save block request.
- // The method returns a cookie (an int), which we must pass back to the
- // UnInhibit method when we cancel our request.
- message_writer.AppendString(
- CommandLine::ForCurrentProcess()->GetProgram().value());
- message_writer.AppendString(DBusPowerSaveBlocker::kPowerSaveReason);
- bus_callback = base::Bind(&KDEPowerSaveBlocker::OnInhibitResponse,
- this);
- pending_inhibit_call_ = true;
- break;
- case PowerSaveBlocker::kPowerSaveBlockPreventNone:
- // To cancel our inhibit request, we have to call a different method.
- // It takes one argument, the cookie returned by the corresponding
- // Inhibit method call.
- method_call.SetMember("UnInhibit");
- message_writer.AppendUint32(inhibit_cookie_);
- bus_callback = base::Bind(&KDEPowerSaveBlocker::OnUnInhibitResponse,
- this);
- break;
- case PowerSaveBlocker::kPowerSaveBlockPreventStateCount:
- // This is an invalid argument
- NOTREACHED();
- break;
- }
-
- object_proxy->CallMethod(&method_call,
- dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- bus_callback);
- }
-
- protected:
- virtual ~KDEPowerSaveBlocker() {}
-
- private:
- // Inhibit() response callback.
- // Stores the cookie so we can use it later when calling UnInhibit().
- // If the response from D-Bus is successful and there is a postponed
- // uninhibit request, we cancel the cookie that we just received.
- void OnInhibitResponse(dbus::Response* response) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(pending_inhibit_call_);
- pending_inhibit_call_ = false;
- if (response) {
- dbus::MessageReader message_reader(response);
- if (message_reader.PopUint32(&inhibit_cookie_)) {
- if (postponed_uninhibit_call_) {
- postponed_uninhibit_call_ = false;
- ApplyBlock(PowerSaveBlocker::kPowerSaveBlockPreventNone);
- }
- return;
- } else {
- LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString();
- }
- }
- inhibit_cookie_ = 0;
- postponed_uninhibit_call_ = false;
- }
-
- // UnInhibit() method callback.
- // We set the |inhibit_cookie_| to 0 even if the D-Bus call failed.
- void OnUnInhibitResponse(dbus::Response* response) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- inhibit_cookie_ = 0;
- };
-
- // The cookie that identifies our last inhibit request,
- // or 0 if there is no active inhibit request.
- uint32 inhibit_cookie_;
-
- // True if we made an inhibit call for which
- // we did not receive a response yet
- bool pending_inhibit_call_;
-
- // True if we have to cancel the cookie we are about to receive
- bool postponed_uninhibit_call_;
-
- DISALLOW_COPY_AND_ASSIGN(KDEPowerSaveBlocker);
-};
-
-// Delegate implementation for Gnome, based on org.gnome.SessionManager
-class GnomePowerSaveBlocker : public DBusPowerSaveBlocker::Delegate {
- public:
- // Inhibit flags defined in the org.gnome.SessionManager interface.
- // Can be OR'd together and passed as argument to the Inhibit() method
- // to specify which power management features we want to suspend.
- enum InhibitFlags {
- kInhibitLogOut = 1,
- kInhibitSwitchUser = 2,
- kInhibitSuspendSession = 4,
- kInhibitMarkSessionAsIdle = 8
- };
-
- GnomePowerSaveBlocker()
- : inhibit_cookie_(0),
- pending_inhibit_calls_(0),
- postponed_uninhibit_calls_(0) {}
-
- virtual void ApplyBlock(
- PowerSaveBlocker::PowerSaveBlockerType type) OVERRIDE {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(postponed_uninhibit_calls_ <= pending_inhibit_calls_);
-
- // If we have a pending inhibit call, we add a postponed uninhibit request,
- // such that it will be canceled as soon as the response arrives. We want to
- // cancel the current inhibit request whether |type| is
- // kPowerSaveBlockPreventNone or not. If |type| represents an inhibit
- // request, we are dealing with the same case as below, just that the reply
- // to the previous inhibit request did not arrive yet, so we have to wait
- // for the cookie in order to cancel it. Meanwhile, we can still make the
- // new request.
- //
- // We also have to check that postponed_uninhibit_calls_ <
- // pending_inhibit_calls_. If this is not the case, then all the pending
- // requests were already canceled and we should not increment the number of
- // postponed uninhibit requests; otherwise we will cancel unwanted future
- // inhibits, that will be made after this call.
- //
- // NOTE: The implementation is based on the fact that we receive the D-Bus
- // replies in the same order in which the requests are made.
- if (pending_inhibit_calls_ > 0 &&
- postponed_uninhibit_calls_ < pending_inhibit_calls_) {
- ++postponed_uninhibit_calls_;
- // If the call was an Uninhibit, then we are done for the moment.
- if (type == PowerSaveBlocker::kPowerSaveBlockPreventNone)
- return;
- }
-
- // If we have an active inhibit request and no pending inhibit calls,
- // we make an uninhibit request to cancel it now.
- if (type != PowerSaveBlocker::kPowerSaveBlockPreventNone &&
- pending_inhibit_calls_ == 0 &&
- inhibit_cookie_ > 0) {
- ApplyBlock(PowerSaveBlocker::kPowerSaveBlockPreventNone);
- }
-
- static const char kGnomeSessionManagerName[] = "org.gnome.SessionManager";
- scoped_refptr<dbus::ObjectProxy> object_proxy =
- DBusPowerSaveBlocker::GetInstance()->bus()->GetObjectProxy(
- kGnomeSessionManagerName,
- dbus::ObjectPath("/org/gnome/SessionManager"));
- dbus::MethodCall method_call(kGnomeSessionManagerName, "Inhibit");
- dbus::MessageWriter message_writer(&method_call);
- base::Callback<void(dbus::Response*)> bus_callback;
-
- unsigned int flags = 0;
- switch (type) {
- case PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep:
- flags |= kInhibitMarkSessionAsIdle;
- break;
- case PowerSaveBlocker::kPowerSaveBlockPreventSystemSleep:
- flags |= kInhibitMarkSessionAsIdle;
- flags |= kInhibitSuspendSession;
- break;
- case PowerSaveBlocker::kPowerSaveBlockPreventNone:
- break;
- case PowerSaveBlocker::kPowerSaveBlockPreventStateCount:
- // This is an invalid argument
- NOTREACHED();
- break;
- }
-
- switch (type) {
- case PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep:
- case PowerSaveBlocker::kPowerSaveBlockPreventSystemSleep:
- // To temporarily suspend the power management features on Gnome,
- // we call org.gnome.SessionManager.Inhibit().
- // The arguments of the method are:
- // app_id: The application identifier
- // toplevel_xid: The toplevel X window identifier
- // reason: The reason for the inhibit
- // flags: Flags that spefify what should be inhibited
- // The method returns and inhibit_cookie, used to uniquely identify
- // this request. It should be used as an argument to Uninhibit()
- // in order to remove the request.
- message_writer.AppendString(
- CommandLine::ForCurrentProcess()->GetProgram().value());
- message_writer.AppendUint32(0); // should be toplevel_xid
- message_writer.AppendString(DBusPowerSaveBlocker::kPowerSaveReason);
- message_writer.AppendUint32(flags);
- bus_callback = base::Bind(&GnomePowerSaveBlocker::OnInhibitResponse,
- this);
- ++pending_inhibit_calls_;
- break;
- case PowerSaveBlocker::kPowerSaveBlockPreventNone:
- // To cancel a previous inhibit request we call
- // org.gnome.SessionManager.Uninhibit().
- // It takes only one argument, the cookie that identifies
- // the request we want to cancel.
- method_call.SetMember("Uninhibit");
- message_writer.AppendUint32(inhibit_cookie_);
- bus_callback = base::Bind(&GnomePowerSaveBlocker::OnUnInhibitResponse,
- this);
- ++pending_inhibit_calls_;
- break;
- case PowerSaveBlocker::kPowerSaveBlockPreventStateCount:
- // This is an invalid argument.
- NOTREACHED();
- break;
- }
-
- object_proxy->CallMethod(&method_call,
- dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- bus_callback);
- }
-
- protected:
- virtual ~GnomePowerSaveBlocker() {}
-
- private:
- // Inhibit() response callback.
- // Stores the cookie so we can use it later when calling UnInhibit().
- // If the response from D-Bus is successful and there is a postponed
- // uninhibit request, we cancel the cookie that we just received.
- void OnInhibitResponse(dbus::Response* response) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK_GT(pending_inhibit_calls_, 0);
- --pending_inhibit_calls_;
- if (response) {
- dbus::MessageReader message_reader(response);
- if (message_reader.PopUint32(&inhibit_cookie_)) {
- if (postponed_uninhibit_calls_ > 0) {
- --postponed_uninhibit_calls_;
- ApplyBlock(PowerSaveBlocker::kPowerSaveBlockPreventNone);
- }
- return;
- } else {
- LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString();
- }
- }
- inhibit_cookie_ = 0;
- if (postponed_uninhibit_calls_ > 0) {
- --postponed_uninhibit_calls_;
- }
- }
-
- // Uninhibit() response callback.
- // We set the |inhibit_cookie_| to 0 even if the D-Bus call failed.
- void OnUnInhibitResponse(dbus::Response* response) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- inhibit_cookie_ = 0;
- };
-
- // The cookie that identifies our last inhibit request,
- // or 0 if there is no active inhibit request.
- uint32 inhibit_cookie_;
-
- // Store the number of inhibit calls for which
- // we did not receive a response yet
- int pending_inhibit_calls_;
-
- // Store the number of Uninhibit requests that arrived,
- // before the corresponding Inhibit calls were completed.
- int postponed_uninhibit_calls_;
-
- DISALLOW_COPY_AND_ASSIGN(GnomePowerSaveBlocker);
-};
-
-const char DBusPowerSaveBlocker::kPowerSaveReason[] = "Power Save Blocker";
-
-// Initialize the DBusPowerSaveBlocker instance:
-// 1. Instantiate a concrete delegate based on the current desktop environment,
-// 2. Instantiate the D-Bus object
-DBusPowerSaveBlocker::DBusPowerSaveBlocker() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- scoped_ptr<base::Environment> env(base::Environment::Create());
- switch (base::nix::GetDesktopEnvironment(env.get())) {
- case base::nix::DESKTOP_ENVIRONMENT_GNOME:
- if (DPMSEnabled())
- delegate_ = new GnomePowerSaveBlocker();
- break;
- case base::nix::DESKTOP_ENVIRONMENT_XFCE:
- case base::nix::DESKTOP_ENVIRONMENT_KDE4:
- if (DPMSEnabled())
- delegate_ = new KDEPowerSaveBlocker();
- break;
- case base::nix::DESKTOP_ENVIRONMENT_KDE3:
- case base::nix::DESKTOP_ENVIRONMENT_OTHER:
- // Not supported, so we exit.
- // We don't create D-Bus objects.
- break;
- }
-
- if (delegate_) {
- dbus::Bus::Options options;
- options.bus_type = dbus::Bus::SESSION;
- options.connection_type = dbus::Bus::PRIVATE;
- // Use the FILE thread to service the D-Bus connection,
- // since we need a thread that allows I/O operations.
- options.dbus_thread_message_loop_proxy =
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE);
- bus_ = new dbus::Bus(options);
- }
-}
-
-DBusPowerSaveBlocker::~DBusPowerSaveBlocker() {
- // We try to shut down the bus, but unfortunately in most of the
- // cases when we delete the singleton instance,
- // the FILE thread is already stopped and there is no way to
- // shutdown the bus object on the origin thread (the UI thread).
- // However, this is not a crucial problem since at this point
- // we are at the very end of the shutting down phase.
- // Connection to D-Bus is just a Unix domain socket, which is not
- // a persistent resource, hence the operating system will take care
- // of closing it when the process terminates.
- if (BrowserThread::IsMessageLoopValid(BrowserThread::FILE)) {
- bus_->ShutdownOnDBusThreadAndBlock();
- }
-}
-
-// static
-bool DBusPowerSaveBlocker::DPMSEnabled() {
- Display* display = base::MessagePumpForUI::GetDefaultXDisplay();
- BOOL enabled = false;
- int dummy;
- if (DPMSQueryExtension(display, &dummy, &dummy) && DPMSCapable(display)) {
- CARD16 state;
- DPMSInfo(display, &state, &enabled);
- }
- return enabled;
-}
-
-// static
-DBusPowerSaveBlocker* DBusPowerSaveBlocker::GetInstance() {
- return Singleton<DBusPowerSaveBlocker>::get();
-}
-
-} // namespace
-
-// Called only from UI thread.
-// static
-void PowerSaveBlocker::ApplyBlock(PowerSaveBlockerType type) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DBusPowerSaveBlocker::GetInstance()->ApplyBlock(type);
-}
-
-// TODO(mdm): remove from the beginning of the file up to (and including) this
-// line to switch to the new implementation.
-#define PowerSaveBlocker PowerSaveBlocker2
-
-namespace {
-
enum DBusAPI {
NO_API, // Disable. No supported API available.
GNOME_API, // Use the GNOME API. (Supports more features.)

Powered by Google App Engine
This is Rietveld 408576698