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
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284

content / browser / background_fetch / background_fetch_data_manager.h [blame]

// Copyright 2017 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_BACKGROUND_FETCH_BACKGROUND_FETCH_DATA_MANAGER_H_
#define CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_DATA_MANAGER_H_

#include <map>
#include <memory>
#include <set>
#include <string>
#include <tuple>
#include <vector>

#include "base/containers/queue.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/observer_list.h"
#include "base/sequence_checker.h"
#include "content/browser/background_fetch/background_fetch.pb.h"
#include "content/browser/background_fetch/background_fetch_registration_id.h"
#include "content/browser/background_fetch/background_fetch_scheduler.h"
#include "content/browser/background_fetch/storage/database_task.h"
#include "content/browser/background_fetch/storage/get_initialization_data_task.h"
#include "content/common/content_export.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom.h"

namespace storage {
class BlobDataHandle;
class QuotaManagerProxy;
}  // namespace storage

namespace content {

class BackgroundFetchDataManagerObserver;
class BackgroundFetchRequestInfo;
class BackgroundFetchRequestMatchParams;
class ChromeBlobStorageContext;
class ServiceWorkerContextWrapper;
class StoragePartitionImpl;

// The BackgroundFetchDataManager is a wrapper around persistent storage (the
// Service Worker database), exposing APIs for the read and write queries needed
// for Background Fetch.
//
// There must only be a single instance of this class per StoragePartition, and
// it must only be used on the UI thread, since it relies on there being no
// other code concurrently reading/writing the Background Fetch keys of the same
// Service Worker database (except for deletions, e.g. it's safe for the Service
// Worker code to remove a ServiceWorkerRegistration and all its keys).
//
// Storage schema is documented in storage/README.md
class CONTENT_EXPORT BackgroundFetchDataManager
    : public background_fetch::DatabaseTaskHost {
 public:
  using GetInitializationDataCallback = base::OnceCallback<void(
      blink::mojom::BackgroundFetchError,
      std::vector<background_fetch::BackgroundFetchInitializationData>)>;
  using SettledFetchesCallback = base::OnceCallback<void(
      blink::mojom::BackgroundFetchError,
      std::vector<blink::mojom::BackgroundFetchSettledFetchPtr>)>;
  using CreateRegistrationCallback = base::OnceCallback<void(
      blink::mojom::BackgroundFetchError,
      blink::mojom::BackgroundFetchRegistrationDataPtr)>;
  using GetRegistrationCallback = base::OnceCallback<void(
      blink::mojom::BackgroundFetchError,
      BackgroundFetchRegistrationId,
      blink::mojom::BackgroundFetchRegistrationDataPtr)>;
  using MarkRegistrationForDeletionCallback =
      base::OnceCallback<void(blink::mojom::BackgroundFetchError,
                              blink::mojom::BackgroundFetchFailureReason)>;
  using GetRequestBlobCallback =
      base::OnceCallback<void(blink::mojom::BackgroundFetchError,
                              blink::mojom::SerializedBlobPtr)>;
  using MarkRequestCompleteCallback =
      base::OnceCallback<void(blink::mojom::BackgroundFetchError)>;
  using NextRequestCallback =
      base::OnceCallback<void(blink::mojom::BackgroundFetchError,
                              scoped_refptr<BackgroundFetchRequestInfo>)>;

  BackgroundFetchDataManager(
      base::WeakPtr<StoragePartitionImpl> storage_partition,
      scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
      scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy);

  BackgroundFetchDataManager(const BackgroundFetchDataManager&) = delete;
  BackgroundFetchDataManager& operator=(const BackgroundFetchDataManager&) =
      delete;

  ~BackgroundFetchDataManager() override;

  // Grabs a reference to CacheStorageManager.
  virtual void Initialize();

  // Adds or removes the given |observer| to this data manager instance.
  void AddObserver(BackgroundFetchDataManagerObserver* observer);
  void RemoveObserver(BackgroundFetchDataManagerObserver* observer);

  // Gets the required data to initialize BackgroundFetchContext with the
  // appropriate JobControllers. This will be called when BackgroundFetchContext
  // is being initialized.
  void GetInitializationData(GetInitializationDataCallback callback);

  // Creates and stores a new registration with the given properties. Will
  // invoke the |callback| when the registration has been created, which may
  // fail due to invalid input or storage errors.
  void CreateRegistration(
      const BackgroundFetchRegistrationId& registration_id,
      std::vector<blink::mojom::FetchAPIRequestPtr> requests,
      blink::mojom::BackgroundFetchOptionsPtr options,
      const SkBitmap& icon,
      bool start_paused,
      const net::IsolationInfo& isolation_info,
      CreateRegistrationCallback callback);

  // Get the BackgroundFetchRegistration.
  void GetRegistration(int64_t service_worker_registration_id,
                       const blink::StorageKey& storage_key,
                       const std::string& developer_id,
                       GetRegistrationCallback callback);

  // Reads the settled fetches for the given |registration_id| based on
  // |match_params|. Both the Request and Response objects will be initialised
  // based on the stored data. Will invoke the |callback| when the list of
  // fetches has been compiled.
  void MatchRequests(
      const BackgroundFetchRegistrationId& registration_id,
      std::unique_ptr<BackgroundFetchRequestMatchParams> match_params,
      SettledFetchesCallback callback);

  // Retrieves the next pending request for |registration_id| and invoke
  // |callback| with it.
  void PopNextRequest(const BackgroundFetchRegistrationId& registration_id,
                      NextRequestCallback callback);

  // Retrieves the request blob associated with |request_info|. THis should be
  // called for requests that are known to have a blob.
  void GetRequestBlob(
      const BackgroundFetchRegistrationId& registration_id,
      const scoped_refptr<BackgroundFetchRequestInfo>& request_info,
      GetRequestBlobCallback callback);

  // Marks |request_info| as complete and calls |callback| when done.
  void MarkRequestAsComplete(
      const BackgroundFetchRegistrationId& registration_id,
      scoped_refptr<BackgroundFetchRequestInfo> request_info,
      MarkRequestCompleteCallback callback);

  // Marks that the
  // backgroundfetchsuccess/backgroundfetchfail/backgroundfetchabort event is
  // being dispatched. It's not possible to call DeleteRegistration at this
  // point as JavaScript may hold a reference to a BackgroundFetchRegistration
  // object and we need to keep the corresponding data around until the last
  // such reference is released (or until shutdown). We can't just move the
  // Background Fetch registration's data to RAM as it might consume too much
  // memory. So instead this step disassociates the |developer_id| from the
  // |unique_id|, so that existing JS objects with a reference to |unique_id|
  // can still access the data, but it can no longer be reached using GetIds or
  // GetRegistration. If |check_for_failure| is true, the task will also check
  // whether there is any associated failure reason with the fetches. This
  // helps figure out whether a success or fail event should be dispatched.
  void MarkRegistrationForDeletion(
      const BackgroundFetchRegistrationId& registration_id,
      bool check_for_failure,
      MarkRegistrationForDeletionCallback callback);

  // Deletes the registration identified by |registration_id|. Should only be
  // called once the refcount of JavaScript BackgroundFetchRegistration objects
  // referring to this registration drops to zero. Will invoke the |callback|
  // when the registration has been deleted from storage.
  void DeleteRegistration(const BackgroundFetchRegistrationId& registration_id,
                          HandleBackgroundFetchErrorCallback callback);

  // List all Background Fetch registration |developer_id|s for a Service
  // Worker.
  void GetDeveloperIdsForServiceWorker(
      int64_t service_worker_registration_id,
      const blink::StorageKey& storage_key,
      blink::mojom::BackgroundFetchService::GetDeveloperIdsCallback callback);

  const base::ObserverList<BackgroundFetchDataManagerObserver>::Unchecked&
  observers() {
    return observers_;
  }

  void Shutdown();

 private:
  FRIEND_TEST_ALL_PREFIXES(BackgroundFetchDataManagerTest, Cleanup);
  friend class BackgroundFetchDataManagerTest;
  friend class BackgroundFetchTestDataManager;
  friend class background_fetch::DatabaseTask;

  // Accessors for tests and DatabaseTasks.
  ServiceWorkerContextWrapper* service_worker_context() const {
    return service_worker_context_.get();
  }
  std::set<std::string>& ref_counted_unique_ids() {
    return ref_counted_unique_ids_;
  }
  ChromeBlobStorageContext* blob_storage_context() const {
    return blob_storage_context_.get();
  }
  const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy() const {
    return quota_manager_proxy_;
  }

  void AddDatabaseTask(std::unique_ptr<background_fetch::DatabaseTask> task);

  // DatabaseTaskHost implementation.
  void OnTaskFinished(background_fetch::DatabaseTask* task) override;
  BackgroundFetchDataManager* data_manager() override;
  base::WeakPtr<background_fetch::DatabaseTaskHost> GetWeakPtr() override;

  void Cleanup();

  // Get a CacheStorage remote for the given |storage_key| and |unique_id|. This
  // will either be a reference to an existing remote or will cause the
  // CacheStorage to be opened.  The BackgroundFetchDataManager owns this
  // remote for the lifetime of the connection.
  mojo::Remote<blink::mojom::CacheStorage>& GetOrOpenCacheStorage(
      const blink::StorageKey& storage_key,
      const std::string& unique_id);
  void OpenCache(const blink::StorageKey& storage_key,
                 const std::string& unique_id,
                 int64_t trace_id,
                 blink::mojom::CacheStorage::OpenCallback callback);
  void DeleteCache(const blink::StorageKey& storage_key,
                   const std::string& unique_id,
                   int64_t trace_id,
                   blink::mojom::CacheStorage::DeleteCallback callback);
  void DidDeleteCache(const std::string& unique_id,
                      blink::mojom::CacheStorage::DeleteCallback callback,
                      blink::mojom::CacheStorageError result);

  void HasCache(const blink::StorageKey& storage_key,
                const std::string& unique_id,
                int64_t trace_id,
                blink::mojom::CacheStorage::HasCallback callback);

  // Whether Shutdown was called on BackgroundFetchContext.
  bool shutting_down_ = false;

  scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;

  base::WeakPtr<StoragePartitionImpl> storage_partition_;

  scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;

  // The blob storage request with which response information will be stored.
  scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;

  // Pending database operations, serialized to ensure consistency.
  // Invariant: the frontmost task, if any, has already been started.
  base::queue<std::unique_ptr<background_fetch::DatabaseTask>> database_tasks_;

  base::ObserverList<BackgroundFetchDataManagerObserver>::Unchecked observers_;

  // The |unique_id|s of registrations that have been deactivated since the
  // browser was last started. They will be automatically deleted when the
  // refcount of JavaScript objects that refers to them goes to zero, unless
  // the browser is shutdown first.
  std::set<std::string> ref_counted_unique_ids_;

  // A map of open CacheStorage remotes keyed by the registration
  // |unique_id|. These remotes are created opportunistically in
  // GetOrOpenCacheStorage(). They are cleared after the Cache has been
  // deleted.
  // TODO(crbug.com/40515511): Possibly update key when CORS support is added.
  std::map<std::string, mojo::Remote<blink::mojom::CacheStorage>>
      cache_storage_remote_map_;
  mojo::Remote<blink::mojom::CacheStorage> null_remote_;

  SEQUENCE_CHECKER(sequence_checker_);

  base::WeakPtrFactory<BackgroundFetchDataManager> weak_ptr_factory_{this};
};

}  // namespace content

#endif  // CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_DATA_MANAGER_H_