blob: 38e02c834ac7126c7f437634347c8e1d48f5a888 [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.
#ifndef CHROME_BROWSER_WEB_APPLICATIONS_LOCKS_WEB_APP_LOCK_MANAGER_H_
#define CHROME_BROWSER_WEB_APPLICATIONS_LOCKS_WEB_APP_LOCK_MANAGER_H_
#include <memory>
#include "base/containers/flat_set.h"
#include "base/functional/callback_forward.h"
#include "base/location.h"
#include "base/memory/raw_ref.h"
#include "base/memory/weak_ptr.h"
#include "base/types/pass_key.h"
#include "chrome/browser/web_applications/locks/partitioned_lock_manager.h"
#include "components/webapps/common/web_app_id.h"
namespace base {
class Value;
}
namespace web_app {
class AppLock;
class AppLockDescription;
class LockDescription;
class NoopLock;
class SharedWebContentsLock;
class SharedWebContentsWithAppLock;
class SharedWebContentsWithAppLockDescription;
class WebAppCommandManager;
class WebAppProvider;
// Locks allow types of exclusive access to resources in the WebAppProvider
// system, depending on the lock. These are not for multi-sequence access, but
// instead required due to the async nature of operations in the system. Locks
// do NOT protect against common problems like handling profile shutdown. In
// fact, locks will CHECK-fail if they are called accessed during profile
// shutdown. Thus using a WebAppCommand is a better option, as commands are
// destroyed automatically during shutdown.
//
// Locks can be a great way to make synchronous operations composable. For
// example, the following method call guarantees that it is done in an isolated
// context:
//
// void UpdateWidget(WithAppResources& lock_with_app_exclusivity, webapps::AppId
// id) {
// widget_.SetTitle(lock_with_app_exclusivity.registrar().GetShortName(id));
// ...
// }
//
// To access data across an async call chain, then
// 1) The brokering of the lock needs to be done through a command to make sure
// shutdown is handled.
// 2) a WeakPtr of the lock can be used so the async logic can correctly handle
// this shutdown.
//
// Example of using a lock across an async boundary:
//
// void UpdateWidget(base::WeakPtr<WithAppResources> lock_with_app_exclusivity,
// webapps::AppId id) {
// widget_.SetTitle(lock_with_app_exclusivity.registrar().GetShortName(id));
// TalkToAsyncSystem(..., base::BindOnce(&OnAsyncSystemUpdated,
// lock_with_app_exclusivity));
// }
//
// void OnAsyncSystemUpdated(base::WeakPtr<WithAppResources>
// lock_with_app_exclusivity) {
// if (!lock_with_app_exclusivity) {
// // Do cleanup?
// return;
// }
// ... do things with the lock.
// }
class WebAppLockManager {
public:
using PassKey = base::PassKey<WebAppLockManager>;
WebAppLockManager();
~WebAppLockManager();
void SetProvider(base::PassKey<WebAppCommandManager>,
WebAppProvider& provider);
// Returns if the lock for the shared web contents is free. This means no one
// is using the shared web contents.
bool IsSharedWebContentsLockFree();
// Acquires the lock for the given `lock_description` and `lock`. The `lock`
// must be owned by the caller, and when the lock is destroyed the request
// and/or internal locks are released. `on_lock_acquired` is called when the
// lock is granted. Any access of the `lock` before `on_lock_acquired` is
// called will CHECK-fail.
// TODO(crbug.com/371221610): Move the lock description to be owned by the
// lock.
template <class LockType>
void AcquireLock(const LockType::LockDescription& lock_description,
LockType& lock,
base::OnceClosure on_lock_acquired,
const base::Location& location);
// Upgrades the given lock to a new one, and will call `on_lock_acquired` on
// when the new lock has been acquired.
std::unique_ptr<SharedWebContentsWithAppLockDescription>
UpgradeAndAcquireLock(std::unique_ptr<SharedWebContentsLock> old_lock,
SharedWebContentsWithAppLock& new_lock,
const base::flat_set<webapps::AppId>& app_ids,
base::OnceClosure on_lock_acquired,
const base::Location& location = FROM_HERE);
// Upgrades the given lock to a new one, and will call `on_lock_acquired` on
// when the new lock has been acquired.
std::unique_ptr<AppLockDescription> UpgradeAndAcquireLock(
std::unique_ptr<NoopLock> old_lock,
AppLock& new_lock,
const base::flat_set<webapps::AppId>& app_ids,
base::OnceClosure on_lock_acquired,
const base::Location& location = FROM_HERE);
base::Value ToDebugValue() const;
WebAppProvider& provider() const { return *provider_; }
base::WeakPtr<WebAppLockManager> GetWeakPtr();
private:
// Method used to call `GrantLock` function on the lock, after the
// `lock_manager_` has granted the locks.
// Note: `lock` is guaranteed to be populated, as otherwise the 'holder' for
// the lock will be destroyed, and then this callback is never called.
template <class LockType>
void GrantLock(base::WeakPtr<LockType> lock);
// Acquires the lock for the given `lock`, calling `on_lock_acquired` when
// complete.
void AcquireLockImpl(PartitionedLockHolder& holder,
const LockDescription& lock,
base::OnceClosure on_lock_acquired,
const base::Location& location);
PartitionedLockManager lock_manager_;
raw_ptr<WebAppProvider> provider_ = nullptr;
base::WeakPtrFactory<WebAppLockManager> weak_factory_{this};
};
} // namespace web_app
#endif // CHROME_BROWSER_WEB_APPLICATIONS_LOCKS_WEB_APP_LOCK_MANAGER_H_