Commit 7e1b5a3c authored by derat's avatar derat Committed by Commit bot

chromeos: Fix renderer-freezing race during aborted suspend.

Fix a (long-standing?) race where
chromeos::PowerManagerClient could notify RendererFreezer
that a suspend attempt was imminent *after* already telling
it that the attempt was done.

Also make PowerManagerClient not notify powerd about regular
or dark suspend readiness after it's already seen a
SuspendDone signal.

Add a bunch of unit tests exercising this code, too, and
rework the comments on some previously-added tests.

BUG=646912

Review-Url: https://codereview.chromium.org/2340153002
Cr-Commit-Position: refs/heads/master@{#418887}
parent e0dd83fd
...@@ -543,6 +543,7 @@ class PowerManagerClientImpl : public PowerManagerClient { ...@@ -543,6 +543,7 @@ class PowerManagerClientImpl : public PowerManagerClient {
suspend_is_pending_ = true; suspend_is_pending_ = true;
suspending_from_dark_resume_ = in_dark_resume; suspending_from_dark_resume_ = in_dark_resume;
num_pending_suspend_readiness_callbacks_ = 0; num_pending_suspend_readiness_callbacks_ = 0;
if (suspending_from_dark_resume_) if (suspending_from_dark_resume_)
FOR_EACH_OBSERVER(Observer, observers_, DarkSuspendImminent()); FOR_EACH_OBSERVER(Observer, observers_, DarkSuspendImminent());
else else
...@@ -567,9 +568,23 @@ class PowerManagerClientImpl : public PowerManagerClient { ...@@ -567,9 +568,23 @@ class PowerManagerClientImpl : public PowerManagerClient {
<< " suspend_id=" << proto.suspend_id() << " suspend_id=" << proto.suspend_id()
<< " duration=" << duration.InSeconds() << " sec"; << " duration=" << duration.InSeconds() << " sec";
if (render_process_manager_delegate_) // RenderProcessManagerDelegate is only notified that suspend is imminent
// when readiness is being reported to powerd. If the suspend attempt was
// cancelled before then, we shouldn't notify the delegate about completion.
const bool cancelled_while_regular_suspend_pending =
suspend_is_pending_ && !suspending_from_dark_resume_;
if (render_process_manager_delegate_ &&
!cancelled_while_regular_suspend_pending)
render_process_manager_delegate_->SuspendDone(); render_process_manager_delegate_->SuspendDone();
// powerd always pairs each SuspendImminent signal with SuspendDone before
// starting the next suspend attempt, so we should no longer report
// readiness for any in-progress suspend attempts.
pending_suspend_id_ = -1;
suspend_is_pending_ = false;
suspending_from_dark_resume_ = false;
num_pending_suspend_readiness_callbacks_ = 0;
FOR_EACH_OBSERVER( FOR_EACH_OBSERVER(
PowerManagerClient::Observer, observers_, SuspendDone(duration)); PowerManagerClient::Observer, observers_, SuspendDone(duration));
base::PowerMonitorDeviceSource::HandleSystemResumed(); base::PowerMonitorDeviceSource::HandleSystemResumed();
...@@ -711,7 +726,9 @@ class PowerManagerClientImpl : public PowerManagerClient { ...@@ -711,7 +726,9 @@ class PowerManagerClientImpl : public PowerManagerClient {
// Reports suspend readiness to powerd if no observers are still holding // Reports suspend readiness to powerd if no observers are still holding
// suspend readiness callbacks. // suspend readiness callbacks.
void MaybeReportSuspendReadiness() { void MaybeReportSuspendReadiness() {
if (!suspend_is_pending_ || num_pending_suspend_readiness_callbacks_ > 0) CHECK(suspend_is_pending_);
if (num_pending_suspend_readiness_callbacks_ > 0)
return; return;
std::string method_name; std::string method_name;
...@@ -756,16 +773,16 @@ class PowerManagerClientImpl : public PowerManagerClient { ...@@ -756,16 +773,16 @@ class PowerManagerClientImpl : public PowerManagerClient {
dbus::ObjectProxy* power_manager_proxy_; dbus::ObjectProxy* power_manager_proxy_;
base::ObserverList<Observer> observers_; base::ObserverList<Observer> observers_;
// The delay_id_ obtained from the RegisterSuspendDelay request. // The delay ID obtained from the RegisterSuspendDelay request.
int32_t suspend_delay_id_; int32_t suspend_delay_id_;
bool has_suspend_delay_id_; bool has_suspend_delay_id_;
// The delay_id_ obtained from the RegisterDarkSuspendDelay request. // The delay ID obtained from the RegisterDarkSuspendDelay request.
int32_t dark_suspend_delay_id_; int32_t dark_suspend_delay_id_;
bool has_dark_suspend_delay_id_; bool has_dark_suspend_delay_id_;
// powerd-supplied ID corresponding to an imminent suspend attempt that is // powerd-supplied ID corresponding to an imminent (either regular or dark)
// currently being delayed. // suspend attempt that is currently being delayed.
int32_t pending_suspend_id_; int32_t pending_suspend_id_;
bool suspend_is_pending_; bool suspend_is_pending_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment