#include "services/device/wake_lock/wake_lock_provider.h"
#include <memory>
#include <string>
#include <utility>
#include "base/task/single_thread_task_runner.h"
#include "mojo/public/cpp/bindings/remote_set.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "services/device/wake_lock/wake_lock.h"
#include "services/device/wake_lock/wake_lock_context.h"
#include "services/device/wake_lock/wake_lock_features.h"
namespace device {
struct WakeLockProvider::WakeLockDataPerType {
WakeLockDataPerType() = default;
WakeLockDataPerType(const WakeLockDataPerType&) = delete;
WakeLockDataPerType& operator=(const WakeLockDataPerType&) = delete;
~WakeLockDataPerType() = default;
int64_t count = 0;
std::map<WakeLock*, std::unique_ptr<WakeLock>> wake_locks;
mojo::RemoteSet<mojom::WakeLockObserver> observers;
};
WakeLockProvider::WakeLockProvider(
scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
const WakeLockContextCallback& native_view_getter)
: file_task_runner_(std::move(file_task_runner)),
native_view_getter_(native_view_getter) {
wake_lock_store_[mojom::WakeLockType::kPreventAppSuspension] =
std::make_unique<WakeLockDataPerType>();
wake_lock_store_[mojom::WakeLockType::kPreventDisplaySleep] =
std::make_unique<WakeLockDataPerType>();
wake_lock_store_[mojom::WakeLockType::kPreventDisplaySleepAllowDimming] =
std::make_unique<WakeLockDataPerType>();
}
WakeLockProvider::~WakeLockProvider() {
if (base::FeatureList::IsEnabled(features::kRemoveWakeLockInDestructor)) {
for (auto& wake_lock_data : wake_lock_store_) {
GetWakeLockDataPerType(wake_lock_data.first).wake_locks.clear();
}
}
}
void WakeLockProvider::AddBinding(
mojo::PendingReceiver<mojom::WakeLockProvider> receiver) {
receivers_.Add(this, std::move(receiver));
}
void WakeLockProvider::GetWakeLockContextForID(
int context_id,
mojo::PendingReceiver<mojom::WakeLockContext> receiver) {
DCHECK_GE(context_id, 0);
mojo::MakeSelfOwnedReceiver(
std::make_unique<WakeLockContext>(context_id, file_task_runner_,
native_view_getter_),
std::move(receiver));
}
void WakeLockProvider::GetWakeLockWithoutContext(
mojom::WakeLockType type,
mojom::WakeLockReason reason,
const std::string& description,
mojo::PendingReceiver<mojom::WakeLock> receiver) {
std::unique_ptr<WakeLock> wake_lock = std::make_unique<WakeLock>(
std::move(receiver), type, reason, description,
WakeLockContext::WakeLockInvalidContextId, native_view_getter_, this);
WakeLock* const key = wake_lock.get();
GetWakeLockDataPerType(type).wake_locks[key] = std::move(wake_lock);
}
void WakeLockProvider::NotifyOnWakeLockDeactivation(
mojom::WakeLockType type,
mojo::PendingRemote<mojom::WakeLockObserver> pending_observer) {
mojo::Remote<mojom::WakeLockObserver> observer(std::move(pending_observer));
if (GetWakeLockDataPerType(type).count == 0) {
observer->OnWakeLockDeactivated(type);
}
GetWakeLockDataPerType(type).observers.Add(std::move(observer));
}
void WakeLockProvider::GetActiveWakeLocksForTests(
mojom::WakeLockType type,
GetActiveWakeLocksForTestsCallback callback) {
std::move(callback).Run(GetWakeLockDataPerType(type).count);
}
void WakeLockProvider::OnWakeLockActivated(mojom::WakeLockType type) {
DVLOG(1) << __func__;
const int64_t old_count = GetWakeLockDataPerType(type).count;
DCHECK_GE(old_count, 0);
GetWakeLockDataPerType(type).count = old_count + 1;
}
void WakeLockProvider::OnWakeLockDeactivated(mojom::WakeLockType type) {
DVLOG(1) << __func__;
const int64_t old_count = GetWakeLockDataPerType(type).count;
DCHECK_GT(old_count, 0);
const int64_t new_count = old_count - 1;
GetWakeLockDataPerType(type).count = new_count;
if (new_count == 0) {
for (auto& observer : GetWakeLockDataPerType(type).observers) {
observer->OnWakeLockDeactivated(type);
}
}
}
void WakeLockProvider::OnWakeLockChanged(mojom::WakeLockType old_type,
mojom::WakeLockType new_type) {
OnWakeLockDeactivated(old_type);
OnWakeLockActivated(new_type);
}
void WakeLockProvider::OnConnectionError(mojom::WakeLockType type,
WakeLock* wake_lock) {
size_t result = GetWakeLockDataPerType(type).wake_locks.erase(wake_lock);
DCHECK_GT(result, 0UL);
}
WakeLockProvider::WakeLockDataPerType& WakeLockProvider::GetWakeLockDataPerType(
mojom::WakeLockType type) {
auto it = wake_lock_store_.find(type);
CHECK(it != wake_lock_store_.end());
return *(it->second);
}
}