Index: content/browser/power_save_blocker_x11.cc |
diff --git a/content/browser/power_save_blocker_x11.cc b/content/browser/power_save_blocker_x11.cc |
index 9cd6113e3f06ddf427460b82a291c5bb085de971..c1be00b7675985ee70e9c210f54e85a3fc49c7d9 100644 |
--- a/content/browser/power_save_blocker_x11.cc |
+++ b/content/browser/power_save_blocker_x11.cc |
@@ -93,6 +93,11 @@ class PowerSaveBlockerImpl::Delegate |
void ApplyBlock(DBusAPI api); |
void RemoveBlock(DBusAPI api); |
+ // Asynchronous callback functions for ApplyBlock and RemoveBlock. |
+ // Functions do not receive ownership of |response|. |
+ void ApplyBlockFinished(DBusAPI api, dbus::Response* response); |
+ void RemoveBlockFinished(dbus::Response* response); |
+ |
// If DPMS (the power saving system in X11) 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 |
@@ -115,6 +120,15 @@ class PowerSaveBlockerImpl::Delegate |
bool enqueue_apply_; |
base::Lock lock_; |
+ // Indicates that a D-Bus power save blocking request is in flight. |
+ bool block_inflight_; |
+ // Used to detect erronous redundant calls to RemoveBlock(). |
+ bool unblock_inflight_; |
+ // Indicates that RemoveBlock() is called before ApplyBlock() has finished. |
+ // If it's true, then the RemoveBlock() call will be processed immediately |
+ // after ApplyBlock() has finished. |
+ bool unblock_enqueued_; |
+ |
scoped_refptr<dbus::Bus> bus_; |
// The cookie that identifies our inhibit request, |
@@ -139,6 +153,9 @@ void PowerSaveBlockerImpl::Delegate::Init() { |
base::AutoLock lock(lock_); |
DCHECK(!enqueue_apply_); |
enqueue_apply_ = true; |
+ block_inflight_ = false; |
+ unblock_inflight_ = false; |
+ unblock_enqueued_ = false; |
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
base::Bind(&Delegate::InitOnUIThread, this)); |
} |
@@ -172,7 +189,8 @@ void PowerSaveBlockerImpl::Delegate::InitOnUIThread() { |
void PowerSaveBlockerImpl::Delegate::ApplyBlock(DBusAPI api) { |
DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
- DCHECK(!bus_.get()); // ApplyBlock() should only be called once. |
+ DCHECK(!bus_); // ApplyBlock() should only be called once. |
+ DCHECK(!block_inflight_); |
dbus::Bus::Options options; |
options.bus_type = dbus::Bus::SESSION; |
@@ -233,26 +251,52 @@ void PowerSaveBlockerImpl::Delegate::ApplyBlock(DBusAPI api) { |
break; |
} |
- // We could do this method call asynchronously, but if we did, we'd need to |
- // handle the case where we want to cancel the block before we get a reply. |
- // We're on the FILE thread so it should be OK to block briefly here. |
- scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock( |
- method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
+ block_inflight_ = true; |
+ object_proxy->CallMethod( |
+ method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
+ base::Bind(&PowerSaveBlockerImpl::Delegate::ApplyBlockFinished, this, |
+ api)); |
+} |
+ |
+void PowerSaveBlockerImpl::Delegate::ApplyBlockFinished( |
+ DBusAPI api, |
+ dbus::Response* response) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
+ DCHECK(bus_); |
+ DCHECK(block_inflight_); |
+ block_inflight_ = false; |
+ |
if (response) { |
// The method returns an inhibit_cookie, used to uniquely identify |
// this request. It should be used as an argument to Uninhibit() |
// in order to remove the request. |
- dbus::MessageReader message_reader(response.get()); |
+ dbus::MessageReader message_reader(response); |
if (!message_reader.PopUint32(&inhibit_cookie_)) |
LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString(); |
} else { |
LOG(ERROR) << "No response to Inhibit() request!"; |
} |
+ |
+ if (unblock_enqueued_) { |
+ unblock_enqueued_ = false; |
+ // RemoveBlock() was called while the Inhibit operation was in flight, |
+ // so go ahead and remove the block now. |
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
+ base::Bind(&Delegate::RemoveBlock, this, api_)); |
+ } |
} |
void PowerSaveBlockerImpl::Delegate::RemoveBlock(DBusAPI api) { |
DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
- DCHECK(bus_.get()); // RemoveBlock() should only be called once. |
+ DCHECK(bus_); // RemoveBlock() should only be called once. |
+ DCHECK(!unblock_inflight_); |
+ |
+ if (block_inflight_) { |
+ // Can't call RemoveBlock until ApplyBlock's asynchronous operation has |
+ // finished. Enqueue it for execution once ApplyBlock is done. |
+ unblock_enqueued_ = true; |
miu
2015/05/15 18:43:31
Should you DCHECK(!unblock_enqueued) before this l
Kevin M
2015/05/15 18:55:25
Good idea, done.
|
+ return; |
+ } |
scoped_refptr<dbus::ObjectProxy> object_proxy; |
scoped_ptr<dbus::MethodCall> method_call; |
@@ -279,13 +323,22 @@ void PowerSaveBlockerImpl::Delegate::RemoveBlock(DBusAPI api) { |
dbus::MessageWriter message_writer(method_call.get()); |
message_writer.AppendUint32(inhibit_cookie_); |
- scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock( |
- method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
+ unblock_inflight_ = true; |
+ object_proxy->CallMethod( |
+ method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
+ base::Bind(&PowerSaveBlockerImpl::Delegate::RemoveBlockFinished, this)); |
+} |
+ |
+void PowerSaveBlockerImpl::Delegate::RemoveBlockFinished( |
+ dbus::Response* response) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
+ DCHECK(bus_); |
+ unblock_inflight_ = false; |
+ |
if (!response) |
LOG(ERROR) << "No response to Uninhibit() request!"; |
// We don't care about checking the result. We assume it works; we can't |
// really do anything about it anyway if it fails. |
- inhibit_cookie_ = 0; |
miu
2015/05/15 18:43:31
nit: Either leave this in, or adjust the header fi
Kevin M
2015/05/15 18:55:25
Done.
|
bus_->ShutdownAndBlock(); |
bus_ = NULL; |