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
|
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_ASH_COMPONENTS_POWER_DARK_RESUME_CONTROLLER_H_
#define CHROMEOS_ASH_COMPONENTS_POWER_DARK_RESUME_CONTROLLER_H_
#include "base/component_export.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/unguessable_token.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/wake_lock.mojom.h"
#include "services/device/public/mojom/wake_lock_provider.mojom.h"
namespace ash::system {
// This class listens to dark resume events from the power manager and makes
// decisions on whether to re-suspend the device or keep the device in dark
// resume based on the wake locks activated at the time of a dark resume. It -
//
// 1. Starts a timer to check for any activated app suspension wake locks. This
// gives services time to do work in dark resume. They can activate a wake lock
// to indicate to the system that they are still doing work.
//
// 2. After the timer in 1 expires, an observer for wake lock deactivation is
// set. Also a hard timeout timer is scheduled.
//
// 3. If no wake lock is held then the observer gets notified immediately and
// the power manager is requested to re-suspend the system.
//
// 4. If an app suspension wake lock is acquired then either -
// - The observer from 2 is notified when the wake lock is deactivated and the
// power manager is requested to re-suspend the system.
// Or
// - The hard timeout timer from 2 fires and the power manager is requested to
// re-suspend the system.
//
// 5. If the system transitions to a full resume all dark resume related state
// and timers are cleared as the system wakes up.
class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_POWER) DarkResumeController
: public chromeos::PowerManagerClient::Observer,
public device::mojom::WakeLockObserver {
public:
explicit DarkResumeController(
mojo::PendingRemote<device::mojom::WakeLockProvider> wake_lock_provider);
DarkResumeController(const DarkResumeController&) = delete;
DarkResumeController& operator=(const DarkResumeController&) = delete;
~DarkResumeController() override;
// Time after a dark resume when wake lock count is checked and a decision is
// made to re-suspend or wait for wake lock release.
static constexpr base::TimeDelta kDarkResumeWakeLockCheckTimeout =
base::Seconds(3);
// chromeos::PowerManagerClient::Observer overrides.
void PowerManagerInitialized() override;
void DarkSuspendImminent() override;
void SuspendDone(base::TimeDelta sleep_duration) override;
// mojom::WakeLockObserver overrides.
void OnWakeLockDeactivated(device::mojom::WakeLockType type) override;
// Return true iff all dark resume related state is set i.e the suspend
// readiness token is set and wake lock release event has observers.
bool IsDarkResumeStateSetForTesting() const;
// Return true iff all dark resume related state is reset i.e. suspend
// readiness token is empty, wake lock release event has no observers,
// wake lock check timer is reset, hard timeout timer is reset and there are
// no in flight tasks. This should be true when device exits dark resume
// either by re-suspending or transitioning to full resume.
bool IsDarkResumeStateClearedForTesting() const;
// Returns |dark_resume_hard_timeout_|.
base::TimeDelta GetHardTimeoutForTesting() const;
private:
// Called |kDarkResumeWakeLockCheckTimeout| after a dark resume. Checks if
// app suspension wake locks are held. If no wake locks are held then
// re-suspends the device else schedules HandleDarkResumeHardTimeout.
void HandleDarkResumeWakeLockCheckTimeout();
// Called |kDarkResumeHardTimeout| after a
// HandleDarkResumeWakeLockCheckTimeout. Clears all dark resume state and
// re-suspends the device.
void HandleDarkResumeHardTimeout();
// Clears all state associated with dark resume.
void ClearDarkResumeState();
// Used for acquiring, releasing and observing wake locks.
mojo::Remote<device::mojom::WakeLockProvider> wake_lock_provider_;
// Used when system is ready to suspend after a DarkSupendImminent i.e.
// after a dark resume.
base::UnguessableToken block_suspend_token_;
// The receiver used to implement device::mojom::WakeLockObserver.
mojo::Receiver<device::mojom::WakeLockObserver> wake_lock_observer_receiver_{
this};
// Timer used to schedule HandleDarkResumeWakeLockCheckTimeout.
base::OneShotTimer wake_lock_check_timer_;
// Timer used to schedule HandleDarkResumeHardTimeout.
base::OneShotTimer hard_timeout_timer_;
// Max time to wait for wake lock release after a wake lock check after a dark
// resume. After this time the system is asked to re-suspend. This is
// initialized via PowerManagerClient when it's initialization is complete in
// |PowerManagerInitialized|. Till then there may be a very small window after
// booth when it takes a default value.
base::TimeDelta dark_resume_hard_timeout_;
// Used for checking if HandleDarkResumeWakeLockCheckTimeout and
// HandleDarkResumeHardTimeout run on the same sequence.
SEQUENCE_CHECKER(dark_resume_tasks_sequence_checker_);
// This is invalidated in ClearDarkResumeState as a fail safe measure to clear
// any lingering timer callbacks or wake lock observer callbacks. This is a
// good to have but not a necessity as ClearDarkResumeState cancels any dark
// resume state machine related tasks via other means. In the future if other
// tasks or callbacks need to be added separate from the dark resume state
// machine lifetime then a separate factory needs to be created and used.
base::WeakPtrFactory<DarkResumeController> weak_ptr_factory_{this};
};
} // namespace ash::system
#endif // CHROMEOS_ASH_COMPONENTS_POWER_DARK_RESUME_CONTROLLER_H_
|