tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

StorageIPC.cpp (46701B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "StorageIPC.h"
      8 
      9 #include "LocalStorageManager.h"
     10 #include "SessionStorageCache.h"
     11 #include "SessionStorageManager.h"
     12 #include "SessionStorageObserver.h"
     13 #include "StorageCommon.h"
     14 #include "StorageUtils.h"
     15 #include "mozilla/StoragePrincipalHelper.h"
     16 #include "mozilla/dom/ContentParent.h"
     17 #include "mozilla/dom/LocalStorageCommon.h"
     18 #include "mozilla/ipc/BackgroundChild.h"
     19 #include "mozilla/ipc/BackgroundParent.h"
     20 #include "mozilla/ipc/PBackgroundChild.h"
     21 #include "mozilla/ipc/PBackgroundParent.h"
     22 #include "nsCOMPtr.h"
     23 #include "nsIPrincipal.h"
     24 #include "nsThreadUtils.h"
     25 
     26 namespace mozilla::dom {
     27 
     28 namespace {
     29 
     30 using LocalStorageCacheParentHashtable =
     31    nsClassHashtable<nsCStringHashKey, nsTArray<LocalStorageCacheParent*>>;
     32 
     33 StaticAutoPtr<LocalStorageCacheParentHashtable> gLocalStorageCacheParents;
     34 
     35 StorageDBChild* sStorageChild[kPrivateBrowsingIdCount] = {nullptr, nullptr};
     36 
     37 // False until we shut the storage child down.
     38 bool sStorageChildDown[kPrivateBrowsingIdCount] = {false, false};
     39 
     40 }  // namespace
     41 
     42 LocalStorageCacheChild::LocalStorageCacheChild(LocalStorageCache* aCache)
     43    : mCache(aCache) {
     44  AssertIsOnOwningThread();
     45  MOZ_ASSERT(aCache);
     46  aCache->AssertIsOnOwningThread();
     47 
     48  MOZ_COUNT_CTOR(LocalStorageCacheChild);
     49 }
     50 
     51 LocalStorageCacheChild::~LocalStorageCacheChild() {
     52  AssertIsOnOwningThread();
     53 
     54  MOZ_COUNT_DTOR(LocalStorageCacheChild);
     55 }
     56 
     57 void LocalStorageCacheChild::SendDeleteMeInternal() {
     58  AssertIsOnOwningThread();
     59 
     60  if (mCache) {
     61    mCache->ClearActor();
     62    mCache = nullptr;
     63 
     64    MOZ_ALWAYS_TRUE(PBackgroundLocalStorageCacheChild::SendDeleteMe());
     65  }
     66 }
     67 
     68 void LocalStorageCacheChild::ActorDestroy(ActorDestroyReason aWhy) {
     69  AssertIsOnOwningThread();
     70 
     71  if (mCache) {
     72    mCache->ClearActor();
     73    mCache = nullptr;
     74  }
     75 }
     76 
     77 mozilla::ipc::IPCResult LocalStorageCacheChild::RecvObserve(
     78    const PrincipalInfo& aPrincipalInfo,
     79    const PrincipalInfo& aCachePrincipalInfo,
     80    const uint32_t& aPrivateBrowsingId, const nsAString& aDocumentURI,
     81    const nsAString& aKey, const nsAString& aOldValue,
     82    const nsAString& aNewValue) {
     83  AssertIsOnOwningThread();
     84 
     85  auto principalOrErr = PrincipalInfoToPrincipal(aPrincipalInfo);
     86  if (NS_WARN_IF(principalOrErr.isErr())) {
     87    return IPC_FAIL_NO_REASON(this);
     88  }
     89 
     90  auto cachePrincipalOrErr = PrincipalInfoToPrincipal(aCachePrincipalInfo);
     91  if (NS_WARN_IF(cachePrincipalOrErr.isErr())) {
     92    return IPC_FAIL_NO_REASON(this);
     93  }
     94 
     95  nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
     96  nsCOMPtr<nsIPrincipal> cachePrincipal = cachePrincipalOrErr.unwrap();
     97 
     98  if (StorageUtils::PrincipalsEqual(principal, cachePrincipal)) {
     99    Storage::NotifyChange(/* aStorage */ nullptr, principal, aKey, aOldValue,
    100                          aNewValue,
    101                          /* aStorageType */ u"localStorage", aDocumentURI,
    102                          /* aIsPrivate */ !!aPrivateBrowsingId,
    103                          /* aImmediateDispatch */ true);
    104  }
    105 
    106  return IPC_OK();
    107 }
    108 
    109 // ----------------------------------------------------------------------------
    110 // Child
    111 // ----------------------------------------------------------------------------
    112 
    113 class StorageDBChild::ShutdownObserver final : public nsIObserver {
    114  // Expected to be only 0 or 1.
    115  const uint32_t mPrivateBrowsingId;
    116 
    117 public:
    118  explicit ShutdownObserver(const uint32_t aPrivateBrowsingId)
    119      : mPrivateBrowsingId(aPrivateBrowsingId) {
    120    MOZ_ASSERT(NS_IsMainThread());
    121    MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
    122  }
    123 
    124  NS_DECL_ISUPPORTS
    125  NS_DECL_NSIOBSERVER
    126 
    127 private:
    128  ~ShutdownObserver() { MOZ_ASSERT(NS_IsMainThread()); }
    129 };
    130 
    131 void StorageDBChild::AddIPDLReference() {
    132  MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references");
    133  mIPCOpen = true;
    134  AddRef();
    135 }
    136 
    137 void StorageDBChild::ReleaseIPDLReference() {
    138  MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference");
    139  mIPCOpen = false;
    140  Release();
    141 }
    142 
    143 StorageDBChild::StorageDBChild(LocalStorageManager* aManager,
    144                               const uint32_t aPrivateBrowsingId)
    145    : mManager(aManager),
    146      mPrivateBrowsingId(aPrivateBrowsingId),
    147      mStatus(NS_OK),
    148      mIPCOpen(false) {
    149  MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
    150  MOZ_ASSERT(!NextGenLocalStorageEnabled());
    151 }
    152 
    153 StorageDBChild::~StorageDBChild() = default;
    154 
    155 // static
    156 StorageDBChild* StorageDBChild::Get(const uint32_t aPrivateBrowsingId) {
    157  MOZ_ASSERT(NS_IsMainThread());
    158  MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
    159  MOZ_ASSERT(!NextGenLocalStorageEnabled());
    160 
    161  return sStorageChild[aPrivateBrowsingId];
    162 }
    163 
    164 // static
    165 StorageDBChild* StorageDBChild::GetOrCreate(const uint32_t aPrivateBrowsingId) {
    166  MOZ_ASSERT(NS_IsMainThread());
    167  MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
    168  MOZ_ASSERT(!NextGenLocalStorageEnabled());
    169 
    170  StorageDBChild*& storageChild = sStorageChild[aPrivateBrowsingId];
    171  if (storageChild || sStorageChildDown[aPrivateBrowsingId]) {
    172    // When sStorageChildDown is at true, sStorageChild is null.
    173    // Checking sStorageChildDown flag here prevents reinitialization of
    174    // the storage child after shutdown.
    175    return storageChild;
    176  }
    177 
    178  // Use LocalStorageManager::Ensure in case we're called from
    179  // DOMSessionStorageManager's initializer and we haven't yet initialized the
    180  // local storage manager.
    181  RefPtr<StorageDBChild> newStorageChild =
    182      new StorageDBChild(LocalStorageManager::Ensure(), aPrivateBrowsingId);
    183 
    184  nsresult rv = newStorageChild->Init();
    185  if (NS_WARN_IF(NS_FAILED(rv))) {
    186    return nullptr;
    187  }
    188 
    189  newStorageChild.forget(&storageChild);
    190 
    191  return storageChild;
    192 }
    193 
    194 nsTHashSet<nsCString>& StorageDBChild::OriginsHavingData() {
    195  if (!mOriginsHavingData) {
    196    mOriginsHavingData = MakeUnique<nsTHashSet<nsCString>>();
    197  }
    198 
    199  return *mOriginsHavingData;
    200 }
    201 
    202 nsresult StorageDBChild::Init() {
    203  MOZ_ASSERT(NS_IsMainThread());
    204 
    205  ::mozilla::ipc::PBackgroundChild* actor =
    206      ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
    207  if (NS_WARN_IF(!actor)) {
    208    return NS_ERROR_FAILURE;
    209  }
    210 
    211  nsString profilePath;
    212  if (XRE_IsParentProcess() && mPrivateBrowsingId == 0) {
    213    nsresult rv = StorageDBThread::GetProfilePath(profilePath);
    214    if (NS_WARN_IF(NS_FAILED(rv))) {
    215      return rv;
    216    }
    217  }
    218 
    219  AddIPDLReference();
    220 
    221  actor->SendPBackgroundStorageConstructor(this, profilePath,
    222                                           mPrivateBrowsingId);
    223 
    224  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
    225  MOZ_ASSERT(observerService);
    226 
    227  nsCOMPtr<nsIObserver> observer = new ShutdownObserver(mPrivateBrowsingId);
    228 
    229  MOZ_ALWAYS_SUCCEEDS(
    230      observerService->AddObserver(observer, "xpcom-shutdown", false));
    231 
    232  return NS_OK;
    233 }
    234 
    235 nsresult StorageDBChild::Shutdown() {
    236  // There is nothing to do here, IPC will release automatically and
    237  // the actual thread running on the parent process will also stop
    238  // automatically in profile-before-change topic observer.
    239  return NS_OK;
    240 }
    241 
    242 void StorageDBChild::AsyncPreload(LocalStorageCacheBridge* aCache,
    243                                  bool aPriority) {
    244  if (mIPCOpen) {
    245    // Adding ref to cache for the time of preload.  This ensures a reference to
    246    // to the cache and that all keys will load into this cache object.
    247    mLoadingCaches.Insert(aCache);
    248    SendAsyncPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
    249                     aPriority);
    250  } else {
    251    // No IPC, no love.  But the LoadDone call is expected.
    252    aCache->LoadDone(NS_ERROR_UNEXPECTED);
    253  }
    254 }
    255 
    256 void StorageDBChild::AsyncGetUsage(StorageUsageBridge* aUsage) {
    257  if (mIPCOpen) {
    258    SendAsyncGetUsage(aUsage->OriginScope());
    259  }
    260 }
    261 
    262 void StorageDBChild::SyncPreload(LocalStorageCacheBridge* aCache,
    263                                 bool aForceSync) {
    264  if (NS_FAILED(mStatus)) {
    265    aCache->LoadDone(mStatus);
    266    return;
    267  }
    268 
    269  if (!mIPCOpen) {
    270    aCache->LoadDone(NS_ERROR_UNEXPECTED);
    271    return;
    272  }
    273 
    274  // There is no way to put the child process to a wait state to receive all
    275  // incoming async responses from the parent, hence we have to do a sync
    276  // preload instead.  We are smart though, we only demand keys that are left to
    277  // load in case the async preload has already loaded some keys.
    278  nsTArray<nsString> keys, values;
    279  nsresult rv;
    280  SendPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
    281              aCache->LoadedCount(), &keys, &values, &rv);
    282 
    283  for (uint32_t i = 0; i < keys.Length(); ++i) {
    284    aCache->LoadItem(keys[i], values[i]);
    285  }
    286 
    287  aCache->LoadDone(rv);
    288 }
    289 
    290 nsresult StorageDBChild::AsyncAddItem(LocalStorageCacheBridge* aCache,
    291                                      const nsAString& aKey,
    292                                      const nsAString& aValue) {
    293  if (NS_FAILED(mStatus) || !mIPCOpen) {
    294    return mStatus;
    295  }
    296 
    297  SendAsyncAddItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
    298                   nsString(aKey), nsString(aValue));
    299  OriginsHavingData().Insert(aCache->Origin());
    300  return NS_OK;
    301 }
    302 
    303 nsresult StorageDBChild::AsyncUpdateItem(LocalStorageCacheBridge* aCache,
    304                                         const nsAString& aKey,
    305                                         const nsAString& aValue) {
    306  if (NS_FAILED(mStatus) || !mIPCOpen) {
    307    return mStatus;
    308  }
    309 
    310  SendAsyncUpdateItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
    311                      nsString(aKey), nsString(aValue));
    312  OriginsHavingData().Insert(aCache->Origin());
    313  return NS_OK;
    314 }
    315 
    316 nsresult StorageDBChild::AsyncRemoveItem(LocalStorageCacheBridge* aCache,
    317                                         const nsAString& aKey) {
    318  if (NS_FAILED(mStatus) || !mIPCOpen) {
    319    return mStatus;
    320  }
    321 
    322  SendAsyncRemoveItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
    323                      nsString(aKey));
    324  return NS_OK;
    325 }
    326 
    327 nsresult StorageDBChild::AsyncClear(LocalStorageCacheBridge* aCache) {
    328  if (NS_FAILED(mStatus) || !mIPCOpen) {
    329    return mStatus;
    330  }
    331 
    332  SendAsyncClear(aCache->OriginSuffix(), aCache->OriginNoSuffix());
    333  OriginsHavingData().Remove(aCache->Origin());
    334  return NS_OK;
    335 }
    336 
    337 bool StorageDBChild::ShouldPreloadOrigin(const nsACString& aOrigin) {
    338  // Return true if we didn't receive the origins list yet.
    339  // I tend to rather preserve a bit of early-after-start performance
    340  // than a bit of memory here.
    341  return !mOriginsHavingData || mOriginsHavingData->Contains(aOrigin);
    342 }
    343 
    344 mozilla::ipc::IPCResult StorageDBChild::RecvObserve(
    345    const nsACString& aTopic, const nsAString& aOriginAttributesPattern,
    346    const nsACString& aOriginScope) {
    347  MOZ_ASSERT(!XRE_IsParentProcess());
    348 
    349  if (StorageObserver* obs = StorageObserver::Self()) {
    350    obs->Notify(PromiseFlatCString(aTopic).get(), aOriginAttributesPattern,
    351                aOriginScope);
    352  }
    353 
    354  return IPC_OK();
    355 }
    356 
    357 mozilla::ipc::IPCResult StorageDBChild::RecvOriginsHavingData(
    358    nsTArray<nsCString>&& aOrigins) {
    359  // Force population of mOriginsHavingData even if there are no origins so that
    360  // ShouldPreloadOrigin does not generate false positives for all origins.
    361  if (!aOrigins.Length()) {
    362    (void)OriginsHavingData();
    363  }
    364 
    365  for (uint32_t i = 0; i < aOrigins.Length(); ++i) {
    366    OriginsHavingData().Insert(aOrigins[i]);
    367  }
    368 
    369  return IPC_OK();
    370 }
    371 
    372 mozilla::ipc::IPCResult StorageDBChild::RecvLoadItem(
    373    const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
    374    const nsAString& aKey, const nsAString& aValue) {
    375  LocalStorageCache* aCache =
    376      mManager->GetCache(aOriginSuffix, aOriginNoSuffix);
    377  if (aCache) {
    378    aCache->LoadItem(aKey, aValue);
    379  }
    380 
    381  return IPC_OK();
    382 }
    383 
    384 mozilla::ipc::IPCResult StorageDBChild::RecvLoadDone(
    385    const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
    386    const nsresult& aRv) {
    387  LocalStorageCache* aCache =
    388      mManager->GetCache(aOriginSuffix, aOriginNoSuffix);
    389  if (aCache) {
    390    aCache->LoadDone(aRv);
    391 
    392    // Just drop reference to this cache now since the load is done.
    393    mLoadingCaches.Remove(static_cast<LocalStorageCacheBridge*>(aCache));
    394  }
    395 
    396  return IPC_OK();
    397 }
    398 
    399 mozilla::ipc::IPCResult StorageDBChild::RecvLoadUsage(
    400    const nsACString& aOriginNoSuffix, const int64_t& aUsage) {
    401  RefPtr<StorageUsageBridge> scopeUsage =
    402      mManager->GetOriginUsage(aOriginNoSuffix, mPrivateBrowsingId);
    403  scopeUsage->LoadUsage(aUsage);
    404  return IPC_OK();
    405 }
    406 
    407 mozilla::ipc::IPCResult StorageDBChild::RecvError(const nsresult& aRv) {
    408  mStatus = aRv;
    409  return IPC_OK();
    410 }
    411 
    412 NS_IMPL_ISUPPORTS(StorageDBChild::ShutdownObserver, nsIObserver)
    413 
    414 NS_IMETHODIMP
    415 StorageDBChild::ShutdownObserver::Observe(nsISupports* aSubject,
    416                                          const char* aTopic,
    417                                          const char16_t* aData) {
    418  MOZ_ASSERT(NS_IsMainThread());
    419  MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
    420 
    421  nsCOMPtr<nsIObserverService> observerService =
    422      mozilla::services::GetObserverService();
    423  if (NS_WARN_IF(!observerService)) {
    424    return NS_ERROR_FAILURE;
    425  }
    426 
    427  (void)observerService->RemoveObserver(this, "xpcom-shutdown");
    428 
    429  StorageDBChild*& storageChild = sStorageChild[mPrivateBrowsingId];
    430  if (storageChild) {
    431    sStorageChildDown[mPrivateBrowsingId] = true;
    432 
    433    MOZ_ALWAYS_TRUE(storageChild->PBackgroundStorageChild::SendDeleteMe());
    434 
    435    NS_RELEASE(storageChild);
    436    storageChild = nullptr;
    437  }
    438 
    439  return NS_OK;
    440 }
    441 
    442 SessionStorageObserverChild::SessionStorageObserverChild(
    443    SessionStorageObserver* aObserver)
    444    : mObserver(aObserver) {
    445  AssertIsOnOwningThread();
    446  MOZ_ASSERT(NextGenLocalStorageEnabled());
    447  MOZ_ASSERT(aObserver);
    448  aObserver->AssertIsOnOwningThread();
    449 
    450  MOZ_COUNT_CTOR(SessionStorageObserverChild);
    451 }
    452 
    453 SessionStorageObserverChild::~SessionStorageObserverChild() {
    454  AssertIsOnOwningThread();
    455 
    456  MOZ_COUNT_DTOR(SessionStorageObserverChild);
    457 }
    458 
    459 void SessionStorageObserverChild::SendDeleteMeInternal() {
    460  AssertIsOnOwningThread();
    461 
    462  if (mObserver) {
    463    mObserver->ClearActor();
    464    mObserver = nullptr;
    465 
    466    // Don't check result here since IPC may no longer be available due to
    467    // SessionStorageManager (which holds a strong reference to
    468    // SessionStorageObserver) being destroyed very late in the game.
    469    PSessionStorageObserverChild::SendDeleteMe();
    470  }
    471 }
    472 
    473 void SessionStorageObserverChild::ActorDestroy(ActorDestroyReason aWhy) {
    474  AssertIsOnOwningThread();
    475 
    476  if (mObserver) {
    477    mObserver->ClearActor();
    478    mObserver = nullptr;
    479  }
    480 }
    481 
    482 mozilla::ipc::IPCResult SessionStorageObserverChild::RecvObserve(
    483    const nsACString& aTopic, const nsAString& aOriginAttributesPattern,
    484    const nsACString& aOriginScope) {
    485  AssertIsOnOwningThread();
    486 
    487  if (StorageObserver* obs = StorageObserver::Self()) {
    488    obs->Notify(PromiseFlatCString(aTopic).get(), aOriginAttributesPattern,
    489                aOriginScope);
    490  }
    491 
    492  return IPC_OK();
    493 }
    494 
    495 SessionStorageCacheChild::SessionStorageCacheChild(SessionStorageCache* aCache)
    496    : mCache(aCache) {
    497  AssertIsOnOwningThread();
    498  MOZ_ASSERT(mCache);
    499 
    500  MOZ_COUNT_CTOR(SessionStorageCacheChild);
    501 }
    502 
    503 SessionStorageCacheChild::~SessionStorageCacheChild() {
    504  AssertIsOnOwningThread();
    505 
    506  MOZ_COUNT_DTOR(SessionStorageCacheChild);
    507 }
    508 
    509 void SessionStorageCacheChild::SendDeleteMeInternal() {
    510  AssertIsOnOwningThread();
    511 
    512  if (mCache) {
    513    mCache->ClearActor();
    514    mCache = nullptr;
    515 
    516    MOZ_ALWAYS_TRUE(PBackgroundSessionStorageCacheChild::SendDeleteMe());
    517  }
    518 }
    519 
    520 void SessionStorageCacheChild::ActorDestroy(ActorDestroyReason aWhy) {
    521  AssertIsOnOwningThread();
    522 
    523  if (mCache) {
    524    mCache->ClearActor();
    525    mCache = nullptr;
    526  }
    527 }
    528 
    529 SessionStorageManagerChild::SessionStorageManagerChild(
    530    SessionStorageManager* aSSManager)
    531    : mSSManager(aSSManager) {
    532  AssertIsOnOwningThread();
    533  MOZ_ASSERT(mSSManager);
    534 
    535  MOZ_COUNT_CTOR(SessionStorageManagerChild);
    536 }
    537 
    538 SessionStorageManagerChild::~SessionStorageManagerChild() {
    539  AssertIsOnOwningThread();
    540 
    541  MOZ_COUNT_DTOR(SessionStorageManagerChild);
    542 }
    543 
    544 void SessionStorageManagerChild::SendDeleteMeInternal() {
    545  AssertIsOnOwningThread();
    546 
    547  if (mSSManager) {
    548    mSSManager->ClearActor();
    549    mSSManager = nullptr;
    550 
    551    MOZ_ALWAYS_TRUE(PBackgroundSessionStorageManagerChild::SendDeleteMe());
    552  }
    553 }
    554 
    555 void SessionStorageManagerChild::ActorDestroy(ActorDestroyReason aWhy) {
    556  AssertIsOnOwningThread();
    557 
    558  if (mSSManager) {
    559    mSSManager->ClearActor();
    560    mSSManager = nullptr;
    561  }
    562 }
    563 
    564 mozilla::ipc::IPCResult SessionStorageManagerChild::RecvClearStoragesForOrigin(
    565    const nsACString& aOriginAttrs, const nsACString& aOriginKey) {
    566  AssertIsOnOwningThread();
    567 
    568  if (mSSManager) {
    569    mSSManager->ClearStoragesForOrigin(aOriginAttrs, aOriginKey);
    570  }
    571 
    572  return IPC_OK();
    573 }
    574 
    575 LocalStorageCacheParent::LocalStorageCacheParent(
    576    const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
    577    const nsACString& aOriginKey, uint32_t aPrivateBrowsingId)
    578    : mPrincipalInfo(aPrincipalInfo),
    579      mOriginKey(aOriginKey),
    580      mPrivateBrowsingId(aPrivateBrowsingId),
    581      mActorDestroyed(false) {
    582  ::mozilla::ipc::AssertIsOnBackgroundThread();
    583 }
    584 
    585 LocalStorageCacheParent::~LocalStorageCacheParent() {
    586  MOZ_ASSERT(mActorDestroyed);
    587 }
    588 
    589 void LocalStorageCacheParent::ActorDestroy(ActorDestroyReason aWhy) {
    590  ::mozilla::ipc::AssertIsOnBackgroundThread();
    591  MOZ_ASSERT(!mActorDestroyed);
    592 
    593  mActorDestroyed = true;
    594 
    595  MOZ_ASSERT(gLocalStorageCacheParents);
    596 
    597  nsTArray<LocalStorageCacheParent*>* array;
    598  gLocalStorageCacheParents->Get(mOriginKey, &array);
    599  MOZ_ASSERT(array);
    600 
    601  array->RemoveElement(this);
    602 
    603  if (array->IsEmpty()) {
    604    gLocalStorageCacheParents->Remove(mOriginKey);
    605  }
    606 
    607  if (!gLocalStorageCacheParents->Count()) {
    608    gLocalStorageCacheParents = nullptr;
    609  }
    610 }
    611 
    612 mozilla::ipc::IPCResult LocalStorageCacheParent::RecvDeleteMe() {
    613  ::mozilla::ipc::AssertIsOnBackgroundThread();
    614  MOZ_ASSERT(!mActorDestroyed);
    615 
    616  IProtocol* mgr = Manager();
    617  if (!PBackgroundLocalStorageCacheParent::Send__delete__(this)) {
    618    return IPC_FAIL_NO_REASON(mgr);
    619  }
    620  return IPC_OK();
    621 }
    622 
    623 mozilla::ipc::IPCResult LocalStorageCacheParent::RecvNotify(
    624    const nsAString& aDocumentURI, const nsAString& aKey,
    625    const nsAString& aOldValue, const nsAString& aNewValue) {
    626  ::mozilla::ipc::AssertIsOnBackgroundThread();
    627  MOZ_ASSERT(gLocalStorageCacheParents);
    628 
    629  nsTArray<LocalStorageCacheParent*>* array;
    630  gLocalStorageCacheParents->Get(mOriginKey, &array);
    631  MOZ_ASSERT(array);
    632 
    633  for (LocalStorageCacheParent* localStorageCacheParent : *array) {
    634    if (localStorageCacheParent != this) {
    635      // When bug 1443925 is fixed, we can compare mPrincipalInfo against
    636      // localStorageCacheParent->PrincipalInfo() here on the background thread
    637      // instead of posting it to the main thread.  The advantage of doing so is
    638      // that it would save an IPC message in the case where the principals do
    639      // not match.
    640      (void)localStorageCacheParent->SendObserve(
    641          mPrincipalInfo, localStorageCacheParent->PrincipalInfo(),
    642          mPrivateBrowsingId, aDocumentURI, aKey, aOldValue, aNewValue);
    643    }
    644  }
    645 
    646  return IPC_OK();
    647 }
    648 
    649 // ----------------------------------------------------------------------------
    650 // Parent
    651 // ----------------------------------------------------------------------------
    652 
    653 class StorageDBParent::ObserverSink : public StorageObserverSink {
    654  nsCOMPtr<nsIEventTarget> mOwningEventTarget;
    655 
    656  // Only touched on the PBackground thread.
    657  StorageDBParent* MOZ_NON_OWNING_REF mActor;
    658 
    659 public:
    660  explicit ObserverSink(StorageDBParent* aActor)
    661      : mOwningEventTarget(GetCurrentSerialEventTarget()), mActor(aActor) {
    662    ::mozilla::ipc::AssertIsOnBackgroundThread();
    663    MOZ_ASSERT(aActor);
    664  }
    665 
    666  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StorageDBParent::ObserverSink);
    667 
    668  void Start();
    669 
    670  void Stop();
    671 
    672 private:
    673  ~ObserverSink() = default;
    674 
    675  void AddSink();
    676 
    677  void RemoveSink();
    678 
    679  void Notify(const nsACString& aTopic,
    680              const nsAString& aOriginAttributesPattern,
    681              const nsACString& aOriginScope);
    682 
    683  // StorageObserverSink
    684  nsresult Observe(const char* aTopic, const nsAString& aOriginAttrPattern,
    685                   const nsACString& aOriginScope) override;
    686 };
    687 
    688 NS_IMPL_ADDREF(StorageDBParent)
    689 NS_IMPL_RELEASE(StorageDBParent)
    690 
    691 void StorageDBParent::AddIPDLReference() {
    692  MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references");
    693  mIPCOpen = true;
    694  AddRef();
    695 }
    696 
    697 void StorageDBParent::ReleaseIPDLReference() {
    698  MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference");
    699  mIPCOpen = false;
    700  Release();
    701 }
    702 
    703 namespace {}  // namespace
    704 
    705 StorageDBParent::StorageDBParent(const nsAString& aProfilePath,
    706                                 const uint32_t aPrivateBrowsingId)
    707    : mProfilePath(aProfilePath),
    708      mPrivateBrowsingId(aPrivateBrowsingId),
    709      mIPCOpen(false) {
    710  ::mozilla::ipc::AssertIsOnBackgroundThread();
    711 
    712  // We are always open by IPC only
    713  AddIPDLReference();
    714 }
    715 
    716 StorageDBParent::~StorageDBParent() {
    717  ::mozilla::ipc::AssertIsOnBackgroundThread();
    718 
    719  if (mObserverSink) {
    720    mObserverSink->Stop();
    721    mObserverSink = nullptr;
    722  }
    723 }
    724 
    725 void StorageDBParent::Init() {
    726  ::mozilla::ipc::AssertIsOnBackgroundThread();
    727 
    728  PBackgroundParent* actor = Manager();
    729  MOZ_ASSERT(actor);
    730 
    731  if (::mozilla::ipc::BackgroundParent::IsOtherProcessActor(actor)) {
    732    mObserverSink = new ObserverSink(this);
    733    mObserverSink->Start();
    734  }
    735 
    736  StorageDBThread* storageThread = StorageDBThread::Get(mPrivateBrowsingId);
    737  if (storageThread) {
    738    nsTArray<nsCString> scopes;
    739    storageThread->GetOriginsHavingData(&scopes);
    740    (void)SendOriginsHavingData(scopes);
    741  }
    742 }
    743 
    744 StorageDBParent::CacheParentBridge* StorageDBParent::NewCache(
    745    const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix) {
    746  return new CacheParentBridge(this, aOriginSuffix, aOriginNoSuffix);
    747 }
    748 
    749 void StorageDBParent::ActorDestroy(ActorDestroyReason aWhy) {
    750  // Implement me! Bug 1005169
    751 }
    752 
    753 mozilla::ipc::IPCResult StorageDBParent::RecvDeleteMe() {
    754  ::mozilla::ipc::AssertIsOnBackgroundThread();
    755 
    756  IProtocol* mgr = Manager();
    757  if (!PBackgroundStorageParent::Send__delete__(this)) {
    758    return IPC_FAIL_NO_REASON(mgr);
    759  }
    760  return IPC_OK();
    761 }
    762 
    763 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncPreload(
    764    const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
    765    const bool& aPriority) {
    766  StorageDBThread* storageThread =
    767      StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
    768  if (!storageThread) {
    769    return IPC_FAIL_NO_REASON(this);
    770  }
    771 
    772  storageThread->AsyncPreload(NewCache(aOriginSuffix, aOriginNoSuffix),
    773                              aPriority);
    774 
    775  return IPC_OK();
    776 }
    777 
    778 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncGetUsage(
    779    const nsACString& aOriginNoSuffix) {
    780  StorageDBThread* storageThread =
    781      StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
    782  if (!storageThread) {
    783    return IPC_FAIL_NO_REASON(this);
    784  }
    785 
    786  // The object releases it self in LoadUsage method
    787  RefPtr<UsageParentBridge> usage =
    788      new UsageParentBridge(this, aOriginNoSuffix);
    789 
    790  storageThread->AsyncGetUsage(usage);
    791 
    792  return IPC_OK();
    793 }
    794 
    795 namespace {
    796 
    797 // We need another implementation of LocalStorageCacheBridge to do
    798 // synchronous IPC preload.  This class just receives Load* notifications
    799 // and fills the returning arguments of RecvPreload with the database
    800 // values for us.
    801 class SyncLoadCacheHelper : public LocalStorageCacheBridge {
    802 public:
    803  SyncLoadCacheHelper(const nsACString& aOriginSuffix,
    804                      const nsACString& aOriginNoSuffix,
    805                      uint32_t aAlreadyLoadedCount, nsTArray<nsString>* aKeys,
    806                      nsTArray<nsString>* aValues, nsresult* rv)
    807      : mMonitor("DOM Storage SyncLoad IPC"),
    808        mSuffix(aOriginSuffix),
    809        mOrigin(aOriginNoSuffix),
    810        mKeys(aKeys),
    811        mValues(aValues),
    812        mRv(rv),
    813        mLoaded(false),
    814        mLoadedCount(aAlreadyLoadedCount) {
    815    // Precaution
    816    *mRv = NS_ERROR_UNEXPECTED;
    817  }
    818 
    819  virtual const nsCString Origin() const override {
    820    return LocalStorageManager::CreateOrigin(mSuffix, mOrigin);
    821  }
    822  virtual const nsCString& OriginNoSuffix() const override { return mOrigin; }
    823  virtual const nsCString& OriginSuffix() const override { return mSuffix; }
    824  virtual bool Loaded() override { return mLoaded; }
    825  virtual uint32_t LoadedCount() override { return mLoadedCount; }
    826  virtual bool LoadItem(const nsAString& aKey,
    827                        const nsAString& aValue) override {
    828    // Called on the aCache background thread
    829    MOZ_ASSERT(!mLoaded);
    830    if (mLoaded) {
    831      return false;
    832    }
    833 
    834    ++mLoadedCount;
    835    mKeys->AppendElement(aKey);
    836    mValues->AppendElement(aValue);
    837    return true;
    838  }
    839 
    840  virtual void LoadDone(nsresult aRv) override {
    841    // Called on the aCache background thread
    842    MonitorAutoLock monitor(mMonitor);
    843    MOZ_ASSERT(!mLoaded && mRv);
    844    mLoaded = true;
    845    if (mRv) {
    846      *mRv = aRv;
    847      mRv = nullptr;
    848    }
    849    monitor.Notify();
    850  }
    851 
    852  virtual void LoadWait() override {
    853    // Called on the main thread, exits after LoadDone() call
    854    MonitorAutoLock monitor(mMonitor);
    855    while (!mLoaded) {
    856      monitor.Wait();
    857    }
    858  }
    859 
    860 private:
    861  Monitor mMonitor MOZ_UNANNOTATED;
    862  nsCString mSuffix, mOrigin;
    863  nsTArray<nsString>* mKeys;
    864  nsTArray<nsString>* mValues;
    865  nsresult* mRv;
    866  bool mLoaded;
    867  uint32_t mLoadedCount;
    868 };
    869 
    870 }  // namespace
    871 
    872 mozilla::ipc::IPCResult StorageDBParent::RecvPreload(
    873    const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
    874    const uint32_t& aAlreadyLoadedCount, nsTArray<nsString>* aKeys,
    875    nsTArray<nsString>* aValues, nsresult* aRv) {
    876  StorageDBThread* storageThread =
    877      StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
    878  if (!storageThread) {
    879    return IPC_FAIL_NO_REASON(this);
    880  }
    881 
    882  RefPtr<SyncLoadCacheHelper> cache(
    883      new SyncLoadCacheHelper(aOriginSuffix, aOriginNoSuffix,
    884                              aAlreadyLoadedCount, aKeys, aValues, aRv));
    885 
    886  storageThread->SyncPreload(cache, true);
    887 
    888  return IPC_OK();
    889 }
    890 
    891 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncAddItem(
    892    const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
    893    const nsAString& aKey, const nsAString& aValue) {
    894  StorageDBThread* storageThread =
    895      StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
    896  if (!storageThread) {
    897    return IPC_FAIL_NO_REASON(this);
    898  }
    899 
    900  nsresult rv = storageThread->AsyncAddItem(
    901      NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue);
    902  if (NS_FAILED(rv) && mIPCOpen) {
    903    (void)SendError(rv);
    904  }
    905 
    906  return IPC_OK();
    907 }
    908 
    909 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncUpdateItem(
    910    const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
    911    const nsAString& aKey, const nsAString& aValue) {
    912  StorageDBThread* storageThread =
    913      StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
    914  if (!storageThread) {
    915    return IPC_FAIL_NO_REASON(this);
    916  }
    917 
    918  nsresult rv = storageThread->AsyncUpdateItem(
    919      NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue);
    920  if (NS_FAILED(rv) && mIPCOpen) {
    921    (void)SendError(rv);
    922  }
    923 
    924  return IPC_OK();
    925 }
    926 
    927 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncRemoveItem(
    928    const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
    929    const nsAString& aKey) {
    930  StorageDBThread* storageThread =
    931      StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
    932  if (!storageThread) {
    933    return IPC_FAIL_NO_REASON(this);
    934  }
    935 
    936  nsresult rv = storageThread->AsyncRemoveItem(
    937      NewCache(aOriginSuffix, aOriginNoSuffix), aKey);
    938  if (NS_FAILED(rv) && mIPCOpen) {
    939    (void)SendError(rv);
    940  }
    941 
    942  return IPC_OK();
    943 }
    944 
    945 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncClear(
    946    const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix) {
    947  StorageDBThread* storageThread =
    948      StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
    949  if (!storageThread) {
    950    return IPC_FAIL_NO_REASON(this);
    951  }
    952 
    953  nsresult rv =
    954      storageThread->AsyncClear(NewCache(aOriginSuffix, aOriginNoSuffix));
    955  if (NS_FAILED(rv) && mIPCOpen) {
    956    (void)SendError(rv);
    957  }
    958 
    959  return IPC_OK();
    960 }
    961 
    962 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncFlush() {
    963  StorageDBThread* storageThread = StorageDBThread::Get(mPrivateBrowsingId);
    964  if (!storageThread) {
    965    return IPC_FAIL_NO_REASON(this);
    966  }
    967 
    968  storageThread->AsyncFlush();
    969 
    970  return IPC_OK();
    971 }
    972 
    973 mozilla::ipc::IPCResult StorageDBParent::RecvStartup() {
    974  StorageDBThread* storageThread =
    975      StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
    976  if (!storageThread) {
    977    return IPC_FAIL_NO_REASON(this);
    978  }
    979 
    980  return IPC_OK();
    981 }
    982 
    983 mozilla::ipc::IPCResult StorageDBParent::RecvClearAll() {
    984  StorageDBThread* storageThread =
    985      StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
    986  if (!storageThread) {
    987    return IPC_FAIL_NO_REASON(this);
    988  }
    989 
    990  storageThread->AsyncClearAll();
    991 
    992  return IPC_OK();
    993 }
    994 
    995 mozilla::ipc::IPCResult StorageDBParent::RecvClearMatchingOrigin(
    996    const nsACString& aOriginNoSuffix) {
    997  StorageDBThread* storageThread =
    998      StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
    999  if (!storageThread) {
   1000    return IPC_FAIL_NO_REASON(this);
   1001  }
   1002 
   1003  storageThread->AsyncClearMatchingOrigin(aOriginNoSuffix);
   1004 
   1005  return IPC_OK();
   1006 }
   1007 
   1008 mozilla::ipc::IPCResult StorageDBParent::RecvClearMatchingOriginAttributes(
   1009    const OriginAttributesPattern& aPattern) {
   1010  StorageDBThread* storageThread =
   1011      StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
   1012  if (!storageThread) {
   1013    return IPC_FAIL_NO_REASON(this);
   1014  }
   1015 
   1016  storageThread->AsyncClearMatchingOriginAttributes(aPattern);
   1017 
   1018  return IPC_OK();
   1019 }
   1020 
   1021 void StorageDBParent::Observe(const nsACString& aTopic,
   1022                              const nsAString& aOriginAttributesPattern,
   1023                              const nsACString& aOriginScope) {
   1024  if (mIPCOpen) {
   1025    (void)SendObserve(aTopic, aOriginAttributesPattern, aOriginScope);
   1026  }
   1027 }
   1028 
   1029 namespace {
   1030 
   1031 // Results must be sent back on the main thread
   1032 class LoadRunnable : public Runnable {
   1033 public:
   1034  enum TaskType { loadItem, loadDone };
   1035 
   1036  LoadRunnable(StorageDBParent* aParent, TaskType aType,
   1037               const nsACString& aOriginSuffix,
   1038               const nsACString& aOriginNoSuffix,
   1039               const nsAString& aKey = u""_ns, const nsAString& aValue = u""_ns)
   1040      : Runnable("dom::LoadRunnable"),
   1041        mParent(aParent),
   1042        mType(aType),
   1043        mSuffix(aOriginSuffix),
   1044        mOrigin(aOriginNoSuffix),
   1045        mKey(aKey),
   1046        mValue(aValue),
   1047        mRv(NS_ERROR_NOT_INITIALIZED) {}
   1048 
   1049  LoadRunnable(StorageDBParent* aParent, TaskType aType,
   1050               const nsACString& aOriginSuffix,
   1051               const nsACString& aOriginNoSuffix, nsresult aRv)
   1052      : Runnable("dom::LoadRunnable"),
   1053        mParent(aParent),
   1054        mType(aType),
   1055        mSuffix(aOriginSuffix),
   1056        mOrigin(aOriginNoSuffix),
   1057        mRv(aRv) {}
   1058 
   1059 private:
   1060  RefPtr<StorageDBParent> mParent;
   1061  TaskType mType;
   1062  nsCString mSuffix, mOrigin;
   1063  nsString mKey;
   1064  nsString mValue;
   1065  nsresult mRv;
   1066 
   1067  NS_IMETHOD Run() override {
   1068    if (!mParent->IPCOpen()) {
   1069      return NS_OK;
   1070    }
   1071 
   1072    switch (mType) {
   1073      case loadItem:
   1074        (void)mParent->SendLoadItem(mSuffix, mOrigin, mKey, mValue);
   1075        break;
   1076      case loadDone:
   1077        (void)mParent->SendLoadDone(mSuffix, mOrigin, mRv);
   1078        break;
   1079    }
   1080 
   1081    mParent = nullptr;
   1082 
   1083    return NS_OK;
   1084  }
   1085 };
   1086 
   1087 }  // namespace
   1088 
   1089 // StorageDBParent::CacheParentBridge
   1090 
   1091 const nsCString StorageDBParent::CacheParentBridge::Origin() const {
   1092  return LocalStorageManager::CreateOrigin(mOriginSuffix, mOriginNoSuffix);
   1093 }
   1094 
   1095 bool StorageDBParent::CacheParentBridge::LoadItem(const nsAString& aKey,
   1096                                                  const nsAString& aValue) {
   1097  if (mLoaded) {
   1098    return false;
   1099  }
   1100 
   1101  ++mLoadedCount;
   1102 
   1103  RefPtr<LoadRunnable> r =
   1104      new LoadRunnable(mParent, LoadRunnable::loadItem, mOriginSuffix,
   1105                       mOriginNoSuffix, aKey, aValue);
   1106 
   1107  MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
   1108 
   1109  return true;
   1110 }
   1111 
   1112 void StorageDBParent::CacheParentBridge::LoadDone(nsresult aRv) {
   1113  // Prevent send of duplicate LoadDone.
   1114  if (mLoaded) {
   1115    return;
   1116  }
   1117 
   1118  mLoaded = true;
   1119 
   1120  RefPtr<LoadRunnable> r = new LoadRunnable(
   1121      mParent, LoadRunnable::loadDone, mOriginSuffix, mOriginNoSuffix, aRv);
   1122 
   1123  MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
   1124 }
   1125 
   1126 void StorageDBParent::CacheParentBridge::LoadWait() {
   1127  // Should never be called on this implementation
   1128  MOZ_ASSERT(false);
   1129 }
   1130 
   1131 // XXX Fix me!
   1132 // This should be just:
   1133 // NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::CacheParentBridge, Destroy)
   1134 // But due to different strings used for refcount logging and different return
   1135 // types, this is done manually for now.
   1136 NS_IMETHODIMP_(void)
   1137 StorageDBParent::CacheParentBridge::Release(void) {
   1138  MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
   1139  nsrefcnt count = --mRefCnt;
   1140  NS_LOG_RELEASE(this, count, "LocalStorageCacheBridge");
   1141  if (0 == count) {
   1142    mRefCnt = 1; /* stabilize */
   1143    /* enable this to find non-threadsafe destructors: */
   1144    /* NS_ASSERT_OWNINGTHREAD(_class); */
   1145    Destroy();
   1146  }
   1147 }
   1148 
   1149 void StorageDBParent::CacheParentBridge::Destroy() {
   1150  if (mOwningEventTarget->IsOnCurrentThread()) {
   1151    delete this;
   1152    return;
   1153  }
   1154 
   1155  RefPtr<Runnable> destroyRunnable = NewNonOwningRunnableMethod(
   1156      "CacheParentBridge::Destroy", this, &CacheParentBridge::Destroy);
   1157 
   1158  MOZ_ALWAYS_SUCCEEDS(
   1159      mOwningEventTarget->Dispatch(destroyRunnable, NS_DISPATCH_NORMAL));
   1160 }
   1161 
   1162 // StorageDBParent::UsageParentBridge
   1163 
   1164 namespace {
   1165 
   1166 class UsageRunnable : public Runnable {
   1167 public:
   1168  UsageRunnable(StorageDBParent* aParent, const nsACString& aOriginScope,
   1169                const int64_t& aUsage)
   1170      : Runnable("dom::UsageRunnable"),
   1171        mParent(aParent),
   1172        mOriginScope(aOriginScope),
   1173        mUsage(aUsage) {}
   1174 
   1175 private:
   1176  NS_IMETHOD Run() override {
   1177    if (!mParent->IPCOpen()) {
   1178      return NS_OK;
   1179    }
   1180 
   1181    (void)mParent->SendLoadUsage(mOriginScope, mUsage);
   1182 
   1183    mParent = nullptr;
   1184 
   1185    return NS_OK;
   1186  }
   1187 
   1188  RefPtr<StorageDBParent> mParent;
   1189  nsCString mOriginScope;
   1190  int64_t mUsage;
   1191 };
   1192 
   1193 }  // namespace
   1194 
   1195 void StorageDBParent::UsageParentBridge::LoadUsage(const int64_t aUsage) {
   1196  RefPtr<UsageRunnable> r = new UsageRunnable(mParent, mOriginScope, aUsage);
   1197 
   1198  MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
   1199 }
   1200 
   1201 // XXX Fix me!
   1202 // This should be just:
   1203 // NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::UsageParentBridge, Destroy)
   1204 // But due to different strings used for refcount logging, this is done manually
   1205 // for now.
   1206 NS_IMETHODIMP_(MozExternalRefCountType)
   1207 StorageDBParent::UsageParentBridge::Release(void) {
   1208  MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
   1209  nsrefcnt count = --mRefCnt;
   1210  NS_LOG_RELEASE(this, count, "StorageUsageBridge");
   1211  if (count == 0) {
   1212    Destroy();
   1213    return 0;
   1214  }
   1215  return count;
   1216 }
   1217 
   1218 void StorageDBParent::UsageParentBridge::Destroy() {
   1219  if (mOwningEventTarget->IsOnCurrentThread()) {
   1220    delete this;
   1221    return;
   1222  }
   1223 
   1224  RefPtr<Runnable> destroyRunnable = NewNonOwningRunnableMethod(
   1225      "UsageParentBridge::Destroy", this, &UsageParentBridge::Destroy);
   1226 
   1227  MOZ_ALWAYS_SUCCEEDS(
   1228      mOwningEventTarget->Dispatch(destroyRunnable, NS_DISPATCH_NORMAL));
   1229 }
   1230 
   1231 void StorageDBParent::ObserverSink::Start() {
   1232  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1233 
   1234  RefPtr<Runnable> runnable =
   1235      NewRunnableMethod("StorageDBParent::ObserverSink::AddSink", this,
   1236                        &StorageDBParent::ObserverSink::AddSink);
   1237 
   1238  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
   1239 }
   1240 
   1241 void StorageDBParent::ObserverSink::Stop() {
   1242  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1243 
   1244  mActor = nullptr;
   1245 
   1246  RefPtr<Runnable> runnable =
   1247      NewRunnableMethod("StorageDBParent::ObserverSink::RemoveSink", this,
   1248                        &StorageDBParent::ObserverSink::RemoveSink);
   1249 
   1250  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
   1251 }
   1252 
   1253 void StorageDBParent::ObserverSink::AddSink() {
   1254  MOZ_ASSERT(NS_IsMainThread());
   1255 
   1256  StorageObserver* observer = StorageObserver::Self();
   1257  if (observer) {
   1258    observer->AddSink(this);
   1259  }
   1260 }
   1261 
   1262 void StorageDBParent::ObserverSink::RemoveSink() {
   1263  MOZ_ASSERT(NS_IsMainThread());
   1264 
   1265  StorageObserver* observer = StorageObserver::Self();
   1266  if (observer) {
   1267    observer->RemoveSink(this);
   1268  }
   1269 }
   1270 
   1271 void StorageDBParent::ObserverSink::Notify(
   1272    const nsACString& aTopic, const nsAString& aOriginAttributesPattern,
   1273    const nsACString& aOriginScope) {
   1274  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1275 
   1276  if (mActor) {
   1277    mActor->Observe(aTopic, aOriginAttributesPattern, aOriginScope);
   1278  }
   1279 }
   1280 
   1281 nsresult StorageDBParent::ObserverSink::Observe(
   1282    const char* aTopic, const nsAString& aOriginAttributesPattern,
   1283    const nsACString& aOriginScope) {
   1284  MOZ_ASSERT(NS_IsMainThread());
   1285 
   1286  RefPtr<Runnable> runnable = NewRunnableMethod<nsCString, nsString, nsCString>(
   1287      "StorageDBParent::ObserverSink::Observe2", this,
   1288      &StorageDBParent::ObserverSink::Notify, aTopic, aOriginAttributesPattern,
   1289      aOriginScope);
   1290 
   1291  MOZ_ALWAYS_SUCCEEDS(
   1292      mOwningEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
   1293 
   1294  return NS_OK;
   1295 }
   1296 
   1297 SessionStorageObserverParent::SessionStorageObserverParent()
   1298    : mActorDestroyed(false) {
   1299  MOZ_ASSERT(NS_IsMainThread());
   1300 
   1301  StorageObserver* observer = StorageObserver::Self();
   1302  if (observer) {
   1303    observer->AddSink(this);
   1304  }
   1305 }
   1306 
   1307 SessionStorageObserverParent::~SessionStorageObserverParent() {
   1308  MOZ_ASSERT(mActorDestroyed);
   1309 
   1310  StorageObserver* observer = StorageObserver::Self();
   1311  if (observer) {
   1312    observer->RemoveSink(this);
   1313  }
   1314 }
   1315 
   1316 void SessionStorageObserverParent::ActorDestroy(ActorDestroyReason aWhy) {
   1317  MOZ_ASSERT(NS_IsMainThread());
   1318  MOZ_ASSERT(!mActorDestroyed);
   1319 
   1320  mActorDestroyed = true;
   1321 }
   1322 
   1323 mozilla::ipc::IPCResult SessionStorageObserverParent::RecvDeleteMe() {
   1324  MOZ_ASSERT(NS_IsMainThread());
   1325  MOZ_ASSERT(!mActorDestroyed);
   1326 
   1327  IProtocol* mgr = Manager();
   1328  if (!PSessionStorageObserverParent::Send__delete__(this)) {
   1329    return IPC_FAIL_NO_REASON(mgr);
   1330  }
   1331  return IPC_OK();
   1332 }
   1333 
   1334 nsresult SessionStorageObserverParent::Observe(
   1335    const char* aTopic, const nsAString& aOriginAttributesPattern,
   1336    const nsACString& aOriginScope) {
   1337  MOZ_ASSERT(NS_IsMainThread());
   1338 
   1339  if (!mActorDestroyed) {
   1340    (void)SendObserve(nsDependentCString(aTopic), aOriginAttributesPattern,
   1341                      aOriginScope);
   1342  }
   1343  return NS_OK;
   1344 }
   1345 
   1346 SessionStorageCacheParent::SessionStorageCacheParent(
   1347    const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
   1348    const nsACString& aOriginKey, SessionStorageManagerParent* aActor)
   1349    : mPrincipalInfo(aPrincipalInfo),
   1350      mOriginKey(aOriginKey),
   1351      mManagerActor(aActor) {
   1352  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1353  MOZ_ASSERT(mManagerActor);
   1354 }
   1355 
   1356 SessionStorageCacheParent::~SessionStorageCacheParent() = default;
   1357 
   1358 void SessionStorageCacheParent::ActorDestroy(ActorDestroyReason aWhy) {
   1359  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1360 
   1361  mManagerActor = nullptr;
   1362 }
   1363 
   1364 mozilla::ipc::IPCResult SessionStorageCacheParent::RecvLoad(
   1365    nsTArray<SSSetItemInfo>* aData) {
   1366  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1367  MOZ_ASSERT(mManagerActor);
   1368 
   1369  mLoadReceived.Flip();
   1370 
   1371  RefPtr<BackgroundSessionStorageManager> manager = mManagerActor->GetManager();
   1372  MOZ_ASSERT(manager);
   1373 
   1374  OriginAttributes attrs;
   1375  MOZ_ALWAYS_TRUE(
   1376      StoragePrincipalHelper::GetOriginAttributes(mPrincipalInfo, attrs));
   1377 
   1378  nsAutoCString originAttrs;
   1379  attrs.CreateSuffix(originAttrs);
   1380 
   1381  manager->CopyDataToContentProcess(originAttrs, mOriginKey, *aData);
   1382 
   1383  return IPC_OK();
   1384 }
   1385 
   1386 mozilla::ipc::IPCResult SessionStorageCacheParent::RecvCheckpoint(
   1387    nsTArray<SSWriteInfo>&& aWriteInfos) {
   1388  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1389  MOZ_ASSERT(mManagerActor);
   1390 
   1391  RefPtr<BackgroundSessionStorageManager> manager = mManagerActor->GetManager();
   1392  MOZ_ASSERT(manager);
   1393 
   1394  OriginAttributes attrs;
   1395  StoragePrincipalHelper::GetOriginAttributes(mPrincipalInfo, attrs);
   1396 
   1397  nsAutoCString originAttrs;
   1398  attrs.CreateSuffix(originAttrs);
   1399 
   1400  manager->UpdateData(originAttrs, mOriginKey, aWriteInfos);
   1401 
   1402  return IPC_OK();
   1403 }
   1404 
   1405 mozilla::ipc::IPCResult SessionStorageCacheParent::RecvDeleteMe() {
   1406  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1407  MOZ_ASSERT(mManagerActor);
   1408 
   1409  mManagerActor = nullptr;
   1410 
   1411  IProtocol* mgr = Manager();
   1412  if (!PBackgroundSessionStorageCacheParent::Send__delete__(this)) {
   1413    return IPC_FAIL(
   1414        mgr, "Failed to delete PBackgroundSessionStorageCacheParent actor");
   1415  }
   1416  return IPC_OK();
   1417 }
   1418 
   1419 SessionStorageManagerParent::SessionStorageManagerParent(uint64_t aTopContextId)
   1420    : mBackgroundManager(
   1421          BackgroundSessionStorageManager::GetOrCreate(aTopContextId)) {
   1422  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1423  MOZ_ASSERT(mBackgroundManager);
   1424  mBackgroundManager->AddParticipatingActor(this);
   1425 }
   1426 
   1427 SessionStorageManagerParent::~SessionStorageManagerParent() = default;
   1428 
   1429 void SessionStorageManagerParent::ActorDestroy(ActorDestroyReason aWhy) {
   1430  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1431 
   1432  if (mBackgroundManager) {
   1433    mBackgroundManager->RemoveParticipatingActor(this);
   1434  }
   1435 
   1436  mBackgroundManager = nullptr;
   1437 }
   1438 
   1439 already_AddRefed<PBackgroundSessionStorageCacheParent>
   1440 SessionStorageManagerParent::AllocPBackgroundSessionStorageCacheParent(
   1441    const PrincipalInfo& aPrincipalInfo, const nsACString& aOriginKey) {
   1442  return MakeAndAddRef<SessionStorageCacheParent>(aPrincipalInfo, aOriginKey,
   1443                                                  this);
   1444 }
   1445 
   1446 BackgroundSessionStorageManager* SessionStorageManagerParent::GetManager()
   1447    const {
   1448  return mBackgroundManager;
   1449 }
   1450 
   1451 mozilla::ipc::IPCResult SessionStorageManagerParent::RecvClearStorages(
   1452    const OriginAttributesPattern& aPattern, const nsACString& aOriginScope,
   1453    const uint32_t& aMode) {
   1454  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1455  mBackgroundManager->ClearStorages(aPattern, aOriginScope,
   1456                                    static_cast<DomainMatchingMode>(aMode));
   1457  return IPC_OK();
   1458 }
   1459 
   1460 mozilla::ipc::IPCResult SessionStorageManagerParent::RecvDeleteMe() {
   1461  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1462  MOZ_ASSERT(mBackgroundManager);
   1463 
   1464  mBackgroundManager->RemoveParticipatingActor(this);
   1465 
   1466  mBackgroundManager = nullptr;
   1467 
   1468  IProtocol* mgr = Manager();
   1469  if (!PBackgroundSessionStorageManagerParent::Send__delete__(this)) {
   1470    return IPC_FAIL(
   1471        mgr, "Failed to delete PBackgroundSessionStorageManagerParent actor");
   1472  }
   1473  return IPC_OK();
   1474 }
   1475 
   1476 /*******************************************************************************
   1477 * Exported functions
   1478 ******************************************************************************/
   1479 
   1480 PBackgroundLocalStorageCacheParent* AllocPBackgroundLocalStorageCacheParent(
   1481    const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
   1482    const nsACString& aOriginKey, const uint32_t& aPrivateBrowsingId) {
   1483  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1484 
   1485  RefPtr<LocalStorageCacheParent> actor = new LocalStorageCacheParent(
   1486      aPrincipalInfo, aOriginKey, aPrivateBrowsingId);
   1487 
   1488  // Transfer ownership to IPDL.
   1489  return actor.forget().take();
   1490 }
   1491 
   1492 mozilla::ipc::IPCResult RecvPBackgroundLocalStorageCacheConstructor(
   1493    mozilla::ipc::PBackgroundParent* aBackgroundActor,
   1494    PBackgroundLocalStorageCacheParent* aActor,
   1495    const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
   1496    const nsACString& aOriginKey, const uint32_t& aPrivateBrowsingId) {
   1497  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1498  MOZ_ASSERT(aActor);
   1499 
   1500  auto* actor = static_cast<LocalStorageCacheParent*>(aActor);
   1501 
   1502  if (!gLocalStorageCacheParents) {
   1503    gLocalStorageCacheParents = new LocalStorageCacheParentHashtable();
   1504  }
   1505 
   1506  gLocalStorageCacheParents->GetOrInsertNew(aOriginKey)->AppendElement(actor);
   1507 
   1508  // We are currently trusting the content process not to lie to us.  It is
   1509  // future work to consult the ClientManager to determine whether this is a
   1510  // legitimate origin for the content process.
   1511 
   1512  return IPC_OK();
   1513 }
   1514 
   1515 bool DeallocPBackgroundLocalStorageCacheParent(
   1516    PBackgroundLocalStorageCacheParent* aActor) {
   1517  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1518  MOZ_ASSERT(aActor);
   1519 
   1520  // Transfer ownership back from IPDL.
   1521  RefPtr<LocalStorageCacheParent> actor =
   1522      dont_AddRef(static_cast<LocalStorageCacheParent*>(aActor));
   1523 
   1524  return true;
   1525 }
   1526 
   1527 PBackgroundStorageParent* AllocPBackgroundStorageParent(
   1528    const nsAString& aProfilePath, const uint32_t& aPrivateBrowsingId) {
   1529  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1530 
   1531  if (NS_WARN_IF(NextGenLocalStorageEnabled()) ||
   1532      NS_WARN_IF(aPrivateBrowsingId >= kPrivateBrowsingIdCount)) {
   1533    return nullptr;
   1534  }
   1535 
   1536  return new StorageDBParent(aProfilePath, aPrivateBrowsingId);
   1537 }
   1538 
   1539 mozilla::ipc::IPCResult RecvPBackgroundStorageConstructor(
   1540    PBackgroundStorageParent* aActor, const nsAString& aProfilePath,
   1541    const uint32_t& aPrivateBrowsingId) {
   1542  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1543  MOZ_ASSERT(aActor);
   1544  MOZ_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
   1545  MOZ_ASSERT(!NextGenLocalStorageEnabled());
   1546 
   1547  auto* actor = static_cast<StorageDBParent*>(aActor);
   1548  actor->Init();
   1549  return IPC_OK();
   1550 }
   1551 
   1552 bool DeallocPBackgroundStorageParent(PBackgroundStorageParent* aActor) {
   1553  ::mozilla::ipc::AssertIsOnBackgroundThread();
   1554  MOZ_ASSERT(aActor);
   1555 
   1556  StorageDBParent* actor = static_cast<StorageDBParent*>(aActor);
   1557  actor->ReleaseIPDLReference();
   1558  return true;
   1559 }
   1560 
   1561 PSessionStorageObserverParent* AllocPSessionStorageObserverParent() {
   1562  MOZ_ASSERT(NS_IsMainThread());
   1563 
   1564  RefPtr<SessionStorageObserverParent> actor =
   1565      new SessionStorageObserverParent();
   1566 
   1567  // Transfer ownership to IPDL.
   1568  return actor.forget().take();
   1569 }
   1570 
   1571 bool RecvPSessionStorageObserverConstructor(
   1572    PSessionStorageObserverParent* aActor) {
   1573  MOZ_ASSERT(NS_IsMainThread());
   1574  MOZ_ASSERT(aActor);
   1575 
   1576  return true;
   1577 }
   1578 
   1579 bool DeallocPSessionStorageObserverParent(
   1580    PSessionStorageObserverParent* aActor) {
   1581  MOZ_ASSERT(NS_IsMainThread());
   1582  MOZ_ASSERT(aActor);
   1583 
   1584  // Transfer ownership back from IPDL.
   1585  RefPtr<SessionStorageObserverParent> actor =
   1586      dont_AddRef(static_cast<SessionStorageObserverParent*>(aActor));
   1587 
   1588  return true;
   1589 }
   1590 
   1591 already_AddRefed<PBackgroundSessionStorageManagerParent>
   1592 AllocPBackgroundSessionStorageManagerParent(const uint64_t& aTopContextId) {
   1593  return MakeAndAddRef<SessionStorageManagerParent>(aTopContextId);
   1594 }
   1595 
   1596 }  // namespace mozilla::dom