blob: 7d1807977c40077edd7145d732b713e7f8d6b171 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/web_applications/locks/web_app_lock_manager.h"
#include <memory>
#include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_runner.h"
#include "chrome/browser/web_applications/locks/app_lock.h"
#include "chrome/browser/web_applications/locks/full_system_lock.h"
#include "chrome/browser/web_applications/locks/lock.h"
#include "chrome/browser/web_applications/locks/noop_lock.h"
#include "chrome/browser/web_applications/locks/shared_web_contents_lock.h"
#include "chrome/browser/web_applications/locks/shared_web_contents_with_app_lock.h"
#include "chrome/browser/web_applications/web_app_command_manager.h"
#include "chrome/browser/web_applications/web_app_id.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "components/services/storage/indexed_db/locks/partitioned_lock_id.h"
#include "components/services/storage/indexed_db/locks/partitioned_lock_manager.h"
namespace web_app {
namespace {
enum class LockLevel {
kStatic = 0,
kApp = 1,
kMaxValue = kApp,
};
enum KeysOnStaticLevel {
kFullSystem = 0,
kBackgroundWebContents = 1,
kNoOp = 2,
};
content::PartitionedLockManager::PartitionedLockRequest GetSystemLock(
content::PartitionedLockManager::LockType type) {
return content::PartitionedLockManager::PartitionedLockRequest(
content::PartitionedLockId(
{static_cast<int>(LockLevel::kStatic),
base::NumberToString(KeysOnStaticLevel::kFullSystem)}),
type);
}
content::PartitionedLockManager::PartitionedLockRequest
GetSharedWebContentsLock() {
return content::PartitionedLockManager::PartitionedLockRequest(
content::PartitionedLockId(
{static_cast<int>(LockLevel::kStatic),
base::NumberToString(KeysOnStaticLevel::kBackgroundWebContents)}),
content::PartitionedLockManager::LockType::kExclusive);
}
std::vector<content::PartitionedLockManager::PartitionedLockRequest>
GetAppIdLocks(const base::flat_set<AppId>& app_ids) {
std::vector<content::PartitionedLockManager::PartitionedLockRequest>
lock_requests;
for (const AppId& app_id : app_ids) {
lock_requests.emplace_back(
content::PartitionedLockId({static_cast<int>(LockLevel::kApp), app_id}),
content::PartitionedLockManager::LockType::kExclusive);
}
return lock_requests;
}
std::vector<content::PartitionedLockManager::PartitionedLockRequest>
GetLockRequestsForLock(const LockDescription& lock) {
std::vector<content::PartitionedLockManager::PartitionedLockRequest> requests;
switch (lock.type()) {
case LockDescription::Type::kNoOp:
requests = {
GetSystemLock(content::PartitionedLockManager::LockType::kShared)};
break;
case LockDescription::Type::kApp:
requests = GetAppIdLocks(lock.app_ids());
requests.push_back(
GetSystemLock(content::PartitionedLockManager::LockType::kShared));
break;
case LockDescription::Type::kAppAndWebContents:
requests = GetAppIdLocks(lock.app_ids());
ABSL_FALLTHROUGH_INTENDED;
case LockDescription::Type::kBackgroundWebContents:
requests.push_back(
GetSystemLock(content::PartitionedLockManager::LockType::kShared));
requests.push_back(GetSharedWebContentsLock());
break;
case LockDescription::Type::kFullSystem:
requests = {
GetSystemLock(content::PartitionedLockManager::LockType::kExclusive)};
break;
}
return requests;
}
} // namespace
WebAppLockManager::WebAppLockManager(WebAppProvider& provider)
: provider_(provider) {}
WebAppLockManager::~WebAppLockManager() = default;
bool WebAppLockManager::IsSharedWebContentsLockFree() {
return lock_manager_.TestLock(GetSharedWebContentsLock()) ==
content::PartitionedLockManager::TestLockResult::kFree;
}
void WebAppLockManager::AcquireLock(
base::WeakPtr<content::PartitionedLockHolder> holder,
LockDescription& lock_description,
base::OnceClosure on_lock_acquired) {
std::vector<content::PartitionedLockManager::PartitionedLockRequest>
requests = GetLockRequestsForLock(lock_description);
content::PartitionedLockManager::AcquireOptions options;
options.ensure_async = true;
lock_manager_.AcquireLocks(std::move(requests), holder,
std::move(on_lock_acquired), options);
}
template <>
void WebAppLockManager::AcquireLock(
LockDescription& lock_description,
base::OnceCallback<void(std::unique_ptr<NoopLock>)> on_lock_acquired) {
CHECK(lock_description.type() == LockDescription::Type::kNoOp);
auto lock = std::make_unique<NoopLock>(
std::make_unique<content::PartitionedLockHolder>());
base::WeakPtr<content::PartitionedLockHolder> holder =
lock->holder_->AsWeakPtr();
AcquireLock(holder, lock_description,
base::BindOnce(std::move(on_lock_acquired), std::move(lock)));
}
template <>
void WebAppLockManager::AcquireLock(
LockDescription& lock_description,
base::OnceCallback<void(std::unique_ptr<SharedWebContentsLock>)>
on_lock_acquired) {
CHECK(lock_description.type() ==
LockDescription::Type::kBackgroundWebContents);
auto lock = std::make_unique<SharedWebContentsLock>(
std::make_unique<content::PartitionedLockHolder>(),
*provider_->command_manager().EnsureWebContentsCreated(PassKey()));
base::WeakPtr<content::PartitionedLockHolder> holder =
lock->holder_->AsWeakPtr();
AcquireLock(holder, lock_description,
base::BindOnce(std::move(on_lock_acquired), std::move(lock)));
}
template <>
void WebAppLockManager::AcquireLock(
LockDescription& lock_description,
base::OnceCallback<void(std::unique_ptr<AppLock>)> on_lock_acquired) {
CHECK(lock_description.type() == LockDescription::Type::kApp);
auto lock = std::make_unique<AppLock>(
std::make_unique<content::PartitionedLockHolder>(),
provider_->registrar_unsafe(), provider_->sync_bridge_unsafe(),
provider_->install_finalizer(), provider_->os_integration_manager(),
provider_->install_manager(), provider_->icon_manager(),
provider_->translation_manager(), provider_->ui_manager());
base::WeakPtr<content::PartitionedLockHolder> holder =
lock->holder_->AsWeakPtr();
AcquireLock(holder, lock_description,
base::BindOnce(std::move(on_lock_acquired), std::move(lock)));
}
template <>
void WebAppLockManager::AcquireLock(
LockDescription& lock_description,
base::OnceCallback<void(std::unique_ptr<SharedWebContentsWithAppLock>)>
on_lock_acquired) {
CHECK(lock_description.type() == LockDescription::Type::kAppAndWebContents);
auto lock = std::make_unique<SharedWebContentsWithAppLock>(
std::make_unique<content::PartitionedLockHolder>(),
*provider_->command_manager().EnsureWebContentsCreated(PassKey()),
provider_->registrar_unsafe(), provider_->sync_bridge_unsafe(),
provider_->install_finalizer(), provider_->os_integration_manager(),
provider_->install_manager(), provider_->icon_manager(),
provider_->translation_manager(), provider_->ui_manager());
base::WeakPtr<content::PartitionedLockHolder> holder =
lock->holder_->AsWeakPtr();
AcquireLock(holder, lock_description,
base::BindOnce(std::move(on_lock_acquired), std::move(lock)));
}
template <>
void WebAppLockManager::AcquireLock(
LockDescription& lock_description,
base::OnceCallback<void(std::unique_ptr<FullSystemLock>)>
on_lock_acquired) {
CHECK(lock_description.type() == LockDescription::Type::kFullSystem);
auto lock = std::make_unique<FullSystemLock>(
std::make_unique<content::PartitionedLockHolder>(),
provider_->registrar_unsafe(), provider_->sync_bridge_unsafe(),
provider_->install_finalizer(), provider_->os_integration_manager(),
provider_->install_manager(), provider_->icon_manager(),
provider_->translation_manager(), provider_->ui_manager());
base::WeakPtr<content::PartitionedLockHolder> holder =
lock->holder_->AsWeakPtr();
AcquireLock(holder, lock_description,
base::BindOnce(std::move(on_lock_acquired), std::move(lock)));
}
std::unique_ptr<SharedWebContentsWithAppLockDescription>
WebAppLockManager::UpgradeAndAcquireLock(
std::unique_ptr<SharedWebContentsLock> lock,
const base::flat_set<AppId>& app_ids,
base::OnceCallback<void(std::unique_ptr<SharedWebContentsWithAppLock>)>
on_lock_acquired) {
std::unique_ptr<SharedWebContentsWithAppLockDescription>
result_lock_description =
std::make_unique<SharedWebContentsWithAppLockDescription>(app_ids);
auto result_lock = std::make_unique<SharedWebContentsWithAppLock>(
std::move(lock->holder_),
*provider_->command_manager().EnsureWebContentsCreated(PassKey()),
provider_->registrar_unsafe(), provider_->sync_bridge_unsafe(),
provider_->install_finalizer(), provider_->os_integration_manager(),
provider_->install_manager(), provider_->icon_manager(),
provider_->translation_manager(), provider_->ui_manager());
base::WeakPtr<content::PartitionedLockHolder> holder =
result_lock->holder_->AsWeakPtr();
content::PartitionedLockManager::AcquireOptions options;
options.ensure_async = true;
lock_manager_.AcquireLocks(
GetAppIdLocks(app_ids), holder,
base::BindOnce(std::move(on_lock_acquired), std::move(result_lock)),
options);
return result_lock_description;
}
std::unique_ptr<AppLockDescription> WebAppLockManager::UpgradeAndAcquireLock(
std::unique_ptr<NoopLock> lock,
const base::flat_set<AppId>& app_ids,
base::OnceCallback<void(std::unique_ptr<AppLock>)> on_lock_acquired) {
std::unique_ptr<AppLockDescription> result_lock_description =
std::make_unique<AppLockDescription>(app_ids);
auto result_lock = std::make_unique<AppLock>(
std::move(lock->holder_), provider_->registrar_unsafe(),
provider_->sync_bridge_unsafe(), provider_->install_finalizer(),
provider_->os_integration_manager(), provider_->install_manager(),
provider_->icon_manager(), provider_->translation_manager(),
provider_->ui_manager());
base::WeakPtr<content::PartitionedLockHolder> holder =
result_lock->holder_->AsWeakPtr();
// TODO(dmurph): Create option for lock acquisition callbacks to always be
// posted async. https://crbug.com/1354312
auto posted_callback = base::BindOnce(
base::IgnoreResult(&base::TaskRunner::PostTask),
base::SequencedTaskRunner::GetCurrentDefault(), FROM_HERE,
base::BindOnce(std::move(on_lock_acquired), std::move(result_lock)));
lock_manager_.AcquireLocks(GetAppIdLocks(app_ids), holder,
std::move(posted_callback));
return result_lock_description;
}
} // namespace web_app