power_event_observer.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  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. #include "ash/system/power/power_event_observer.h"
  5. #include <map>
  6. #include <memory>
  7. #include <utility>
  8. #include "ash/display/projecting_observer.h"
  9. #include "ash/login_status.h"
  10. #include "ash/root_window_controller.h"
  11. #include "ash/session/session_controller_impl.h"
  12. #include "ash/shell.h"
  13. #include "ash/system/model/clock_model.h"
  14. #include "ash/system/model/system_tray_model.h"
  15. #include "ash/wallpaper/wallpaper_widget_controller.h"
  16. #include "ash/wm/lock_state_controller.h"
  17. #include "ash/wm/lock_state_observer.h"
  18. #include "base/bind.h"
  19. #include "base/location.h"
  20. #include "base/scoped_multi_source_observation.h"
  21. #include "base/threading/thread_task_runner_handle.h"
  22. #include "chromeos/ash/components/feature_usage/feature_usage_metrics.h"
  23. #include "ui/aura/window.h"
  24. #include "ui/aura/window_tree_host.h"
  25. #include "ui/base/user_activity/user_activity_detector.h"
  26. #include "ui/compositor/compositor.h"
  27. #include "ui/compositor/compositor_observer.h"
  28. #include "ui/display/manager/display_configurator.h"
  29. namespace ash {
  30. namespace {
  31. void OnSuspendDisplaysCompleted(base::UnguessableToken token, bool status) {
  32. chromeos::PowerManagerClient::Get()->UnblockSuspend(token);
  33. }
  34. // Returns whether the screen should be locked when device is suspended.
  35. bool ShouldLockOnSuspend() {
  36. SessionControllerImpl* controller = ash::Shell::Get()->session_controller();
  37. return controller->ShouldLockScreenAutomatically() &&
  38. controller->CanLockScreen();
  39. }
  40. // One-shot class that runs a callback after all compositors start and
  41. // complete two compositing cycles. This should ensure that buffer swap with the
  42. // current UI has happened.
  43. // After the first compositing cycle, the display compositor starts drawing the
  44. // UI changes, and schedules a buffer swap. Given that the display compositor
  45. // will not start drawing the next frame before the previous swap happens, when
  46. // the second compositing cycle ends, it should be safe to assume the required
  47. // buffer swap happened at that point.
  48. // Note that the compositor watcher will wait for any pending wallpaper
  49. // animation for a root window to finish before it starts observing compositor
  50. // cycles, to ensure it picks up wallpaper state from after the animation ends,
  51. // and avoids issues like https://crbug.com/820436.
  52. class CompositorWatcher : public ui::CompositorObserver {
  53. public:
  54. // |callback| - called when all visible root window compositors complete
  55. // required number of compositing cycles. It will not be called after
  56. // CompositorWatcher instance is deleted, nor from the CompositorWatcher
  57. // destructor.
  58. explicit CompositorWatcher(base::OnceClosure callback)
  59. : callback_(std::move(callback)), compositor_observations_(this) {
  60. Start();
  61. }
  62. CompositorWatcher(const CompositorWatcher&) = delete;
  63. CompositorWatcher& operator=(const CompositorWatcher&) = delete;
  64. ~CompositorWatcher() override = default;
  65. // ui::CompositorObserver:
  66. void OnCompositingDidCommit(ui::Compositor* compositor) override {
  67. if (!pending_compositing_.count(compositor) ||
  68. pending_compositing_[compositor].state !=
  69. CompositingState::kWaitingForCommit) {
  70. return;
  71. }
  72. pending_compositing_[compositor].state =
  73. CompositingState::kWaitingForStarted;
  74. }
  75. void OnCompositingStarted(ui::Compositor* compositor,
  76. base::TimeTicks start_time) override {
  77. if (!pending_compositing_.count(compositor) ||
  78. pending_compositing_[compositor].state !=
  79. CompositingState::kWaitingForStarted) {
  80. return;
  81. }
  82. pending_compositing_[compositor].state = CompositingState::kWaitingForEnded;
  83. }
  84. void OnCompositingEnded(ui::Compositor* compositor) override {
  85. if (!pending_compositing_.count(compositor))
  86. return;
  87. CompositorInfo& compositor_info = pending_compositing_[compositor];
  88. if (compositor_info.state != CompositingState::kWaitingForEnded)
  89. return;
  90. compositor_info.observed_cycles++;
  91. if (compositor_info.observed_cycles < kRequiredCompositingCycles) {
  92. compositor_info.state = CompositingState::kWaitingForCommit;
  93. compositor->ScheduleDraw();
  94. return;
  95. }
  96. compositor_observations_.RemoveObservation(compositor);
  97. pending_compositing_.erase(compositor);
  98. RunCallbackIfAllCompositingEnded();
  99. }
  100. void OnCompositingShuttingDown(ui::Compositor* compositor) override {
  101. compositor_observations_.RemoveObservation(compositor);
  102. pending_compositing_.erase(compositor);
  103. RunCallbackIfAllCompositingEnded();
  104. }
  105. private:
  106. // CompositorWatcher observes compositors for compositing events, in order to
  107. // determine whether compositing cycles end for all root window compositors.
  108. // This enum is used to track this cycle. Compositing goes through the
  109. // following states: DidCommit -> CompositingStarted -> CompositingEnded.
  110. enum class CompositingState {
  111. kWaitingForWallpaperAnimation,
  112. kWaitingForCommit,
  113. kWaitingForStarted,
  114. kWaitingForEnded,
  115. };
  116. struct CompositorInfo {
  117. // State of the current compositing cycle.
  118. CompositingState state = CompositingState::kWaitingForCommit;
  119. // Number of observed compositing cycles.
  120. int observed_cycles = 0;
  121. };
  122. // Number of compositing cycles that have to complete for each compositor
  123. // in order for a CompositorWatcher to run the callback.
  124. static constexpr int kRequiredCompositingCycles = 2;
  125. // Starts observing all visible root window compositors.
  126. void Start() {
  127. for (aura::Window* window : Shell::GetAllRootWindows()) {
  128. ui::Compositor* compositor = window->GetHost()->compositor();
  129. if (!compositor->IsVisible())
  130. continue;
  131. DCHECK(!pending_compositing_.count(compositor));
  132. compositor_observations_.AddObservation(compositor);
  133. pending_compositing_[compositor].state =
  134. CompositingState::kWaitingForWallpaperAnimation;
  135. WallpaperWidgetController* wallpaper_widget_controller =
  136. RootWindowController::ForWindow(window)
  137. ->wallpaper_widget_controller();
  138. if (wallpaper_widget_controller->IsAnimating()) {
  139. wallpaper_widget_controller->AddAnimationEndCallback(
  140. base::BindOnce(&CompositorWatcher::StartObservingCompositing,
  141. weak_ptr_factory_.GetWeakPtr(), compositor));
  142. } else {
  143. StartObservingCompositing(compositor);
  144. }
  145. }
  146. // Post task to make sure callback is not invoked synchronously as watcher
  147. // is started.
  148. base::ThreadTaskRunnerHandle::Get()->PostTask(
  149. FROM_HERE,
  150. base::BindOnce(&CompositorWatcher::RunCallbackIfAllCompositingEnded,
  151. weak_ptr_factory_.GetWeakPtr()));
  152. }
  153. // Called when the wallpaper animations end for the root window associated
  154. // with the compositor. It starts observing the compositor's compositing
  155. // cycles.
  156. void StartObservingCompositing(ui::Compositor* compositor) {
  157. if (!pending_compositing_.count(compositor) ||
  158. pending_compositing_[compositor].state !=
  159. CompositingState::kWaitingForWallpaperAnimation) {
  160. return;
  161. }
  162. pending_compositing_[compositor].state =
  163. CompositingState::kWaitingForCommit;
  164. // Schedule a draw to force at least one more compositing cycle.
  165. compositor->ScheduleDraw();
  166. }
  167. // If all observed root window compositors have gone through a compositing
  168. // cycle, runs |callback_|.
  169. void RunCallbackIfAllCompositingEnded() {
  170. if (pending_compositing_.empty() && callback_)
  171. std::move(callback_).Run();
  172. }
  173. base::OnceClosure callback_;
  174. // Per-compositor compositing state tracked by |this|. The map will
  175. // not contain compositors that were not visible at the time the
  176. // CompositorWatcher was started - the main purpose of tracking compositing
  177. // state is to determine whether compositors can be safely stopped (i.e. their
  178. // visibility set to false), so there should be no need for tracking
  179. // compositors that were hidden to start with.
  180. std::map<ui::Compositor*, CompositorInfo> pending_compositing_;
  181. base::ScopedMultiSourceObservation<ui::Compositor, ui::CompositorObserver>
  182. compositor_observations_;
  183. base::WeakPtrFactory<CompositorWatcher> weak_ptr_factory_{this};
  184. };
  185. const char kLockOnSuspendFeature[] = "LockOnSuspend";
  186. } // namespace
  187. class LockOnSuspendUsage : public feature_usage::FeatureUsageMetrics::Delegate {
  188. public:
  189. LockOnSuspendUsage() = default;
  190. void RecordUsage() { lock_on_suspend_usage_.RecordUsage(/*success=*/true); }
  191. // feature_usage::FeatureUsageMetrics::Delegate:
  192. bool IsEligible() const final {
  193. // We only track lock-on-suspend usage by real users. Thus
  194. // LockOnSuspendUsage should be created only for such users.
  195. DCHECK(ash::Shell::Get()->session_controller()->CanLockScreen());
  196. return true;
  197. }
  198. bool IsEnabled() const final { return ShouldLockOnSuspend(); }
  199. private:
  200. feature_usage::FeatureUsageMetrics lock_on_suspend_usage_{
  201. kLockOnSuspendFeature, this};
  202. };
  203. PowerEventObserver::PowerEventObserver()
  204. : lock_state_(Shell::Get()->session_controller()->IsScreenLocked()
  205. ? LockState::kLocked
  206. : LockState::kUnlocked),
  207. session_observer_(this) {
  208. chromeos::PowerManagerClient::Get()->AddObserver(this);
  209. if (Shell::Get()->session_controller()->CanLockScreen())
  210. lock_on_suspend_usage_ = std::make_unique<LockOnSuspendUsage>();
  211. }
  212. PowerEventObserver::~PowerEventObserver() {
  213. chromeos::PowerManagerClient::Get()->RemoveObserver(this);
  214. }
  215. void PowerEventObserver::OnLockAnimationsComplete() {
  216. VLOG(1) << "Screen locker animations have completed.";
  217. if (lock_state_ != LockState::kLocking)
  218. return;
  219. lock_state_ = LockState::kLockedCompositingPending;
  220. // If suspending, run pending animations to the end immediately, as there is
  221. // no point in waiting for them to finish given that the device is suspending.
  222. if (block_suspend_token_)
  223. EndPendingWallpaperAnimations();
  224. // The |compositor_watcher_| is owned by this, and the callback passed to it
  225. // won't be called after |compositor_watcher_|'s destruction, so
  226. // base::Unretained is safe here.
  227. compositor_watcher_ = std::make_unique<CompositorWatcher>(
  228. base::BindOnce(&PowerEventObserver::OnCompositorsReadyForSuspend,
  229. base::Unretained(this)));
  230. }
  231. void PowerEventObserver::SuspendImminent(
  232. power_manager::SuspendImminent::Reason reason) {
  233. suspend_in_progress_ = true;
  234. block_suspend_token_ = base::UnguessableToken::Create();
  235. chromeos::PowerManagerClient::Get()->BlockSuspend(block_suspend_token_,
  236. "PowerEventObserver");
  237. // Stop compositing immediately if
  238. // * the screen lock flow has already completed
  239. // * screen is not locked, and should remain unlocked during suspend
  240. if (lock_state_ == LockState::kLocked ||
  241. (lock_state_ == LockState::kUnlocked && !ShouldLockOnSuspend())) {
  242. StopCompositingAndSuspendDisplays();
  243. } else {
  244. // If screen is getting locked during suspend, delay suspend until screen
  245. // lock finishes, and post-lock frames get picked up by display compositors.
  246. if (lock_state_ == LockState::kUnlocked) {
  247. VLOG(1) << "Requesting screen lock from PowerEventObserver suspend";
  248. lock_state_ = LockState::kLocking;
  249. Shell::Get()->lock_state_controller()->LockWithoutAnimation();
  250. if (lock_on_suspend_usage_)
  251. lock_on_suspend_usage_->RecordUsage();
  252. } else if (lock_state_ != LockState::kLocking) {
  253. // If the screen is still being locked (i.e. in kLocking state),
  254. // EndPendingWallpaperAnimations() will be called in
  255. // OnLockAnimationsComplete().
  256. EndPendingWallpaperAnimations();
  257. }
  258. }
  259. }
  260. void PowerEventObserver::SuspendDoneEx(
  261. const power_manager::SuspendDone& proto) {
  262. suspend_in_progress_ = false;
  263. Shell::Get()->display_configurator()->ResumeDisplays();
  264. Shell::Get()->system_tray_model()->clock()->NotifyRefreshClock();
  265. // If the suspend request was being blocked while waiting for the lock
  266. // animation to complete, clear the blocker since the suspend has already
  267. // completed. This prevents rendering requests from being blocked after a
  268. // resume if the lock screen took too long to show.
  269. block_suspend_token_ = {};
  270. StartRootWindowCompositors();
  271. // If this is a resume from hibernation, the user just authenticated in order
  272. // to launch the resume image. Dismiss the lock screen here to avoid making
  273. // them log in twice.
  274. if (proto.deepest_state() ==
  275. power_manager::SuspendDone_SuspendState_TO_DISK) {
  276. Shell::Get()->session_controller()->HideLockScreen();
  277. }
  278. }
  279. void PowerEventObserver::LidEventReceived(
  280. chromeos::PowerManagerClient::LidState state,
  281. base::TimeTicks timestamp) {
  282. lid_state_ = state;
  283. MaybeLockOnLidClose(
  284. ash::Shell::Get()->projecting_observer()->is_projecting());
  285. }
  286. void PowerEventObserver::SetIsProjecting(bool is_projecting) {
  287. MaybeLockOnLidClose(is_projecting);
  288. }
  289. void PowerEventObserver::MaybeLockOnLidClose(bool is_projecting) {
  290. SessionControllerImpl* controller = ash::Shell::Get()->session_controller();
  291. VLOG(1) << "Lock screen on lid close: lid=" << static_cast<int>(lid_state_)
  292. << ", lock=" << static_cast<int>(lock_state_)
  293. << ", projecting=" << is_projecting
  294. << ", policy=" << controller->ShouldLockScreenAutomatically()
  295. << ", can_lock=" << controller->CanLockScreen();
  296. if (lid_state_ == chromeos::PowerManagerClient::LidState::CLOSED &&
  297. lock_state_ == LockState::kUnlocked && !is_projecting &&
  298. controller->ShouldLockScreenAutomatically() &&
  299. controller->CanLockScreen()) {
  300. VLOG(1) << "Screen locked due to lid close";
  301. lock_state_ = LockState::kLocking;
  302. Shell::Get()->lock_state_controller()->LockWithoutAnimation();
  303. }
  304. }
  305. void PowerEventObserver::OnLoginStatusChanged(LoginStatus) {
  306. // Bail if usage tracker is already created.
  307. if (lock_on_suspend_usage_)
  308. return;
  309. // We only care about users who could lock the screen.
  310. if (!ash::Shell::Get()->session_controller()->CanLockScreen())
  311. return;
  312. lock_on_suspend_usage_ = std::make_unique<LockOnSuspendUsage>();
  313. }
  314. void PowerEventObserver::OnLockStateChanged(bool locked) {
  315. if (locked) {
  316. lock_state_ = LockState::kLocking;
  317. // The screen is now locked but the pending suspend, if any, will be blocked
  318. // until all the animations have completed.
  319. if (block_suspend_token_)
  320. VLOG(1) << "Screen locked due to suspend";
  321. else
  322. VLOG(1) << "Screen locked without suspend";
  323. } else {
  324. lock_state_ = LockState::kUnlocked;
  325. compositor_watcher_.reset();
  326. if (suspend_in_progress_) {
  327. LOG(WARNING) << "Screen unlocked during suspend";
  328. // If screen gets unlocked during suspend, which could theoretically
  329. // happen if the user initiated unlock just as device started unlocking
  330. // (though, it seems unlikely this would be encountered in practice),
  331. // relock the device if required. Otherwise, if suspend is blocked due to
  332. // screen locking, unblock it.
  333. if (ShouldLockOnSuspend()) {
  334. lock_state_ = LockState::kLocking;
  335. Shell::Get()->lock_state_controller()->LockWithoutAnimation();
  336. if (lock_on_suspend_usage_)
  337. lock_on_suspend_usage_->RecordUsage();
  338. } else if (block_suspend_token_) {
  339. StopCompositingAndSuspendDisplays();
  340. }
  341. }
  342. }
  343. }
  344. void PowerEventObserver::StartRootWindowCompositors() {
  345. for (aura::Window* window : Shell::GetAllRootWindows()) {
  346. ui::Compositor* compositor = window->GetHost()->compositor();
  347. if (!compositor->IsVisible())
  348. compositor->SetVisible(true);
  349. }
  350. }
  351. void PowerEventObserver::StopCompositingAndSuspendDisplays() {
  352. DCHECK(block_suspend_token_);
  353. DCHECK(!compositor_watcher_.get());
  354. for (aura::Window* window : Shell::GetAllRootWindows()) {
  355. ui::Compositor* compositor = window->GetHost()->compositor();
  356. compositor->SetVisible(false);
  357. }
  358. ui::UserActivityDetector::Get()->OnDisplayPowerChanging();
  359. Shell::Get()->display_configurator()->SuspendDisplays(
  360. base::BindOnce(&OnSuspendDisplaysCompleted, block_suspend_token_));
  361. block_suspend_token_ = {};
  362. }
  363. void PowerEventObserver::EndPendingWallpaperAnimations() {
  364. for (aura::Window* window : Shell::GetAllRootWindows()) {
  365. WallpaperWidgetController* wallpaper_widget_controller =
  366. RootWindowController::ForWindow(window)->wallpaper_widget_controller();
  367. if (wallpaper_widget_controller->IsAnimating())
  368. wallpaper_widget_controller->StopAnimating();
  369. }
  370. }
  371. void PowerEventObserver::OnCompositorsReadyForSuspend() {
  372. compositor_watcher_.reset();
  373. lock_state_ = LockState::kLocked;
  374. if (block_suspend_token_)
  375. StopCompositingAndSuspendDisplays();
  376. }
  377. } // namespace ash