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 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_FILE_SYSTEM_ACCESS_FILE_SYSTEM_ACCESS_LOCK_MANAGER_H_
#define CONTENT_BROWSER_FILE_SYSTEM_ACCESS_FILE_SYSTEM_ACCESS_LOCK_MANAGER_H_
#include <map>
#include <optional>
#include "base/files/file_path.h"
#include "base/memory/ref_counted_delete_on_sequence.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/types/id_type.h"
#include "base/types/pass_key.h"
#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
#include "content/common/content_export.h"
#include "content/public/browser/global_routing_id.h"
namespace storage {
class FileSystemURL;
} // namespace storage
namespace content {
class FileSystemAccessManagerImpl;
class Lock;
class RootLock;
// This class is in charge of the creation of Locks. Locks restrict the access
// to a specific file or directory, preventing unexpected concurrent access to
// data. It is owned by the FileSystemAccessManagerImpl.
class CONTENT_EXPORT FileSystemAccessLockManager
: public base::RefCountedDeleteOnSequence<FileSystemAccessLockManager> {
public:
class LockHandle;
using PassKey = base::PassKey<FileSystemAccessLockManager>;
// This type represents a locking type used to prevent other locking types
// from acquiring a lock.
using LockType = base::IdType32<class LockTypeTag>;
using TakeLockCallback = base::OnceCallback<void(scoped_refptr<LockHandle>)>;
// A handle to a `Lock` passed to the frame that holds the lock. The `Lock` is
// kept alive as long as there is some `LockHandle` to it.
class CONTENT_EXPORT LockHandle : public base::RefCounted<LockHandle> {
public:
LockHandle(LockHandle const&) = delete;
LockHandle& operator=(LockHandle const&) = delete;
const LockType& type() const { return type_; }
bool IsExclusive() const { return is_exclusive_; }
private:
friend class Lock;
friend class base::RefCounted<LockHandle>;
LockHandle(base::WeakPtr<Lock> lock,
scoped_refptr<LockHandle> parent_lock_handle,
const GlobalRenderFrameHostId& frame_id);
// On destruction, lets its `lock_` know it is no longer held.
~LockHandle();
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtr<Lock> lock_ GUARDED_BY_CONTEXT(sequence_checker_);
const LockType type_;
const bool is_exclusive_;
const scoped_refptr<LockHandle> parent_lock_handle_;
// The frame id of the associated render frame host that holds this lock
// handle.
const GlobalRenderFrameHostId frame_id_;
};
explicit FileSystemAccessLockManager(
base::PassKey<FileSystemAccessManagerImpl> pass_key);
FileSystemAccessLockManager(FileSystemAccessLockManager const&) = delete;
FileSystemAccessLockManager& operator=(FileSystemAccessLockManager const&) =
delete;
// Attempts to take a lock of `lock_type` on `url`. Passes a handle of the
// lock to `callback` if successful. The lock is released when there are no
// handles to it.
//
// `frame_id` is the `GlobalRenderFrameHostId` of the render frame host
// associated with the frame that holds this handle.
//
// If there is an existing lock that is in contention with the `lock_type`, it
// will evict pages that hold the existing lock if they are all inactive (e.g.
// in the BFCache).
void TakeLock(const GlobalRenderFrameHostId& frame_id,
const storage::FileSystemURL& url,
LockType lock_type,
TakeLockCallback callback);
// Returns true if there is not an existing lock on `url` that is contentious
// with `lock_type`.
//
// This may return `false` but the same arguments would succeed for `TakeLock`
// since `TakeLock` may evict pages to take the lock.
bool IsContentious(const storage::FileSystemURL& url, LockType lock_type);
// Creates a new shared lock type.
[[nodiscard]] LockType CreateSharedLockType();
// Gets the exclusive lock type.
[[nodiscard]] LockType GetExclusiveLockType();
// Gets the `ancestor_lock_type_` for testing.
[[nodiscard]] LockType GetAncestorLockTypeForTesting();
// Gets a weak pointer to `this` to test if its been destroyed.
[[nodiscard]] base::WeakPtr<FileSystemAccessLockManager>
GetWeakPtrForTesting();
private:
friend class base::DeleteHelper<FileSystemAccessLockManager>;
friend class base::RefCountedDeleteOnSequence<FileSystemAccessLockManager>;
friend RootLock;
~FileSystemAccessLockManager();
enum class EntryPathType {
// A path on the local file system. Files with these paths can be operated
// on by base::File.
kLocal,
// A path on an "external" file system. These paths can only be accessed via
// the filesystem abstraction in //storage/browser/file_system, and a
// storage::FileSystemURL of type storage::kFileSystemTypeExternal.
kExternal,
// A path from a sandboxed file system. These paths can be accessed by a
// storage::FileSystemURL of type storage::kFileSystemTypeTemporary.
kSandboxed,
};
struct RootLocator {
static RootLocator FromFileSystemURL(const storage::FileSystemURL& url);
RootLocator(const EntryPathType& type,
const std::optional<storage::BucketLocator>& bucket_locator);
RootLocator(const RootLocator&);
~RootLocator();
bool operator<(const RootLocator& other) const;
const EntryPathType type;
// Non-null iff `type` is kSandboxed.
const std::optional<storage::BucketLocator> bucket_locator;
};
// Releases the root lock for `root_locator`. Called from the RootLock.
void ReleaseRoot(const RootLocator& root_locator);
RootLock* GetRootLock(const RootLocator& root_locator);
RootLock* GetOrCreateRootLock(const RootLocator& root_locator);
SEQUENCE_CHECKER(sequence_checker_);
std::map<RootLocator, std::unique_ptr<RootLock>> root_locks_
GUARDED_BY_CONTEXT(sequence_checker_);
LockType::Generator lock_type_generator_;
LockType exclusive_lock_type_ = lock_type_generator_.GenerateNextId();
// The shared lock type that the lock manager uses to lock ancestors of locked
// entry locators. Should not be used outside of the lock manager or testing.
LockType ancestor_lock_type_ = lock_type_generator_.GenerateNextId();
base::WeakPtrFactory<FileSystemAccessLockManager> weak_factory_
GUARDED_BY_CONTEXT(sequence_checker_){this};
};
} // namespace content
#endif // CONTENT_BROWSER_FILE_SYSTEM_ACCESS_FILE_SYSTEM_ACCESS_LOCK_MANAGER_H_
|