forked from mirrors/gecko-dev
		
	 0819f35e51
			
		
	
	
		0819f35e51
		
	
	
	
	
		
			
			Backed out changeset 516c4fb1e4b8 (bug 525063) Backed out changeset 6ff8aaef2866 (bug 525063) Backed out changeset bf13e4103150 (bug 525063) Backed out changeset d7d2f08e051c (bug 525063)
		
			
				
	
	
		
			1262 lines
		
	
	
	
		
			31 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1262 lines
		
	
	
	
		
			31 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "StorageIPC.h"
 | |
| 
 | |
| #include "LocalStorageManager.h"
 | |
| 
 | |
| #include "mozilla/dom/ContentChild.h"
 | |
| #include "mozilla/dom/ContentParent.h"
 | |
| #include "mozilla/ipc/BackgroundChild.h"
 | |
| #include "mozilla/ipc/BackgroundParent.h"
 | |
| #include "mozilla/ipc/PBackgroundChild.h"
 | |
| #include "mozilla/ipc/PBackgroundParent.h"
 | |
| #include "mozilla/Unused.h"
 | |
| #include "nsIDiskSpaceWatcher.h"
 | |
| #include "nsThreadUtils.h"
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace dom {
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| StorageDBChild* sStorageChild = nullptr;
 | |
| 
 | |
| // False until we shut the storage child down.
 | |
| bool sStorageChildDown = false;
 | |
| 
 | |
| }
 | |
| 
 | |
| // ----------------------------------------------------------------------------
 | |
| // Child
 | |
| // ----------------------------------------------------------------------------
 | |
| 
 | |
| class StorageDBChild::ShutdownObserver final
 | |
|   : public nsIObserver
 | |
| {
 | |
| public:
 | |
|   ShutdownObserver()
 | |
|   {
 | |
|     MOZ_ASSERT(NS_IsMainThread());
 | |
|   }
 | |
| 
 | |
|   NS_DECL_ISUPPORTS
 | |
|   NS_DECL_NSIOBSERVER
 | |
| 
 | |
| private:
 | |
|   ~ShutdownObserver()
 | |
|   {
 | |
|     MOZ_ASSERT(NS_IsMainThread());
 | |
|   }
 | |
| };
 | |
| 
 | |
| void
 | |
| StorageDBChild::AddIPDLReference()
 | |
| {
 | |
|   MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references");
 | |
|   mIPCOpen = true;
 | |
|   AddRef();
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBChild::ReleaseIPDLReference()
 | |
| {
 | |
|   MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference");
 | |
|   mIPCOpen = false;
 | |
|   Release();
 | |
| }
 | |
| 
 | |
| StorageDBChild::StorageDBChild(LocalStorageManager* aManager)
 | |
|   : mManager(aManager)
 | |
|   , mStatus(NS_OK)
 | |
|   , mIPCOpen(false)
 | |
| {
 | |
| }
 | |
| 
 | |
| StorageDBChild::~StorageDBChild()
 | |
| {
 | |
| }
 | |
| 
 | |
| // static
 | |
| StorageDBChild*
 | |
| StorageDBChild::Get()
 | |
| {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   return sStorageChild;
 | |
| }
 | |
| 
 | |
| // static
 | |
| StorageDBChild*
 | |
| StorageDBChild::GetOrCreate()
 | |
| {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   if (sStorageChild || sStorageChildDown) {
 | |
|     // When sStorageChildDown is at true, sStorageChild is null.
 | |
|     // Checking sStorageChildDown flag here prevents reinitialization of
 | |
|     // the storage child after shutdown.
 | |
|     return sStorageChild;
 | |
|   }
 | |
| 
 | |
|   // Use LocalStorageManager::Ensure in case we're called from
 | |
|   // DOMSessionStorageManager's initializer and we haven't yet initialized the
 | |
|   // local storage manager.
 | |
|   RefPtr<StorageDBChild> storageChild =
 | |
|     new StorageDBChild(LocalStorageManager::Ensure());
 | |
| 
 | |
|   nsresult rv = storageChild->Init();
 | |
|   if (NS_WARN_IF(NS_FAILED(rv))) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   storageChild.forget(&sStorageChild);
 | |
| 
 | |
|   return sStorageChild;
 | |
| }
 | |
| 
 | |
| nsTHashtable<nsCStringHashKey>&
 | |
| StorageDBChild::OriginsHavingData()
 | |
| {
 | |
|   if (!mOriginsHavingData) {
 | |
|     mOriginsHavingData = new nsTHashtable<nsCStringHashKey>;
 | |
|   }
 | |
| 
 | |
|   return *mOriginsHavingData;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| StorageDBChild::Init()
 | |
| {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   PBackgroundChild* actor = BackgroundChild::GetOrCreateForCurrentThread();
 | |
|   if (NS_WARN_IF(!actor)) {
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   nsString profilePath;
 | |
|   if (XRE_IsParentProcess()) {
 | |
|     nsresult rv = StorageDBThread::GetProfilePath(profilePath);
 | |
|     if (NS_WARN_IF(NS_FAILED(rv))) {
 | |
|       return rv;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   AddIPDLReference();
 | |
| 
 | |
|   actor->SendPBackgroundStorageConstructor(this, profilePath);
 | |
| 
 | |
|   nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
 | |
|   MOZ_ASSERT(observerService);
 | |
| 
 | |
|   nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
 | |
| 
 | |
|   MOZ_ALWAYS_SUCCEEDS(
 | |
|     observerService->AddObserver(observer,
 | |
|                                  "xpcom-shutdown",
 | |
|                                  false));
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| StorageDBChild::Shutdown()
 | |
| {
 | |
|   // There is nothing to do here, IPC will release automatically and
 | |
|   // the actual thread running on the parent process will also stop
 | |
|   // automatically in profile-before-change topic observer.
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBChild::AsyncPreload(LocalStorageCacheBridge* aCache, bool aPriority)
 | |
| {
 | |
|   if (mIPCOpen) {
 | |
|     // Adding ref to cache for the time of preload.  This ensures a reference to
 | |
|     // to the cache and that all keys will load into this cache object.
 | |
|     mLoadingCaches.PutEntry(aCache);
 | |
|     SendAsyncPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
 | |
|                      aPriority);
 | |
|   } else {
 | |
|     // No IPC, no love.  But the LoadDone call is expected.
 | |
|     aCache->LoadDone(NS_ERROR_UNEXPECTED);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBChild::AsyncGetUsage(StorageUsageBridge* aUsage)
 | |
| {
 | |
|   if (mIPCOpen) {
 | |
|     SendAsyncGetUsage(aUsage->OriginScope());
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBChild::SyncPreload(LocalStorageCacheBridge* aCache, bool aForceSync)
 | |
| {
 | |
|   if (NS_FAILED(mStatus)) {
 | |
|     aCache->LoadDone(mStatus);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!mIPCOpen) {
 | |
|     aCache->LoadDone(NS_ERROR_UNEXPECTED);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // There is no way to put the child process to a wait state to receive all
 | |
|   // incoming async responses from the parent, hence we have to do a sync
 | |
|   // preload instead.  We are smart though, we only demand keys that are left to
 | |
|   // load in case the async preload has already loaded some keys.
 | |
|   InfallibleTArray<nsString> keys, values;
 | |
|   nsresult rv;
 | |
|   SendPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
 | |
|               aCache->LoadedCount(), &keys, &values, &rv);
 | |
| 
 | |
|   for (uint32_t i = 0; i < keys.Length(); ++i) {
 | |
|     aCache->LoadItem(keys[i], values[i]);
 | |
|   }
 | |
| 
 | |
|   aCache->LoadDone(rv);
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| StorageDBChild::AsyncAddItem(LocalStorageCacheBridge* aCache,
 | |
|                              const nsAString& aKey,
 | |
|                              const nsAString& aValue)
 | |
| {
 | |
|   if (NS_FAILED(mStatus) || !mIPCOpen) {
 | |
|     return mStatus;
 | |
|   }
 | |
| 
 | |
|   SendAsyncAddItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
 | |
|                    nsString(aKey), nsString(aValue));
 | |
|   OriginsHavingData().PutEntry(aCache->Origin());
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| StorageDBChild::AsyncUpdateItem(LocalStorageCacheBridge* aCache,
 | |
|                                 const nsAString& aKey,
 | |
|                                 const nsAString& aValue)
 | |
| {
 | |
|   if (NS_FAILED(mStatus) || !mIPCOpen) {
 | |
|     return mStatus;
 | |
|   }
 | |
| 
 | |
|   SendAsyncUpdateItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
 | |
|                       nsString(aKey), nsString(aValue));
 | |
|   OriginsHavingData().PutEntry(aCache->Origin());
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| StorageDBChild::AsyncRemoveItem(LocalStorageCacheBridge* aCache,
 | |
|                                 const nsAString& aKey)
 | |
| {
 | |
|   if (NS_FAILED(mStatus) || !mIPCOpen) {
 | |
|     return mStatus;
 | |
|   }
 | |
| 
 | |
|   SendAsyncRemoveItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
 | |
|                       nsString(aKey));
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| StorageDBChild::AsyncClear(LocalStorageCacheBridge* aCache)
 | |
| {
 | |
|   if (NS_FAILED(mStatus) || !mIPCOpen) {
 | |
|     return mStatus;
 | |
|   }
 | |
| 
 | |
|   SendAsyncClear(aCache->OriginSuffix(), aCache->OriginNoSuffix());
 | |
|   OriginsHavingData().RemoveEntry(aCache->Origin());
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| bool
 | |
| StorageDBChild::ShouldPreloadOrigin(const nsACString& aOrigin)
 | |
| {
 | |
|   // Return true if we didn't receive the origins list yet.
 | |
|   // I tend to rather preserve a bit of early-after-start performance
 | |
|   // than a bit of memory here.
 | |
|   return !mOriginsHavingData || mOriginsHavingData->Contains(aOrigin);
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBChild::RecvObserve(const nsCString& aTopic,
 | |
|                             const nsString& aOriginAttributesPattern,
 | |
|                             const nsCString& aOriginScope)
 | |
| {
 | |
|   MOZ_ASSERT(!XRE_IsParentProcess());
 | |
| 
 | |
|   StorageObserver::Self()->Notify(
 | |
|     aTopic.get(), aOriginAttributesPattern, aOriginScope);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBChild::RecvOriginsHavingData(nsTArray<nsCString>&& aOrigins)
 | |
| {
 | |
|   // Force population of mOriginsHavingData even if there are no origins so that
 | |
|   // ShouldPreloadOrigin does not generate false positives for all origins.
 | |
|   if (!aOrigins.Length()) {
 | |
|     Unused << OriginsHavingData();
 | |
|   }
 | |
| 
 | |
|   for (uint32_t i = 0; i < aOrigins.Length(); ++i) {
 | |
|     OriginsHavingData().PutEntry(aOrigins[i]);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBChild::RecvLoadItem(const nsCString& aOriginSuffix,
 | |
|                              const nsCString& aOriginNoSuffix,
 | |
|                              const nsString& aKey,
 | |
|                              const nsString& aValue)
 | |
| {
 | |
|   LocalStorageCache* aCache =
 | |
|     mManager->GetCache(aOriginSuffix, aOriginNoSuffix);
 | |
|   if (aCache) {
 | |
|     aCache->LoadItem(aKey, aValue);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBChild::RecvLoadDone(const nsCString& aOriginSuffix,
 | |
|                              const nsCString& aOriginNoSuffix,
 | |
|                              const nsresult& aRv)
 | |
| {
 | |
|   LocalStorageCache* aCache =
 | |
|     mManager->GetCache(aOriginSuffix, aOriginNoSuffix);
 | |
|   if (aCache) {
 | |
|     aCache->LoadDone(aRv);
 | |
| 
 | |
|     // Just drop reference to this cache now since the load is done.
 | |
|     mLoadingCaches.RemoveEntry(static_cast<LocalStorageCacheBridge*>(aCache));
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBChild::RecvLoadUsage(const nsCString& aOriginNoSuffix,
 | |
|                               const int64_t& aUsage)
 | |
| {
 | |
|   RefPtr<StorageUsageBridge> scopeUsage =
 | |
|     mManager->GetOriginUsage(aOriginNoSuffix);
 | |
|   scopeUsage->LoadUsage(aUsage);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBChild::RecvError(const nsresult& aRv)
 | |
| {
 | |
|   mStatus = aRv;
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| NS_IMPL_ISUPPORTS(StorageDBChild::ShutdownObserver, nsIObserver)
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| StorageDBChild::
 | |
| ShutdownObserver::Observe(nsISupports* aSubject,
 | |
|                           const char* aTopic,
 | |
|                           const char16_t* aData)
 | |
| {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
|   MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
 | |
| 
 | |
|   nsCOMPtr<nsIObserverService> observerService =
 | |
|     mozilla::services::GetObserverService();
 | |
|   if (NS_WARN_IF(!observerService)) {
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   Unused << observerService->RemoveObserver(this, "xpcom-shutdown");
 | |
| 
 | |
|   if (sStorageChild) {
 | |
|     sStorageChildDown = true;
 | |
| 
 | |
|     MOZ_ALWAYS_TRUE(sStorageChild->PBackgroundStorageChild::SendDeleteMe());
 | |
| 
 | |
|     NS_RELEASE(sStorageChild);
 | |
|     sStorageChild = nullptr;
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| // ----------------------------------------------------------------------------
 | |
| // Parent
 | |
| // ----------------------------------------------------------------------------
 | |
| 
 | |
| class StorageDBParent::ObserverSink
 | |
|   : public StorageObserverSink
 | |
| {
 | |
|   nsCOMPtr<nsIEventTarget> mOwningEventTarget;
 | |
| 
 | |
|   // Only touched on the PBackground thread.
 | |
|   StorageDBParent* MOZ_NON_OWNING_REF mActor;
 | |
| 
 | |
| public:
 | |
|   explicit ObserverSink(StorageDBParent* aActor)
 | |
|     : mOwningEventTarget(GetCurrentThreadEventTarget())
 | |
|     , mActor(aActor)
 | |
|   {
 | |
|     AssertIsOnBackgroundThread();
 | |
|     MOZ_ASSERT(aActor);
 | |
|   }
 | |
| 
 | |
|   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StorageDBParent::ObserverSink);
 | |
| 
 | |
|   void
 | |
|   Start();
 | |
| 
 | |
|   void
 | |
|   Stop();
 | |
| 
 | |
| private:
 | |
|   ~ObserverSink() = default;
 | |
| 
 | |
|   void
 | |
|   AddSink();
 | |
| 
 | |
|   void
 | |
|   RemoveSink();
 | |
| 
 | |
|   void
 | |
|   Notify(const nsCString& aTopic,
 | |
|          const nsString& aOriginAttributesPattern,
 | |
|          const nsCString& aOriginScope);
 | |
| 
 | |
|   // StorageObserverSink
 | |
|   nsresult
 | |
|   Observe(const char* aTopic,
 | |
|           const nsAString& aOriginAttrPattern,
 | |
|           const nsACString& aOriginScope) override;
 | |
| };
 | |
| 
 | |
| NS_IMPL_ADDREF(StorageDBParent)
 | |
| NS_IMPL_RELEASE(StorageDBParent)
 | |
| 
 | |
| void
 | |
| StorageDBParent::AddIPDLReference()
 | |
| {
 | |
|   MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references");
 | |
|   mIPCOpen = true;
 | |
|   AddRef();
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBParent::ReleaseIPDLReference()
 | |
| {
 | |
|   MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference");
 | |
|   mIPCOpen = false;
 | |
|   Release();
 | |
| }
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| class CheckLowDiskSpaceRunnable
 | |
|   : public Runnable
 | |
| {
 | |
|   nsCOMPtr<nsIEventTarget> mOwningEventTarget;
 | |
|   RefPtr<StorageDBParent> mParent;
 | |
|   bool mLowDiskSpace;
 | |
| 
 | |
| public:
 | |
|   explicit CheckLowDiskSpaceRunnable(StorageDBParent* aParent)
 | |
|     : Runnable("dom::CheckLowDiskSpaceRunnable")
 | |
|     , mOwningEventTarget(GetCurrentThreadEventTarget())
 | |
|     , mParent(aParent)
 | |
|     , mLowDiskSpace(false)
 | |
|   {
 | |
|     AssertIsOnBackgroundThread();
 | |
|     MOZ_ASSERT(aParent);
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   NS_IMETHOD Run() override
 | |
|   {
 | |
|     if (IsOnBackgroundThread()) {
 | |
|       MOZ_ASSERT(mParent);
 | |
| 
 | |
|       if (!mParent->IPCOpen()) {
 | |
|         return NS_OK;
 | |
|       }
 | |
| 
 | |
|       if (mLowDiskSpace) {
 | |
|         mozilla::Unused << mParent->SendObserve(
 | |
|           nsDependentCString("low-disk-space"), EmptyString(), EmptyCString());
 | |
|       }
 | |
| 
 | |
|       mParent = nullptr;
 | |
| 
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|     nsCOMPtr<nsIDiskSpaceWatcher> diskSpaceWatcher =
 | |
|       do_GetService("@mozilla.org/toolkit/disk-space-watcher;1");
 | |
|     if (!diskSpaceWatcher) {
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     diskSpaceWatcher->GetIsDiskFull(&mLowDiskSpace);
 | |
| 
 | |
|     MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| };
 | |
| 
 | |
| } // namespace
 | |
| 
 | |
| StorageDBParent::StorageDBParent(const nsString& aProfilePath)
 | |
|   : mProfilePath(aProfilePath)
 | |
|   , mIPCOpen(false)
 | |
| {
 | |
|   AssertIsOnBackgroundThread();
 | |
| 
 | |
|   // We are always open by IPC only
 | |
|   AddIPDLReference();
 | |
| }
 | |
| 
 | |
| StorageDBParent::~StorageDBParent()
 | |
| {
 | |
|   AssertIsOnBackgroundThread();
 | |
| 
 | |
|   if (mObserverSink) {
 | |
|     mObserverSink->Stop();
 | |
|     mObserverSink = nullptr;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBParent::Init()
 | |
| {
 | |
|   AssertIsOnBackgroundThread();
 | |
| 
 | |
|   PBackgroundParent* actor = Manager();
 | |
|   MOZ_ASSERT(actor);
 | |
| 
 | |
|   if (BackgroundParent::IsOtherProcessActor(actor)) {
 | |
|     mObserverSink = new ObserverSink(this);
 | |
|     mObserverSink->Start();
 | |
|   }
 | |
| 
 | |
|   StorageDBThread* storageThread = StorageDBThread::Get();
 | |
|   if (storageThread) {
 | |
|     InfallibleTArray<nsCString> scopes;
 | |
|     storageThread->GetOriginsHavingData(&scopes);
 | |
|     mozilla::Unused << SendOriginsHavingData(scopes);
 | |
|   }
 | |
| 
 | |
|   // We need to check if the device is in a low disk space situation, so
 | |
|   // we can forbid in that case any write in localStorage.
 | |
| 
 | |
|   RefPtr<CheckLowDiskSpaceRunnable> runnable =
 | |
|     new CheckLowDiskSpaceRunnable(this);
 | |
| 
 | |
|   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
 | |
| }
 | |
| 
 | |
| StorageDBParent::CacheParentBridge*
 | |
| StorageDBParent::NewCache(const nsACString& aOriginSuffix,
 | |
|                           const nsACString& aOriginNoSuffix)
 | |
| {
 | |
|   return new CacheParentBridge(this, aOriginSuffix, aOriginNoSuffix);
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBParent::ActorDestroy(ActorDestroyReason aWhy)
 | |
| {
 | |
|   // Implement me! Bug 1005169
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBParent::RecvDeleteMe()
 | |
| {
 | |
|   AssertIsOnBackgroundThread();
 | |
| 
 | |
|   IProtocol* mgr = Manager();
 | |
|   if (!PBackgroundStorageParent::Send__delete__(this)) {
 | |
|     return IPC_FAIL_NO_REASON(mgr);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBParent::RecvAsyncPreload(const nsCString& aOriginSuffix,
 | |
|                                   const nsCString& aOriginNoSuffix,
 | |
|                                   const bool& aPriority)
 | |
| {
 | |
|   StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
 | |
|   if (!storageThread) {
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   storageThread->AsyncPreload(NewCache(aOriginSuffix, aOriginNoSuffix),
 | |
|                               aPriority);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBParent::RecvAsyncGetUsage(const nsCString& aOriginNoSuffix)
 | |
| {
 | |
|   StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
 | |
|   if (!storageThread) {
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   // The object releases it self in LoadUsage method
 | |
|   RefPtr<UsageParentBridge> usage =
 | |
|     new UsageParentBridge(this, aOriginNoSuffix);
 | |
| 
 | |
|   storageThread->AsyncGetUsage(usage);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| // We need another implementation of LocalStorageCacheBridge to do
 | |
| // synchronous IPC preload.  This class just receives Load* notifications
 | |
| // and fills the returning arguments of RecvPreload with the database
 | |
| // values for us.
 | |
| class SyncLoadCacheHelper : public LocalStorageCacheBridge
 | |
| {
 | |
| public:
 | |
|   SyncLoadCacheHelper(const nsCString& aOriginSuffix,
 | |
|                       const nsCString& aOriginNoSuffix,
 | |
|                       uint32_t aAlreadyLoadedCount,
 | |
|                       InfallibleTArray<nsString>* aKeys,
 | |
|                       InfallibleTArray<nsString>* aValues,
 | |
|                       nsresult* rv)
 | |
|   : mMonitor("DOM Storage SyncLoad IPC")
 | |
|   , mSuffix(aOriginSuffix)
 | |
|   , mOrigin(aOriginNoSuffix)
 | |
|   , mKeys(aKeys)
 | |
|   , mValues(aValues)
 | |
|   , mRv(rv)
 | |
|   , mLoaded(false)
 | |
|   , mLoadedCount(aAlreadyLoadedCount)
 | |
|   {
 | |
|     // Precaution
 | |
|     *mRv = NS_ERROR_UNEXPECTED;
 | |
|   }
 | |
| 
 | |
|   virtual const nsCString Origin() const override
 | |
|   {
 | |
|     return LocalStorageManager::CreateOrigin(mSuffix, mOrigin);
 | |
|   }
 | |
|   virtual const nsCString& OriginNoSuffix() const override { return mOrigin; }
 | |
|   virtual const nsCString& OriginSuffix() const override { return mSuffix; }
 | |
|   virtual bool Loaded() override { return mLoaded; }
 | |
|   virtual uint32_t LoadedCount() override { return mLoadedCount; }
 | |
|   virtual bool LoadItem(const nsAString& aKey, const nsString& aValue) override
 | |
|   {
 | |
|     // Called on the aCache background thread
 | |
|     MOZ_ASSERT(!mLoaded);
 | |
|     if (mLoaded) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     ++mLoadedCount;
 | |
|     mKeys->AppendElement(aKey);
 | |
|     mValues->AppendElement(aValue);
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   virtual void LoadDone(nsresult aRv) override
 | |
|   {
 | |
|     // Called on the aCache background thread
 | |
|     MonitorAutoLock monitor(mMonitor);
 | |
|     MOZ_ASSERT(!mLoaded && mRv);
 | |
|     mLoaded = true;
 | |
|     if (mRv) {
 | |
|       *mRv = aRv;
 | |
|       mRv = nullptr;
 | |
|     }
 | |
|     monitor.Notify();
 | |
|   }
 | |
| 
 | |
|   virtual void LoadWait() override
 | |
|   {
 | |
|     // Called on the main thread, exits after LoadDone() call
 | |
|     MonitorAutoLock monitor(mMonitor);
 | |
|     while (!mLoaded) {
 | |
|       monitor.Wait();
 | |
|     }
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   Monitor mMonitor;
 | |
|   nsCString mSuffix, mOrigin;
 | |
|   InfallibleTArray<nsString>* mKeys;
 | |
|   InfallibleTArray<nsString>* mValues;
 | |
|   nsresult* mRv;
 | |
|   bool mLoaded;
 | |
|   uint32_t mLoadedCount;
 | |
| };
 | |
| 
 | |
| } // namespace
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBParent::RecvPreload(const nsCString& aOriginSuffix,
 | |
|                              const nsCString& aOriginNoSuffix,
 | |
|                              const uint32_t& aAlreadyLoadedCount,
 | |
|                              InfallibleTArray<nsString>* aKeys,
 | |
|                              InfallibleTArray<nsString>* aValues,
 | |
|                              nsresult* aRv)
 | |
| {
 | |
|   StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
 | |
|   if (!storageThread) {
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   RefPtr<SyncLoadCacheHelper> cache(
 | |
|     new SyncLoadCacheHelper(aOriginSuffix, aOriginNoSuffix, aAlreadyLoadedCount,
 | |
|                             aKeys, aValues, aRv));
 | |
| 
 | |
|   storageThread->SyncPreload(cache, true);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBParent::RecvAsyncAddItem(const nsCString& aOriginSuffix,
 | |
|                                   const nsCString& aOriginNoSuffix,
 | |
|                                   const nsString& aKey,
 | |
|                                   const nsString& aValue)
 | |
| {
 | |
|   StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
 | |
|   if (!storageThread) {
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   nsresult rv =
 | |
|     storageThread->AsyncAddItem(NewCache(aOriginSuffix, aOriginNoSuffix),
 | |
|                                 aKey,
 | |
|                                 aValue);
 | |
|   if (NS_FAILED(rv) && mIPCOpen) {
 | |
|     mozilla::Unused << SendError(rv);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBParent::RecvAsyncUpdateItem(const nsCString& aOriginSuffix,
 | |
|                                      const nsCString& aOriginNoSuffix,
 | |
|                                      const nsString& aKey,
 | |
|                                      const nsString& aValue)
 | |
| {
 | |
|   StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
 | |
|   if (!storageThread) {
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   nsresult rv =
 | |
|     storageThread->AsyncUpdateItem(NewCache(aOriginSuffix, aOriginNoSuffix),
 | |
|                                    aKey,
 | |
|                                    aValue);
 | |
|   if (NS_FAILED(rv) && mIPCOpen) {
 | |
|     mozilla::Unused << SendError(rv);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBParent::RecvAsyncRemoveItem(const nsCString& aOriginSuffix,
 | |
|                                      const nsCString& aOriginNoSuffix,
 | |
|                                      const nsString& aKey)
 | |
| {
 | |
|   StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
 | |
|   if (!storageThread) {
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   nsresult rv =
 | |
|     storageThread->AsyncRemoveItem(NewCache(aOriginSuffix, aOriginNoSuffix),
 | |
|                                    aKey);
 | |
|   if (NS_FAILED(rv) && mIPCOpen) {
 | |
|     mozilla::Unused << SendError(rv);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBParent::RecvAsyncClear(const nsCString& aOriginSuffix,
 | |
|                                 const nsCString& aOriginNoSuffix)
 | |
| {
 | |
|   StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
 | |
|   if (!storageThread) {
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   nsresult rv =
 | |
|     storageThread->AsyncClear(NewCache(aOriginSuffix, aOriginNoSuffix));
 | |
|   if (NS_FAILED(rv) && mIPCOpen) {
 | |
|     mozilla::Unused << SendError(rv);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBParent::RecvAsyncFlush()
 | |
| {
 | |
|   StorageDBThread* storageThread = StorageDBThread::Get();
 | |
|   if (!storageThread) {
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   storageThread->AsyncFlush();
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBParent::RecvStartup()
 | |
| {
 | |
|   StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
 | |
|   if (!storageThread) {
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBParent::RecvClearAll()
 | |
| {
 | |
|   StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
 | |
|   if (!storageThread) {
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   storageThread->AsyncClearAll();
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBParent::RecvClearMatchingOrigin(const nsCString& aOriginNoSuffix)
 | |
| {
 | |
|   StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
 | |
|   if (!storageThread) {
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   storageThread->AsyncClearMatchingOrigin(aOriginNoSuffix);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| StorageDBParent::RecvClearMatchingOriginAttributes(
 | |
|                                         const OriginAttributesPattern& aPattern)
 | |
| {
 | |
|   StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
 | |
|   if (!storageThread) {
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   storageThread->AsyncClearMatchingOriginAttributes(aPattern);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBParent::Observe(const nsCString& aTopic,
 | |
|                          const nsString& aOriginAttributesPattern,
 | |
|                          const nsCString& aOriginScope)
 | |
| {
 | |
|   if (mIPCOpen) {
 | |
|     mozilla::Unused <<
 | |
|       SendObserve(aTopic, aOriginAttributesPattern, aOriginScope);
 | |
|   }
 | |
| }
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| // Results must be sent back on the main thread
 | |
| class LoadRunnable : public Runnable
 | |
| {
 | |
| public:
 | |
|   enum TaskType {
 | |
|     loadItem,
 | |
|     loadDone
 | |
|   };
 | |
| 
 | |
|   LoadRunnable(StorageDBParent* aParent,
 | |
|                TaskType aType,
 | |
|                const nsACString& aOriginSuffix,
 | |
|                const nsACString& aOriginNoSuffix,
 | |
|                const nsAString& aKey = EmptyString(),
 | |
|                const nsAString& aValue = EmptyString())
 | |
|     : Runnable("dom::LoadRunnable")
 | |
|     , mParent(aParent)
 | |
|     , mType(aType)
 | |
|     , mSuffix(aOriginSuffix)
 | |
|     , mOrigin(aOriginNoSuffix)
 | |
|     , mKey(aKey)
 | |
|     , mValue(aValue)
 | |
|   { }
 | |
| 
 | |
|   LoadRunnable(StorageDBParent* aParent,
 | |
|                TaskType aType,
 | |
|                const nsACString& aOriginSuffix,
 | |
|                const nsACString& aOriginNoSuffix,
 | |
|                nsresult aRv)
 | |
|     : Runnable("dom::LoadRunnable")
 | |
|     , mParent(aParent)
 | |
|     , mType(aType)
 | |
|     , mSuffix(aOriginSuffix)
 | |
|     , mOrigin(aOriginNoSuffix)
 | |
|     , mRv(aRv)
 | |
|   { }
 | |
| 
 | |
| private:
 | |
|   RefPtr<StorageDBParent> mParent;
 | |
|   TaskType mType;
 | |
|   nsCString mSuffix, mOrigin;
 | |
|   nsString mKey;
 | |
|   nsString mValue;
 | |
|   nsresult mRv;
 | |
| 
 | |
|   NS_IMETHOD Run() override
 | |
|   {
 | |
|     if (!mParent->IPCOpen()) {
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     switch (mType)
 | |
|     {
 | |
|     case loadItem:
 | |
|       mozilla::Unused << mParent->SendLoadItem(mSuffix, mOrigin, mKey, mValue);
 | |
|       break;
 | |
|     case loadDone:
 | |
|       mozilla::Unused << mParent->SendLoadDone(mSuffix, mOrigin, mRv);
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     mParent = nullptr;
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| };
 | |
| 
 | |
| } // namespace
 | |
| 
 | |
| // StorageDBParent::CacheParentBridge
 | |
| 
 | |
| const nsCString
 | |
| StorageDBParent::CacheParentBridge::Origin() const
 | |
| {
 | |
|   return LocalStorageManager::CreateOrigin(mOriginSuffix, mOriginNoSuffix);
 | |
| }
 | |
| 
 | |
| bool
 | |
| StorageDBParent::CacheParentBridge::LoadItem(const nsAString& aKey,
 | |
|                                              const nsString& aValue)
 | |
| {
 | |
|   if (mLoaded) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   ++mLoadedCount;
 | |
| 
 | |
|   RefPtr<LoadRunnable> r =
 | |
|     new LoadRunnable(mParent, LoadRunnable::loadItem, mOriginSuffix,
 | |
|                      mOriginNoSuffix, aKey, aValue);
 | |
| 
 | |
|   MOZ_ALWAYS_SUCCEEDS(
 | |
|     mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBParent::CacheParentBridge::LoadDone(nsresult aRv)
 | |
| {
 | |
|   // Prevent send of duplicate LoadDone.
 | |
|   if (mLoaded) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   mLoaded = true;
 | |
| 
 | |
|   RefPtr<LoadRunnable> r =
 | |
|     new LoadRunnable(mParent, LoadRunnable::loadDone, mOriginSuffix,
 | |
|                      mOriginNoSuffix, aRv);
 | |
| 
 | |
|   MOZ_ALWAYS_SUCCEEDS(
 | |
|     mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBParent::CacheParentBridge::LoadWait()
 | |
| {
 | |
|   // Should never be called on this implementation
 | |
|   MOZ_ASSERT(false);
 | |
| }
 | |
| 
 | |
| // XXX Fix me!
 | |
| // This should be just:
 | |
| // NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::CacheParentBridge, Destroy)
 | |
| // But due to different strings used for refcount logging and different return
 | |
| // types, this is done manually for now.
 | |
| NS_IMETHODIMP_(void)
 | |
| StorageDBParent::CacheParentBridge::Release(void)
 | |
| {
 | |
|   MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
 | |
|   nsrefcnt count = --mRefCnt;
 | |
|   NS_LOG_RELEASE(this, count, "LocalStorageCacheBridge");
 | |
|   if (0 == count) {
 | |
|     mRefCnt = 1; /* stabilize */
 | |
|     /* enable this to find non-threadsafe destructors: */
 | |
|     /* NS_ASSERT_OWNINGTHREAD(_class); */
 | |
|     Destroy();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBParent::CacheParentBridge::Destroy()
 | |
| {
 | |
|   if (mOwningEventTarget->IsOnCurrentThread()) {
 | |
|     delete this;
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   RefPtr<Runnable> destroyRunnable =
 | |
|     NewNonOwningRunnableMethod("CacheParentBridge::Destroy",
 | |
|                                this,
 | |
|                                &CacheParentBridge::Destroy);
 | |
| 
 | |
|   MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(destroyRunnable,
 | |
|                                                    NS_DISPATCH_NORMAL));
 | |
| }
 | |
| 
 | |
| // StorageDBParent::UsageParentBridge
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| class UsageRunnable : public Runnable
 | |
| {
 | |
| public:
 | |
|   UsageRunnable(StorageDBParent* aParent,
 | |
|                 const nsACString& aOriginScope,
 | |
|                 const int64_t& aUsage)
 | |
|     : Runnable("dom::UsageRunnable")
 | |
|     , mParent(aParent)
 | |
|     , mOriginScope(aOriginScope)
 | |
|     , mUsage(aUsage)
 | |
|   {}
 | |
| 
 | |
| private:
 | |
|   NS_IMETHOD Run() override
 | |
|   {
 | |
|     if (!mParent->IPCOpen()) {
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     mozilla::Unused << mParent->SendLoadUsage(mOriginScope, mUsage);
 | |
| 
 | |
|     mParent = nullptr;
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   RefPtr<StorageDBParent> mParent;
 | |
|   nsCString mOriginScope;
 | |
|   int64_t mUsage;
 | |
| };
 | |
| 
 | |
| } // namespace
 | |
| 
 | |
| void
 | |
| StorageDBParent::UsageParentBridge::LoadUsage(const int64_t aUsage)
 | |
| {
 | |
|   RefPtr<UsageRunnable> r = new UsageRunnable(mParent, mOriginScope, aUsage);
 | |
| 
 | |
|   MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
 | |
| }
 | |
| 
 | |
| // XXX Fix me!
 | |
| // This should be just:
 | |
| // NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::UsageParentBridge, Destroy)
 | |
| // But due to different strings used for refcount logging, this is done manually
 | |
| // for now.
 | |
| NS_IMETHODIMP_(MozExternalRefCountType)
 | |
| StorageDBParent::UsageParentBridge::Release(void)
 | |
| {
 | |
|   MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
 | |
|   nsrefcnt count = --mRefCnt;
 | |
|   NS_LOG_RELEASE(this, count, "StorageUsageBridge");
 | |
|   if (count == 0) {
 | |
|     Destroy();
 | |
|     return 0;
 | |
|   }
 | |
|   return count;
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBParent::UsageParentBridge::Destroy()
 | |
| {
 | |
|   if (mOwningEventTarget->IsOnCurrentThread()) {
 | |
|     delete this;
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   RefPtr<Runnable> destroyRunnable =
 | |
|     NewNonOwningRunnableMethod("UsageParentBridge::Destroy",
 | |
|                                this,
 | |
|                                &UsageParentBridge::Destroy);
 | |
| 
 | |
|   MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(destroyRunnable,
 | |
|                                                    NS_DISPATCH_NORMAL));
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBParent::
 | |
| ObserverSink::Start()
 | |
| {
 | |
|   AssertIsOnBackgroundThread();
 | |
| 
 | |
|   RefPtr<Runnable> runnable =
 | |
|     NewRunnableMethod("StorageDBParent::ObserverSink::AddSink",
 | |
|                       this,
 | |
|                       &StorageDBParent::ObserverSink::AddSink);
 | |
| 
 | |
|   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBParent::
 | |
| ObserverSink::Stop()
 | |
| {
 | |
|   AssertIsOnBackgroundThread();
 | |
| 
 | |
|   mActor = nullptr;
 | |
| 
 | |
|   RefPtr<Runnable> runnable =
 | |
|     NewRunnableMethod("StorageDBParent::ObserverSink::RemoveSink",
 | |
|                       this,
 | |
|                       &StorageDBParent::ObserverSink::RemoveSink);
 | |
| 
 | |
|   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBParent::
 | |
| ObserverSink::AddSink()
 | |
| {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   StorageObserver* observer = StorageObserver::Self();
 | |
|   if (observer) {
 | |
|     observer->AddSink(this);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBParent::
 | |
| ObserverSink::RemoveSink()
 | |
| {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   StorageObserver* observer = StorageObserver::Self();
 | |
|   if (observer) {
 | |
|     observer->RemoveSink(this);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| StorageDBParent::
 | |
| ObserverSink::Notify(const nsCString& aTopic,
 | |
|                      const nsString& aOriginAttributesPattern,
 | |
|                      const nsCString& aOriginScope)
 | |
| {
 | |
|   AssertIsOnBackgroundThread();
 | |
| 
 | |
|   if (mActor) {
 | |
|     mActor->Observe(aTopic, aOriginAttributesPattern, aOriginScope);
 | |
|   }
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| StorageDBParent::
 | |
| ObserverSink::Observe(const char* aTopic,
 | |
|                       const nsAString& aOriginAttributesPattern,
 | |
|                       const nsACString& aOriginScope)
 | |
| {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   RefPtr<Runnable> runnable =
 | |
|     NewRunnableMethod<nsCString, nsString, nsCString>(
 | |
|       "StorageDBParent::ObserverSink::Observe2",
 | |
|       this,
 | |
|       &StorageDBParent::ObserverSink::Notify,
 | |
|       aTopic,
 | |
|       aOriginAttributesPattern,
 | |
|       aOriginScope);
 | |
| 
 | |
|   MOZ_ALWAYS_SUCCEEDS(
 | |
|     mOwningEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
|  * Exported functions
 | |
|  ******************************************************************************/
 | |
| 
 | |
| PBackgroundStorageParent*
 | |
| AllocPBackgroundStorageParent(const nsString& aProfilePath)
 | |
| {
 | |
|   AssertIsOnBackgroundThread();
 | |
| 
 | |
|   return new StorageDBParent(aProfilePath);
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| RecvPBackgroundStorageConstructor(PBackgroundStorageParent* aActor,
 | |
|                                   const nsString& aProfilePath)
 | |
| {
 | |
|   AssertIsOnBackgroundThread();
 | |
|   MOZ_ASSERT(aActor);
 | |
| 
 | |
|   auto* actor = static_cast<StorageDBParent*>(aActor);
 | |
|   actor->Init();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| bool
 | |
| DeallocPBackgroundStorageParent(PBackgroundStorageParent* aActor)
 | |
| {
 | |
|   AssertIsOnBackgroundThread();
 | |
|   MOZ_ASSERT(aActor);
 | |
| 
 | |
|   StorageDBParent* actor = static_cast<StorageDBParent*>(aActor);
 | |
|   actor->ReleaseIPDLReference();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| } // namespace dom
 | |
| } // namespace mozilla
 |