#include <map>
#include <utility>
#include "base/functional/bind.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/device_service_test_base.h"
#include "services/device/public/mojom/wake_lock.mojom.h"
#include "services/device/public/mojom/wake_lock_provider.mojom.h"
namespace device {
namespace {
class TestWakeLockObserver : public mojom::WakeLockObserver {
public:
TestWakeLockObserver() {
wake_lock_events_.emplace(mojom::WakeLockType::kPreventAppSuspension,
EventCount());
wake_lock_events_.emplace(mojom::WakeLockType::kPreventDisplaySleep,
EventCount());
wake_lock_events_.emplace(
mojom::WakeLockType::kPreventDisplaySleepAllowDimming, EventCount());
}
TestWakeLockObserver(const TestWakeLockObserver&) = delete;
TestWakeLockObserver& operator=(const TestWakeLockObserver&) = delete;
~TestWakeLockObserver() override = default;
void AddReceiver(mojo::PendingReceiver<mojom::WakeLockObserver> receiver) {
receivers_.Add(this, std::move(receiver));
}
void OnWakeLockDeactivated(mojom::WakeLockType type) override {
wake_lock_events_[type].on_deactivation_count++;
}
int64_t GetOnDeactivationCount(mojom::WakeLockType type) {
DCHECK(wake_lock_events_.find(type) != wake_lock_events_.end());
return wake_lock_events_[type].on_deactivation_count;
}
private:
struct EventCount {
int64_t on_activation_count = 0;
int64_t on_deactivation_count = 0;
};
mojo::ReceiverSet<mojom::WakeLockObserver> receivers_;
std::map<mojom::WakeLockType, EventCount> wake_lock_events_;
};
class WakeLockTest : public DeviceServiceTestBase {
public:
WakeLockTest() = default;
WakeLockTest(const WakeLockTest&) = delete;
WakeLockTest& operator=(const WakeLockTest&) = delete;
~WakeLockTest() override = default;
protected:
void SetUp() override {
DeviceServiceTestBase::SetUp();
device_service()->BindWakeLockProvider(
wake_lock_provider_.BindNewPipeAndPassReceiver());
wake_lock_provider_->GetWakeLockWithoutContext(
mojom::WakeLockType::kPreventAppSuspension,
mojom::WakeLockReason::kOther, "WakeLockTest",
wake_lock_.BindNewPipeAndPassReceiver());
}
void OnChangeType(base::OnceClosure quit_closure, bool result) {
result_ = result;
std::move(quit_closure).Run();
}
void OnHasWakeLock(base::OnceClosure quit_closure, bool has_wakelock) {
has_wakelock_ = has_wakelock;
std::move(quit_closure).Run();
}
bool ChangeType(mojom::WakeLockType type) {
result_ = false;
base::RunLoop run_loop;
wake_lock_->ChangeType(
type, base::BindOnce(&WakeLockTest::OnChangeType,
base::Unretained(this), run_loop.QuitClosure()));
run_loop.Run();
return result_;
}
bool HasWakeLock() {
has_wakelock_ = false;
base::RunLoop run_loop;
wake_lock_->HasWakeLockForTests(base::BindOnce(&WakeLockTest::OnHasWakeLock,
base::Unretained(this),
run_loop.QuitClosure()));
run_loop.Run();
return has_wakelock_;
}
int GetActiveWakeLocks(mojom::WakeLockType type) {
base::RunLoop run_loop;
int result_count = 0;
wake_lock_provider_->GetActiveWakeLocksForTests(
type,
base::BindOnce(
[](base::RunLoop* run_loop, int* result_count, int32_t count) {
*result_count = count;
run_loop->Quit();
},
&run_loop, &result_count));
run_loop.Run();
return result_count;
}
bool has_wakelock_;
bool result_;
mojo::Remote<device::mojom::WakeLockProvider> wake_lock_provider_;
mojo::Remote<mojom::WakeLock> wake_lock_;
};
TEST_F(WakeLockTest, RequestThenCancel) {
EXPECT_FALSE(HasWakeLock());
wake_lock_->RequestWakeLock();
EXPECT_TRUE(HasWakeLock());
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_->CancelWakeLock();
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
}
TEST_F(WakeLockTest, CancelThenRequest) {
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_->CancelWakeLock();
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_->RequestWakeLock();
EXPECT_TRUE(HasWakeLock());
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_->CancelWakeLock();
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
}
TEST_F(WakeLockTest, MultipleRequests) {
EXPECT_FALSE(HasWakeLock());
wake_lock_->RequestWakeLock();
wake_lock_->RequestWakeLock();
wake_lock_->RequestWakeLock();
EXPECT_TRUE(HasWakeLock());
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_->CancelWakeLock();
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
}
TEST_F(WakeLockTest, ChangeType) {
EXPECT_FALSE(HasWakeLock());
#if !BUILDFLAG(IS_ANDROID)
EXPECT_TRUE(ChangeType(device::mojom::WakeLockType::kPreventAppSuspension));
EXPECT_TRUE(ChangeType(device::mojom::WakeLockType::kPreventDisplaySleep));
EXPECT_TRUE(ChangeType(
device::mojom::WakeLockType::kPreventDisplaySleepAllowDimming));
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventDisplaySleep));
EXPECT_EQ(0, GetActiveWakeLocks(
mojom::WakeLockType::kPreventDisplaySleepAllowDimming));
wake_lock_->RequestWakeLock();
EXPECT_TRUE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventDisplaySleep));
EXPECT_EQ(1, GetActiveWakeLocks(
mojom::WakeLockType::kPreventDisplaySleepAllowDimming));
EXPECT_TRUE(ChangeType(device::mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventDisplaySleep));
EXPECT_EQ(0, GetActiveWakeLocks(
mojom::WakeLockType::kPreventDisplaySleepAllowDimming));
EXPECT_TRUE(ChangeType(device::mojom::WakeLockType::kPreventDisplaySleep));
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventDisplaySleep));
EXPECT_EQ(0, GetActiveWakeLocks(
mojom::WakeLockType::kPreventDisplaySleepAllowDimming));
EXPECT_TRUE(ChangeType(
device::mojom::WakeLockType::kPreventDisplaySleepAllowDimming));
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventDisplaySleep));
EXPECT_EQ(1, GetActiveWakeLocks(
mojom::WakeLockType::kPreventDisplaySleepAllowDimming));
EXPECT_TRUE(HasWakeLock());
wake_lock_->RequestWakeLock();
wake_lock_->RequestWakeLock();
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventDisplaySleep));
EXPECT_EQ(1, GetActiveWakeLocks(
mojom::WakeLockType::kPreventDisplaySleepAllowDimming));
mojo::Remote<mojom::WakeLock> wake_lock_1;
wake_lock_->AddClient(wake_lock_1.BindNewPipeAndPassReceiver());
EXPECT_FALSE(ChangeType(device::mojom::WakeLockType::kPreventAppSuspension));
wake_lock_->CancelWakeLock();
wake_lock_1->CancelWakeLock();
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventDisplaySleep));
EXPECT_EQ(0, GetActiveWakeLocks(
mojom::WakeLockType::kPreventDisplaySleepAllowDimming));
#else
EXPECT_FALSE(ChangeType(device::mojom::WakeLockType::kPreventAppSuspension));
EXPECT_FALSE(ChangeType(device::mojom::WakeLockType::kPreventDisplaySleep));
EXPECT_FALSE(ChangeType(
device::mojom::WakeLockType::kPreventDisplaySleepAllowDimming));
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventDisplaySleep));
EXPECT_EQ(0, GetActiveWakeLocks(
mojom::WakeLockType::kPreventDisplaySleepAllowDimming));
#endif
}
TEST_F(WakeLockTest, OnWakeLockProviderConnectionError) {
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_->RequestWakeLock();
EXPECT_TRUE(HasWakeLock());
int32_t count =
GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension);
EXPECT_EQ(1, count);
wake_lock_provider_.reset();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(HasWakeLock());
device_service()->BindWakeLockProvider(
wake_lock_provider_.BindNewPipeAndPassReceiver());
EXPECT_EQ(count,
GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_->CancelWakeLock();
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
}
TEST_F(WakeLockTest, MultipleClients) {
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
mojo::Remote<mojom::WakeLock> wake_lock_1;
mojo::Remote<mojom::WakeLock> wake_lock_2;
mojo::Remote<mojom::WakeLock> wake_lock_3;
wake_lock_->AddClient(wake_lock_1.BindNewPipeAndPassReceiver());
wake_lock_->AddClient(wake_lock_2.BindNewPipeAndPassReceiver());
wake_lock_->AddClient(wake_lock_3.BindNewPipeAndPassReceiver());
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_1->RequestWakeLock();
wake_lock_2->RequestWakeLock();
wake_lock_3->RequestWakeLock();
EXPECT_TRUE(HasWakeLock());
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_1->CancelWakeLock();
wake_lock_2->CancelWakeLock();
EXPECT_TRUE(HasWakeLock());
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_3->CancelWakeLock();
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
}
TEST_F(WakeLockTest, OnWakeLockConnectionError) {
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
mojo::Remote<mojom::WakeLock> wake_lock_1;
mojo::Remote<mojom::WakeLock> wake_lock_2;
mojo::Remote<mojom::WakeLock> wake_lock_3;
wake_lock_->AddClient(wake_lock_1.BindNewPipeAndPassReceiver());
wake_lock_->AddClient(wake_lock_2.BindNewPipeAndPassReceiver());
wake_lock_->AddClient(wake_lock_3.BindNewPipeAndPassReceiver());
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_1->RequestWakeLock();
wake_lock_2->RequestWakeLock();
wake_lock_3->RequestWakeLock();
EXPECT_TRUE(HasWakeLock());
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_1.reset();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(HasWakeLock());
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_2.reset();
wake_lock_3.reset();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
}
TEST_F(WakeLockTest, MixedTest) {
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
mojo::Remote<mojom::WakeLock> wake_lock_1;
mojo::Remote<mojom::WakeLock> wake_lock_2;
mojo::Remote<mojom::WakeLock> wake_lock_3;
wake_lock_->AddClient(wake_lock_1.BindNewPipeAndPassReceiver());
wake_lock_->AddClient(wake_lock_2.BindNewPipeAndPassReceiver());
wake_lock_->AddClient(wake_lock_3.BindNewPipeAndPassReceiver());
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_1->RequestWakeLock();
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_1->CancelWakeLock();
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_2->RequestWakeLock();
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_1->RequestWakeLock();
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_1->RequestWakeLock();
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_3->CancelWakeLock();
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_3->CancelWakeLock();
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_2->CancelWakeLock();
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_3->RequestWakeLock();
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_2.reset();
EXPECT_TRUE(HasWakeLock());
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_1.reset();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(HasWakeLock());
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
wake_lock_3->CancelWakeLock();
EXPECT_FALSE(HasWakeLock());
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
}
TEST_F(WakeLockTest, SameWakeLockTypeObserverTest) {
mojo::PendingRemote<mojom::WakeLockObserver> observer;
TestWakeLockObserver test_wake_lock_observer;
test_wake_lock_observer.AddReceiver(
observer.InitWithNewPipeAndPassReceiver());
wake_lock_provider_->NotifyOnWakeLockDeactivation(
mojom::WakeLockType::kPreventAppSuspension, std::move(observer));
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(1, test_wake_lock_observer.GetOnDeactivationCount(
mojom::WakeLockType::kPreventAppSuspension));
wake_lock_->RequestWakeLock();
wake_lock_->RequestWakeLock();
wake_lock_.FlushForTesting();
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(1, test_wake_lock_observer.GetOnDeactivationCount(
mojom::WakeLockType::kPreventAppSuspension));
mojo::Remote<mojom::WakeLock> wake_lock2;
wake_lock_provider_->GetWakeLockWithoutContext(
device::mojom::WakeLockType::kPreventAppSuspension,
device::mojom::WakeLockReason::kOther, "WakeLockTest",
wake_lock2.BindNewPipeAndPassReceiver());
wake_lock2->RequestWakeLock();
wake_lock2.FlushForTesting();
EXPECT_EQ(2, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(1, test_wake_lock_observer.GetOnDeactivationCount(
mojom::WakeLockType::kPreventAppSuspension));
wake_lock_->CancelWakeLock();
wake_lock_.FlushForTesting();
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(1, test_wake_lock_observer.GetOnDeactivationCount(
mojom::WakeLockType::kPreventAppSuspension));
base::RunLoop run_loop4;
wake_lock2.reset();
run_loop4.RunUntilIdle();
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(2, test_wake_lock_observer.GetOnDeactivationCount(
mojom::WakeLockType::kPreventAppSuspension));
base::RunLoop run_loop5;
wake_lock_.reset();
run_loop5.RunUntilIdle();
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(2, test_wake_lock_observer.GetOnDeactivationCount(
mojom::WakeLockType::kPreventAppSuspension));
}
TEST_F(WakeLockTest, DifferentWakeLockTypesObserverTest) {
mojo::PendingRemote<mojom::WakeLockObserver> observer;
TestWakeLockObserver test_wake_lock_observer;
test_wake_lock_observer.AddReceiver(
observer.InitWithNewPipeAndPassReceiver());
wake_lock_provider_->NotifyOnWakeLockDeactivation(
mojom::WakeLockType::kPreventAppSuspension, std::move(observer));
observer.reset();
test_wake_lock_observer.AddReceiver(
observer.InitWithNewPipeAndPassReceiver());
wake_lock_provider_->NotifyOnWakeLockDeactivation(
mojom::WakeLockType::kPreventDisplaySleep, std::move(observer));
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventDisplaySleep));
EXPECT_EQ(1, test_wake_lock_observer.GetOnDeactivationCount(
mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(1, test_wake_lock_observer.GetOnDeactivationCount(
mojom::WakeLockType::kPreventDisplaySleep));
mojo::Remote<mojom::WakeLock> wake_lock2;
wake_lock_provider_->GetWakeLockWithoutContext(
device::mojom::WakeLockType::kPreventDisplaySleep,
device::mojom::WakeLockReason::kOther, "WakeLockTest",
wake_lock2.BindNewPipeAndPassReceiver());
wake_lock_->RequestWakeLock();
wake_lock2->RequestWakeLock();
wake_lock_.FlushForTesting();
wake_lock2.FlushForTesting();
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(1, GetActiveWakeLocks(mojom::WakeLockType::kPreventDisplaySleep));
EXPECT_EQ(1, test_wake_lock_observer.GetOnDeactivationCount(
mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(1, test_wake_lock_observer.GetOnDeactivationCount(
mojom::WakeLockType::kPreventDisplaySleep));
base::RunLoop run_loop2;
wake_lock_.reset();
wake_lock2.reset();
run_loop2.RunUntilIdle();
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(0, GetActiveWakeLocks(mojom::WakeLockType::kPreventDisplaySleep));
EXPECT_EQ(2, test_wake_lock_observer.GetOnDeactivationCount(
mojom::WakeLockType::kPreventAppSuspension));
EXPECT_EQ(2, test_wake_lock_observer.GetOnDeactivationCount(
mojom::WakeLockType::kPreventDisplaySleep));
}
}
}