1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ash/wm/lock_state_controller.h"
6 
7 #include <algorithm>
8 #include <string>
9 #include <utility>
10 
11 #include "ash/accessibility/accessibility_controller_impl.h"
12 #include "ash/cancel_mode.h"
13 #include "ash/public/cpp/shell_window_ids.h"
14 #include "ash/public/cpp/shutdown_controller.h"
15 #include "ash/root_window_controller.h"
16 #include "ash/session/session_controller_impl.h"
17 #include "ash/shell.h"
18 #include "ash/shell_delegate.h"
19 #include "ash/shutdown_reason.h"
20 #include "ash/wallpaper/wallpaper_controller_impl.h"
21 #include "ash/wallpaper/wallpaper_widget_controller.h"
22 #include "ash/wm/session_state_animator.h"
23 #include "ash/wm/session_state_animator_impl.h"
24 #include "base/bind.h"
25 #include "base/callback_helpers.h"
26 #include "base/command_line.h"
27 #include "base/location.h"
28 #include "base/logging.h"
29 #include "base/metrics/histogram_macros.h"
30 #include "base/metrics/user_metrics.h"
31 #include "base/strings/string_util.h"
32 #include "base/system/sys_info.h"
33 #include "base/timer/timer.h"
34 #include "ui/aura/window_tree_host.h"
35 #include "ui/views/controls/menu/menu_controller.h"
36 #include "ui/wm/core/compound_event_filter.h"
37 #include "ui/wm/core/cursor_manager.h"
38 
39 #define UMA_HISTOGRAM_LOCK_TIMES(name, sample)                     \
40   UMA_HISTOGRAM_CUSTOM_TIMES(name, sample,                         \
41                              base::TimeDelta::FromMilliseconds(1), \
42                              base::TimeDelta::FromSeconds(50), 100)
43 
44 namespace ash {
45 
46 namespace {
47 
48 // ASan/TSan/MSan instrument each memory access. This may slow the execution
49 // down significantly.
50 #if defined(MEMORY_SANITIZER)
51 // For MSan the slowdown depends heavily on the value of msan_track_origins GYP
52 // flag. The multiplier below corresponds to msan_track_origins=1.
53 constexpr int kTimeoutMultiplier = 6;
54 #elif defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER)
55 constexpr int kTimeoutMultiplier = 2;
56 #else
57 constexpr int kTimeoutMultiplier = 1;
58 #endif
59 
60 constexpr int kMaxShutdownSoundDurationMs = 1500;
61 
62 // Amount of time to wait for our lock requests to be honored before giving up.
63 constexpr base::TimeDelta kLockFailTimeout =
64     base::TimeDelta::FromSeconds(8 * kTimeoutMultiplier);
65 
66 // Additional time to wait after starting the fast-close shutdown animation
67 // before actually requesting shutdown, to give the animation time to finish.
68 constexpr base::TimeDelta kShutdownRequestDelay =
69     base::TimeDelta::FromMilliseconds(50);
70 
71 }  // namespace
72 
73 // static
74 const int LockStateController::kPreLockContainersMask =
75     SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS |
76     SessionStateAnimator::SHELF;
77 
LockStateController(ShutdownController * shutdown_controller)78 LockStateController::LockStateController(
79     ShutdownController* shutdown_controller)
80     : animator_(new SessionStateAnimatorImpl()),
81       shutdown_controller_(shutdown_controller),
82       scoped_session_observer_(this) {
83   DCHECK(shutdown_controller_);
84   Shell::GetPrimaryRootWindow()->GetHost()->AddObserver(this);
85 }
86 
~LockStateController()87 LockStateController::~LockStateController() {
88   Shell::GetPrimaryRootWindow()->GetHost()->RemoveObserver(this);
89 }
90 
AddObserver(LockStateObserver * observer)91 void LockStateController::AddObserver(LockStateObserver* observer) {
92   observers_.AddObserver(observer);
93 }
94 
RemoveObserver(LockStateObserver * observer)95 void LockStateController::RemoveObserver(LockStateObserver* observer) {
96   observers_.RemoveObserver(observer);
97 }
98 
StartLockAnimation()99 void LockStateController::StartLockAnimation() {
100   if (animating_lock_)
101     return;
102 
103   animating_lock_ = true;
104   StoreUnlockedProperties();
105   VLOG(1) << "StartLockAnimation";
106   PreLockAnimation(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, true);
107   DispatchCancelMode();
108   OnLockStateEvent(LockStateObserver::EVENT_PRELOCK_ANIMATION_STARTED);
109 }
110 
StartShutdownAnimation(ShutdownReason reason)111 void LockStateController::StartShutdownAnimation(ShutdownReason reason) {
112   shutdown_reason_ = reason;
113 
114   Shell* shell = Shell::Get();
115   // Hide cursor, but let it reappear if the mouse moves.
116   if (shell->cursor_manager())
117     shell->cursor_manager()->HideCursor();
118 
119   animator_->StartAnimation(
120       SessionStateAnimator::ROOT_CONTAINER,
121       SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
122       SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
123   StartPreShutdownAnimationTimer();
124 }
125 
LockWithoutAnimation()126 void LockStateController::LockWithoutAnimation() {
127   if (animating_lock_)
128     return;
129   animating_lock_ = true;
130   post_lock_immediate_animation_ = true;
131   animator_->StartAnimation(kPreLockContainersMask,
132                             SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
133                             SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
134   OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_STARTED);
135   Shell::Get()->session_controller()->LockScreen();
136 }
137 
LockRequested()138 bool LockStateController::LockRequested() {
139   return lock_fail_timer_.IsRunning();
140 }
141 
ShutdownRequested()142 bool LockStateController::ShutdownRequested() {
143   return shutting_down_;
144 }
145 
CancelLockAnimation()146 void LockStateController::CancelLockAnimation() {
147   VLOG(1) << "CancelLockAnimation";
148   animating_lock_ = false;
149   Shell::Get()->wallpaper_controller()->RestoreWallpaperBlurForLockState(
150       saved_blur_);
151   base::OnceClosure next_animation_starter =
152       base::BindOnce(&LockStateController::LockAnimationCancelled,
153                      weak_ptr_factory_.GetWeakPtr());
154   SessionStateAnimator::AnimationSequence* animation_sequence =
155       animator_->BeginAnimationSequence(std::move(next_animation_starter));
156 
157   animation_sequence->StartAnimation(
158       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
159       SessionStateAnimator::ANIMATION_UNDO_LIFT,
160       SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS);
161   animation_sequence->StartAnimation(
162       SessionStateAnimator::SHELF, SessionStateAnimator::ANIMATION_FADE_IN,
163       SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS);
164   AnimateWallpaperHidingIfNecessary(
165       SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
166       animation_sequence);
167 
168   animation_sequence->EndSequence();
169 }
170 
CanCancelShutdownAnimation()171 bool LockStateController::CanCancelShutdownAnimation() {
172   return pre_shutdown_timer_.IsRunning();
173 }
174 
CancelShutdownAnimation()175 void LockStateController::CancelShutdownAnimation() {
176   if (!CanCancelShutdownAnimation())
177     return;
178 
179   animator_->StartAnimation(
180       SessionStateAnimator::ROOT_CONTAINER,
181       SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS,
182       SessionStateAnimator::ANIMATION_SPEED_REVERT_SHUTDOWN);
183   pre_shutdown_timer_.Stop();
184 }
185 
RequestShutdown(ShutdownReason reason)186 void LockStateController::RequestShutdown(ShutdownReason reason) {
187   if (shutting_down_)
188     return;
189 
190   shutting_down_ = true;
191   shutdown_reason_ = reason;
192 
193   ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
194   cursor_manager->HideCursor();
195   cursor_manager->LockCursor();
196 
197   animator_->StartAnimation(
198       SessionStateAnimator::ROOT_CONTAINER,
199       SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
200       SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
201   StartRealShutdownTimer(true);
202 }
203 
OnLockScreenHide(base::OnceClosure callback)204 void LockStateController::OnLockScreenHide(base::OnceClosure callback) {
205   StartUnlockAnimationBeforeUIDestroyed(std::move(callback));
206 }
207 
SetLockScreenDisplayedCallback(base::OnceClosure callback)208 void LockStateController::SetLockScreenDisplayedCallback(
209     base::OnceClosure callback) {
210   DCHECK(lock_screen_displayed_callback_.is_null());
211   if (system_is_locked_ && !animating_lock_)
212     std::move(callback).Run();
213   else
214     lock_screen_displayed_callback_ = std::move(callback);
215 }
216 
OnHostCloseRequested(aura::WindowTreeHost * host)217 void LockStateController::OnHostCloseRequested(aura::WindowTreeHost* host) {
218   Shell::Get()->session_controller()->RequestSignOut();
219 }
220 
OnChromeTerminating()221 void LockStateController::OnChromeTerminating() {
222   // If we hear that Chrome is exiting but didn't request it ourselves, all we
223   // can really hope for is that we'll have time to clear the screen.
224   // This is also the case when the user signs off.
225   if (!shutting_down_) {
226     shutting_down_ = true;
227     ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
228     cursor_manager->HideCursor();
229     cursor_manager->LockCursor();
230     animator_->StartAnimation(SessionStateAnimator::kAllNonRootContainersMask,
231                               SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
232                               SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
233   }
234 }
235 
OnLockStateChanged(bool locked)236 void LockStateController::OnLockStateChanged(bool locked) {
237   DCHECK((lock_fail_timer_.IsRunning() && lock_duration_timer_ != nullptr) ||
238          (!lock_fail_timer_.IsRunning() && lock_duration_timer_ == nullptr));
239   VLOG(1) << "OnLockStateChanged called with locked: " << locked
240           << ", shutting_down_: " << shutting_down_
241           << ", system_is_locked_: " << system_is_locked_
242           << ", lock_fail_timer_.IsRunning(): " << lock_fail_timer_.IsRunning();
243 
244   if (shutting_down_ || (system_is_locked_ == locked))
245     return;
246 
247   system_is_locked_ = locked;
248 
249   if (locked) {
250     StartPostLockAnimation();
251 
252     lock_fail_timer_.Stop();
253 
254     if (lock_duration_timer_) {
255       UMA_HISTOGRAM_LOCK_TIMES("Ash.WindowManager.Lock.Success",
256                                lock_duration_timer_->Elapsed());
257       lock_duration_timer_.reset();
258     }
259   } else {
260     StartUnlockAnimationAfterUIDestroyed();
261   }
262 }
263 
OnLockFailTimeout()264 void LockStateController::OnLockFailTimeout() {
265   UMA_HISTOGRAM_LOCK_TIMES("Ash.WindowManager.Lock.Timeout",
266                            lock_duration_timer_->Elapsed());
267   lock_duration_timer_.reset();
268   DCHECK(!system_is_locked_);
269 
270   LOG(FATAL) << "Screen lock took too long; crashing intentionally";
271 }
272 
StartPreShutdownAnimationTimer()273 void LockStateController::StartPreShutdownAnimationTimer() {
274   pre_shutdown_timer_.Stop();
275   pre_shutdown_timer_.Start(
276       FROM_HERE,
277       animator_->GetDuration(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN),
278       this, &LockStateController::OnPreShutdownAnimationTimeout);
279 }
280 
OnPreShutdownAnimationTimeout()281 void LockStateController::OnPreShutdownAnimationTimeout() {
282   VLOG(1) << "OnPreShutdownAnimationTimeout";
283   shutting_down_ = true;
284 
285   Shell* shell = Shell::Get();
286   if (shell->cursor_manager())
287     shell->cursor_manager()->HideCursor();
288 
289   StartRealShutdownTimer(false);
290 }
291 
StartRealShutdownTimer(bool with_animation_time)292 void LockStateController::StartRealShutdownTimer(bool with_animation_time) {
293   base::TimeDelta duration = kShutdownRequestDelay;
294   if (with_animation_time) {
295     duration +=
296         animator_->GetDuration(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
297   }
298   // Play and get shutdown sound duration from chrome in |sound_duration|. And
299   // start real shutdown after a delay of |duration|.
300   base::TimeDelta sound_duration =
301       std::min(Shell::Get()->accessibility_controller()->PlayShutdownSound(),
302                base::TimeDelta::FromMilliseconds(kMaxShutdownSoundDurationMs));
303   duration = std::max(duration, sound_duration);
304   real_shutdown_timer_.Start(FROM_HERE, duration, this,
305                              &LockStateController::OnRealPowerTimeout);
306 }
307 
OnRealPowerTimeout()308 void LockStateController::OnRealPowerTimeout() {
309   VLOG(1) << "OnRealPowerTimeout";
310   DCHECK(shutting_down_);
311   DCHECK(shutdown_reason_);
312   // Shut down or reboot based on device policy.
313   shutdown_controller_->ShutDownOrReboot(*shutdown_reason_);
314 }
315 
PreLockAnimation(SessionStateAnimator::AnimationSpeed speed,bool request_lock_on_completion)316 void LockStateController::PreLockAnimation(
317     SessionStateAnimator::AnimationSpeed speed,
318     bool request_lock_on_completion) {
319   saved_blur_ = Shell::GetPrimaryRootWindowController()
320                     ->wallpaper_widget_controller()
321                     ->GetWallpaperBlur();
322   Shell::Get()->wallpaper_controller()->UpdateWallpaperBlurForLockState(true);
323   base::OnceClosure next_animation_starter = base::BindOnce(
324       &LockStateController::PreLockAnimationFinished,
325       weak_ptr_factory_.GetWeakPtr(), request_lock_on_completion);
326   SessionStateAnimator::AnimationSequence* animation_sequence =
327       animator_->BeginAnimationSequence(std::move(next_animation_starter));
328 
329   animation_sequence->StartAnimation(
330       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
331       SessionStateAnimator::ANIMATION_LIFT, speed);
332   animation_sequence->StartAnimation(SessionStateAnimator::SHELF,
333                                      SessionStateAnimator::ANIMATION_FADE_OUT,
334                                      speed);
335   // Hide the screen locker containers so we can raise them later.
336   animator_->StartAnimation(SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
337                             SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
338                             SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
339   AnimateWallpaperAppearanceIfNecessary(speed, animation_sequence);
340 
341   animation_sequence->EndSequence();
342 }
343 
StartPostLockAnimation()344 void LockStateController::StartPostLockAnimation() {
345   VLOG(1) << "StartPostLockAnimation";
346   base::OnceClosure next_animation_starter =
347       base::BindOnce(&LockStateController::PostLockAnimationFinished,
348                      weak_ptr_factory_.GetWeakPtr());
349   SessionStateAnimator::AnimationSequence* animation_sequence =
350       animator_->BeginAnimationSequence(std::move(next_animation_starter));
351 
352   animation_sequence->StartAnimation(
353       SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
354       SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN,
355       post_lock_immediate_animation_
356           ? SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE
357           : SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
358   // Show the lock screen shelf. This is a no-op if views-based shelf is
359   // disabled, since shelf is in NonLockScreenContainersContainer.
360   animation_sequence->StartAnimation(
361       SessionStateAnimator::SHELF, SessionStateAnimator::ANIMATION_FADE_IN,
362       post_lock_immediate_animation_
363           ? SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE
364           : SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
365   animation_sequence->EndSequence();
366 }
367 
StartUnlockAnimationBeforeUIDestroyed(base::OnceClosure callback)368 void LockStateController::StartUnlockAnimationBeforeUIDestroyed(
369     base::OnceClosure callback) {
370   VLOG(1) << "StartUnlockAnimationBeforeUIDestroyed";
371   // Hide the lock screen shelf. This is a no-op if views-based shelf is
372   // disabled, since shelf is in NonLockScreenContainersContainer.
373   animator_->StartAnimation(SessionStateAnimator::SHELF,
374                             SessionStateAnimator::ANIMATION_FADE_OUT,
375                             SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
376   animator_->StartAnimationWithCallback(
377       SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
378       SessionStateAnimator::ANIMATION_LIFT,
379       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, std::move(callback));
380 }
381 
StartUnlockAnimationAfterUIDestroyed()382 void LockStateController::StartUnlockAnimationAfterUIDestroyed() {
383   VLOG(1) << "StartUnlockAnimationAfterUIDestroyed";
384   base::OnceClosure next_animation_starter = base::BindOnce(
385       &LockStateController::UnlockAnimationAfterUIDestroyedFinished,
386       weak_ptr_factory_.GetWeakPtr());
387   SessionStateAnimator::AnimationSequence* animation_sequence =
388       animator_->BeginAnimationSequence(std::move(next_animation_starter));
389 
390   animation_sequence->StartAnimation(
391       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
392       SessionStateAnimator::ANIMATION_DROP,
393       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
394   animation_sequence->StartAnimation(
395       SessionStateAnimator::SHELF, SessionStateAnimator::ANIMATION_FADE_IN,
396       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
397   AnimateWallpaperHidingIfNecessary(
398       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, animation_sequence);
399   animation_sequence->EndSequence();
400 }
401 
LockAnimationCancelled()402 void LockStateController::LockAnimationCancelled() {
403   RestoreUnlockedProperties();
404 }
405 
PreLockAnimationFinished(bool request_lock)406 void LockStateController::PreLockAnimationFinished(bool request_lock) {
407   VLOG(1) << "PreLockAnimationFinished";
408 
409   // Don't do anything (including starting the lock-fail timer) if the screen
410   // was already locked while the animation was going.
411   if (system_is_locked_) {
412     DCHECK(!request_lock) << "Got request to lock already-locked system "
413                           << "at completion of pre-lock animation";
414     return;
415   }
416 
417   if (request_lock) {
418     base::RecordAction(base::UserMetricsAction("Accel_LockScreen_LockButton"));
419     Shell::Get()->session_controller()->LockScreen();
420   }
421 
422   lock_fail_timer_.Start(FROM_HERE, kLockFailTimeout, this,
423                          &LockStateController::OnLockFailTimeout);
424 
425   lock_duration_timer_.reset(new base::ElapsedTimer());
426 }
427 
PostLockAnimationFinished()428 void LockStateController::PostLockAnimationFinished() {
429   animating_lock_ = false;
430   post_lock_immediate_animation_ = false;
431   VLOG(1) << "PostLockAnimationFinished";
432   OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED);
433   if (!lock_screen_displayed_callback_.is_null())
434     std::move(lock_screen_displayed_callback_).Run();
435 
436   CHECK(!views::MenuController::GetActiveInstance());
437 }
438 
UnlockAnimationAfterUIDestroyedFinished()439 void LockStateController::UnlockAnimationAfterUIDestroyedFinished() {
440   Shell::Get()->wallpaper_controller()->UpdateWallpaperBlurForLockState(false);
441   RestoreUnlockedProperties();
442 }
443 
StoreUnlockedProperties()444 void LockStateController::StoreUnlockedProperties() {
445   if (!unlocked_properties_) {
446     unlocked_properties_.reset(new UnlockedStateProperties());
447     unlocked_properties_->wallpaper_is_hidden = animator_->IsWallpaperHidden();
448   }
449   if (unlocked_properties_->wallpaper_is_hidden) {
450     // Hide wallpaper so that it can be animated later.
451     animator_->StartAnimation(SessionStateAnimator::WALLPAPER,
452                               SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
453                               SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
454     animator_->ShowWallpaper();
455   }
456 }
457 
RestoreUnlockedProperties()458 void LockStateController::RestoreUnlockedProperties() {
459   if (!unlocked_properties_)
460     return;
461   if (unlocked_properties_->wallpaper_is_hidden) {
462     animator_->HideWallpaper();
463     // Restore wallpaper visibility.
464     animator_->StartAnimation(SessionStateAnimator::WALLPAPER,
465                               SessionStateAnimator::ANIMATION_FADE_IN,
466                               SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
467   }
468   unlocked_properties_.reset();
469 }
470 
AnimateWallpaperAppearanceIfNecessary(SessionStateAnimator::AnimationSpeed speed,SessionStateAnimator::AnimationSequence * animation_sequence)471 void LockStateController::AnimateWallpaperAppearanceIfNecessary(
472     SessionStateAnimator::AnimationSpeed speed,
473     SessionStateAnimator::AnimationSequence* animation_sequence) {
474   if (unlocked_properties_.get() && unlocked_properties_->wallpaper_is_hidden) {
475     animation_sequence->StartAnimation(SessionStateAnimator::WALLPAPER,
476                                        SessionStateAnimator::ANIMATION_FADE_IN,
477                                        speed);
478   }
479 }
480 
AnimateWallpaperHidingIfNecessary(SessionStateAnimator::AnimationSpeed speed,SessionStateAnimator::AnimationSequence * animation_sequence)481 void LockStateController::AnimateWallpaperHidingIfNecessary(
482     SessionStateAnimator::AnimationSpeed speed,
483     SessionStateAnimator::AnimationSequence* animation_sequence) {
484   if (unlocked_properties_.get() && unlocked_properties_->wallpaper_is_hidden) {
485     animation_sequence->StartAnimation(SessionStateAnimator::WALLPAPER,
486                                        SessionStateAnimator::ANIMATION_FADE_OUT,
487                                        speed);
488   }
489 }
490 
OnLockStateEvent(LockStateObserver::EventType event)491 void LockStateController::OnLockStateEvent(LockStateObserver::EventType event) {
492   for (auto& observer : observers_)
493     observer.OnLockStateEvent(event);
494 }
495 
496 }  // namespace ash
497