diff options
author | derat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-29 17:05:14 +0000 |
---|---|---|
committer | derat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-29 17:05:14 +0000 |
commit | 77894b4bd8771c77112a41e19d95094c09853229 (patch) | |
tree | aecc02d1b91439d2a8cb29d5e987ce3704ca240c /chromeos/dbus/power_manager_client.cc | |
parent | 2ef8a345d3a96ede613c10214b590fd9bc205b86 (diff) | |
download | chromium_src-77894b4bd8771c77112a41e19d95094c09853229.zip chromium_src-77894b4bd8771c77112a41e19d95094c09853229.tar.gz chromium_src-77894b4bd8771c77112a41e19d95094c09853229.tar.bz2 |
chromeos: Support delaying suspend asynchronously.
This adds PowerManagerClient::GetSuspendReadinessCallback(),
which PowerManagerClient::Observer implementations can call
from within SuspendImminent(). The method returns a Closure
that the observer can call after doing asynchronous work to
report that it's ready for the system to be suspended.
It also makes SessionManagerClient listen for ScreenIsLocked
and ScreenIsUnlocked signals and removes an unused
GetIsScreenLocked() method.
BUG=171960,128798
Review URL: https://codereview.chromium.org/12095006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@179350 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos/dbus/power_manager_client.cc')
-rw-r--r-- | chromeos/dbus/power_manager_client.cc | 109 |
1 files changed, 88 insertions, 21 deletions
diff --git a/chromeos/dbus/power_manager_client.cc b/chromeos/dbus/power_manager_client.cc index 38ad0ae..0dfa12b 100644 --- a/chromeos/dbus/power_manager_client.cc +++ b/chromeos/dbus/power_manager_client.cc @@ -12,6 +12,7 @@ #include "base/memory/scoped_ptr.h" #include "base/observer_list.h" #include "base/stringprintf.h" +#include "base/threading/platform_thread.h" #include "base/time.h" #include "base/timer.h" #include "chromeos/dbus/power_manager/input_event.pb.h" @@ -33,9 +34,13 @@ const int kSuspendDelayTimeoutMs = 5000; class PowerManagerClientImpl : public PowerManagerClient { public: explicit PowerManagerClientImpl(dbus::Bus* bus) - : power_manager_proxy_(NULL), + : origin_thread_id_(base::PlatformThread::CurrentId()), + power_manager_proxy_(NULL), suspend_delay_id_(-1), has_suspend_delay_id_(false), + pending_suspend_id_(-1), + suspend_is_pending_(false), + num_pending_suspend_readiness_callbacks_(0), weak_ptr_factory_(this) { power_manager_proxy_ = bus->GetObjectProxy( power_manager::kPowerManagerServiceName, @@ -340,7 +345,20 @@ class PowerManagerClientImpl : public PowerManagerClient { dbus::ObjectProxy::EmptyResponseCallback()); } + virtual base::Closure GetSuspendReadinessCallback() OVERRIDE { + DCHECK(OnOriginThread()); + DCHECK(suspend_is_pending_); + num_pending_suspend_readiness_callbacks_++; + return base::Bind(&PowerManagerClientImpl::HandleObserverSuspendReadiness, + weak_ptr_factory_.GetWeakPtr(), pending_suspend_id_); + } + private: + // Returns true if the current thread is the origin thread. + bool OnOriginThread() { + return base::PlatformThread::CurrentId() == origin_thread_id_; + } + // Called when a dbus signal is initially connected. void SignalConnected(const std::string& interface_name, const std::string& signal_name, @@ -554,28 +572,19 @@ class PowerManagerClientImpl : public PowerManagerClient { << power_manager::kSuspendImminentSignal << " signal"; return; } - int32 suspend_id = protobuf_imminent.suspend_id(); - - FOR_EACH_OBSERVER(Observer, observers_, SuspendImminent()); - - dbus::MethodCall method_call( - power_manager::kPowerManagerInterface, - power_manager::kHandleSuspendReadinessMethod); - dbus::MessageWriter writer(&method_call); - - power_manager::SuspendReadinessInfo protobuf_request; - protobuf_request.set_delay_id(suspend_delay_id_); - protobuf_request.set_suspend_id(suspend_id); - if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) { - LOG(ERROR) << "Error constructing message for " - << power_manager::kHandleSuspendReadinessMethod; - return; + if (suspend_is_pending_) { + LOG(WARNING) << "Got " << power_manager::kSuspendImminentSignal + << " signal about pending suspend attempt " + << protobuf_imminent.suspend_id() << " while still waiting " + << "on attempt " << pending_suspend_id_; } - power_manager_proxy_->CallMethod( - &method_call, - dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, - dbus::ObjectProxy::EmptyResponseCallback()); + + pending_suspend_id_ = protobuf_imminent.suspend_id(); + suspend_is_pending_ = true; + num_pending_suspend_readiness_callbacks_ = 0; + FOR_EACH_OBSERVER(Observer, observers_, SuspendImminent()); + MaybeReportSuspendReadiness(); } void InputEventReceived(dbus::Signal* signal) { @@ -636,6 +645,51 @@ class PowerManagerClientImpl : public PowerManagerClient { } } + // Records the fact that an observer has finished doing asynchronous work + // that was blocking a pending suspend attempt and possibly reports + // suspend readiness to powerd. Called by callbacks returned via + // GetSuspendReadinessCallback(). + void HandleObserverSuspendReadiness(int32 suspend_id) { + DCHECK(OnOriginThread()); + if (!suspend_is_pending_ || suspend_id != pending_suspend_id_) + return; + + num_pending_suspend_readiness_callbacks_--; + MaybeReportSuspendReadiness(); + } + + // Reports suspend readiness to powerd if no observers are still holding + // suspend readiness callbacks. + void MaybeReportSuspendReadiness() { + if (!suspend_is_pending_ || num_pending_suspend_readiness_callbacks_ > 0) + return; + + dbus::MethodCall method_call( + power_manager::kPowerManagerInterface, + power_manager::kHandleSuspendReadinessMethod); + dbus::MessageWriter writer(&method_call); + + power_manager::SuspendReadinessInfo protobuf_request; + protobuf_request.set_delay_id(suspend_delay_id_); + protobuf_request.set_suspend_id(pending_suspend_id_); + + pending_suspend_id_ = -1; + suspend_is_pending_ = false; + + if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) { + LOG(ERROR) << "Error constructing message for " + << power_manager::kHandleSuspendReadinessMethod; + return; + } + power_manager_proxy_->CallMethod( + &method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + dbus::ObjectProxy::EmptyResponseCallback()); + } + + // Origin thread (i.e. the UI thread in production). + base::PlatformThreadId origin_thread_id_; + dbus::ObjectProxy* power_manager_proxy_; ObserverList<Observer> observers_; @@ -643,6 +697,16 @@ class PowerManagerClientImpl : public PowerManagerClient { int32 suspend_delay_id_; bool has_suspend_delay_id_; + // powerd-supplied ID corresponding to an imminent suspend attempt that is + // currently being delayed. + int32 pending_suspend_id_; + bool suspend_is_pending_; + + // Number of callbacks that have been returned by + // GetSuspendReadinessCallback() during the currently-pending suspend + // attempt but have not yet been called. + int num_pending_suspend_readiness_callbacks_; + // Wall time from the latest signal telling us that the system was about to // suspend to memory. base::Time last_suspend_wall_time_; @@ -756,6 +820,9 @@ class PowerManagerClientStubImpl : public PowerManagerClient { } virtual void CancelPowerStateOverrides(uint32 request_id) OVERRIDE {} virtual void SetIsProjecting(bool is_projecting) OVERRIDE {} + virtual base::Closure GetSuspendReadinessCallback() OVERRIDE { + return base::Closure(); + } private: void Update() { |