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
|