Commit 91b547aa authored by Abhishek Bhardwaj's avatar Abhishek Bhardwaj Committed by Commit Bot

Reland "arc: Add wake lock based logic to re-suspend after dark resume"

This is a reland of https://crrev.com/c/1297474.

This change adds functionality to support lock screen notifications for
Android. The wake lock module now listens to dark resume notifications
from the power manager. It -

1. Starts a timer to check for partial wake locks acquired by Android.

2. After the timer in 1 expires, if no partial wake lock is acquired the
power manager is requested to re-suspend the system. If a partial wake
lock is acquired, then another hard timeout timer is set and also an
observer to wake lock release is set.

3. If wake lock is released, the system is re-suspended immediately.

4. If a wake lock is still acquired but the hard timeout expires then
the system is re-suspended immediately.

5. If the system transitions to a full resume all dark resume related
state and timers are cleared.

On top of this change -

1. Changes were added to fix linker errors by declaring static constants
in the source file as well.

2. Refactored some functions in the test code.

BUG=chromium:898297
TEST=Unit tests and end to end test with Android applications.

Change-Id: I573f130fad2ed092d8acb83fb3319614b4ce8e02
Reviewed-on: https://chromium-review.googlesource.com/c/1302866Reviewed-by: default avatarYusuke Sato <yusukes@chromium.org>
Commit-Queue: Abhishek Bhardwaj <abhishekbh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#603264}
parent 667acf6d
...@@ -66,6 +66,7 @@ static_library("arc") { ...@@ -66,6 +66,7 @@ static_library("arc") {
"volume_mounter/arc_volume_mounter_bridge.h", "volume_mounter/arc_volume_mounter_bridge.h",
"wake_lock/arc_wake_lock_bridge.cc", "wake_lock/arc_wake_lock_bridge.cc",
"wake_lock/arc_wake_lock_bridge.h", "wake_lock/arc_wake_lock_bridge.h",
"wake_lock/wake_lock_observer.h",
] ]
public_deps = [ public_deps = [
......
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "base/observer_list.h"
#include "base/task/post_task.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/power_policy_controller.h" #include "chromeos/dbus/power_policy_controller.h"
#include "components/arc/arc_bridge_service.h" #include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_browser_context_keyed_service_factory_base.h" #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
...@@ -46,7 +49,8 @@ class ArcWakeLockBridgeFactory ...@@ -46,7 +49,8 @@ class ArcWakeLockBridgeFactory
// WakeLockRequester requests a wake lock from the device service in response // WakeLockRequester requests a wake lock from the device service in response
// to wake lock requests of a given type from Android. A count is kept of // to wake lock requests of a given type from Android. A count is kept of
// outstanding Android requests so that only a single actual wake lock is used. // outstanding Android requests so that only a single actual wake lock is
// used.
class ArcWakeLockBridge::WakeLockRequester { class ArcWakeLockBridge::WakeLockRequester {
public: public:
WakeLockRequester(device::mojom::WakeLockType type, WakeLockRequester(device::mojom::WakeLockType type,
...@@ -76,6 +80,9 @@ class ArcWakeLockBridge::WakeLockRequester { ...@@ -76,6 +80,9 @@ class ArcWakeLockBridge::WakeLockRequester {
} }
wake_lock_->RequestWakeLock(); wake_lock_->RequestWakeLock();
for (auto& observer : observers_)
observer.OnWakeLockAcquire();
} }
// Decrements the number of outstanding Android requests. Cancels the device // Decrements the number of outstanding Android requests. Cancels the device
...@@ -94,10 +101,27 @@ class ArcWakeLockBridge::WakeLockRequester { ...@@ -94,10 +101,27 @@ class ArcWakeLockBridge::WakeLockRequester {
} }
DCHECK(wake_lock_); DCHECK(wake_lock_);
DVLOG(1) << "Partial wake force release. Count: " << wake_lock_count_; DVLOG(1) << "Partial wake lock force release. Count: " << wake_lock_count_;
wake_lock_->CancelWakeLock(); wake_lock_->CancelWakeLock();
for (auto& observer : observers_)
observer.OnWakeLockRelease();
}
bool IsWakeLockHeld() const { return wake_lock_count_ > 0; }
void AddObserver(WakeLockObserver* observer) {
DCHECK(observer);
observers_.AddObserver(observer);
} }
void RemoveObserver(WakeLockObserver* observer) {
DCHECK(observer);
observers_.RemoveObserver(observer);
}
bool HasObservers() const { return observers_.might_have_observers(); }
// Runs the message loop until replies have been received for all pending // Runs the message loop until replies have been received for all pending
// requests on |wake_lock_|. // requests on |wake_lock_|.
void FlushForTesting() { void FlushForTesting() {
...@@ -118,6 +142,8 @@ class ArcWakeLockBridge::WakeLockRequester { ...@@ -118,6 +142,8 @@ class ArcWakeLockBridge::WakeLockRequester {
// Lazily initialized in response to first request. // Lazily initialized in response to first request.
device::mojom::WakeLockPtr wake_lock_; device::mojom::WakeLockPtr wake_lock_;
base::ObserverList<WakeLockObserver>::Unchecked observers_;
DISALLOW_COPY_AND_ASSIGN(WakeLockRequester); DISALLOW_COPY_AND_ASSIGN(WakeLockRequester);
}; };
...@@ -138,6 +164,9 @@ ArcWakeLockBridge* ArcWakeLockBridge::GetForBrowserContextForTesting( ...@@ -138,6 +164,9 @@ ArcWakeLockBridge* ArcWakeLockBridge::GetForBrowserContextForTesting(
return ArcWakeLockBridgeFactory::GetForBrowserContextForTesting(context); return ArcWakeLockBridgeFactory::GetForBrowserContextForTesting(context);
} }
constexpr base::TimeDelta ArcWakeLockBridge::kDarkResumeWakeLockCheckTimeout;
constexpr base::TimeDelta ArcWakeLockBridge::kDarkResumeHardTimeout;
ArcWakeLockBridge::ArcWakeLockBridge(content::BrowserContext* context, ArcWakeLockBridge::ArcWakeLockBridge(content::BrowserContext* context,
ArcBridgeService* bridge_service) ArcBridgeService* bridge_service)
: arc_bridge_service_(bridge_service), : arc_bridge_service_(bridge_service),
...@@ -145,11 +174,16 @@ ArcWakeLockBridge::ArcWakeLockBridge(content::BrowserContext* context, ...@@ -145,11 +174,16 @@ ArcWakeLockBridge::ArcWakeLockBridge(content::BrowserContext* context,
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
arc_bridge_service_->wake_lock()->SetHost(this); arc_bridge_service_->wake_lock()->SetHost(this);
arc_bridge_service_->wake_lock()->AddObserver(this); arc_bridge_service_->wake_lock()->AddObserver(this);
chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(
this);
} }
ArcWakeLockBridge::~ArcWakeLockBridge() { ArcWakeLockBridge::~ArcWakeLockBridge() {
arc_bridge_service_->wake_lock()->RemoveObserver(this); arc_bridge_service_->wake_lock()->RemoveObserver(this);
arc_bridge_service_->wake_lock()->SetHost(nullptr); arc_bridge_service_->wake_lock()->SetHost(nullptr);
// In case some this wasn't cleared while handling a dark resume.
GetWakeLockRequester(device::mojom::WakeLockType::kPreventAppSuspension)
->RemoveObserver(this);
} }
void ArcWakeLockBridge::OnConnectionClosed() { void ArcWakeLockBridge::OnConnectionClosed() {
...@@ -157,11 +191,6 @@ void ArcWakeLockBridge::OnConnectionClosed() { ...@@ -157,11 +191,6 @@ void ArcWakeLockBridge::OnConnectionClosed() {
wake_lock_requesters_.clear(); wake_lock_requesters_.clear();
} }
void ArcWakeLockBridge::FlushWakeLocksForTesting() {
for (const auto& it : wake_lock_requesters_)
it.second->FlushForTesting();
}
void ArcWakeLockBridge::AcquirePartialWakeLock( void ArcWakeLockBridge::AcquirePartialWakeLock(
AcquirePartialWakeLockCallback callback) { AcquirePartialWakeLockCallback callback) {
GetWakeLockRequester(device::mojom::WakeLockType::kPreventAppSuspension) GetWakeLockRequester(device::mojom::WakeLockType::kPreventAppSuspension)
...@@ -176,6 +205,104 @@ void ArcWakeLockBridge::ReleasePartialWakeLock( ...@@ -176,6 +205,104 @@ void ArcWakeLockBridge::ReleasePartialWakeLock(
std::move(callback).Run(true); std::move(callback).Run(true);
} }
void ArcWakeLockBridge::DarkSuspendImminent() {
DVLOG(1) << __func__;
suspend_readiness_cb_ = chromeos::DBusThreadManager::Get()
->GetPowerManagerClient()
->GetSuspendReadinessCallback(FROM_HERE);
// Post task that will check for any wake locks acquired in dark resume.
base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&ArcWakeLockBridge::HandleDarkResumeWakeLockCheckTimeout,
dark_resume_weak_ptr_factory_.GetWeakPtr()),
kDarkResumeWakeLockCheckTimeout);
}
void ArcWakeLockBridge::SuspendDone(const base::TimeDelta& sleep_duration) {
DVLOG(1) << __func__;
// Clear any dark resume state when the device resumes.
ClearDarkResumeState();
}
void ArcWakeLockBridge::OnWakeLockRelease() {
// This observer is only registered once dark resume starts.
DCHECK(suspend_readiness_cb_);
DVLOG(1) << __func__;
// At this point the instance has done its work, tell the power daemon to
// re-suspend.
std::move(suspend_readiness_cb_).Run();
ClearDarkResumeState();
}
void ArcWakeLockBridge::FlushWakeLocksForTesting() {
for (const auto& it : wake_lock_requesters_)
it.second->FlushForTesting();
}
bool ArcWakeLockBridge::IsSuspendReadinessStateSetForTesting() const {
return !suspend_readiness_cb_.is_null();
}
bool ArcWakeLockBridge::WakeLockHasObserversForTesting(
device::mojom::WakeLockType type) {
return GetWakeLockRequester(
device::mojom::WakeLockType::kPreventAppSuspension)
->HasObservers();
}
void ArcWakeLockBridge::HandleDarkResumeWakeLockCheckTimeout() {
DVLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(dark_resume_tasks_sequence_checker_);
// Check if any wake locks are held at this point. If not, then it's assumed
// the instance either acquired and released one or had no reason to acquire
// one in the first place. If it wants to after this then too bad, tell the
// power daemon to re-suspend and invalidate any other state associated with
// dark resume.
if (!GetWakeLockRequester(device::mojom::WakeLockType::kPreventAppSuspension)
->IsWakeLockHeld()) {
DVLOG(1) << "Wake lock not held during check";
std::move(suspend_readiness_cb_).Run();
ClearDarkResumeState();
return;
}
DVLOG(1) << "Wake lock held during check";
// If a wake lock is held then register for a wake lock release
// notification. As soon as it's released tell power daemon to re-suspend.
// If the instance takes a long time then tell powerd daemon to re-suspend
// after a hard timeout irrespective of wake locks held.
GetWakeLockRequester(device::mojom::WakeLockType::kPreventAppSuspension)
->AddObserver(this);
// Post 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.
base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&ArcWakeLockBridge::HandleDarkResumeHardTimeout,
dark_resume_weak_ptr_factory_.GetWeakPtr()),
kDarkResumeHardTimeout);
}
void ArcWakeLockBridge::HandleDarkResumeHardTimeout() {
DVLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(dark_resume_tasks_sequence_checker_);
// Enough is enough. Tell power daemon it's okay to suspend.
DCHECK(suspend_readiness_cb_);
std::move(suspend_readiness_cb_).Run();
ClearDarkResumeState();
}
void ArcWakeLockBridge::ClearDarkResumeState() {
DVLOG(1) << __func__;
// Invalidate all other state associated with dark resume.
suspend_readiness_cb_.Reset();
GetWakeLockRequester(device::mojom::WakeLockType::kPreventAppSuspension)
->RemoveObserver(this);
dark_resume_weak_ptr_factory_.InvalidateWeakPtrs();
}
ArcWakeLockBridge::WakeLockRequester* ArcWakeLockBridge::GetWakeLockRequester( ArcWakeLockBridge::WakeLockRequester* ArcWakeLockBridge::GetWakeLockRequester(
device::mojom::WakeLockType type) { device::mojom::WakeLockType type) {
auto it = wake_lock_requesters_.find(type); auto it = wake_lock_requesters_.find(type);
......
...@@ -10,8 +10,11 @@ ...@@ -10,8 +10,11 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "chromeos/dbus/power_manager_client.h"
#include "components/arc/common/wake_lock.mojom.h" #include "components/arc/common/wake_lock.mojom.h"
#include "components/arc/connection_observer.h" #include "components/arc/connection_observer.h"
#include "components/arc/wake_lock/wake_lock_observer.h"
#include "components/keyed_service/core/keyed_service.h" #include "components/keyed_service/core/keyed_service.h"
#include "content/public/common/service_manager_connection.h" #include "content/public/common/service_manager_connection.h"
#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding.h"
...@@ -30,7 +33,9 @@ class ArcBridgeService; ...@@ -30,7 +33,9 @@ class ArcBridgeService;
// Sets wake up timers / alarms based on calls from the instance. // Sets wake up timers / alarms based on calls from the instance.
class ArcWakeLockBridge : public KeyedService, class ArcWakeLockBridge : public KeyedService,
public ConnectionObserver<mojom::WakeLockInstance>, public ConnectionObserver<mojom::WakeLockInstance>,
public mojom::WakeLockHost { public mojom::WakeLockHost,
public chromeos::PowerManagerClient::Observer,
public WakeLockObserver {
public: public:
// Returns the factory instance for this class. // Returns the factory instance for this class.
static BrowserContextKeyedServiceFactory* GetFactory(); static BrowserContextKeyedServiceFactory* GetFactory();
...@@ -54,13 +59,36 @@ class ArcWakeLockBridge : public KeyedService, ...@@ -54,13 +59,36 @@ class ArcWakeLockBridge : public KeyedService,
// ConnectionObserver<mojom::WakeLockInstance>::Observer overrides. // ConnectionObserver<mojom::WakeLockInstance>::Observer overrides.
void OnConnectionClosed() override; void OnConnectionClosed() override;
// mojom::WakeLockHost overrides.
void AcquirePartialWakeLock(AcquirePartialWakeLockCallback callback) override;
void ReleasePartialWakeLock(ReleasePartialWakeLockCallback callback) override;
// chromeos::PowerManagerClient::Observer overrides.
void DarkSuspendImminent() override;
void SuspendDone(const base::TimeDelta& sleep_duration) override;
// WakeLockObserver override.
void OnWakeLockRelease() override;
// Runs the message loop until replies have been received for all pending // Runs the message loop until replies have been received for all pending
// device service requests in |wake_lock_requesters_|. // device service requests in |wake_lock_requesters_|.
void FlushWakeLocksForTesting(); void FlushWakeLocksForTesting();
// mojom::WakeLockHost overrides. // Checks if |suspend_readiness_cb_| is set.
void AcquirePartialWakeLock(AcquirePartialWakeLockCallback callback) override; bool IsSuspendReadinessStateSetForTesting() const;
void ReleasePartialWakeLock(ReleasePartialWakeLockCallback callback) override;
// Returns true iff wake lock of |type| has observers.
bool WakeLockHasObserversForTesting(device::mojom::WakeLockType type);
// 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::TimeDelta::FromSeconds(3);
// 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.
static constexpr base::TimeDelta kDarkResumeHardTimeout =
base::TimeDelta::FromSeconds(10);
private: private:
class WakeLockRequester; class WakeLockRequester;
...@@ -68,6 +96,20 @@ class ArcWakeLockBridge : public KeyedService, ...@@ -68,6 +96,20 @@ class ArcWakeLockBridge : public KeyedService,
// Returns the WakeLockRequester for |type|, creating one if needed. // Returns the WakeLockRequester for |type|, creating one if needed.
WakeLockRequester* GetWakeLockRequester(device::mojom::WakeLockType type); WakeLockRequester* GetWakeLockRequester(device::mojom::WakeLockType type);
// Runs |kDarkResumeWakeLockCheckTimeout| time delta after a dark resume.
// Checks if app suspension wake locks (partial wake locks for Android) are
// held. If no wake locks are held then re-suspends the device else schedules
// |HandleDarkResumeHardTimeout|.
void HandleDarkResumeWakeLockCheckTimeout();
// Runs |kDarkResumeHardTimeout| time delta after a
// |HandleDarkResumeWakeLockCheckTimeout|. Clears all dark resume state and
// re-suspends the device.
void HandleDarkResumeHardTimeout();
// Clears all state associated with dark resume.
void ClearDarkResumeState();
ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager. ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager.
// If non-null, used instead of the process-wide connector to fetch services. // If non-null, used instead of the process-wide connector to fetch services.
...@@ -78,8 +120,21 @@ class ArcWakeLockBridge : public KeyedService, ...@@ -78,8 +120,21 @@ class ArcWakeLockBridge : public KeyedService,
std::map<device::mojom::WakeLockType, std::unique_ptr<WakeLockRequester>> std::map<device::mojom::WakeLockType, std::unique_ptr<WakeLockRequester>>
wake_lock_requesters_; wake_lock_requesters_;
// Called when system is ready to supend after a |DarkSupendImminent| i.e.
// after a dark resume.
base::OnceClosure suspend_readiness_cb_;
mojo::Binding<mojom::WakeLockHost> binding_; mojo::Binding<mojom::WakeLockHost> binding_;
// Used for checking if |DarkResumeWakeLockCheckTimeout| and
// |DarkResumeHardTimeout| run on the same sequence.
SEQUENCE_CHECKER(dark_resume_tasks_sequence_checker_);
// Factory used to schedule and cancel
// |HandleDarkResumeWakeLockCheckTimeout| and |HandleDarkResumeHardTimeout|.
// At any point either none or one of these tasks is in flight.
base::WeakPtrFactory<ArcWakeLockBridge> dark_resume_weak_ptr_factory_{this};
base::WeakPtrFactory<ArcWakeLockBridge> weak_ptr_factory_; base::WeakPtrFactory<ArcWakeLockBridge> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ArcWakeLockBridge); DISALLOW_COPY_AND_ASSIGN(ArcWakeLockBridge);
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_power_manager_client.h"
#include "components/arc/arc_bridge_service.h" #include "components/arc/arc_bridge_service.h"
#include "components/arc/common/power.mojom.h" #include "components/arc/common/power.mojom.h"
#include "components/arc/test/connection_holder_util.h" #include "components/arc/test/connection_holder_util.h"
...@@ -24,7 +26,9 @@ using device::mojom::WakeLockType; ...@@ -24,7 +26,9 @@ using device::mojom::WakeLockType;
class ArcWakeLockBridgeTest : public testing::Test { class ArcWakeLockBridgeTest : public testing::Test {
public: public:
ArcWakeLockBridgeTest() { ArcWakeLockBridgeTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME) {
auto wake_lock_provider_ptr = auto wake_lock_provider_ptr =
std::make_unique<device::TestWakeLockProvider>(); std::make_unique<device::TestWakeLockProvider>();
wake_lock_provider_ = wake_lock_provider_ptr.get(); wake_lock_provider_ = wake_lock_provider_ptr.get();
...@@ -34,6 +38,10 @@ class ArcWakeLockBridgeTest : public testing::Test { ...@@ -34,6 +38,10 @@ class ArcWakeLockBridgeTest : public testing::Test {
std::move(wake_lock_provider_ptr)); std::move(wake_lock_provider_ptr));
connector_ = connector_factory_->CreateConnector(); connector_ = connector_factory_->CreateConnector();
fake_power_manager_client_ = new chromeos::FakePowerManagerClient;
chromeos::DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient(
base::WrapUnique(fake_power_manager_client_));
bridge_service_ = std::make_unique<ArcBridgeService>(); bridge_service_ = std::make_unique<ArcBridgeService>();
wake_lock_bridge_ = wake_lock_bridge_ =
std::make_unique<ArcWakeLockBridge>(nullptr, bridge_service_.get()); std::make_unique<ArcWakeLockBridge>(nullptr, bridge_service_.get());
...@@ -44,6 +52,27 @@ class ArcWakeLockBridgeTest : public testing::Test { ...@@ -44,6 +52,27 @@ class ArcWakeLockBridgeTest : public testing::Test {
~ArcWakeLockBridgeTest() override { DestroyWakeLockInstance(); } ~ArcWakeLockBridgeTest() override { DestroyWakeLockInstance(); }
protected: protected:
// Creates a FakeWakeLockInstance for |bridge_service_|. This results in
// ArcWakeLockBridge::OnInstanceReady() being called.
void CreateWakeLockInstance() {
instance_ = std::make_unique<FakeWakeLockInstance>();
bridge_service_->wake_lock()->SetInstance(instance_.get());
WaitForInstanceReady(bridge_service_->wake_lock());
}
// Destroys the FakeWakeLockInstance. This results in
// ArcWakeLockBridge::OnInstanceClosed() being called.
void DestroyWakeLockInstance() {
if (!instance_)
return;
bridge_service_->wake_lock()->CloseInstance(instance_.get());
instance_.reset();
}
device::TestWakeLockProvider* GetWakeLockProvider() const {
return wake_lock_provider_;
}
// Returns true iff there is no failure acquiring a system wake lock. // Returns true iff there is no failure acquiring a system wake lock.
bool AcquirePartialWakeLock() { bool AcquirePartialWakeLock() {
base::RunLoop loop; base::RunLoop loop;
...@@ -66,30 +95,29 @@ class ArcWakeLockBridgeTest : public testing::Test { ...@@ -66,30 +95,29 @@ class ArcWakeLockBridgeTest : public testing::Test {
return result; return result;
} }
// Creates a FakeWakeLockInstance for |bridge_service_|. This results in // Return true iff all dark resume related state is set i.e the suspend
// ArcWakeLockBridge::OnInstanceReady() being called. // readiness callback is set and wake lock release event has observers.
void CreateWakeLockInstance() { bool IsDarkResumeStateSet() const {
instance_ = std::make_unique<FakeWakeLockInstance>(); return wake_lock_bridge_->IsSuspendReadinessStateSetForTesting() &&
bridge_service_->wake_lock()->SetInstance(instance_.get()); wake_lock_bridge_->WakeLockHasObserversForTesting(
WaitForInstanceReady(bridge_service_->wake_lock()); WakeLockType::kPreventAppSuspension);
}
// Destroys the FakeWakeLockInstance. This results in
// ArcWakeLockBridge::OnInstanceClosed() being called.
void DestroyWakeLockInstance() {
if (!instance_)
return;
bridge_service_->wake_lock()->CloseInstance(instance_.get());
instance_.reset();
} }
device::TestWakeLockProvider* GetWakeLockProvider() { // Return true iff all dark resume related state is reset. This should be true
return wake_lock_provider_; // when device exits dark resume either by re-suspending or transitioning to
// full resume.
bool IsDarkResumeStateReset() const {
return !wake_lock_bridge_->WakeLockHasObserversForTesting(
WakeLockType::kPreventAppSuspension) &&
!wake_lock_bridge_->IsSuspendReadinessStateSetForTesting();
} }
private:
base::test::ScopedTaskEnvironment scoped_task_environment_; base::test::ScopedTaskEnvironment scoped_task_environment_;
// Owned by chromeos::DBusThreadManager.
chromeos::FakePowerManagerClient* fake_power_manager_client_;
private:
std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_; std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
std::unique_ptr<service_manager::Connector> connector_; std::unique_ptr<service_manager::Connector> connector_;
device::TestWakeLockProvider* wake_lock_provider_; device::TestWakeLockProvider* wake_lock_provider_;
...@@ -155,4 +183,94 @@ TEST_F(ArcWakeLockBridgeTest, ReleaseWakeLockOnInstanceClosed) { ...@@ -155,4 +183,94 @@ TEST_F(ArcWakeLockBridgeTest, ReleaseWakeLockOnInstanceClosed) {
WakeLockType::kPreventAppSuspension)); WakeLockType::kPreventAppSuspension));
} }
TEST_F(ArcWakeLockBridgeTest, CheckSuspendAfterDarkResumeNoWakeLocksHeld) {
// Trigger a dark resume event, move time forward to trigger a wake lock check
// and check if a re-suspend happened if no wake locks were acquired.
fake_power_manager_client_->SendDarkSuspendImminent();
scoped_task_environment_.FastForwardBy(
ArcWakeLockBridge::kDarkResumeWakeLockCheckTimeout);
base::RunLoop run_loop;
run_loop.RunUntilIdle();
EXPECT_TRUE(IsDarkResumeStateReset());
// Trigger a dark resume event, acquire and release a wake lock and move time
// forward to trigger a wake lock check. The device should re-suspend in this
// case since no wake locks were held at the time of the wake lock check.
fake_power_manager_client_->SendDarkSuspendImminent();
EXPECT_TRUE(AcquirePartialWakeLock());
EXPECT_TRUE(ReleasePartialWakeLock());
scoped_task_environment_.FastForwardBy(
ArcWakeLockBridge::kDarkResumeWakeLockCheckTimeout);
base::RunLoop run_loop2;
run_loop2.RunUntilIdle();
EXPECT_TRUE(IsDarkResumeStateReset());
}
TEST_F(ArcWakeLockBridgeTest, CheckSuspendAfterDarkResumeWakeLocksHeld) {
// Trigger a dark resume event, acquire a wake lock and move time forward to a
// wake lock check. At this point the system shouldn't re-suspend i.e. the
// suspend readiness callback should be set and wake lock release should have
// observers.
fake_power_manager_client_->SendDarkSuspendImminent();
EXPECT_TRUE(AcquirePartialWakeLock());
scoped_task_environment_.FastForwardBy(
ArcWakeLockBridge::kDarkResumeWakeLockCheckTimeout);
base::RunLoop run_loop;
run_loop.RunUntilIdle();
EXPECT_TRUE(IsDarkResumeStateSet());
// Move time forward by < |kDarkResumeHardTimeout| and release the
// partial wake lock.This should instantaneously re-suspend the device.
scoped_task_environment_.FastForwardBy(
ArcWakeLockBridge::kDarkResumeHardTimeout -
base::TimeDelta::FromSeconds(1));
EXPECT_TRUE(ReleasePartialWakeLock());
base::RunLoop run_loop2;
run_loop2.RunUntilIdle();
EXPECT_TRUE(IsDarkResumeStateReset());
}
TEST_F(ArcWakeLockBridgeTest, CheckSuspendAfterDarkResumeHardTimeout) {
// Trigger a dark resume event, acquire a wake lock and move time forward to a
// wake lock check. At this point the system shouldn't re-suspend i.e. the
// suspend readiness callback should be set and wake lock release should have
// observers.
fake_power_manager_client_->SendDarkSuspendImminent();
EXPECT_TRUE(AcquirePartialWakeLock());
scoped_task_environment_.FastForwardBy(
ArcWakeLockBridge::kDarkResumeWakeLockCheckTimeout);
base::RunLoop run_loop;
run_loop.RunUntilIdle();
EXPECT_TRUE(IsDarkResumeStateSet());
// Move time forward by |kDarkResumeHardTimeout|. At this point the
// device should re-suspend even though the wake lock is acquired.
scoped_task_environment_.FastForwardBy(
ArcWakeLockBridge::kDarkResumeHardTimeout);
EXPECT_EQ(1, GetWakeLockProvider()->GetActiveWakeLocksOfType(
WakeLockType::kPreventAppSuspension));
base::RunLoop run_loop2;
run_loop2.RunUntilIdle();
EXPECT_TRUE(IsDarkResumeStateReset());
}
TEST_F(ArcWakeLockBridgeTest, CheckStateResetAfterSuspendDone) {
// Trigger a dark resume event, acquire a wake lock and move time forward to a
// wake lock check. At this point the system shouldn't re-suspend i.e. the
// suspend readiness callback should be set and wake lock release should have
// observers.
fake_power_manager_client_->SendDarkSuspendImminent();
EXPECT_TRUE(AcquirePartialWakeLock());
scoped_task_environment_.FastForwardBy(
ArcWakeLockBridge::kDarkResumeWakeLockCheckTimeout);
base::RunLoop run_loop;
run_loop.RunUntilIdle();
EXPECT_TRUE(IsDarkResumeStateSet());
// Trigger suspend done event. Check if state is reset as dark resume would be
// exited.
fake_power_manager_client_->SendSuspendDone();
EXPECT_TRUE(IsDarkResumeStateReset());
}
} // namespace arc } // namespace arc
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_ARC_WAKE_LOCK_WAKE_LOCK_OBSERVER_H_
#define COMPONENTS_ARC_WAKE_LOCK_WAKE_LOCK_OBSERVER_H_
namespace arc {
// This is an interface for classes that want to learn when Android wake locks
// are acquired or released. Observer should register themselves by calling the
// overriding class's AddObserver() method.
class WakeLockObserver {
public:
virtual ~WakeLockObserver() = default;
// Called when the tracked wake lock is acquired the first time i.e.
// number of holders increases to 1.
virtual void OnWakeLockAcquire() {}
// Called when the tracked wake lock is released the last time i.e. the number
// of holders goes to 0.
virtual void OnWakeLockRelease() {}
};
} // namespace arc
#endif // COMPONENTS_ARC_WAKE_LOCK_WAKE_LOCK_OBSERVER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment