1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
// 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_
|