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

Unified Diff: ash/system/chromeos/power/power_event_observer.cc

Issue 910393002: Disable rendering when suspending on chrome os (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Make PowerEventObserver getter cros-specific Created 5 years, 10 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: ash/system/chromeos/power/power_event_observer.cc
diff --git a/ash/system/chromeos/power/power_event_observer.cc b/ash/system/chromeos/power/power_event_observer.cc
index 65567f4ed0212ae97e70810a73ca2cb144506225..1510ddd69303de1040aab6c1179f4137fa1c7991 100644
--- a/ash/system/chromeos/power/power_event_observer.cc
+++ b/ash/system/chromeos/power/power_event_observer.cc
@@ -10,13 +10,37 @@
#include "ash/wm/power_button_controller.h"
#include "base/prefs/pref_service.h"
#include "chromeos/dbus/dbus_thread_manager.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/base/user_activity/user_activity_detector.h"
+#include "ui/compositor/compositor.h"
#include "ui/display/chromeos/display_configurator.h"
namespace ash {
+namespace {
+
+// Tells the compositor for each of the displays to finish all pending
+// rendering requests and block any new ones.
+void StopRenderingRequests() {
+ for (aura::Window* window : Shell::GetAllRootWindows()) {
+ ui::Compositor* compositor = window->GetHost()->compositor();
+ compositor->SetVisible(false);
+ compositor->FinishAllRendering();
+ }
+}
+
+// Tells the compositor for each of the displays to resume sending rendering
+// requests to the GPU.
+void ResumeRenderingRequests() {
+ for (aura::Window* window : Shell::GetAllRootWindows())
+ window->GetHost()->compositor()->SetVisible(true);
+}
+
+} // namespace
+
PowerEventObserver::PowerEventObserver()
- : screen_locked_(false) {
+ : screen_locked_(false), waiting_for_lock_screen_animations_(false) {
chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
AddObserver(this);
chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
@@ -30,6 +54,18 @@ PowerEventObserver::~PowerEventObserver() {
RemoveObserver(this);
}
+void PowerEventObserver::OnLockAnimationsComplete() {
+ VLOG(1) << "Screen locker animations have completed.";
+ waiting_for_lock_screen_animations_ = false;
+
+ if (!screen_lock_callback_.is_null()) {
+ StopRenderingRequests();
+
+ screen_lock_callback_.Run();
+ screen_lock_callback_.Reset();
+ }
+}
+
void PowerEventObserver::BrightnessChanged(int level, bool user_initiated) {
Shell::GetInstance()->power_button_controller()->OnScreenBrightnessChanged(
static_cast<double>(level));
@@ -39,8 +75,19 @@ void PowerEventObserver::SuspendImminent() {
Shell* shell = Shell::GetInstance();
SessionStateDelegate* delegate = shell->session_state_delegate();
- // If the lock-before-suspending pref is set, get a callback to block
- // suspend and ask the session manager to lock the screen.
+ // This class is responsible for disabling all rendering requests at suspend
+ // time and then enabling them at resume time. When the
+ // lock-before-suspending pref is not set this is easy to do since
+ // StopRenderingRequests() is just called directly from this function. If the
+ // lock-before-suspending pref _is_ set, then the suspend needs to be delayed
+ // until the lock screen is fully visible. While it is sufficient from a
+ // security perspective to block only until the lock screen is ready, which
+ // guarantees that the contents of the user's screen are no longer visible,
+ // this leads to poor UX on the first resume since neither the user pod nor
+ // the header bar will be visible for a few hundred milliseconds until the GPU
+ // process starts rendering again. To deal with this, the suspend is delayed
+ // until all the lock screen animations have completed and the suspend request
+ // is unblocked from OnLockAnimationsComplete().
if (!screen_locked_ && delegate->ShouldLockScreenBeforeSuspending() &&
delegate->CanLockScreen()) {
screen_lock_callback_ = chromeos::DBusThreadManager::Get()->
@@ -48,6 +95,21 @@ void PowerEventObserver::SuspendImminent() {
VLOG(1) << "Requesting screen lock from PowerEventObserver";
chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
RequestLockScreen();
+ } else if (waiting_for_lock_screen_animations_) {
+ // The lock-before-suspending pref has been set and the lock screen is ready
+ // but the animations have not completed yet. This can happen if a suspend
+ // request is canceled after the lock screen is ready but before the
+ // animations have completed and then another suspend request is immediately
+ // started. In practice, it is highly unlikely that this will ever happen
+ // but it's better to be safe since the cost of not dealing with it properly
+ // is a memory leak in the GPU and weird artifacts on the screen.
+ screen_lock_callback_ = chromeos::DBusThreadManager::Get()
+ ->GetPowerManagerClient()
+ ->GetSuspendReadinessCallback();
+ } else {
+ // The lock-before-suspending pref is not set or the screen has already been
+ // locked and the animations have completed. Rendering can be stopped now.
+ StopRenderingRequests();
}
ui::UserActivityDetector::Get()->OnDisplayPowerChanging();
@@ -57,19 +119,24 @@ void PowerEventObserver::SuspendImminent() {
void PowerEventObserver::SuspendDone(const base::TimeDelta& sleep_duration) {
Shell::GetInstance()->display_configurator()->ResumeDisplays();
Shell::GetInstance()->system_tray_notifier()->NotifyRefreshClock();
+
+ // If the suspend request was being blocked while waiting for the lock
+ // animation to complete, clear the blocker since the suspend has already
+ // completed. This prevents rendering requests from being blocked after a
+ // resume if the lock screen took too long to show.
+ screen_lock_callback_.Reset();
+
+ ResumeRenderingRequests();
}
void PowerEventObserver::ScreenIsLocked() {
screen_locked_ = true;
+ waiting_for_lock_screen_animations_ = true;
- // Stop blocking suspend after the screen is locked.
+ // The screen is now locked but the pending suspend, if any, will be blocked
+ // until all the animations have completed.
if (!screen_lock_callback_.is_null()) {
VLOG(1) << "Screen locked due to suspend";
- // Run the callback asynchronously. ScreenIsLocked() is currently
- // called asynchronously after RequestLockScreen(), but this guards
- // against it being made synchronous later.
- base::MessageLoop::current()->PostTask(FROM_HERE, screen_lock_callback_);
- screen_lock_callback_.Reset();
} else {
VLOG(1) << "Screen locked without suspend";
}
« no previous file with comments | « ash/system/chromeos/power/power_event_observer.h ('k') | ash/system/chromeos/power/power_event_observer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698