1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/cache_storage/legacy/legacy_cache_storage.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10 #include <set>
11 #include <string>
12 #include <utility>
13 #include <vector>
14
15 #include "base/barrier_closure.h"
16 #include "base/bind.h"
17 #include "base/bind_helpers.h"
18 #include "base/files/file_util.h"
19 #include "base/files/memory_mapped_file.h"
20 #include "base/guid.h"
21 #include "base/hash/sha1.h"
22 #include "base/location.h"
23 #include "base/memory/ptr_util.h"
24 #include "base/memory/ref_counted.h"
25 #include "base/memory/scoped_refptr.h"
26 #include "base/metrics/histogram_macros.h"
27 #include "base/numerics/safe_conversions.h"
28 #include "base/sequenced_task_runner.h"
29 #include "base/stl_util.h"
30 #include "base/strings/string_number_conversions.h"
31 #include "base/strings/string_util.h"
32 #include "base/threading/sequenced_task_runner_handle.h"
33 #include "base/trace_event/trace_event.h"
34 #include "base/trace_event/traced_value.h"
35 #include "content/browser/cache_storage/cache_storage.pb.h"
36 #include "content/browser/cache_storage/cache_storage_cache.h"
37 #include "content/browser/cache_storage/cache_storage_cache_handle.h"
38 #include "content/browser/cache_storage/cache_storage_histogram_utils.h"
39 #include "content/browser/cache_storage/cache_storage_index.h"
40 #include "content/browser/cache_storage/cache_storage_quota_client.h"
41 #include "content/browser/cache_storage/cache_storage_scheduler.h"
42 #include "content/browser/cache_storage/cache_storage_trace_utils.h"
43 #include "content/browser/cache_storage/legacy/legacy_cache_storage_manager.h"
44 #include "content/common/background_fetch/background_fetch_types.h"
45 #include "crypto/symmetric_key.h"
46 #include "net/base/directory_lister.h"
47 #include "net/base/net_errors.h"
48 #include "storage/browser/blob/blob_storage_context.h"
49 #include "storage/browser/quota/padding_key.h"
50 #include "storage/browser/quota/quota_manager_proxy.h"
51 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
52
53 using blink::mojom::CacheStorageError;
54 using blink::mojom::StorageType;
55 using crypto::SymmetricKey;
56
57 namespace content {
58
59 namespace {
60
HexedHash(const std::string & value)61 std::string HexedHash(const std::string& value) {
62 std::string value_hash = base::SHA1HashString(value);
63 std::string valued_hexed_hash = base::ToLowerASCII(
64 base::HexEncode(value_hash.c_str(), value_hash.length()));
65 return valued_hexed_hash;
66 }
67
SizeRetrievedFromAllCaches(std::unique_ptr<int64_t> accumulator,LegacyCacheStorage::SizeCallback callback)68 void SizeRetrievedFromAllCaches(std::unique_ptr<int64_t> accumulator,
69 LegacyCacheStorage::SizeCallback callback) {
70 base::SequencedTaskRunnerHandle::Get()->PostTask(
71 FROM_HERE, base::BindOnce(std::move(callback), *accumulator));
72 }
73
74 } // namespace
75
76 const char LegacyCacheStorage::kIndexFileName[] = "index.txt";
77
78 struct LegacyCacheStorage::CacheMatchResponse {
79 CacheMatchResponse() = default;
80 ~CacheMatchResponse() = default;
81
82 CacheStorageError error;
83 blink::mojom::FetchAPIResponsePtr response;
84 std::unique_ptr<storage::BlobDataHandle> blob_data_handle;
85 };
86
87 // Handles the loading and clean up of CacheStorageCache objects.
88 class LegacyCacheStorage::CacheLoader {
89 public:
90 using CacheCallback =
91 base::OnceCallback<void(std::unique_ptr<LegacyCacheStorageCache>)>;
92 using BoolCallback = base::OnceCallback<void(bool)>;
93 using CacheStorageIndexLoadCallback =
94 base::OnceCallback<void(std::unique_ptr<CacheStorageIndex>)>;
95
CacheLoader(base::SequencedTaskRunner * cache_task_runner,scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,scoped_refptr<BlobStorageContextWrapper> blob_storage_context,LegacyCacheStorage * cache_storage,const url::Origin & origin,CacheStorageOwner owner)96 CacheLoader(base::SequencedTaskRunner* cache_task_runner,
97 scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
98 scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
99 scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
100 LegacyCacheStorage* cache_storage,
101 const url::Origin& origin,
102 CacheStorageOwner owner)
103 : cache_task_runner_(cache_task_runner),
104 scheduler_task_runner_(std::move(scheduler_task_runner)),
105 quota_manager_proxy_(std::move(quota_manager_proxy)),
106 blob_storage_context_(std::move(blob_storage_context)),
107 cache_storage_(cache_storage),
108 origin_(origin),
109 owner_(owner) {
110 DCHECK(!origin_.opaque());
111 }
112
~CacheLoader()113 virtual ~CacheLoader() {}
114
115 // Creates a CacheStorageCache with the given name. It does not attempt to
116 // load the backend, that happens lazily when the cache is used.
117 virtual std::unique_ptr<LegacyCacheStorageCache> CreateCache(
118 const std::string& cache_name,
119 int64_t cache_size,
120 int64_t cache_padding,
121 std::unique_ptr<SymmetricKey> cache_padding_key) = 0;
122
123 // Deletes any pre-existing cache of the same name and then loads it.
124 virtual void PrepareNewCacheDestination(const std::string& cache_name,
125 CacheCallback callback) = 0;
126
127 // After the backend has been deleted, do any extra house keeping such as
128 // removing the cache's directory.
129 virtual void CleanUpDeletedCache(CacheStorageCache* cache) = 0;
130
131 // Writes the cache index to disk if applicable.
132 virtual void WriteIndex(const CacheStorageIndex& index,
133 BoolCallback callback) = 0;
134
135 // Loads the cache index from disk if applicable.
136 virtual void LoadIndex(CacheStorageIndexLoadCallback callback) = 0;
137
138 // Called when CacheStorage has created a cache. Used to hold onto a handle to
139 // the cache if necessary.
NotifyCacheCreated(const std::string & cache_name,CacheStorageCacheHandle cache_handle)140 virtual void NotifyCacheCreated(const std::string& cache_name,
141 CacheStorageCacheHandle cache_handle) {}
142
143 // Notification that the cache for |cache_handle| has been doomed. If the
144 // loader is holding a handle to the cache, it should drop it now.
NotifyCacheDoomed(CacheStorageCacheHandle cache_handle)145 virtual void NotifyCacheDoomed(CacheStorageCacheHandle cache_handle) {}
146
147 protected:
148 const scoped_refptr<base::SequencedTaskRunner> cache_task_runner_;
149 const scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner_;
150
151 // Owned by CacheStorage which owns this. This is guaranteed to outlive
152 // CacheLoader, but we store a reference to keep it alive for callbacks.
153 scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
154
155 scoped_refptr<BlobStorageContextWrapper> blob_storage_context_;
156
157 // Raw pointer is safe because this object is owned by cache_storage_.
158 LegacyCacheStorage* cache_storage_;
159
160 url::Origin origin_;
161 CacheStorageOwner owner_;
162 };
163
164 // Creates memory-only ServiceWorkerCaches. Because these caches have no
165 // persistent storage it is not safe to free them from memory if they might be
166 // used again. Therefore this class holds a reference to each cache until the
167 // cache is doomed.
168 class LegacyCacheStorage::MemoryLoader
169 : public LegacyCacheStorage::CacheLoader {
170 public:
MemoryLoader(base::SequencedTaskRunner * cache_task_runner,scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,scoped_refptr<BlobStorageContextWrapper> blob_storage_context,LegacyCacheStorage * cache_storage,const url::Origin & origin,CacheStorageOwner owner)171 MemoryLoader(base::SequencedTaskRunner* cache_task_runner,
172 scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
173 scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
174 scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
175 LegacyCacheStorage* cache_storage,
176 const url::Origin& origin,
177 CacheStorageOwner owner)
178 : CacheLoader(cache_task_runner,
179 std::move(scheduler_task_runner),
180 std::move(quota_manager_proxy),
181 std::move(blob_storage_context),
182 cache_storage,
183 origin,
184 owner) {}
185
CreateCache(const std::string & cache_name,int64_t cache_size,int64_t cache_padding,std::unique_ptr<SymmetricKey> cache_padding_key)186 std::unique_ptr<LegacyCacheStorageCache> CreateCache(
187 const std::string& cache_name,
188 int64_t cache_size,
189 int64_t cache_padding,
190 std::unique_ptr<SymmetricKey> cache_padding_key) override {
191 return LegacyCacheStorageCache::CreateMemoryCache(
192 origin_, owner_, cache_name, cache_storage_, scheduler_task_runner_,
193 quota_manager_proxy_, blob_storage_context_,
194 storage::CopyDefaultPaddingKey());
195 }
196
PrepareNewCacheDestination(const std::string & cache_name,CacheCallback callback)197 void PrepareNewCacheDestination(const std::string& cache_name,
198 CacheCallback callback) override {
199 std::unique_ptr<LegacyCacheStorageCache> cache =
200 CreateCache(cache_name, 0 /*cache_size*/, 0 /* cache_padding */,
201 storage::CopyDefaultPaddingKey());
202 std::move(callback).Run(std::move(cache));
203 }
204
CleanUpDeletedCache(CacheStorageCache * cache)205 void CleanUpDeletedCache(CacheStorageCache* cache) override {}
206
WriteIndex(const CacheStorageIndex & index,BoolCallback callback)207 void WriteIndex(const CacheStorageIndex& index,
208 BoolCallback callback) override {
209 std::move(callback).Run(true);
210 }
211
LoadIndex(CacheStorageIndexLoadCallback callback)212 void LoadIndex(CacheStorageIndexLoadCallback callback) override {
213 std::move(callback).Run(std::make_unique<CacheStorageIndex>());
214 }
215
NotifyCacheCreated(const std::string & cache_name,CacheStorageCacheHandle cache_handle)216 void NotifyCacheCreated(const std::string& cache_name,
217 CacheStorageCacheHandle cache_handle) override {
218 DCHECK(!base::Contains(cache_handles_, cache_name));
219 cache_handles_.insert(std::make_pair(cache_name, std::move(cache_handle)));
220 }
221
NotifyCacheDoomed(CacheStorageCacheHandle cache_handle)222 void NotifyCacheDoomed(CacheStorageCacheHandle cache_handle) override {
223 auto* impl = LegacyCacheStorageCache::From(cache_handle);
224 DCHECK(base::Contains(cache_handles_, impl->cache_name()));
225 cache_handles_.erase(impl->cache_name());
226 }
227
228 private:
229 typedef std::map<std::string, CacheStorageCacheHandle> CacheHandles;
~MemoryLoader()230 ~MemoryLoader() override {}
231
232 // Keep a reference to each cache to ensure that it's not freed before the
233 // client calls LegacyCacheStorage::Delete or the CacheStorage is
234 // freed.
235 CacheHandles cache_handles_;
236 };
237
238 class LegacyCacheStorage::SimpleCacheLoader
239 : public LegacyCacheStorage::CacheLoader {
240 public:
SimpleCacheLoader(const base::FilePath & origin_path,base::SequencedTaskRunner * cache_task_runner,scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,scoped_refptr<BlobStorageContextWrapper> blob_storage_context,LegacyCacheStorage * cache_storage,const url::Origin & origin,CacheStorageOwner owner)241 SimpleCacheLoader(
242 const base::FilePath& origin_path,
243 base::SequencedTaskRunner* cache_task_runner,
244 scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
245 scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
246 scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
247 LegacyCacheStorage* cache_storage,
248 const url::Origin& origin,
249 CacheStorageOwner owner)
250 : CacheLoader(cache_task_runner,
251 std::move(scheduler_task_runner),
252 std::move(quota_manager_proxy),
253 std::move(blob_storage_context),
254 cache_storage,
255 origin,
256 owner),
257 origin_path_(origin_path) {}
258
CreateCache(const std::string & cache_name,int64_t cache_size,int64_t cache_padding,std::unique_ptr<SymmetricKey> cache_padding_key)259 std::unique_ptr<LegacyCacheStorageCache> CreateCache(
260 const std::string& cache_name,
261 int64_t cache_size,
262 int64_t cache_padding,
263 std::unique_ptr<SymmetricKey> cache_padding_key) override {
264 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
265 DCHECK(base::Contains(cache_name_to_cache_dir_, cache_name));
266
267 std::string cache_dir = cache_name_to_cache_dir_[cache_name];
268 base::FilePath cache_path = origin_path_.AppendASCII(cache_dir);
269 return LegacyCacheStorageCache::CreatePersistentCache(
270 origin_, owner_, cache_name, cache_storage_, cache_path,
271 scheduler_task_runner_, quota_manager_proxy_, blob_storage_context_,
272 cache_size, cache_padding, std::move(cache_padding_key));
273 }
274
PrepareNewCacheDestination(const std::string & cache_name,CacheCallback callback)275 void PrepareNewCacheDestination(const std::string& cache_name,
276 CacheCallback callback) override {
277 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
278
279 PostTaskAndReplyWithResult(
280 cache_task_runner_.get(), FROM_HERE,
281 base::BindOnce(&SimpleCacheLoader::PrepareNewCacheDirectoryInPool,
282 origin_path_),
283 base::BindOnce(&SimpleCacheLoader::PrepareNewCacheCreateCache,
284 weak_ptr_factory_.GetWeakPtr(), cache_name,
285 std::move(callback)));
286 }
287
288 // Runs on the cache_task_runner_.
PrepareNewCacheDirectoryInPool(const base::FilePath & origin_path)289 static std::string PrepareNewCacheDirectoryInPool(
290 const base::FilePath& origin_path) {
291 std::string cache_dir;
292 base::FilePath cache_path;
293 do {
294 cache_dir = base::GenerateGUID();
295 cache_path = origin_path.AppendASCII(cache_dir);
296 } while (base::PathExists(cache_path));
297
298 return base::CreateDirectory(cache_path) ? cache_dir : "";
299 }
300
PrepareNewCacheCreateCache(const std::string & cache_name,CacheCallback callback,const std::string & cache_dir)301 void PrepareNewCacheCreateCache(const std::string& cache_name,
302 CacheCallback callback,
303 const std::string& cache_dir) {
304 if (cache_dir.empty()) {
305 std::move(callback).Run(nullptr);
306 return;
307 }
308
309 cache_name_to_cache_dir_[cache_name] = cache_dir;
310 std::move(callback).Run(CreateCache(
311 cache_name, LegacyCacheStorage::kSizeUnknown,
312 LegacyCacheStorage::kSizeUnknown, storage::CopyDefaultPaddingKey()));
313 }
314
CleanUpDeletedCache(CacheStorageCache * cache)315 void CleanUpDeletedCache(CacheStorageCache* cache) override {
316 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
317 DCHECK(base::Contains(doomed_cache_to_path_, cache));
318
319 base::FilePath cache_path =
320 origin_path_.AppendASCII(doomed_cache_to_path_[cache]);
321 doomed_cache_to_path_.erase(cache);
322
323 cache_task_runner_->PostTask(
324 FROM_HERE,
325 base::BindOnce(&SimpleCacheLoader::CleanUpDeleteCacheDirInPool,
326 cache_path));
327 }
328
CleanUpDeleteCacheDirInPool(const base::FilePath & cache_path)329 static void CleanUpDeleteCacheDirInPool(const base::FilePath& cache_path) {
330 base::DeleteFileRecursively(cache_path);
331 }
332
WriteIndex(const CacheStorageIndex & index,BoolCallback callback)333 void WriteIndex(const CacheStorageIndex& index,
334 BoolCallback callback) override {
335 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
336
337 // 1. Create the index file as a string. (WriteIndex)
338 // 2. Write the file to disk. (WriteIndexWriteToFileInPool)
339
340 proto::CacheStorageIndex protobuf_index;
341 // GetURL().spec() is used here rather than Serialize() to ensure
342 // backwards compatibility with older data. The serializations are
343 // subtly different, e.g. Origin does not include a trailing "/".
344 // TODO(crbug.com/809329): Add a test for validating fields in the proto
345 protobuf_index.set_origin(origin_.GetURL().spec());
346
347 for (const auto& cache_metadata : index.ordered_cache_metadata()) {
348 DCHECK(base::Contains(cache_name_to_cache_dir_, cache_metadata.name));
349
350 proto::CacheStorageIndex::Cache* index_cache = protobuf_index.add_cache();
351 index_cache->set_name(cache_metadata.name);
352 index_cache->set_cache_dir(cache_name_to_cache_dir_[cache_metadata.name]);
353 if (cache_metadata.size == LegacyCacheStorage::kSizeUnknown)
354 index_cache->clear_size();
355 else
356 index_cache->set_size(cache_metadata.size);
357 index_cache->set_padding_key(cache_metadata.padding_key);
358 index_cache->set_padding(cache_metadata.padding);
359 index_cache->set_padding_version(
360 LegacyCacheStorageCache::GetResponsePaddingVersion());
361 }
362
363 std::string serialized;
364 bool success = protobuf_index.SerializeToString(&serialized);
365 DCHECK(success);
366
367 base::FilePath tmp_path = origin_path_.AppendASCII("index.txt.tmp");
368 base::FilePath index_path =
369 origin_path_.AppendASCII(LegacyCacheStorage::kIndexFileName);
370
371 PostTaskAndReplyWithResult(
372 cache_task_runner_.get(), FROM_HERE,
373 base::BindOnce(&SimpleCacheLoader::WriteIndexWriteToFileInPool,
374 tmp_path, index_path, serialized, quota_manager_proxy_,
375 origin_),
376 std::move(callback));
377 }
378
WriteIndexWriteToFileInPool(const base::FilePath & tmp_path,const base::FilePath & index_path,const std::string & data,scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,const url::Origin & origin)379 static bool WriteIndexWriteToFileInPool(
380 const base::FilePath& tmp_path,
381 const base::FilePath& index_path,
382 const std::string& data,
383 scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
384 const url::Origin& origin) {
385 int bytes_written = base::WriteFile(tmp_path, data.c_str(), data.size());
386 if (bytes_written != base::checked_cast<int>(data.size())) {
387 base::DeleteFile(tmp_path, /* recursive */ false);
388 quota_manager_proxy->NotifyWriteFailed(origin);
389 return false;
390 }
391
392 // Atomically rename the temporary index file to become the real one.
393 return base::ReplaceFile(tmp_path, index_path, nullptr);
394 }
395
LoadIndex(CacheStorageIndexLoadCallback callback)396 void LoadIndex(CacheStorageIndexLoadCallback callback) override {
397 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
398
399 PostTaskAndReplyWithResult(
400 cache_task_runner_.get(), FROM_HERE,
401 base::BindOnce(&SimpleCacheLoader::ReadAndMigrateIndexInPool,
402 origin_path_, quota_manager_proxy_, origin_),
403 base::BindOnce(&SimpleCacheLoader::LoadIndexDidReadIndex,
404 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
405 }
406
LoadIndexDidReadIndex(CacheStorageIndexLoadCallback callback,proto::CacheStorageIndex protobuf_index)407 void LoadIndexDidReadIndex(CacheStorageIndexLoadCallback callback,
408 proto::CacheStorageIndex protobuf_index) {
409 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
410
411 std::unique_ptr<std::set<std::string>> cache_dirs(
412 new std::set<std::string>);
413
414 auto index = std::make_unique<CacheStorageIndex>();
415 for (int i = 0, max = protobuf_index.cache_size(); i < max; ++i) {
416 const proto::CacheStorageIndex::Cache& cache = protobuf_index.cache(i);
417 DCHECK(cache.has_cache_dir());
418 int64_t cache_size =
419 cache.has_size() ? cache.size() : LegacyCacheStorage::kSizeUnknown;
420 int64_t cache_padding;
421 if (cache.has_padding()) {
422 if (cache.has_padding_version() &&
423 cache.padding_version() ==
424 LegacyCacheStorageCache::GetResponsePaddingVersion()) {
425 cache_padding = cache.padding();
426 } else {
427 // The padding algorithm version changed so set to unknown to force
428 // recalculation.
429 cache_padding = LegacyCacheStorage::kSizeUnknown;
430 }
431 } else {
432 cache_padding = LegacyCacheStorage::kSizeUnknown;
433 }
434
435 std::string cache_padding_key =
436 cache.has_padding_key() ? cache.padding_key()
437 : storage::SerializeDefaultPaddingKey();
438
439 index->Insert(CacheStorageIndex::CacheMetadata(
440 cache.name(), cache_size, cache_padding,
441 std::move(cache_padding_key)));
442 cache_name_to_cache_dir_[cache.name()] = cache.cache_dir();
443 cache_dirs->insert(cache.cache_dir());
444 }
445
446 cache_task_runner_->PostTask(
447 FROM_HERE, base::BindOnce(&DeleteUnreferencedCachesInPool, origin_path_,
448 std::move(cache_dirs)));
449 std::move(callback).Run(std::move(index));
450 }
451
NotifyCacheDoomed(CacheStorageCacheHandle cache_handle)452 void NotifyCacheDoomed(CacheStorageCacheHandle cache_handle) override {
453 auto* impl = LegacyCacheStorageCache::From(cache_handle);
454 DCHECK(base::Contains(cache_name_to_cache_dir_, impl->cache_name()));
455 auto iter = cache_name_to_cache_dir_.find(impl->cache_name());
456 doomed_cache_to_path_[cache_handle.value()] = iter->second;
457 cache_name_to_cache_dir_.erase(iter);
458 }
459
460 private:
461 friend class MigratedLegacyCacheDirectoryNameTest;
~SimpleCacheLoader()462 ~SimpleCacheLoader() override {}
463
464 // Iterates over the caches and deletes any directory not found in
465 // |cache_dirs|. Runs on cache_task_runner_
DeleteUnreferencedCachesInPool(const base::FilePath & cache_base_dir,std::unique_ptr<std::set<std::string>> cache_dirs)466 static void DeleteUnreferencedCachesInPool(
467 const base::FilePath& cache_base_dir,
468 std::unique_ptr<std::set<std::string>> cache_dirs) {
469 base::FileEnumerator file_enum(cache_base_dir, false /* recursive */,
470 base::FileEnumerator::DIRECTORIES);
471 std::vector<base::FilePath> dirs_to_delete;
472 {
473 base::FilePath cache_path;
474 while (!(cache_path = file_enum.Next()).empty()) {
475 if (!base::Contains(*cache_dirs, cache_path.BaseName().AsUTF8Unsafe()))
476 dirs_to_delete.push_back(cache_path);
477 }
478 }
479
480 for (const base::FilePath& cache_path : dirs_to_delete)
481 base::DeleteFileRecursively(cache_path);
482 }
483
484 // Runs on cache_task_runner_
ReadAndMigrateIndexInPool(const base::FilePath & origin_path,scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,const url::Origin & origin)485 static proto::CacheStorageIndex ReadAndMigrateIndexInPool(
486 const base::FilePath& origin_path,
487 scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
488 const url::Origin& origin) {
489 const base::FilePath index_path =
490 origin_path.AppendASCII(LegacyCacheStorage::kIndexFileName);
491
492 proto::CacheStorageIndex index;
493 std::string body;
494 if (!base::ReadFileToString(index_path, &body) ||
495 !index.ParseFromString(body))
496 return proto::CacheStorageIndex();
497 body.clear();
498
499 base::File::Info file_info;
500 base::Time index_last_modified;
501 if (GetFileInfo(index_path, &file_info))
502 index_last_modified = file_info.last_modified;
503 bool index_modified = false;
504
505 // Look for caches that have no cache_dir. Give any such caches a directory
506 // with a random name and move them there. Then, rewrite the index file.
507 // Additionally invalidate the size of any index entries where the cache was
508 // modified after the index (making it out-of-date).
509 for (int i = 0, max = index.cache_size(); i < max; ++i) {
510 const proto::CacheStorageIndex::Cache& cache = index.cache(i);
511 if (cache.has_cache_dir()) {
512 if (cache.has_size()) {
513 base::FilePath cache_dir = origin_path.AppendASCII(cache.cache_dir());
514 if (!GetFileInfo(cache_dir, &file_info) ||
515 index_last_modified <= file_info.last_modified) {
516 // Index is older than this cache, so invalidate index entries that
517 // may change as a result of cache operations.
518 index.mutable_cache(i)->clear_size();
519 }
520 }
521 } else {
522 // Find a new home for the cache.
523 base::FilePath legacy_cache_path =
524 origin_path.AppendASCII(HexedHash(cache.name()));
525 std::string cache_dir;
526 base::FilePath cache_path;
527 do {
528 cache_dir = base::GenerateGUID();
529 cache_path = origin_path.AppendASCII(cache_dir);
530 } while (base::PathExists(cache_path));
531
532 if (!base::Move(legacy_cache_path, cache_path)) {
533 // If the move fails then the cache is in a bad state. Return an empty
534 // index so that the CacheStorage can start fresh. The unreferenced
535 // caches will be discarded later in initialization.
536 return proto::CacheStorageIndex();
537 }
538
539 index.mutable_cache(i)->set_cache_dir(cache_dir);
540 index.mutable_cache(i)->clear_size();
541 index_modified = true;
542 }
543 }
544
545 if (index_modified) {
546 base::FilePath tmp_path = origin_path.AppendASCII("index.txt.tmp");
547 if (!index.SerializeToString(&body) ||
548 !WriteIndexWriteToFileInPool(tmp_path, index_path, body,
549 std::move(quota_manager_proxy),
550 origin)) {
551 return proto::CacheStorageIndex();
552 }
553 }
554
555 return index;
556 }
557
558 const base::FilePath origin_path_;
559 std::map<std::string, std::string> cache_name_to_cache_dir_;
560 std::map<CacheStorageCache*, std::string> doomed_cache_to_path_;
561
562 SEQUENCE_CHECKER(sequence_checker_);
563 base::WeakPtrFactory<SimpleCacheLoader> weak_ptr_factory_{this};
564 };
565
LegacyCacheStorage(const base::FilePath & path,bool memory_only,base::SequencedTaskRunner * cache_task_runner,scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,scoped_refptr<BlobStorageContextWrapper> blob_storage_context,LegacyCacheStorageManager * cache_storage_manager,const url::Origin & origin,CacheStorageOwner owner)566 LegacyCacheStorage::LegacyCacheStorage(
567 const base::FilePath& path,
568 bool memory_only,
569 base::SequencedTaskRunner* cache_task_runner,
570 scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
571 scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
572 scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
573 LegacyCacheStorageManager* cache_storage_manager,
574 const url::Origin& origin,
575 CacheStorageOwner owner)
576 : CacheStorage(origin),
577 initialized_(false),
578 initializing_(false),
579 memory_only_(memory_only),
580 scheduler_(
581 new CacheStorageScheduler(CacheStorageSchedulerClient::kStorage,
582 scheduler_task_runner)),
583 origin_path_(path),
584 cache_task_runner_(cache_task_runner),
585 quota_manager_proxy_(quota_manager_proxy),
586 blob_storage_context_(std::move(blob_storage_context)),
587 owner_(owner),
588 cache_storage_manager_(cache_storage_manager) {
589 if (memory_only) {
590 cache_loader_.reset(new MemoryLoader(
591 cache_task_runner_.get(), std::move(scheduler_task_runner),
592 quota_manager_proxy, blob_storage_context_, this, origin, owner));
593 return;
594 }
595
596 cache_loader_.reset(new SimpleCacheLoader(
597 origin_path_, cache_task_runner_.get(), std::move(scheduler_task_runner),
598 quota_manager_proxy, blob_storage_context_, this, origin, owner));
599
600 #if defined(OS_ANDROID)
601 app_status_listener_ = base::android::ApplicationStatusListener::New(
602 base::BindRepeating(&LegacyCacheStorage::OnApplicationStateChange,
603 weak_factory_.GetWeakPtr()));
604 #endif
605 }
606
~LegacyCacheStorage()607 LegacyCacheStorage::~LegacyCacheStorage() {
608 FlushIndexIfDirty();
609 }
610
CreateHandle()611 CacheStorageHandle LegacyCacheStorage::CreateHandle() {
612 return CacheStorageHandle(weak_factory_.GetWeakPtr());
613 }
614
AddHandleRef()615 void LegacyCacheStorage::AddHandleRef() {
616 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
617 handle_ref_count_ += 1;
618 }
619
DropHandleRef()620 void LegacyCacheStorage::DropHandleRef() {
621 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
622 DCHECK_GT(handle_ref_count_, 0U);
623 handle_ref_count_ -= 1;
624 if (!handle_ref_count_ && cache_storage_manager_) {
625 ReleaseUnreferencedCaches();
626 cache_storage_manager_->CacheStorageUnreferenced(this, origin_, owner_);
627 }
628 }
629
OpenCache(const std::string & cache_name,int64_t trace_id,CacheAndErrorCallback callback)630 void LegacyCacheStorage::OpenCache(const std::string& cache_name,
631 int64_t trace_id,
632 CacheAndErrorCallback callback) {
633 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
634
635 if (!initialized_)
636 LazyInit();
637
638 quota_manager_proxy_->NotifyStorageAccessed(origin_, StorageType::kTemporary);
639
640 // TODO: Hold a handle to this CacheStorage instance while executing
641 // operations to better support use by internal code that may
642 // start a single operation without explicitly maintaining a
643 // handle.
644 auto id = scheduler_->CreateId();
645 scheduler_->ScheduleOperation(
646 id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kOpen,
647 CacheStorageSchedulerPriority::kNormal,
648 base::BindOnce(
649 &LegacyCacheStorage::OpenCacheImpl, weak_factory_.GetWeakPtr(),
650 cache_name, trace_id,
651 scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
652 }
653
HasCache(const std::string & cache_name,int64_t trace_id,BoolAndErrorCallback callback)654 void LegacyCacheStorage::HasCache(const std::string& cache_name,
655 int64_t trace_id,
656 BoolAndErrorCallback callback) {
657 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
658
659 if (!initialized_)
660 LazyInit();
661
662 quota_manager_proxy_->NotifyStorageAccessed(origin_, StorageType::kTemporary);
663
664 auto id = scheduler_->CreateId();
665 scheduler_->ScheduleOperation(
666 id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kHas,
667 CacheStorageSchedulerPriority::kNormal,
668 base::BindOnce(
669 &LegacyCacheStorage::HasCacheImpl, weak_factory_.GetWeakPtr(),
670 cache_name, trace_id,
671 scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
672 }
673
DoomCache(const std::string & cache_name,int64_t trace_id,ErrorCallback callback)674 void LegacyCacheStorage::DoomCache(const std::string& cache_name,
675 int64_t trace_id,
676 ErrorCallback callback) {
677 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
678
679 if (!initialized_)
680 LazyInit();
681
682 quota_manager_proxy_->NotifyStorageAccessed(origin_, StorageType::kTemporary);
683
684 auto id = scheduler_->CreateId();
685 scheduler_->ScheduleOperation(
686 id, CacheStorageSchedulerMode::kExclusive,
687 CacheStorageSchedulerOp::kDelete, CacheStorageSchedulerPriority::kNormal,
688 base::BindOnce(
689 &LegacyCacheStorage::DoomCacheImpl, weak_factory_.GetWeakPtr(),
690 cache_name, trace_id,
691 scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
692 }
693
EnumerateCaches(int64_t trace_id,EnumerateCachesCallback callback)694 void LegacyCacheStorage::EnumerateCaches(int64_t trace_id,
695 EnumerateCachesCallback callback) {
696 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
697
698 if (!initialized_)
699 LazyInit();
700
701 quota_manager_proxy_->NotifyStorageAccessed(origin_, StorageType::kTemporary);
702
703 auto id = scheduler_->CreateId();
704 scheduler_->ScheduleOperation(
705 id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kKeys,
706 CacheStorageSchedulerPriority::kNormal,
707 base::BindOnce(
708 &LegacyCacheStorage::EnumerateCachesImpl, weak_factory_.GetWeakPtr(),
709 trace_id,
710 scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
711 }
712
MatchCache(const std::string & cache_name,blink::mojom::FetchAPIRequestPtr request,blink::mojom::CacheQueryOptionsPtr match_options,CacheStorageSchedulerPriority priority,int64_t trace_id,CacheStorageCache::ResponseCallback callback)713 void LegacyCacheStorage::MatchCache(
714 const std::string& cache_name,
715 blink::mojom::FetchAPIRequestPtr request,
716 blink::mojom::CacheQueryOptionsPtr match_options,
717 CacheStorageSchedulerPriority priority,
718 int64_t trace_id,
719 CacheStorageCache::ResponseCallback callback) {
720 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
721
722 if (!initialized_)
723 LazyInit();
724
725 quota_manager_proxy_->NotifyStorageAccessed(origin_, StorageType::kTemporary);
726
727 auto id = scheduler_->CreateId();
728 scheduler_->ScheduleOperation(
729 id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kMatch,
730 CacheStorageSchedulerPriority::kNormal,
731 base::BindOnce(
732 &LegacyCacheStorage::MatchCacheImpl, weak_factory_.GetWeakPtr(),
733 cache_name, std::move(request), std::move(match_options), priority,
734 trace_id,
735 scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
736 }
737
MatchAllCaches(blink::mojom::FetchAPIRequestPtr request,blink::mojom::CacheQueryOptionsPtr match_options,CacheStorageSchedulerPriority priority,int64_t trace_id,CacheStorageCache::ResponseCallback callback)738 void LegacyCacheStorage::MatchAllCaches(
739 blink::mojom::FetchAPIRequestPtr request,
740 blink::mojom::CacheQueryOptionsPtr match_options,
741 CacheStorageSchedulerPriority priority,
742 int64_t trace_id,
743 CacheStorageCache::ResponseCallback callback) {
744 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
745
746 if (!initialized_)
747 LazyInit();
748
749 quota_manager_proxy_->NotifyStorageAccessed(origin_, StorageType::kTemporary);
750
751 auto id = scheduler_->CreateId();
752 scheduler_->ScheduleOperation(
753 id, CacheStorageSchedulerMode::kShared,
754 CacheStorageSchedulerOp::kMatchAll,
755 CacheStorageSchedulerPriority::kNormal,
756 base::BindOnce(
757 &LegacyCacheStorage::MatchAllCachesImpl, weak_factory_.GetWeakPtr(),
758 std::move(request), std::move(match_options), priority, trace_id,
759 scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
760 }
761
WriteToCache(const std::string & cache_name,blink::mojom::FetchAPIRequestPtr request,blink::mojom::FetchAPIResponsePtr response,int64_t trace_id,LegacyCacheStorage::ErrorCallback callback)762 void LegacyCacheStorage::WriteToCache(
763 const std::string& cache_name,
764 blink::mojom::FetchAPIRequestPtr request,
765 blink::mojom::FetchAPIResponsePtr response,
766 int64_t trace_id,
767 LegacyCacheStorage::ErrorCallback callback) {
768 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
769
770 if (!initialized_)
771 LazyInit();
772
773 quota_manager_proxy_->NotifyStorageAccessed(origin_, StorageType::kTemporary);
774
775 // Note, this is a shared operation since it only reads CacheStorage data.
776 // The CacheStorageCache is responsible for making its put operation
777 // exclusive.
778 auto id = scheduler_->CreateId();
779 scheduler_->ScheduleOperation(
780 id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kPut,
781 CacheStorageSchedulerPriority::kNormal,
782 base::BindOnce(
783 &LegacyCacheStorage::WriteToCacheImpl, weak_factory_.GetWeakPtr(),
784 cache_name, std::move(request), std::move(response), trace_id,
785 scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
786 }
787
GetSizeThenCloseAllCaches(SizeCallback callback)788 void LegacyCacheStorage::GetSizeThenCloseAllCaches(SizeCallback callback) {
789 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
790
791 if (!initialized_)
792 LazyInit();
793
794 // Note, this is a shared operation since it only reads CacheStorage data.
795 // The CacheStorageCache is responsible for making its close operation
796 // exclusive.
797 auto id = scheduler_->CreateId();
798 scheduler_->ScheduleOperation(
799 id, CacheStorageSchedulerMode::kShared,
800 CacheStorageSchedulerOp::kSizeThenClose,
801 CacheStorageSchedulerPriority::kNormal,
802 base::BindOnce(
803 &LegacyCacheStorage::GetSizeThenCloseAllCachesImpl,
804 weak_factory_.GetWeakPtr(),
805 scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
806 }
807
Size(LegacyCacheStorage::SizeCallback callback)808 void LegacyCacheStorage::Size(LegacyCacheStorage::SizeCallback callback) {
809 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
810
811 if (!initialized_)
812 LazyInit();
813
814 auto id = scheduler_->CreateId();
815 scheduler_->ScheduleOperation(
816 id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kSize,
817 CacheStorageSchedulerPriority::kNormal,
818 base::BindOnce(
819 &LegacyCacheStorage::SizeImpl, weak_factory_.GetWeakPtr(),
820 scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
821 }
822
ResetManager()823 void LegacyCacheStorage::ResetManager() {
824 cache_storage_manager_ = nullptr;
825 }
826
NotifyCacheContentChanged(const std::string & cache_name)827 void LegacyCacheStorage::NotifyCacheContentChanged(
828 const std::string& cache_name) {
829 if (cache_storage_manager_)
830 cache_storage_manager_->NotifyCacheContentChanged(origin_, cache_name);
831 }
832
ScheduleWriteIndex()833 void LegacyCacheStorage::ScheduleWriteIndex() {
834 // These values are chosen to be equal or greater than the simple disk_cache
835 // index write delays. We want the cache_storage index to be written last.
836 static const int64_t kWriteIndexDelayMilliseconds = 20050;
837 static const int64_t kWriteIndexBackgroundDelayMilliseconds = 150;
838 int64_t delay_ms = app_on_background_ ? kWriteIndexBackgroundDelayMilliseconds
839 : kWriteIndexDelayMilliseconds;
840 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
841 index_write_task_.Reset(base::BindOnce(&LegacyCacheStorage::WriteIndex,
842 weak_factory_.GetWeakPtr(),
843 base::DoNothing::Once<bool>()));
844 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
845 FROM_HERE, index_write_task_.callback(),
846 base::TimeDelta::FromMilliseconds(delay_ms));
847 }
848
WriteIndex(base::OnceCallback<void (bool)> callback)849 void LegacyCacheStorage::WriteIndex(base::OnceCallback<void(bool)> callback) {
850 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
851 auto id = scheduler_->CreateId();
852 scheduler_->ScheduleOperation(
853 id, CacheStorageSchedulerMode::kExclusive,
854 CacheStorageSchedulerOp::kWriteIndex,
855 CacheStorageSchedulerPriority::kNormal,
856 base::BindOnce(
857 &LegacyCacheStorage::WriteIndexImpl, weak_factory_.GetWeakPtr(),
858 scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
859 }
860
WriteIndexImpl(base::OnceCallback<void (bool)> callback)861 void LegacyCacheStorage::WriteIndexImpl(
862 base::OnceCallback<void(bool)> callback) {
863 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
864 DCHECK(scheduler_->IsRunningExclusiveOperation());
865 cache_loader_->WriteIndex(*cache_index_, std::move(callback));
866 }
867
InitiateScheduledIndexWriteForTest(base::OnceCallback<void (bool)> callback)868 bool LegacyCacheStorage::InitiateScheduledIndexWriteForTest(
869 base::OnceCallback<void(bool)> callback) {
870 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
871 if (index_write_pending()) {
872 index_write_task_.Cancel();
873 WriteIndex(std::move(callback));
874 return true;
875 }
876 std::move(callback).Run(true /* success */);
877 return false;
878 }
879
CacheSizeUpdated(const LegacyCacheStorageCache * cache)880 void LegacyCacheStorage::CacheSizeUpdated(
881 const LegacyCacheStorageCache* cache) {
882 // Should not be called for doomed caches.
883 DCHECK(!base::Contains(doomed_caches_,
884 const_cast<LegacyCacheStorageCache*>(cache)));
885 DCHECK_NE(cache->cache_padding(), kSizeUnknown);
886 bool size_changed =
887 cache_index_->SetCacheSize(cache->cache_name(), cache->cache_size());
888 bool padding_changed = cache_index_->SetCachePadding(cache->cache_name(),
889 cache->cache_padding());
890 if (size_changed || padding_changed)
891 ScheduleWriteIndex();
892 }
893
ReleaseUnreferencedCaches()894 void LegacyCacheStorage::ReleaseUnreferencedCaches() {
895 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
896 for (auto& entry : cache_map_) {
897 if (entry.second && entry.second->IsUnreferenced())
898 entry.second.reset();
899 }
900 }
901
CacheUnreferenced(LegacyCacheStorageCache * cache)902 void LegacyCacheStorage::CacheUnreferenced(LegacyCacheStorageCache* cache) {
903 DCHECK(cache);
904 DCHECK(cache->IsUnreferenced());
905 auto doomed_caches_it = doomed_caches_.find(cache);
906 if (doomed_caches_it != doomed_caches_.end()) {
907 // The last reference to a doomed cache is gone, perform clean up.
908 DeleteCacheFinalize(cache);
909 return;
910 }
911
912 // Opportunistically keep warmed caches open when the CacheStorage is
913 // still actively referenced. Repeatedly opening and closing simple
914 // disk_cache backends can be quite slow. This is easy to trigger when
915 // a site uses caches.match() frequently because the a Cache object is
916 // never exposed to script to explicitly hold the backend open.
917 if (handle_ref_count_)
918 return;
919
920 // The CacheStorage is not actively being referenced. Close the cache
921 // immediately.
922 auto cache_map_it = cache_map_.find(cache->cache_name());
923 DCHECK(cache_map_it != cache_map_.end());
924
925 cache_map_it->second.reset();
926 }
927
StartAsyncOperationForTesting()928 CacheStorageSchedulerId LegacyCacheStorage::StartAsyncOperationForTesting() {
929 auto id = scheduler_->CreateId();
930 scheduler_->ScheduleOperation(
931 id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kTest,
932 CacheStorageSchedulerPriority::kNormal, base::DoNothing());
933 return id;
934 }
935
CompleteAsyncOperationForTesting(CacheStorageSchedulerId id)936 void LegacyCacheStorage::CompleteAsyncOperationForTesting(
937 CacheStorageSchedulerId id) {
938 scheduler_->CompleteOperationAndRunNext(id);
939 }
940
941 // Init is run lazily so that it is called on the proper MessageLoop.
LazyInit()942 void LegacyCacheStorage::LazyInit() {
943 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
944 DCHECK(!initialized_);
945
946 if (initializing_)
947 return;
948
949 DCHECK(!scheduler_->ScheduledOperations());
950
951 initializing_ = true;
952 init_id_ = scheduler_->CreateId();
953 scheduler_->ScheduleOperation(
954 init_id_, CacheStorageSchedulerMode::kExclusive,
955 CacheStorageSchedulerOp::kInit, CacheStorageSchedulerPriority::kNormal,
956 base::BindOnce(&LegacyCacheStorage::LazyInitImpl,
957 weak_factory_.GetWeakPtr()));
958 }
959
LazyInitImpl()960 void LegacyCacheStorage::LazyInitImpl() {
961 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
962 DCHECK(!initialized_);
963 DCHECK(initializing_);
964
965 // 1. Get the cache index (async call)
966 // 2. For each cache name, load the cache (async call)
967 // 3. Once each load is complete, update the map variables.
968 // 4. Call the list of waiting callbacks.
969
970 DCHECK(scheduler_->IsRunningExclusiveOperation());
971 cache_loader_->LoadIndex(base::BindOnce(
972 &LegacyCacheStorage::LazyInitDidLoadIndex, weak_factory_.GetWeakPtr()));
973 }
974
LazyInitDidLoadIndex(std::unique_ptr<CacheStorageIndex> index)975 void LegacyCacheStorage::LazyInitDidLoadIndex(
976 std::unique_ptr<CacheStorageIndex> index) {
977 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
978 DCHECK(cache_map_.empty());
979
980 for (const auto& cache_metadata : index->ordered_cache_metadata()) {
981 cache_map_.insert(std::make_pair(cache_metadata.name, nullptr));
982 }
983
984 DCHECK(!cache_index_);
985 cache_index_ = std::move(index);
986
987 initializing_ = false;
988 initialized_ = true;
989
990 scheduler_->CompleteOperationAndRunNext(init_id_);
991 }
992
OpenCacheImpl(const std::string & cache_name,int64_t trace_id,CacheAndErrorCallback callback)993 void LegacyCacheStorage::OpenCacheImpl(const std::string& cache_name,
994 int64_t trace_id,
995 CacheAndErrorCallback callback) {
996 TRACE_EVENT_WITH_FLOW1("CacheStorage", "LegacyCacheStorage::OpenCacheImpl",
997 TRACE_ID_GLOBAL(trace_id),
998 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
999 "cache_name", cache_name);
1000 CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name);
1001 if (cache_handle.value()) {
1002 std::move(callback).Run(std::move(cache_handle),
1003 CacheStorageError::kSuccess);
1004 return;
1005 }
1006
1007 DCHECK(scheduler_->IsRunningExclusiveOperation());
1008 cache_loader_->PrepareNewCacheDestination(
1009 cache_name, base::BindOnce(&LegacyCacheStorage::CreateCacheDidCreateCache,
1010 weak_factory_.GetWeakPtr(), cache_name,
1011 trace_id, std::move(callback)));
1012 }
1013
CreateCacheDidCreateCache(const std::string & cache_name,int64_t trace_id,CacheAndErrorCallback callback,std::unique_ptr<LegacyCacheStorageCache> cache)1014 void LegacyCacheStorage::CreateCacheDidCreateCache(
1015 const std::string& cache_name,
1016 int64_t trace_id,
1017 CacheAndErrorCallback callback,
1018 std::unique_ptr<LegacyCacheStorageCache> cache) {
1019 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1020
1021 TRACE_EVENT_WITH_FLOW0("CacheStorage",
1022 "LegacyCacheStorage::CreateCacheDidCreateCache",
1023 TRACE_ID_GLOBAL(trace_id),
1024 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1025
1026 UMA_HISTOGRAM_BOOLEAN("ServiceWorkerCache.CreateCacheStorageResult",
1027 static_cast<bool>(cache));
1028
1029 if (!cache) {
1030 std::move(callback).Run(
1031 CacheStorageCacheHandle(),
1032 MakeErrorStorage(ErrorStorageType::kDidCreateNullCache));
1033 return;
1034 }
1035
1036 LegacyCacheStorageCache* cache_ptr = cache.get();
1037
1038 cache_map_.insert(std::make_pair(cache_name, std::move(cache)));
1039 cache_index_->Insert(CacheStorageIndex::CacheMetadata(
1040 cache_name, cache_ptr->cache_size(), cache_ptr->cache_padding(),
1041 cache_ptr->cache_padding_key()->key()));
1042
1043 CacheStorageCacheHandle handle = cache_ptr->CreateHandle();
1044 index_write_task_.Cancel();
1045 cache_loader_->WriteIndex(
1046 *cache_index_,
1047 base::BindOnce(&LegacyCacheStorage::CreateCacheDidWriteIndex,
1048 weak_factory_.GetWeakPtr(), std::move(callback),
1049 cache_ptr->CreateHandle(), trace_id));
1050
1051 cache_loader_->NotifyCacheCreated(cache_name, std::move(handle));
1052 if (cache_storage_manager_)
1053 cache_storage_manager_->NotifyCacheListChanged(origin_);
1054 }
1055
CreateCacheDidWriteIndex(CacheAndErrorCallback callback,CacheStorageCacheHandle cache_handle,int64_t trace_id,bool success)1056 void LegacyCacheStorage::CreateCacheDidWriteIndex(
1057 CacheAndErrorCallback callback,
1058 CacheStorageCacheHandle cache_handle,
1059 int64_t trace_id,
1060 bool success) {
1061 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1062 DCHECK(cache_handle.value());
1063
1064 TRACE_EVENT_WITH_FLOW0("CacheStorage",
1065 "LegacyCacheStorage::CreateCacheDidWriteIndex",
1066 TRACE_ID_GLOBAL(trace_id),
1067 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1068
1069 // TODO(jkarlin): Handle !success.
1070
1071 std::move(callback).Run(std::move(cache_handle), CacheStorageError::kSuccess);
1072 }
1073
HasCacheImpl(const std::string & cache_name,int64_t trace_id,BoolAndErrorCallback callback)1074 void LegacyCacheStorage::HasCacheImpl(const std::string& cache_name,
1075 int64_t trace_id,
1076 BoolAndErrorCallback callback) {
1077 TRACE_EVENT_WITH_FLOW1("CacheStorage", "LegacyCacheStorage::HasCacheImpl",
1078 TRACE_ID_GLOBAL(trace_id),
1079 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
1080 "cache_name", cache_name);
1081 bool has_cache = base::Contains(cache_map_, cache_name);
1082 std::move(callback).Run(has_cache, CacheStorageError::kSuccess);
1083 }
1084
DoomCacheImpl(const std::string & cache_name,int64_t trace_id,ErrorCallback callback)1085 void LegacyCacheStorage::DoomCacheImpl(const std::string& cache_name,
1086 int64_t trace_id,
1087 ErrorCallback callback) {
1088 TRACE_EVENT_WITH_FLOW1("CacheStorage", "LegacyCacheStorage::DoomCacheImpl",
1089 TRACE_ID_GLOBAL(trace_id),
1090 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
1091 "cache_name", cache_name);
1092 CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name);
1093 if (!cache_handle.value()) {
1094 base::SequencedTaskRunnerHandle::Get()->PostTask(
1095 FROM_HERE,
1096 base::BindOnce(std::move(callback), CacheStorageError::kErrorNotFound));
1097 return;
1098 }
1099
1100 DCHECK(scheduler_->IsRunningExclusiveOperation());
1101 LegacyCacheStorageCache::From(cache_handle)->SetObserver(nullptr);
1102 cache_index_->DoomCache(cache_name);
1103 index_write_task_.Cancel();
1104 cache_loader_->WriteIndex(
1105 *cache_index_,
1106 base::BindOnce(&LegacyCacheStorage::DeleteCacheDidWriteIndex,
1107 weak_factory_.GetWeakPtr(), std::move(cache_handle),
1108 std::move(callback), trace_id));
1109 }
1110
DeleteCacheDidWriteIndex(CacheStorageCacheHandle cache_handle,ErrorCallback callback,int64_t trace_id,bool success)1111 void LegacyCacheStorage::DeleteCacheDidWriteIndex(
1112 CacheStorageCacheHandle cache_handle,
1113 ErrorCallback callback,
1114 int64_t trace_id,
1115 bool success) {
1116 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1117 auto* impl = LegacyCacheStorageCache::From(cache_handle);
1118
1119 TRACE_EVENT_WITH_FLOW0("CacheStorage",
1120 "LegacyCacheStorage::DeleteCacheDidWriteIndex",
1121 TRACE_ID_GLOBAL(trace_id),
1122 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1123
1124 if (!success) {
1125 // Undo any changes if the index couldn't be written to disk.
1126 cache_index_->RestoreDoomedCache();
1127 impl->SetObserver(this);
1128 std::move(callback).Run(
1129 MakeErrorStorage(ErrorStorageType::kDeleteCacheFailed));
1130 return;
1131 }
1132
1133 cache_index_->FinalizeDoomedCache();
1134
1135 auto map_iter = cache_map_.find(impl->cache_name());
1136 DCHECK(map_iter != cache_map_.end());
1137
1138 doomed_caches_.insert(
1139 std::make_pair(map_iter->second.get(), std::move(map_iter->second)));
1140 cache_map_.erase(map_iter);
1141
1142 cache_loader_->NotifyCacheDoomed(std::move(cache_handle));
1143 if (cache_storage_manager_)
1144 cache_storage_manager_->NotifyCacheListChanged(origin_);
1145
1146 std::move(callback).Run(CacheStorageError::kSuccess);
1147 }
1148
1149 // Call this once the last handle to a doomed cache is gone. It's okay if this
1150 // doesn't get to complete before shutdown, the cache will be removed from disk
1151 // on next startup in that case.
DeleteCacheFinalize(LegacyCacheStorageCache * doomed_cache)1152 void LegacyCacheStorage::DeleteCacheFinalize(
1153 LegacyCacheStorageCache* doomed_cache) {
1154 doomed_cache->Size(base::BindOnce(&LegacyCacheStorage::DeleteCacheDidGetSize,
1155 weak_factory_.GetWeakPtr(), doomed_cache));
1156 }
1157
DeleteCacheDidGetSize(LegacyCacheStorageCache * doomed_cache,int64_t cache_size)1158 void LegacyCacheStorage::DeleteCacheDidGetSize(
1159 LegacyCacheStorageCache* doomed_cache,
1160 int64_t cache_size) {
1161 quota_manager_proxy_->NotifyStorageModified(
1162 CacheStorageQuotaClient::GetIDFromOwner(owner_), origin_,
1163 StorageType::kTemporary, -1 * cache_size);
1164
1165 cache_loader_->CleanUpDeletedCache(doomed_cache);
1166 auto doomed_caches_iter = doomed_caches_.find(doomed_cache);
1167 DCHECK(doomed_caches_iter != doomed_caches_.end());
1168 doomed_caches_.erase(doomed_caches_iter);
1169 }
1170
EnumerateCachesImpl(int64_t trace_id,EnumerateCachesCallback callback)1171 void LegacyCacheStorage::EnumerateCachesImpl(int64_t trace_id,
1172 EnumerateCachesCallback callback) {
1173 TRACE_EVENT_WITH_FLOW0("CacheStorage",
1174 "LegacyCacheStorage::EnumerateCachesImpl",
1175 TRACE_ID_GLOBAL(trace_id),
1176 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1177
1178 std::vector<std::string> list;
1179
1180 for (const auto& metadata : cache_index_->ordered_cache_metadata()) {
1181 list.push_back(metadata.name);
1182 }
1183
1184 std::move(callback).Run(std::move(list));
1185 }
1186
MatchCacheImpl(const std::string & cache_name,blink::mojom::FetchAPIRequestPtr request,blink::mojom::CacheQueryOptionsPtr match_options,CacheStorageSchedulerPriority priority,int64_t trace_id,CacheStorageCache::ResponseCallback callback)1187 void LegacyCacheStorage::MatchCacheImpl(
1188 const std::string& cache_name,
1189 blink::mojom::FetchAPIRequestPtr request,
1190 blink::mojom::CacheQueryOptionsPtr match_options,
1191 CacheStorageSchedulerPriority priority,
1192 int64_t trace_id,
1193 CacheStorageCache::ResponseCallback callback) {
1194 TRACE_EVENT_WITH_FLOW2("CacheStorage", "LegacyCacheStorage::MatchCacheImpl",
1195 TRACE_ID_GLOBAL(trace_id),
1196 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
1197 "cache_name", cache_name, "request",
1198 CacheStorageTracedValue(request));
1199
1200 CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name);
1201
1202 if (!cache_handle.value()) {
1203 std::move(callback).Run(CacheStorageError::kErrorCacheNameNotFound,
1204 nullptr);
1205 return;
1206 }
1207
1208 // Pass the cache handle along to the callback to keep the cache open until
1209 // match is done.
1210 CacheStorageCache* cache_ptr = cache_handle.value();
1211 cache_ptr->Match(
1212 std::move(request), std::move(match_options), priority, trace_id,
1213 base::BindOnce(&LegacyCacheStorage::MatchCacheDidMatch,
1214 weak_factory_.GetWeakPtr(), std::move(cache_handle),
1215 trace_id, std::move(callback)));
1216 }
1217
MatchCacheDidMatch(CacheStorageCacheHandle cache_handle,int64_t trace_id,CacheStorageCache::ResponseCallback callback,CacheStorageError error,blink::mojom::FetchAPIResponsePtr response)1218 void LegacyCacheStorage::MatchCacheDidMatch(
1219 CacheStorageCacheHandle cache_handle,
1220 int64_t trace_id,
1221 CacheStorageCache::ResponseCallback callback,
1222 CacheStorageError error,
1223 blink::mojom::FetchAPIResponsePtr response) {
1224 TRACE_EVENT_WITH_FLOW0("CacheStorage",
1225 "LegacyCacheStorage::MatchCacheDidMatch",
1226 TRACE_ID_GLOBAL(trace_id),
1227 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1228 std::move(callback).Run(error, std::move(response));
1229 }
1230
MatchAllCachesImpl(blink::mojom::FetchAPIRequestPtr request,blink::mojom::CacheQueryOptionsPtr match_options,CacheStorageSchedulerPriority priority,int64_t trace_id,CacheStorageCache::ResponseCallback callback)1231 void LegacyCacheStorage::MatchAllCachesImpl(
1232 blink::mojom::FetchAPIRequestPtr request,
1233 blink::mojom::CacheQueryOptionsPtr match_options,
1234 CacheStorageSchedulerPriority priority,
1235 int64_t trace_id,
1236 CacheStorageCache::ResponseCallback callback) {
1237 TRACE_EVENT_WITH_FLOW0("CacheStorage",
1238 "LegacyCacheStorage::MatchAllCachesImpl",
1239 TRACE_ID_GLOBAL(trace_id),
1240 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1241
1242 std::vector<CacheMatchResponse>* match_responses =
1243 new std::vector<CacheMatchResponse>(cache_index_->num_entries());
1244
1245 base::RepeatingClosure barrier_closure = base::BarrierClosure(
1246 cache_index_->num_entries(),
1247 base::BindOnce(&LegacyCacheStorage::MatchAllCachesDidMatchAll,
1248 weak_factory_.GetWeakPtr(),
1249 base::WrapUnique(match_responses), trace_id,
1250 std::move(callback)));
1251
1252 size_t idx = 0;
1253 for (const auto& cache_metadata : cache_index_->ordered_cache_metadata()) {
1254 CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_metadata.name);
1255 DCHECK(cache_handle.value());
1256
1257 CacheStorageCache* cache_ptr = cache_handle.value();
1258 cache_ptr->Match(
1259 BackgroundFetchSettledFetch::CloneRequest(request),
1260 match_options ? match_options->Clone() : nullptr, priority, trace_id,
1261 base::BindOnce(&LegacyCacheStorage::MatchAllCachesDidMatch,
1262 weak_factory_.GetWeakPtr(), std::move(cache_handle),
1263 &match_responses->at(idx), barrier_closure, trace_id));
1264 idx++;
1265 }
1266 }
1267
MatchAllCachesDidMatch(CacheStorageCacheHandle cache_handle,CacheMatchResponse * out_match_response,const base::RepeatingClosure & barrier_closure,int64_t trace_id,CacheStorageError error,blink::mojom::FetchAPIResponsePtr response)1268 void LegacyCacheStorage::MatchAllCachesDidMatch(
1269 CacheStorageCacheHandle cache_handle,
1270 CacheMatchResponse* out_match_response,
1271 const base::RepeatingClosure& barrier_closure,
1272 int64_t trace_id,
1273 CacheStorageError error,
1274 blink::mojom::FetchAPIResponsePtr response) {
1275 TRACE_EVENT_WITH_FLOW0("CacheStorage",
1276 "LegacyCacheStorage::MatchAllCachesDidMatch",
1277 TRACE_ID_GLOBAL(trace_id),
1278 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1279 out_match_response->error = error;
1280 out_match_response->response = std::move(response);
1281 barrier_closure.Run();
1282 }
1283
MatchAllCachesDidMatchAll(std::unique_ptr<std::vector<CacheMatchResponse>> match_responses,int64_t trace_id,CacheStorageCache::ResponseCallback callback)1284 void LegacyCacheStorage::MatchAllCachesDidMatchAll(
1285 std::unique_ptr<std::vector<CacheMatchResponse>> match_responses,
1286 int64_t trace_id,
1287 CacheStorageCache::ResponseCallback callback) {
1288 TRACE_EVENT_WITH_FLOW0("CacheStorage",
1289 "LegacyCacheStorage::MatchAllCachesDidMatchAll",
1290 TRACE_ID_GLOBAL(trace_id),
1291 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1292 for (CacheMatchResponse& match_response : *match_responses) {
1293 if (match_response.error == CacheStorageError::kErrorNotFound)
1294 continue;
1295 std::move(callback).Run(match_response.error,
1296 std::move(match_response.response));
1297 return;
1298 }
1299 std::move(callback).Run(CacheStorageError::kErrorNotFound, nullptr);
1300 }
1301
WriteToCacheImpl(const std::string & cache_name,blink::mojom::FetchAPIRequestPtr request,blink::mojom::FetchAPIResponsePtr response,int64_t trace_id,LegacyCacheStorage::ErrorCallback callback)1302 void LegacyCacheStorage::WriteToCacheImpl(
1303 const std::string& cache_name,
1304 blink::mojom::FetchAPIRequestPtr request,
1305 blink::mojom::FetchAPIResponsePtr response,
1306 int64_t trace_id,
1307 LegacyCacheStorage::ErrorCallback callback) {
1308 TRACE_EVENT_WITH_FLOW2("CacheStorage", "LegacyCacheStorage::WriteToCacheImpl",
1309 TRACE_ID_GLOBAL(trace_id),
1310 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
1311 "cache_name", cache_name, "request",
1312 CacheStorageTracedValue(request));
1313
1314 CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name);
1315
1316 if (!cache_handle.value()) {
1317 std::move(callback).Run(CacheStorageError::kErrorCacheNameNotFound);
1318 return;
1319 }
1320
1321 CacheStorageCache* cache_ptr = cache_handle.value();
1322 DCHECK(cache_ptr);
1323
1324 cache_ptr->Put(std::move(request), std::move(response), trace_id,
1325 std::move(callback));
1326 }
1327
GetLoadedCache(const std::string & cache_name)1328 CacheStorageCacheHandle LegacyCacheStorage::GetLoadedCache(
1329 const std::string& cache_name) {
1330 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1331 DCHECK(initialized_);
1332
1333 auto map_iter = cache_map_.find(cache_name);
1334 if (map_iter == cache_map_.end())
1335 return CacheStorageCacheHandle();
1336
1337 CacheStorageCache* cache = map_iter->second.get();
1338
1339 if (!cache) {
1340 const CacheStorageIndex::CacheMetadata* metadata =
1341 cache_index_->GetMetadata(cache_name);
1342 DCHECK(metadata);
1343 std::unique_ptr<LegacyCacheStorageCache> new_cache =
1344 cache_loader_->CreateCache(
1345 cache_name, metadata->size, metadata->padding,
1346 storage::DeserializePaddingKey(metadata->padding_key));
1347 CacheStorageCache* cache_ptr = new_cache.get();
1348 map_iter->second = std::move(new_cache);
1349
1350 return cache_ptr->CreateHandle();
1351 }
1352
1353 return cache->CreateHandle();
1354 }
1355
SizeRetrievedFromCache(CacheStorageCacheHandle cache_handle,base::OnceClosure closure,int64_t * accumulator,int64_t size)1356 void LegacyCacheStorage::SizeRetrievedFromCache(
1357 CacheStorageCacheHandle cache_handle,
1358 base::OnceClosure closure,
1359 int64_t* accumulator,
1360 int64_t size) {
1361 auto* impl = LegacyCacheStorageCache::From(cache_handle);
1362 if (doomed_caches_.find(impl) == doomed_caches_.end())
1363 cache_index_->SetCacheSize(impl->cache_name(), size);
1364 *accumulator += size;
1365 std::move(closure).Run();
1366 }
1367
GetSizeThenCloseAllCachesImpl(SizeCallback callback)1368 void LegacyCacheStorage::GetSizeThenCloseAllCachesImpl(SizeCallback callback) {
1369 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1370 DCHECK(initialized_);
1371
1372 std::unique_ptr<int64_t> accumulator(new int64_t(0));
1373 int64_t* accumulator_ptr = accumulator.get();
1374
1375 base::RepeatingClosure barrier_closure = base::BarrierClosure(
1376 cache_index_->num_entries() + doomed_caches_.size(),
1377 base::BindOnce(&SizeRetrievedFromAllCaches, std::move(accumulator),
1378 std::move(callback)));
1379
1380 for (const auto& cache_metadata : cache_index_->ordered_cache_metadata()) {
1381 auto cache_handle = GetLoadedCache(cache_metadata.name);
1382 LegacyCacheStorageCache::From(cache_handle)
1383 ->GetSizeThenClose(
1384 base::BindOnce(&LegacyCacheStorage::SizeRetrievedFromCache,
1385 weak_factory_.GetWeakPtr(), std::move(cache_handle),
1386 barrier_closure, accumulator_ptr));
1387 }
1388
1389 for (const auto& cache_it : doomed_caches_) {
1390 LegacyCacheStorageCache* cache = cache_it.first;
1391 cache->GetSizeThenClose(base::BindOnce(
1392 &LegacyCacheStorage::SizeRetrievedFromCache, weak_factory_.GetWeakPtr(),
1393 cache->CreateHandle(), barrier_closure, accumulator_ptr));
1394 }
1395 }
1396
SizeImpl(SizeCallback callback)1397 void LegacyCacheStorage::SizeImpl(SizeCallback callback) {
1398 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1399 DCHECK(initialized_);
1400
1401 if (cache_index_->GetPaddedStorageSize() != kSizeUnknown) {
1402 base::SequencedTaskRunnerHandle::Get()->PostTask(
1403 FROM_HERE, base::BindOnce(std::move(callback),
1404 cache_index_->GetPaddedStorageSize()));
1405 return;
1406 }
1407
1408 std::unique_ptr<int64_t> accumulator(new int64_t(0));
1409 int64_t* accumulator_ptr = accumulator.get();
1410
1411 base::RepeatingClosure barrier_closure = base::BarrierClosure(
1412 cache_index_->num_entries(),
1413 base::BindOnce(&SizeRetrievedFromAllCaches, std::move(accumulator),
1414 std::move(callback)));
1415
1416 for (const auto& cache_metadata : cache_index_->ordered_cache_metadata()) {
1417 if (cache_metadata.size != LegacyCacheStorage::kSizeUnknown) {
1418 *accumulator_ptr += cache_metadata.size;
1419 barrier_closure.Run();
1420 continue;
1421 }
1422 CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_metadata.name);
1423 LegacyCacheStorageCache::From(cache_handle)
1424 ->Size(base::BindOnce(&LegacyCacheStorage::SizeRetrievedFromCache,
1425 weak_factory_.GetWeakPtr(),
1426 std::move(cache_handle), barrier_closure,
1427 accumulator_ptr));
1428 }
1429 }
1430
FlushIndexIfDirty()1431 void LegacyCacheStorage::FlushIndexIfDirty() {
1432 if (!index_write_pending())
1433 return;
1434 index_write_task_.Cancel();
1435 cache_loader_->WriteIndex(*cache_index_, base::DoNothing::Once<bool>());
1436 }
1437
1438 #if defined(OS_ANDROID)
OnApplicationStateChange(base::android::ApplicationState state)1439 void LegacyCacheStorage::OnApplicationStateChange(
1440 base::android::ApplicationState state) {
1441 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1442 if (state == base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) {
1443 app_on_background_ = false;
1444 } else if (state == base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES) {
1445 app_on_background_ = true;
1446 FlushIndexIfDirty();
1447 }
1448 }
1449 #endif
1450
1451 } // namespace content
1452