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 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
|
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef STORAGE_BROWSER_BLOB_BLOB_STORAGE_CONTEXT_H_
#define STORAGE_BROWSER_BLOB_BLOB_STORAGE_CONTEXT_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/component_export.h"
#include "base/files/file_path.h"
#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/trace_event/memory_dump_provider.h"
#include "components/services/storage/public/mojom/blob_storage_context.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "storage/browser/blob/blob_entry.h"
#include "storage/browser/blob/blob_memory_controller.h"
#include "storage/browser/blob/blob_storage_constants.h"
#include "storage/browser/blob/blob_storage_registry.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
namespace content {
class ChromeBlobStorageContext;
namespace indexed_db_backing_store_unittest {
class BlobStorageContextShim;
} // namespace indexed_db_backing_store_unittest
} // namespace content
namespace storage {
class BlobDataBuilder;
class BlobDataHandle;
class BlobDataSnapshot;
class ShareableBlobDataItem;
// This class handles the logistics of blob storage within the browser process.
// This class is not threadsafe, access on IO thread. In Chromium there is one
// instance per profile.
class COMPONENT_EXPORT(STORAGE_BROWSER) BlobStorageContext
: public base::trace_event::MemoryDumpProvider,
public mojom::BlobStorageContext {
public:
using TransportAllowedCallback = BlobEntry::TransportAllowedCallback;
using BuildAbortedCallback = BlobEntry::BuildAbortedCallback;
// Initializes the context without disk support.
BlobStorageContext();
// Disk support is enabled if |file_runner| isn't null.
BlobStorageContext(const base::FilePath& profile_directory,
const base::FilePath& blob_storage_directory,
scoped_refptr<base::TaskRunner> file_runner);
BlobStorageContext(const BlobStorageContext&) = delete;
BlobStorageContext& operator=(const BlobStorageContext&) = delete;
~BlobStorageContext() override;
// The following three methods all lookup a BlobDataHandle based on some
// input. If no blob matching the input exists these methods return null.
std::unique_ptr<BlobDataHandle> GetBlobDataFromUUID(const std::string& uuid);
// If this BlobStorageContext is deleted before this method finishes, the
// callback will still be called with null.
void GetBlobDataFromBlobRemote(
mojo::PendingRemote<blink::mojom::Blob> blob,
base::OnceCallback<void(std::unique_ptr<BlobDataHandle>)> callback);
// Always returns a handle to a blob. Use BlobStatus::GetBlobStatus() and
// BlobStatus::RunOnConstructionComplete(callback) to determine construction
// completion and possible errors.
std::unique_ptr<BlobDataHandle> AddFinishedBlob(
std::unique_ptr<BlobDataBuilder> builder);
std::unique_ptr<BlobDataHandle> AddFinishedBlob(
const std::string& uuid,
const std::string& content_type,
const std::string& content_disposition,
std::vector<scoped_refptr<ShareableBlobDataItem>> items);
std::unique_ptr<BlobDataHandle> AddBrokenBlob(
const std::string& uuid,
const std::string& content_type,
const std::string& content_disposition,
BlobStatus reason);
size_t blob_count() const { return registry_.blob_count(); }
const BlobStorageRegistry& registry() { return registry_; }
// This builds a blob with the given |input_builder| and returns a handle to
// the constructed Blob. Blob metadata and data should be accessed through
// this handle.
// If there is data present that needs further population then we will call
// |transport_allowed_callback| when we're ready for the user data to be
// populated with the PENDING_DATA_POPULATION status. This can happen
// synchronously or asynchronously. Otherwise |transport_allowed_callback|
// should be null. In the further population case, the caller must call either
// NotifyTransportComplete or CancelBuildingBlob after
// |transport_allowed_callback| is called to signify the data is finished
// populating or an error occurred (respectively).
// If the returned handle is broken, then the possible error cases are:
// * OUT_OF_MEMORY if we don't have enough memory to store the blob,
// * REFERENCED_BLOB_BROKEN if a referenced blob is broken or we're
// referencing ourself.
std::unique_ptr<BlobDataHandle> BuildBlob(
std::unique_ptr<BlobDataBuilder> input_builder,
TransportAllowedCallback transport_allowed_callback);
// Similar to BuildBlob, but this merely registers a blob that will be built
// in the future. The caller must later call either BuildPreregisteredBlob
// (to actually start building the blob), or CancelBuildingBlob (if an error
// occured).
// The returned BlobDataHandle (as well as any handles returned by
// GetBlobDataFromUUID before BuildPreregisteredBlob is called) will always
// have kUnknownSize for its size. A BlobDataHandle with the correct size is
// later returned by BuildPreregisteredBlob.
std::unique_ptr<BlobDataHandle> AddFutureBlob(
const std::string& uuid,
const std::string& content_type,
const std::string& content_disposition,
BuildAbortedCallback build_aborted_callback);
// Same as BuildBlob, but for a blob that was previously registered by calling
// AddFutureBlob.
std::unique_ptr<BlobDataHandle> BuildPreregisteredBlob(
std::unique_ptr<BlobDataBuilder> input_builder,
TransportAllowedCallback transport_allowed_callback);
// This breaks a blob that is currently being built by using the BuildBlob
// method above. Any callbacks waiting on this blob, including the
// |transport_allowed_callback| callback given to BuildBlob, will be called
// with this status code.
void CancelBuildingBlob(const std::string& uuid, BlobStatus code);
// After calling BuildBlob above, the caller should call this method to
// notify the construction system that the unpopulated data in the given blob
// has been. populated. Caller must have all pending items populated in the
// original builder |input_builder| given in BuildBlob or we'll check-fail.
// If there is no pending data in the |input_builder| for the BuildBlob call,
// then this method doesn't need to be called.
void NotifyTransportComplete(const std::string& uuid);
const BlobMemoryController& memory_controller() { return memory_controller_; }
base::WeakPtr<BlobStorageContext> AsWeakPtr() {
return ptr_factory_.GetWeakPtr();
}
void Bind(mojo::PendingReceiver<mojom::BlobStorageContext> receiver);
void set_limits_for_testing(const BlobStorageLimits& limits) {
mutable_memory_controller()->set_limits_for_testing(limits);
}
void DisableFilePagingForTesting() {
mutable_memory_controller()->DisableFilePaging(base::File::FILE_OK);
}
protected:
friend class content::ChromeBlobStorageContext;
friend class BlobBuilderFromStream;
friend class BlobDataHandle;
friend class BlobDataHandle::BlobDataHandleShared;
friend class BlobRegistryImplTest;
friend class BlobStorageContextTest;
friend class BlobURLTokenImpl;
friend class content::indexed_db_backing_store_unittest::
BlobStorageContextShim;
enum class TransportQuotaType { MEMORY, FILE };
void IncrementBlobRefCount(const std::string& uuid);
void DecrementBlobRefCount(const std::string& uuid);
// This will return an empty snapshot until the blob is complete.
// TODO(dmurph): After we make the snapshot method in BlobHandle private, then
// make this DCHECK on the blob not being complete.
std::unique_ptr<BlobDataSnapshot> CreateSnapshot(const std::string& uuid);
BlobStatus GetBlobStatus(const std::string& uuid) const;
// Runs |done| when construction completes with the final status of the blob.
void RunOnConstructionComplete(const std::string& uuid,
BlobStatusCallback done_callback);
// Runs |done| when construction begins (when the blob is no longer
// PENDING_CONSTRUCTION) with the new status of the blob.
void RunOnConstructionBegin(const std::string& uuid,
BlobStatusCallback done_callback);
BlobStorageRegistry* mutable_registry() { return ®istry_; }
BlobMemoryController* mutable_memory_controller() {
return &memory_controller_;
}
private:
std::unique_ptr<BlobDataHandle> BuildBlobInternal(
BlobEntry* entry,
std::unique_ptr<BlobDataBuilder> input_builder,
TransportAllowedCallback transport_allowed_callback);
std::unique_ptr<BlobDataHandle> CreateHandle(const std::string& uuid,
BlobEntry* entry);
void NotifyTransportCompleteInternal(BlobEntry* entry);
void CancelBuildingBlobInternal(BlobEntry* entry, BlobStatus reason);
void FinishBuilding(BlobEntry* entry);
void RequestTransport(
BlobEntry* entry,
std::vector<BlobMemoryController::FileCreationInfo> files);
// The files array is empty for memory quota request responses.
void OnEnoughSpaceForTransport(
const std::string& uuid,
std::vector<BlobMemoryController::FileCreationInfo> files,
bool can_fit);
void OnEnoughSpaceForCopies(const std::string& uuid, bool can_fit);
void OnDependentBlobFinished(const std::string& owning_blob_uuid,
BlobStatus reason);
void ClearAndFreeMemory(BlobEntry* entry);
// base::trace_event::MemoryDumpProvider implementation.
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) override;
// mojom::BlobStorageContext implementation.
void RegisterFromDataItem(mojo::PendingReceiver<blink::mojom::Blob> blob,
const std::string& uuid,
mojom::BlobDataItemPtr item) override;
void RegisterFromMemory(mojo::PendingReceiver<::blink::mojom::Blob> blob,
const std::string& uuid,
mojo_base::BigBuffer data) override;
void WriteBlobToFile(mojo::PendingRemote<::blink::mojom::Blob> blob,
const base::FilePath& path,
bool flush_on_write,
std::optional<base::Time> last_modified,
WriteBlobToFileCallback callback) override;
void Clone(mojo::PendingReceiver<mojom::BlobStorageContext> cloned) override;
base::FilePath profile_directory_;
BlobStorageRegistry registry_;
BlobMemoryController memory_controller_;
mojo::ReceiverSet<mojom::BlobStorageContext> receivers_;
base::WeakPtrFactory<BlobStorageContext> ptr_factory_{this};
};
} // namespace storage
#endif // STORAGE_BROWSER_BLOB_BLOB_STORAGE_CONTEXT_H_
|