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 | |
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')
-rw-r--r-- | chromeos/dbus/mock_power_manager_client.h | 1 | ||||
-rw-r--r-- | chromeos/dbus/mock_session_manager_client.h | 1 | ||||
-rw-r--r-- | chromeos/dbus/power_manager_client.cc | 109 | ||||
-rw-r--r-- | chromeos/dbus/power_manager_client.h | 9 | ||||
-rw-r--r-- | chromeos/dbus/session_manager_client.cc | 52 | ||||
-rw-r--r-- | chromeos/dbus/session_manager_client.h | 21 |
6 files changed, 145 insertions, 48 deletions
diff --git a/chromeos/dbus/mock_power_manager_client.h b/chromeos/dbus/mock_power_manager_client.h index b9129cc..48c7c26 100644 --- a/chromeos/dbus/mock_power_manager_client.h +++ b/chromeos/dbus/mock_power_manager_client.h @@ -42,6 +42,7 @@ class MockPowerManagerClient : public PowerManagerClient { const PowerStateRequestIdCallback&)); MOCK_METHOD1(CancelPowerStateOverrides, void(uint32)); MOCK_METHOD1(SetIsProjecting, void(bool)); + MOCK_METHOD0(GetSuspendReadinessCallback, base::Closure(void)); }; } // namespace chromeos diff --git a/chromeos/dbus/mock_session_manager_client.h b/chromeos/dbus/mock_session_manager_client.h index 2841439..53b5d6d 100644 --- a/chromeos/dbus/mock_session_manager_client.h +++ b/chromeos/dbus/mock_session_manager_client.h @@ -31,7 +31,6 @@ class MockSessionManagerClient : public SessionManagerClient { MOCK_METHOD0(NotifyLockScreenShown, void(void)); MOCK_METHOD0(RequestUnlockScreen, void(void)); MOCK_METHOD0(NotifyLockScreenDismissed, void(void)); - MOCK_METHOD0(GetIsScreenLocked, bool(void)); MOCK_METHOD1(RetrieveDevicePolicy, void(const RetrievePolicyCallback&)); MOCK_METHOD1(RetrieveUserPolicy, void(const RetrievePolicyCallback&)); MOCK_METHOD2(RetrieveDeviceLocalAccountPolicy, 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() { diff --git a/chromeos/dbus/power_manager_client.h b/chromeos/dbus/power_manager_client.h index 1e23b7e..caf86b6 100644 --- a/chromeos/dbus/power_manager_client.h +++ b/chromeos/dbus/power_manager_client.h @@ -69,6 +69,11 @@ class CHROMEOS_EXPORT PowerManagerClient { // Called when the system is about to suspend. Suspend is deferred until // all observers' implementations of this method have finished running. + // + // If an observer wishes to asynchronously delay suspend, + // PowerManagerClient::GetSuspendReadinessCallback() may be called from + // within SuspendImminent(). The returned callback must be called once + // the observer is ready for suspend. virtual void SuspendImminent() {} // Called when the power button is pressed or released. @@ -179,6 +184,10 @@ class CHROMEOS_EXPORT PowerManagerClient { // video outputs attached. virtual void SetIsProjecting(bool is_projecting) = 0; + // Returns a callback that can be called by an observer to report + // readiness for suspend. See Observer::SuspendImminent(). + virtual base::Closure GetSuspendReadinessCallback() = 0; + // Creates the instance. static PowerManagerClient* Create(DBusClientImplementationType type, dbus::Bus* bus); diff --git a/chromeos/dbus/session_manager_client.cc b/chromeos/dbus/session_manager_client.cc index 452ddf3..fd84214 100644 --- a/chromeos/dbus/session_manager_client.cc +++ b/chromeos/dbus/session_manager_client.cc @@ -20,12 +20,13 @@ class SessionManagerClientImpl : public SessionManagerClient { public: explicit SessionManagerClientImpl(dbus::Bus* bus) : session_manager_proxy_(NULL), - screen_locked_(false), weak_ptr_factory_(this) { session_manager_proxy_ = bus->GetObjectProxy( login_manager::kSessionManagerServiceName, dbus::ObjectPath(login_manager::kSessionManagerServicePath)); + // Signals emitted on Chromium's interface. Many of these ought to be + // method calls instead. session_manager_proxy_->ConnectToSignal( chromium::kChromiumInterface, chromium::kOwnerKeySetSignal, @@ -33,7 +34,6 @@ class SessionManagerClientImpl : public SessionManagerClient { weak_ptr_factory_.GetWeakPtr()), base::Bind(&SessionManagerClientImpl::SignalConnected, weak_ptr_factory_.GetWeakPtr())); - session_manager_proxy_->ConnectToSignal( chromium::kChromiumInterface, chromium::kPropertyChangeCompleteSignal, @@ -41,7 +41,6 @@ class SessionManagerClientImpl : public SessionManagerClient { weak_ptr_factory_.GetWeakPtr()), base::Bind(&SessionManagerClientImpl::SignalConnected, weak_ptr_factory_.GetWeakPtr())); - session_manager_proxy_->ConnectToSignal( chromium::kChromiumInterface, chromium::kLockScreenSignal, @@ -49,7 +48,6 @@ class SessionManagerClientImpl : public SessionManagerClient { weak_ptr_factory_.GetWeakPtr()), base::Bind(&SessionManagerClientImpl::SignalConnected, weak_ptr_factory_.GetWeakPtr())); - session_manager_proxy_->ConnectToSignal( chromium::kChromiumInterface, chromium::kUnlockScreenSignal, @@ -57,7 +55,6 @@ class SessionManagerClientImpl : public SessionManagerClient { weak_ptr_factory_.GetWeakPtr()), base::Bind(&SessionManagerClientImpl::SignalConnected, weak_ptr_factory_.GetWeakPtr())); - session_manager_proxy_->ConnectToSignal( chromium::kChromiumInterface, chromium::kLivenessRequestedSignal, @@ -65,6 +62,22 @@ class SessionManagerClientImpl : public SessionManagerClient { weak_ptr_factory_.GetWeakPtr()), base::Bind(&SessionManagerClientImpl::SignalConnected, weak_ptr_factory_.GetWeakPtr())); + + // Signals emitted on the session manager's interface. + session_manager_proxy_->ConnectToSignal( + login_manager::kSessionManagerInterface, + login_manager::kScreenIsLockedSignal, + base::Bind(&SessionManagerClientImpl::ScreenIsLockedReceived, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&SessionManagerClientImpl::SignalConnected, + weak_ptr_factory_.GetWeakPtr())); + session_manager_proxy_->ConnectToSignal( + login_manager::kSessionManagerInterface, + login_manager::kScreenIsUnlockedSignal, + base::Bind(&SessionManagerClientImpl::ScreenIsUnlockedReceived, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&SessionManagerClientImpl::SignalConnected, + weak_ptr_factory_.GetWeakPtr())); } virtual ~SessionManagerClientImpl() { @@ -164,10 +177,6 @@ class SessionManagerClientImpl : public SessionManagerClient { login_manager::kSessionManagerHandleLockScreenDismissed); } - virtual bool GetIsScreenLocked() OVERRIDE { - return screen_locked_; - } - virtual void RetrieveDevicePolicy( const RetrievePolicyCallback& callback) OVERRIDE { CallRetrievePolicy(login_manager::kSessionManagerRetrievePolicy, @@ -369,12 +378,10 @@ class SessionManagerClientImpl : public SessionManagerClient { } void ScreenLockReceived(dbus::Signal* signal) { - screen_locked_ = true; FOR_EACH_OBSERVER(Observer, observers_, LockScreen()); } void ScreenUnlockReceived(dbus::Signal* signal) { - screen_locked_ = false; FOR_EACH_OBSERVER(Observer, observers_, UnlockScreen()); } @@ -383,6 +390,14 @@ class SessionManagerClientImpl : public SessionManagerClient { login_manager::kSessionManagerHandleLivenessConfirmed); } + void ScreenIsLockedReceived(dbus::Signal* signal) { + FOR_EACH_OBSERVER(Observer, observers_, ScreenIsLocked()); + } + + void ScreenIsUnlockedReceived(dbus::Signal* signal) { + FOR_EACH_OBSERVER(Observer, observers_, ScreenIsUnlocked()); + } + // Called when the object is connected to the signal. void SignalConnected(const std::string& interface_name, const std::string& signal_name, @@ -392,7 +407,6 @@ class SessionManagerClientImpl : public SessionManagerClient { dbus::ObjectProxy* session_manager_proxy_; ObserverList<Observer> observers_; - bool screen_locked_; // Note: This should remain the last member so it'll be destroyed and // invalidate its weak pointers before any other members are destroyed. @@ -405,7 +419,7 @@ class SessionManagerClientImpl : public SessionManagerClient { // which does nothing. class SessionManagerClientStubImpl : public SessionManagerClient { public: - SessionManagerClientStubImpl() : screen_locked_(false) {} + SessionManagerClientStubImpl() {} virtual ~SessionManagerClientStubImpl() {} // SessionManagerClient overrides. @@ -426,16 +440,17 @@ class SessionManagerClientStubImpl : public SessionManagerClient { virtual void StopSession() OVERRIDE {} virtual void StartDeviceWipe() OVERRIDE {} virtual void RequestLockScreen() OVERRIDE { - screen_locked_ = true; FOR_EACH_OBSERVER(Observer, observers_, LockScreen()); } - virtual void NotifyLockScreenShown() OVERRIDE {} + virtual void NotifyLockScreenShown() OVERRIDE { + FOR_EACH_OBSERVER(Observer, observers_, ScreenIsLocked()); + } virtual void RequestUnlockScreen() OVERRIDE { - screen_locked_ = false; FOR_EACH_OBSERVER(Observer, observers_, UnlockScreen()); } - virtual void NotifyLockScreenDismissed() OVERRIDE {} - virtual bool GetIsScreenLocked() OVERRIDE { return screen_locked_; } + virtual void NotifyLockScreenDismissed() OVERRIDE { + FOR_EACH_OBSERVER(Observer, observers_, ScreenIsUnlocked()); + } virtual void RetrieveDevicePolicy( const RetrievePolicyCallback& callback) OVERRIDE { callback.Run(device_policy_); @@ -468,7 +483,6 @@ class SessionManagerClientStubImpl : public SessionManagerClient { private: ObserverList<Observer> observers_; - bool screen_locked_; std::string device_policy_; std::string user_policy_; diff --git a/chromeos/dbus/session_manager_client.h b/chromeos/dbus/session_manager_client.h index d7b91d4..1aa9441 100644 --- a/chromeos/dbus/session_manager_client.h +++ b/chromeos/dbus/session_manager_client.h @@ -30,12 +30,24 @@ class CHROMEOS_EXPORT SessionManagerClient { // Called when the property change is complete. virtual void PropertyChangeComplete(bool success) {} - // Called when the screen is locked. + // Called when the session manager requests that the lock screen be + // displayed. NotifyLockScreenShown() is called after the lock screen + // is shown (the canonical "is the screen locked?" state lives in the + // session manager). virtual void LockScreen() {} - // Called when the screen is unlocked. + // Called when the session manager requests that the lock screen be + // dismissed. NotifyLockScreenDismissed() is called afterward. virtual void UnlockScreen() {} + // Called when the session manager announces that the screen has been locked + // successfully (i.e. after NotifyLockScreenShown() has been called). + virtual void ScreenIsLocked() {} + + // Called when the session manager announces that the screen has been + // unlocked successfully (i.e. after NotifyLockScreenDismissed() has + // been called). + virtual void ScreenIsUnlocked() {} }; // Adds and removes the observer. @@ -77,11 +89,6 @@ class CHROMEOS_EXPORT SessionManagerClient { // Notifies that the lock screen is dismissed. virtual void NotifyLockScreenDismissed() = 0; - // Returns whether or not the screen is locked. Implementation should cache - // this state so that it can return immediately. Useful for observers that - // need to know the current screen lock state when they are added. - virtual bool GetIsScreenLocked() = 0; - // Used for RetrieveDevicePolicy, RetrieveUserPolicy and // RetrieveDeviceLocalAccountPolicy. Takes a serialized protocol buffer as // string. Upon success, we will pass a protobuf to the callback. On |