File: dark_resume_controller.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (149 lines) | stat: -rw-r--r-- 5,737 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/ash/components/power/dark_resume_controller.h"

#include <utility>

#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/device/public/mojom/wake_lock_provider.mojom.h"

namespace ash::system {

namespace {

// The default value of |dark_resume_hard_timeout_| till
// |PowerManagerInitialized| is called.
constexpr base::TimeDelta kDefaultDarkResumeHardTimeout = base::Seconds(20);

}  // namespace

// static.
constexpr base::TimeDelta DarkResumeController::kDarkResumeWakeLockCheckTimeout;

DarkResumeController::DarkResumeController(
    mojo::PendingRemote<device::mojom::WakeLockProvider> wake_lock_provider)
    : wake_lock_provider_(std::move(wake_lock_provider)),
      dark_resume_hard_timeout_(kDefaultDarkResumeHardTimeout) {
  DCHECK(!dark_resume_hard_timeout_.is_zero());
  chromeos::PowerManagerClient::Get()->AddObserver(this);
}

DarkResumeController::~DarkResumeController() {
  chromeos::PowerManagerClient::Get()->RemoveObserver(this);
}

void DarkResumeController::PowerManagerInitialized() {
  dark_resume_hard_timeout_ =
      chromeos::PowerManagerClient::Get()->GetDarkSuspendDelayTimeout();
}

void DarkResumeController::DarkSuspendImminent() {
  DVLOG(1) << __func__;
  block_suspend_token_ = base::UnguessableToken::Create();
  chromeos::PowerManagerClient::Get()->BlockSuspend(block_suspend_token_,
                                                    "DarkResumeController");
  // Schedule task that will check for any wake locks acquired in dark resume.
  DCHECK(!wake_lock_check_timer_.IsRunning());
  wake_lock_check_timer_.Start(
      FROM_HERE, kDarkResumeWakeLockCheckTimeout,
      base::BindOnce(
          &DarkResumeController::HandleDarkResumeWakeLockCheckTimeout,
          weak_ptr_factory_.GetWeakPtr()));
}

void DarkResumeController::SuspendDone(base::TimeDelta sleep_duration) {
  DVLOG(1) << __func__;
  // Clear any dark resume state when the device resumes.
  ClearDarkResumeState();
}

void DarkResumeController::OnWakeLockDeactivated(
    device::mojom::WakeLockType type) {
  // If this callback fires then one of two scenarios happened -
  // 1. No wake lock was held after |kDarkResumeWakeLockCheckTimeout|.
  // 2. Wake lock was held but was released before the hard timeout.
  //
  // The device is now ready to re-suspend after this dark resume event. Tell
  // the power daemon to re-suspend and invalidate any other state associated
  // with dark resume.
  DVLOG(1) << __func__;
  // The observer is only registered once dark resume starts.
  DCHECK(block_suspend_token_);
  chromeos::PowerManagerClient::Get()->UnblockSuspend(block_suspend_token_);
  block_suspend_token_ = {};
  ClearDarkResumeState();
}

bool DarkResumeController::IsDarkResumeStateSetForTesting() const {
  return block_suspend_token_ && wake_lock_observer_receiver_.is_bound();
}

base::TimeDelta DarkResumeController::GetHardTimeoutForTesting() const {
  return dark_resume_hard_timeout_;
}

bool DarkResumeController::IsDarkResumeStateClearedForTesting() const {
  return !weak_ptr_factory_.HasWeakPtrs() &&
         !wake_lock_check_timer_.IsRunning() &&
         !hard_timeout_timer_.IsRunning() && !block_suspend_token_ &&
         !wake_lock_observer_receiver_.is_bound();
}

void DarkResumeController::HandleDarkResumeWakeLockCheckTimeout() {
  DVLOG(1) << __func__;
  DCHECK_CALLED_ON_VALID_SEQUENCE(dark_resume_tasks_sequence_checker_);
  wake_lock_check_timer_.Stop();
  // Setup observer for wake lock deactivation. If a wake lock is not activated
  // this calls back immediately, else whenever the wake lock is deactivated.
  // The device will be suspended on a deactivation notification i.e. in
  // OnDeactivation.
  wake_lock_provider_->NotifyOnWakeLockDeactivation(
      device::mojom::WakeLockType::kPreventAppSuspension,
      wake_lock_observer_receiver_.BindNewPipeAndPassRemote());

  // Schedule task that will tell the power daemon to re-suspend after a dark
  // resume irrespective of any state. This is a last resort timeout to ensure
  // the device doesn't stay up indefinitely in dark resume.
  DCHECK(!hard_timeout_timer_.IsRunning());
  hard_timeout_timer_.Start(
      FROM_HERE, dark_resume_hard_timeout_,
      base::BindOnce(&DarkResumeController::HandleDarkResumeHardTimeout,
                     weak_ptr_factory_.GetWeakPtr()));
}

void DarkResumeController::HandleDarkResumeHardTimeout() {
  DVLOG(1) << __func__;
  DCHECK_CALLED_ON_VALID_SEQUENCE(dark_resume_tasks_sequence_checker_);
  hard_timeout_timer_.Stop();
  // Enough is enough. Tell power daemon it's okay to suspend.
  DCHECK(block_suspend_token_);
  chromeos::PowerManagerClient::Get()->UnblockSuspend(block_suspend_token_);
  block_suspend_token_ = {};
  ClearDarkResumeState();
}

void DarkResumeController::ClearDarkResumeState() {
  DVLOG(1) << __func__;
  // Reset the token that is used to trigger a re-suspend. Won't be needed
  // if the dark resume state machine is ending.
  block_suspend_token_ = {};

  // This automatically invalidates any WakeLockObserver and associated callback
  // in this case OnDeactivation.
  wake_lock_observer_receiver_.reset();

  // Stops timer and invalidates HandleDarkResumeWakeLockCheckTimeout.
  wake_lock_check_timer_.Stop();

  // Stops timer and invalidates HandleDarkResumeHardTimeout.
  hard_timeout_timer_.Stop();

  // At this point all pending callbacks should be invalidated. This is a last
  // fail safe to not have any lingering tasks associated with the dark resume
  // state machine.
  weak_ptr_factory_.InvalidateWeakPtrs();
}

}  // namespace ash::system