author | Jan Varga <jvarga@mozilla.com> |
Wed, 11 Nov 2020 13:12:57 +0000 | |
changeset 556739 | 661f0d8ae4c44db58e668c831b555dbc038b77d0 |
parent 556738 | 4806fdbc8d1781fffa7f4aed8e15dbe770e3ba3b |
child 556740 | 95c4cfea94a24d7573b36826ba3a015ca82b8a6d |
push id | 37940 |
push user | ccoroiu@mozilla.com |
push date | Wed, 11 Nov 2020 16:38:50 +0000 |
treeherder | mozilla-central@661f0d8ae4c4 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | asuth, dom-workers-and-storage-reviewers |
bugs | 1669437 |
milestone | 84.0a1 |
first release with | nightly linux32
661f0d8ae4c4
/
84.0a1
/
20201111163850
/
files
nightly linux64
661f0d8ae4c4
/
84.0a1
/
20201111163850
/
files
nightly mac
661f0d8ae4c4
/
84.0a1
/
20201111163850
/
files
nightly win32
661f0d8ae4c4
/
84.0a1
/
20201111163850
/
files
nightly win64
661f0d8ae4c4
/
84.0a1
/
20201111163850
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
84.0a1
/
20201111163850
/
pushlog to previous
nightly linux64
84.0a1
/
20201111163850
/
pushlog to previous
nightly mac
84.0a1
/
20201111163850
/
pushlog to previous
nightly win32
84.0a1
/
20201111163850
/
pushlog to previous
nightly win64
84.0a1
/
20201111163850
/
pushlog to previous
|
--- a/dom/storage/LocalStorageCache.cpp +++ b/dom/storage/LocalStorageCache.cpp @@ -124,16 +124,17 @@ void LocalStorageCache::Init(LocalStorag nsIPrincipal* aPrincipal, const nsACString& aQuotaOriginScope) { if (mInitialized) { return; } mInitialized = true; aPrincipal->OriginAttributesRef().CreateSuffix(mOriginSuffix); + mPrivateBrowsingId = aPrincipal->GetPrivateBrowsingId(); mPersistent = aPersistent; if (aQuotaOriginScope.IsEmpty()) { mQuotaOriginScope = Origin(); } else { mQuotaOriginScope = aQuotaOriginScope; } if (mPersistent) { @@ -142,17 +143,17 @@ void LocalStorageCache::Init(LocalStorag } // Check the quota string has (or has not) the identical origin suffix as // this storage cache is bound to. MOZ_ASSERT(StringBeginsWith(mQuotaOriginScope, mOriginSuffix)); MOZ_ASSERT(mOriginSuffix.IsEmpty() != StringBeginsWith(mQuotaOriginScope, "^"_ns)); - mUsage = aManager->GetOriginUsage(mQuotaOriginScope); + mUsage = aManager->GetOriginUsage(mQuotaOriginScope, mPrivateBrowsingId); } void LocalStorageCache::NotifyObservers(const LocalStorage* aStorage, const nsString& aKey, const nsString& aOldValue, const nsString& aNewValue) { AssertIsOnOwningThread(); MOZ_ASSERT(aStorage); @@ -209,17 +210,18 @@ bool LocalStorageCache::ProcessUsageDelt return true; } void LocalStorageCache::Preload() { if (mLoaded || !mPersistent) { return; } - StorageDBChild* storageChild = StorageDBChild::GetOrCreate(); + StorageDBChild* storageChild = + StorageDBChild::GetOrCreate(mPrivateBrowsingId); if (!storageChild) { mLoaded = true; mLoadResult = NS_ERROR_FAILURE; return; } storageChild->AsyncPreload(this); } @@ -249,17 +251,17 @@ void LocalStorageCache::WaitForPreload(T // SyncPreload will just wait for it to finish rather then synchronously // read from the database. It seems to me more optimal. // TODO place for A/B testing (force main thread load vs. let preload finish) // No need to check sDatabase for being non-null since preload is either // done before we've shut the DB down or when the DB could not start, // preload has not even be started. - StorageDBChild::Get()->SyncPreload(this); + StorageDBChild::Get(mPrivateBrowsingId)->SyncPreload(this); } nsresult LocalStorageCache::GetLength(const LocalStorage* aStorage, uint32_t* aRetval) { if (Persist(aStorage)) { WaitForPreload(Telemetry::LOCALDOMSTORAGE_GETLENGTH_BLOCKING_MS); if (NS_FAILED(mLoadResult)) { return mLoadResult; @@ -369,17 +371,17 @@ nsresult LocalStorageCache::SetItem(cons return NS_OK; } #if !defined(MOZ_WIDGET_ANDROID) NotifyObservers(aStorage, nsString(aKey), aOld, aValue); #endif if (Persist(aStorage)) { - StorageDBChild* storageChild = StorageDBChild::Get(); + StorageDBChild* storageChild = StorageDBChild::Get(mPrivateBrowsingId); if (!storageChild) { NS_ERROR( "Writing to localStorage after the database has been shut down" ", data lose!"); return NS_ERROR_NOT_INITIALIZED; } if (DOMStringIsNull(aOld)) { @@ -418,17 +420,17 @@ nsresult LocalStorageCache::RemoveItem(c return NS_OK; } #if !defined(MOZ_WIDGET_ANDROID) NotifyObservers(aStorage, nsString(aKey), aOld, VoidString()); #endif if (Persist(aStorage)) { - StorageDBChild* storageChild = StorageDBChild::Get(); + StorageDBChild* storageChild = StorageDBChild::Get(mPrivateBrowsingId); if (!storageChild) { NS_ERROR( "Writing to localStorage after the database has been shut down" ", data lose!"); return NS_ERROR_NOT_INITIALIZED; } return storageChild->AsyncRemoveItem(this, aKey); @@ -469,17 +471,17 @@ nsresult LocalStorageCache::Clear(const #if !defined(MOZ_WIDGET_ANDROID) if (hadData) { NotifyObservers(aStorage, VoidString(), VoidString(), VoidString()); } #endif if (Persist(aStorage) && (refresh || hadData)) { - StorageDBChild* storageChild = StorageDBChild::Get(); + StorageDBChild* storageChild = StorageDBChild::Get(mPrivateBrowsingId); if (!storageChild) { NS_ERROR( "Writing to localStorage after the database has been shut down" ", data lose!"); return NS_ERROR_NOT_INITIALIZED; } return storageChild->AsyncClear(this);
--- a/dom/storage/LocalStorageCache.h +++ b/dom/storage/LocalStorageCache.h @@ -251,16 +251,19 @@ class LocalStorageCache : public LocalSt // all keys and coresponding values are loaded from the database. // This flag never goes from true back to false. Since this flag is // critical for mData hashtable synchronization, it's made atomic. Atomic<bool, ReleaseAcquire> mLoaded; // Result of load from the database. Valid after mLoaded flag has been set. nsresult mLoadResult; + // Expected to be only 0 or 1. + uint32_t mPrivateBrowsingId; + // Init() method has been called bool mInitialized : 1; // This cache is about to be bound with the database (i.e. it has // to load from the DB first and has to persist when modifying the // default data set.) bool mPersistent : 1;
--- a/dom/storage/LocalStorageManager.cpp +++ b/dom/storage/LocalStorageManager.cpp @@ -56,17 +56,19 @@ LocalStorageManager::LocalStorageManager "Somebody is trying to " "do_CreateInstance(\"@mozilla/dom/localStorage-manager;1\""); sSelf = this; if (!XRE_IsParentProcess()) { // Do this only on the child process. The thread IPC bridge // is also used to communicate chrome observer notifications. // Note: must be called after we set sSelf - StorageDBChild::GetOrCreate(); + for (const uint32_t id : {0, 1}) { + StorageDBChild::GetOrCreate(id); + } } } LocalStorageManager::~LocalStorageManager() { StorageObserver* observer = StorageObserver::Self(); if (observer) { observer->RemoveSink(this); } @@ -95,25 +97,26 @@ LocalStorageCache* LocalStorageManager:: if (!entry) { return nullptr; } return entry->cache(); } already_AddRefed<StorageUsage> LocalStorageManager::GetOriginUsage( - const nsACString& aOriginNoSuffix) { + const nsACString& aOriginNoSuffix, const uint32_t aPrivateBrowsingId) { RefPtr<StorageUsage> usage; if (mUsages.Get(aOriginNoSuffix, &usage)) { return usage.forget(); } usage = new StorageUsage(aOriginNoSuffix); - StorageDBChild* storageChild = StorageDBChild::GetOrCreate(); + StorageDBChild* storageChild = + StorageDBChild::GetOrCreate(aPrivateBrowsingId); if (storageChild) { storageChild->AsyncGetUsage(usage); } mUsages.Put(aOriginNoSuffix, usage); return usage.forget(); } @@ -162,19 +165,22 @@ nsresult LocalStorageManager::GetStorage // Get or create a cache for the given scope if (!cache) { if (aCreateMode == CreateMode::UseIfExistsNeverCreate) { *aRetval = nullptr; return NS_OK; } if (aCreateMode == CreateMode::CreateIfShouldPreload) { + const uint32_t privateBrowsingId = + aStoragePrincipal->GetPrivateBrowsingId(); + // This is a demand to just preload the cache, if the scope has // no data stored, bypass creation and preload of the cache. - StorageDBChild* db = StorageDBChild::Get(); + StorageDBChild* db = StorageDBChild::Get(privateBrowsingId); if (db) { if (!db->ShouldPreloadOrigin(LocalStorageManager::CreateOrigin( originAttrSuffix, originKey))) { return NS_OK; } } else { if (originKey.EqualsLiteral("knalb.:about")) { return NS_OK;
--- a/dom/storage/LocalStorageManager.h +++ b/dom/storage/LocalStorageManager.h @@ -40,17 +40,17 @@ class LocalStorageManager final : public static uint32_t GetQuota(); // Gets (but not ensures) cache for the given scope LocalStorageCache* GetCache(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix); // Returns object keeping usage cache for the scope. already_AddRefed<StorageUsage> GetOriginUsage( - const nsACString& aOriginNoSuffix); + const nsACString& aOriginNoSuffix, uint32_t aPrivateBrowsingId); static nsAutoCString CreateOrigin(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix); private: ~LocalStorageManager(); // StorageObserverSink, handler to various chrome clearing notification
--- a/dom/storage/StorageDBThread.cpp +++ b/dom/storage/StorageDBThread.cpp @@ -47,20 +47,20 @@ namespace mozilla { namespace dom { using namespace StorageUtils; namespace { // anon -StorageDBThread* sStorageThread = nullptr; +StorageDBThread* sStorageThread[2] = {nullptr, nullptr}; // False until we shut the storage thread down. -bool sStorageThreadDown = false; +bool sStorageThreadDown[2] = {false, false}; } // namespace // XXX Fix me! #if 0 StorageDBBridge::StorageDBBridge() { } @@ -92,69 +92,79 @@ class StorageDBThread::InitHelper final ~InitHelper() override = default; nsresult RunOnMainThread(); NS_DECL_NSIRUNNABLE }; class StorageDBThread::NoteBackgroundThreadRunnable final : public Runnable { + // Expected to be only 0 or 1. + const uint32_t mPrivateBrowsingId; nsCOMPtr<nsIEventTarget> mOwningThread; public: - NoteBackgroundThreadRunnable() + explicit NoteBackgroundThreadRunnable(const uint32_t aPrivateBrowsingId) : Runnable("dom::StorageDBThread::NoteBackgroundThreadRunnable"), + mPrivateBrowsingId(aPrivateBrowsingId), mOwningThread(GetCurrentEventTarget()) {} private: ~NoteBackgroundThreadRunnable() override = default; NS_DECL_NSIRUNNABLE }; -StorageDBThread::StorageDBThread() +StorageDBThread::StorageDBThread(const uint32_t aPrivateBrowsingId) : mThread(nullptr), mThreadObserver(new ThreadObserver()), mStopIOThread(false), mWALModeEnabled(false), mDBReady(false), mStatus(NS_OK), mWorkerStatements(mWorkerConnection), mReaderStatements(mReaderConnection), mFlushImmediately(false), - mPriorityCounter(0) {} + mPrivateBrowsingId(aPrivateBrowsingId), + mPriorityCounter(0) { + MOZ_ASSERT(aPrivateBrowsingId <= 1); +} // static -StorageDBThread* StorageDBThread::Get() { +StorageDBThread* StorageDBThread::Get(const uint32_t aPrivateBrowsingId) { ::mozilla::ipc::AssertIsOnBackgroundThread(); + MOZ_ASSERT(aPrivateBrowsingId <= 1); - return sStorageThread; + return sStorageThread[aPrivateBrowsingId]; } // static -StorageDBThread* StorageDBThread::GetOrCreate(const nsString& aProfilePath) { +StorageDBThread* StorageDBThread::GetOrCreate( + const nsString& aProfilePath, const uint32_t aPrivateBrowsingId) { ::mozilla::ipc::AssertIsOnBackgroundThread(); + MOZ_ASSERT(aPrivateBrowsingId <= 1); - if (sStorageThread || sStorageThreadDown) { + StorageDBThread*& storageThread = sStorageThread[aPrivateBrowsingId]; + if (storageThread || sStorageThreadDown[aPrivateBrowsingId]) { // When sStorageThreadDown is at true, sStorageThread is null. // Checking sStorageThreadDown flag here prevents reinitialization of // the storage thread after shutdown. - return sStorageThread; + return storageThread; } - auto storageThread = MakeUnique<StorageDBThread>(); + auto newStorageThread = MakeUnique<StorageDBThread>(aPrivateBrowsingId); - nsresult rv = storageThread->Init(aProfilePath); + nsresult rv = newStorageThread->Init(aProfilePath); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } - sStorageThread = storageThread.release(); + storageThread = newStorageThread.release(); - return sStorageThread; + return storageThread; } // static nsresult StorageDBThread::GetProfilePath(nsString& aProfilePath) { MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(NS_IsMainThread()); // Need to determine location on the main thread, since @@ -180,66 +190,66 @@ nsresult StorageDBThread::GetProfilePath } return NS_OK; } nsresult StorageDBThread::Init(const nsString& aProfilePath) { ::mozilla::ipc::AssertIsOnBackgroundThread(); - nsresult rv; + if (mPrivateBrowsingId == 0) { + nsresult rv; + + nsString profilePath; + if (aProfilePath.IsEmpty()) { + RefPtr<InitHelper> helper = new InitHelper(); - nsString profilePath; - if (aProfilePath.IsEmpty()) { - RefPtr<InitHelper> helper = new InitHelper(); + rv = helper->SyncDispatchAndReturnProfilePath(profilePath); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } else { + profilePath = aProfilePath; + } - rv = helper->SyncDispatchAndReturnProfilePath(profilePath); + mDatabaseFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - } else { - profilePath = aProfilePath; - } - mDatabaseFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; + rv = mDatabaseFile->InitWithPath(profilePath); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = mDatabaseFile->Append(u"webappsstore.sqlite"_ns); + NS_ENSURE_SUCCESS(rv, rv); } - rv = mDatabaseFile->InitWithPath(profilePath); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - rv = mDatabaseFile->Append(u"webappsstore.sqlite"_ns); - NS_ENSURE_SUCCESS(rv, rv); - // Need to keep the lock to avoid setting mThread later then // the thread body executes. MonitorAutoLock monitor(mThreadObserver->GetMonitor()); mThread = PR_CreateThread(PR_USER_THREAD, &StorageDBThread::ThreadFunc, this, PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 262144); if (!mThread) { return NS_ERROR_OUT_OF_MEMORY; } RefPtr<NoteBackgroundThreadRunnable> runnable = - new NoteBackgroundThreadRunnable(); + new NoteBackgroundThreadRunnable(mPrivateBrowsingId); MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable)); return NS_OK; } nsresult StorageDBThread::Shutdown() { ::mozilla::ipc::AssertIsOnBackgroundThread(); - sStorageThreadDown = true; - if (!mThread) { return NS_ERROR_NOT_INITIALIZED; } Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_SHUTDOWN_DATABASE_MS> timer; { MonitorAutoLock monitor(mThreadObserver->GetMonitor()); @@ -517,24 +527,34 @@ nsresult StorageDBThread::OpenDatabaseCo nsresult rv; MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr<mozIStorageService> service = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); - rv = service->OpenUnsharedDatabase(mDatabaseFile, - getter_AddRefs(mWorkerConnection)); - if (rv == NS_ERROR_FILE_CORRUPTED) { - // delete the db and try opening again - rv = mDatabaseFile->Remove(false); - NS_ENSURE_SUCCESS(rv, rv); + if (mPrivateBrowsingId == 0) { + MOZ_ASSERT(mDatabaseFile); + rv = service->OpenUnsharedDatabase(mDatabaseFile, getter_AddRefs(mWorkerConnection)); + if (rv == NS_ERROR_FILE_CORRUPTED) { + // delete the db and try opening again + rv = mDatabaseFile->Remove(false); + NS_ENSURE_SUCCESS(rv, rv); + rv = service->OpenUnsharedDatabase(mDatabaseFile, + getter_AddRefs(mWorkerConnection)); + } + } else { + MOZ_ASSERT(mPrivateBrowsingId == 1); + + rv = service->OpenSpecialDatabase(kMozStorageMemoryStorageKey, + "lsprivatedb"_ns, + getter_AddRefs(mWorkerConnection)); } NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } nsresult StorageDBThread::OpenAndUpdateDatabase() { nsresult rv; @@ -557,26 +577,28 @@ nsresult StorageDBThread::InitDatabase() // Here we are on the worker thread. This opens the worker connection. MOZ_ASSERT(!NS_IsMainThread()); rv = OpenAndUpdateDatabase(); NS_ENSURE_SUCCESS(rv, rv); rv = StorageDBUpdater::Update(mWorkerConnection); if (NS_FAILED(rv)) { - // Update has failed, rather throw the database away and try - // opening and setting it up again. - rv = mWorkerConnection->Close(); - mWorkerConnection = nullptr; - NS_ENSURE_SUCCESS(rv, rv); + if (mPrivateBrowsingId == 0) { + // Update has failed, rather throw the database away and try + // opening and setting it up again. + rv = mWorkerConnection->Close(); + mWorkerConnection = nullptr; + NS_ENSURE_SUCCESS(rv, rv); - rv = mDatabaseFile->Remove(false); - NS_ENSURE_SUCCESS(rv, rv); + rv = mDatabaseFile->Remove(false); + NS_ENSURE_SUCCESS(rv, rv); - rv = OpenAndUpdateDatabase(); + rv = OpenAndUpdateDatabase(); + } NS_ENSURE_SUCCESS(rv, rv); } // Create a read-only clone (void)mWorkerConnection->Clone(true, getter_AddRefs(mReaderConnection)); NS_ENSURE_TRUE(mReaderConnection, NS_ERROR_FAILURE); // Database open and all initiation operation are done. Switching this flag @@ -1524,36 +1546,39 @@ StorageDBThread::InitHelper::Run() { NS_IMETHODIMP StorageDBThread::NoteBackgroundThreadRunnable::Run() { MOZ_ASSERT(NS_IsMainThread()); StorageObserver* observer = StorageObserver::Self(); MOZ_ASSERT(observer); - observer->NoteBackgroundThread(mOwningThread); + observer->NoteBackgroundThread(mPrivateBrowsingId, mOwningThread); return NS_OK; } NS_IMETHODIMP StorageDBThread::ShutdownRunnable::Run() { if (NS_IsMainThread()) { mDone = true; return NS_OK; } ::mozilla::ipc::AssertIsOnBackgroundThread(); - if (sStorageThread) { - sStorageThread->Shutdown(); + StorageDBThread*& storageThread = sStorageThread[mPrivateBrowsingId]; + if (storageThread) { + sStorageThreadDown[mPrivateBrowsingId] = true; - delete sStorageThread; - sStorageThread = nullptr; + storageThread->Shutdown(); + + delete storageThread; + storageThread = nullptr; } MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this)); return NS_OK; } } // namespace dom
--- a/dom/storage/StorageDBThread.h +++ b/dom/storage/StorageDBThread.h @@ -287,38 +287,43 @@ class StorageDBThread final { Monitor mMonitor; }; class InitHelper; class NoteBackgroundThreadRunnable; class ShutdownRunnable : public Runnable { + // Expected to be only 0 or 1. + const uint32_t mPrivateBrowsingId; // Only touched on the main thread. bool& mDone; public: - explicit ShutdownRunnable(bool& aDone) - : Runnable("dom::StorageDBThread::ShutdownRunnable"), mDone(aDone) { + explicit ShutdownRunnable(const uint32_t aPrivateBrowsingId, bool& aDone) + : Runnable("dom::StorageDBThread::ShutdownRunnable"), + mPrivateBrowsingId(aPrivateBrowsingId), + mDone(aDone) { MOZ_ASSERT(NS_IsMainThread()); } private: ~ShutdownRunnable() = default; NS_DECL_NSIRUNNABLE }; public: - StorageDBThread(); + explicit StorageDBThread(uint32_t aPrivateBrowsingId); virtual ~StorageDBThread() = default; - static StorageDBThread* Get(); + static StorageDBThread* Get(uint32_t aPrivateBrowsingId); - static StorageDBThread* GetOrCreate(const nsString& aProfilePath); + static StorageDBThread* GetOrCreate(const nsString& aProfilePath, + uint32_t aPrivateBrowsingId); static nsresult GetProfilePath(nsString& aProfilePath); virtual nsresult Init(const nsString& aProfilePath); // Flushes all uncommited data and stops the I/O thread. virtual nsresult Shutdown(); @@ -424,16 +429,19 @@ class StorageDBThread final { // List of preloading operations, in chronological or priority order. // Executed prioritly over pending update operations. nsTArray<DBOperation*> mPreloads; // Collector of pending update operations PendingOperations mPendingTasks; + // Expected to be only 0 or 1. + const uint32_t mPrivateBrowsingId; + // Counter of calls for thread priority rising. int32_t mPriorityCounter; // Helper to direct an operation to one of the arrays above; // also checks IsOriginClearPending for preloads nsresult InsertDBOp(DBOperation* aOperation); // Opens the database, first thing we do after start of the thread.
--- a/dom/storage/StorageIPC.cpp +++ b/dom/storage/StorageIPC.cpp @@ -27,20 +27,20 @@ namespace dom { namespace { typedef nsClassHashtable<nsCStringHashKey, nsTArray<LocalStorageCacheParent*>> LocalStorageCacheParentHashtable; StaticAutoPtr<LocalStorageCacheParentHashtable> gLocalStorageCacheParents; -StorageDBChild* sStorageChild = nullptr; +StorageDBChild* sStorageChild[2] = {nullptr, nullptr}; // False until we shut the storage child down. -bool sStorageChildDown = false; +bool sStorageChildDown[2] = {false, false}; } // namespace LocalStorageCacheChild::LocalStorageCacheChild(LocalStorageCache* aCache) : mCache(aCache) { AssertIsOnOwningThread(); MOZ_ASSERT(aCache); aCache->AssertIsOnOwningThread(); @@ -106,18 +106,24 @@ mozilla::ipc::IPCResult LocalStorageCach return IPC_OK(); } // ---------------------------------------------------------------------------- // Child // ---------------------------------------------------------------------------- class StorageDBChild::ShutdownObserver final : public nsIObserver { + // Expected to be only 0 or 1. + const uint32_t mPrivateBrowsingId; + public: - ShutdownObserver() { MOZ_ASSERT(NS_IsMainThread()); } + explicit ShutdownObserver(const uint32_t aPrivateBrowsingId) + : mPrivateBrowsingId(aPrivateBrowsingId) { + MOZ_ASSERT(NS_IsMainThread()); + } NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER private: ~ShutdownObserver() { MOZ_ASSERT(NS_IsMainThread()); } }; @@ -128,57 +134,65 @@ void StorageDBChild::AddIPDLReference() } 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(LocalStorageManager* aManager, + const uint32_t aPrivateBrowsingId) + : mManager(aManager), + mPrivateBrowsingId(aPrivateBrowsingId), + mStatus(NS_OK), + mIPCOpen(false) { + MOZ_ASSERT(aPrivateBrowsingId <= 1); MOZ_ASSERT(!NextGenLocalStorageEnabled()); } StorageDBChild::~StorageDBChild() = default; // static -StorageDBChild* StorageDBChild::Get() { +StorageDBChild* StorageDBChild::Get(const uint32_t aPrivateBrowsingId) { MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aPrivateBrowsingId <= 1); MOZ_ASSERT(!NextGenLocalStorageEnabled()); - return sStorageChild; + return sStorageChild[aPrivateBrowsingId]; } // static -StorageDBChild* StorageDBChild::GetOrCreate() { +StorageDBChild* StorageDBChild::GetOrCreate(const uint32_t aPrivateBrowsingId) { MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aPrivateBrowsingId <= 1); MOZ_ASSERT(!NextGenLocalStorageEnabled()); - if (sStorageChild || sStorageChildDown) { + StorageDBChild*& storageChild = sStorageChild[aPrivateBrowsingId]; + if (storageChild || sStorageChildDown[aPrivateBrowsingId]) { // When sStorageChildDown is at true, sStorageChild is null. // Checking sStorageChildDown flag here prevents reinitialization of // the storage child after shutdown. - return sStorageChild; + return storageChild; } // 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()); + RefPtr<StorageDBChild> newStorageChild = + new StorageDBChild(LocalStorageManager::Ensure(), aPrivateBrowsingId); - nsresult rv = storageChild->Init(); + nsresult rv = newStorageChild->Init(); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } - storageChild.forget(&sStorageChild); + newStorageChild.forget(&storageChild); - return sStorageChild; + return storageChild; } nsTHashtable<nsCStringHashKey>& StorageDBChild::OriginsHavingData() { if (!mOriginsHavingData) { mOriginsHavingData = MakeUnique<nsTHashtable<nsCStringHashKey>>(); } return *mOriginsHavingData; @@ -189,31 +203,32 @@ nsresult StorageDBChild::Init() { ::mozilla::ipc::PBackgroundChild* actor = ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread(); if (NS_WARN_IF(!actor)) { return NS_ERROR_FAILURE; } nsString profilePath; - if (XRE_IsParentProcess()) { + if (XRE_IsParentProcess() && mPrivateBrowsingId == 0) { nsresult rv = StorageDBThread::GetProfilePath(profilePath); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } AddIPDLReference(); - actor->SendPBackgroundStorageConstructor(this, profilePath); + actor->SendPBackgroundStorageConstructor(this, profilePath, + mPrivateBrowsingId); nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); MOZ_ASSERT(observerService); - nsCOMPtr<nsIObserver> observer = new ShutdownObserver(); + nsCOMPtr<nsIObserver> observer = new ShutdownObserver(mPrivateBrowsingId); MOZ_ALWAYS_SUCCEEDS( observerService->AddObserver(observer, "xpcom-shutdown", false)); return NS_OK; } nsresult StorageDBChild::Shutdown() { @@ -375,17 +390,17 @@ mozilla::ipc::IPCResult StorageDBChild:: } return IPC_OK(); } mozilla::ipc::IPCResult StorageDBChild::RecvLoadUsage( const nsCString& aOriginNoSuffix, const int64_t& aUsage) { RefPtr<StorageUsageBridge> scopeUsage = - mManager->GetOriginUsage(aOriginNoSuffix); + mManager->GetOriginUsage(aOriginNoSuffix, mPrivateBrowsingId); scopeUsage->LoadUsage(aUsage); return IPC_OK(); } mozilla::ipc::IPCResult StorageDBChild::RecvError(const nsresult& aRv) { mStatus = aRv; return IPC_OK(); } @@ -402,23 +417,24 @@ StorageDBChild::ShutdownObserver::Observ 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; + StorageDBChild*& storageChild = sStorageChild[mPrivateBrowsingId]; + if (storageChild) { + sStorageChildDown[mPrivateBrowsingId] = true; - MOZ_ALWAYS_TRUE(sStorageChild->PBackgroundStorageChild::SendDeleteMe()); + MOZ_ALWAYS_TRUE(storageChild->PBackgroundStorageChild::SendDeleteMe()); - NS_RELEASE(sStorageChild); - sStorageChild = nullptr; + NS_RELEASE(storageChild); + storageChild = nullptr; } return NS_OK; } SessionStorageObserverChild::SessionStorageObserverChild( SessionStorageObserver* aObserver) : mObserver(aObserver) { @@ -662,18 +678,21 @@ void StorageDBParent::AddIPDLReference() void StorageDBParent::ReleaseIPDLReference() { MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference"); mIPCOpen = false; Release(); } namespace {} // namespace -StorageDBParent::StorageDBParent(const nsString& aProfilePath) - : mProfilePath(aProfilePath), mIPCOpen(false) { +StorageDBParent::StorageDBParent(const nsString& aProfilePath, + const uint32_t aPrivateBrowsingId) + : mProfilePath(aProfilePath), + mPrivateBrowsingId(aPrivateBrowsingId), + mIPCOpen(false) { ::mozilla::ipc::AssertIsOnBackgroundThread(); // We are always open by IPC only AddIPDLReference(); } StorageDBParent::~StorageDBParent() { ::mozilla::ipc::AssertIsOnBackgroundThread(); @@ -690,17 +709,17 @@ void StorageDBParent::Init() { PBackgroundParent* actor = Manager(); MOZ_ASSERT(actor); if (::mozilla::ipc::BackgroundParent::IsOtherProcessActor(actor)) { mObserverSink = new ObserverSink(this); mObserverSink->Start(); } - StorageDBThread* storageThread = StorageDBThread::Get(); + StorageDBThread* storageThread = StorageDBThread::Get(mPrivateBrowsingId); if (storageThread) { nsTArray<nsCString> scopes; storageThread->GetOriginsHavingData(&scopes); mozilla::Unused << SendOriginsHavingData(scopes); } } StorageDBParent::CacheParentBridge* StorageDBParent::NewCache( @@ -720,30 +739,32 @@ mozilla::ipc::IPCResult StorageDBParent: 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); + StorageDBThread* storageThread = + StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 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); + StorageDBThread* storageThread = + StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); if (!storageThread) { return IPC_FAIL_NO_REASON(this); } // The object releases it self in LoadUsage method RefPtr<UsageParentBridge> usage = new UsageParentBridge(this, aOriginNoSuffix); @@ -828,143 +849,152 @@ class SyncLoadCacheHelper : public Local }; } // namespace mozilla::ipc::IPCResult StorageDBParent::RecvPreload( const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix, const uint32_t& aAlreadyLoadedCount, nsTArray<nsString>* aKeys, nsTArray<nsString>* aValues, nsresult* aRv) { - StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath); + StorageDBThread* storageThread = + StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 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); + StorageDBThread* storageThread = + StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 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); + StorageDBThread* storageThread = + StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 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); + StorageDBThread* storageThread = + StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 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); + StorageDBThread* storageThread = + StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 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(); + StorageDBThread* storageThread = StorageDBThread::Get(mPrivateBrowsingId); if (!storageThread) { return IPC_FAIL_NO_REASON(this); } storageThread->AsyncFlush(); return IPC_OK(); } mozilla::ipc::IPCResult StorageDBParent::RecvStartup() { - StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath); + StorageDBThread* storageThread = + StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); if (!storageThread) { return IPC_FAIL_NO_REASON(this); } return IPC_OK(); } mozilla::ipc::IPCResult StorageDBParent::RecvClearAll() { - StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath); + StorageDBThread* storageThread = + StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 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); + StorageDBThread* storageThread = + StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 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); + StorageDBThread* storageThread = + StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); if (!storageThread) { return IPC_FAIL_NO_REASON(this); } storageThread->AsyncClearMatchingOriginAttributes(aPattern); return IPC_OK(); } @@ -1454,24 +1484,25 @@ bool DeallocPBackgroundLocalStorageCache // Transfer ownership back from IPDL. RefPtr<LocalStorageCacheParent> actor = dont_AddRef(static_cast<LocalStorageCacheParent*>(aActor)); return true; } PBackgroundStorageParent* AllocPBackgroundStorageParent( - const nsString& aProfilePath) { + const nsString& aProfilePath, const uint32_t& aPrivateBrowsingId) { ::mozilla::ipc::AssertIsOnBackgroundThread(); - return new StorageDBParent(aProfilePath); + return new StorageDBParent(aProfilePath, aPrivateBrowsingId); } mozilla::ipc::IPCResult RecvPBackgroundStorageConstructor( - PBackgroundStorageParent* aActor, const nsString& aProfilePath) { + PBackgroundStorageParent* aActor, const nsString& aProfilePath, + const uint32_t& aPrivateBrowsingId) { ::mozilla::ipc::AssertIsOnBackgroundThread(); MOZ_ASSERT(aActor); auto* actor = static_cast<StorageDBParent*>(aActor); actor->Init(); return IPC_OK(); }
--- a/dom/storage/StorageIPC.h +++ b/dom/storage/StorageIPC.h @@ -95,21 +95,21 @@ class LocalStorageCacheChild final : pub // and expects asynchronous answers. Those are then transparently // forwarded back to consumers on the child process. class StorageDBChild final : public PBackgroundStorageChild { class ShutdownObserver; virtual ~StorageDBChild(); public: - explicit StorageDBChild(LocalStorageManager* aManager); + StorageDBChild(LocalStorageManager* aManager, uint32_t aPrivateBrowsingId); - static StorageDBChild* Get(); + static StorageDBChild* Get(uint32_t aPrivateBrowsingId); - static StorageDBChild* GetOrCreate(); + static StorageDBChild* GetOrCreate(uint32_t aPrivateBrowsingId); NS_INLINE_DECL_REFCOUNTING(StorageDBChild); void AddIPDLReference(); void ReleaseIPDLReference(); virtual nsresult Init(); virtual nsresult Shutdown(); @@ -173,16 +173,19 @@ class StorageDBChild final : public PBac // Origins having data hash, for optimization purposes only UniquePtr<nsTHashtable<nsCStringHashKey>> mOriginsHavingData; // List of caches waiting for preload. This ensures the contract that // AsyncPreload call references the cache for time of the preload. nsTHashtable<nsRefPtrHashKey<LocalStorageCacheBridge>> mLoadingCaches; + // Expected to be only 0 or 1. + const uint32_t mPrivateBrowsingId; + // Status of the remote database nsresult mStatus; bool mIPCOpen; }; class SessionStorageObserverChild final : public PSessionStorageObserverChild { friend class SessionStorageManager; @@ -327,17 +330,17 @@ class LocalStorageCacheParent final // Also responsible for forwardning all chrome operation notifications // such as cookie cleaning etc to the child process. class StorageDBParent final : public PBackgroundStorageParent { class ObserverSink; virtual ~StorageDBParent(); public: - explicit StorageDBParent(const nsString& aProfilePath); + StorageDBParent(const nsString& aProfilePath, uint32_t aPrivateBrowsingId); void Init(); NS_IMETHOD_(MozExternalRefCountType) AddRef(void); NS_IMETHOD_(MozExternalRefCountType) Release(void); void AddIPDLReference(); void ReleaseIPDLReference(); @@ -464,16 +467,19 @@ class StorageDBParent final : public PBa // A hack to deal with deadlock between the parent process main thread and // background thread when invoking StorageDBThread::GetOrCreate because it // cannot safely perform a synchronous dispatch back to the main thread // (because we are already synchronously doing things on the stack). // Populated for the same process actors, empty for other process actors. nsString mProfilePath; + // Expected to be only 0 or 1. + const uint32_t mPrivateBrowsingId; + ThreadSafeAutoRefCnt mRefCnt; NS_DECL_OWNINGTHREAD // True when IPC channel is open and Send*() methods are OK to use. bool mIPCOpen; }; class SessionStorageObserverParent final : public PSessionStorageObserverParent, @@ -569,20 +575,21 @@ mozilla::ipc::IPCResult RecvPBackgroundL PBackgroundLocalStorageCacheParent* aActor, const mozilla::ipc::PrincipalInfo& aPrincipalInfo, const nsCString& aOriginKey, const uint32_t& aPrivateBrowsingId); bool DeallocPBackgroundLocalStorageCacheParent( PBackgroundLocalStorageCacheParent* aActor); PBackgroundStorageParent* AllocPBackgroundStorageParent( - const nsString& aProfilePath); + const nsString& aProfilePath, const uint32_t& aPrivateBrowsingId); mozilla::ipc::IPCResult RecvPBackgroundStorageConstructor( - PBackgroundStorageParent* aActor, const nsString& aProfilePath); + PBackgroundStorageParent* aActor, const nsString& aProfilePath, + const uint32_t& aPrivateBrowsingId); bool DeallocPBackgroundStorageParent(PBackgroundStorageParent* aActor); PSessionStorageObserverParent* AllocPSessionStorageObserverParent(); bool RecvPSessionStorageObserverConstructor( PSessionStorageObserverParent* aActor);
--- a/dom/storage/StorageObserver.cpp +++ b/dom/storage/StorageObserver.cpp @@ -32,16 +32,18 @@ namespace dom { using namespace StorageUtils; static const char kStartupTopic[] = "sessionstore-windows-restored"; static const uint32_t kStartupDelay = 0; const char kTestingPref[] = "dom.storage.testing"; +constexpr auto kPrivateBrowsingPattern = u"{ \"privateBrowsingId\": 1 }"_ns; + NS_IMPL_ISUPPORTS(StorageObserver, nsIObserver, nsISupportsWeakReference) StorageObserver* StorageObserver::sSelf = nullptr; // static nsresult StorageObserver::Init() { if (sSelf) { return NS_OK; @@ -124,18 +126,21 @@ void StorageObserver::RemoveSink(Storage void StorageObserver::Notify(const char* aTopic, const nsAString& aOriginAttributesPattern, const nsACString& aOriginScope) { for (auto* sink : mSinks.ForwardRange()) { sink->Observe(aTopic, aOriginAttributesPattern, aOriginScope); } } -void StorageObserver::NoteBackgroundThread(nsIEventTarget* aBackgroundThread) { - mBackgroundThread = aBackgroundThread; +void StorageObserver::NoteBackgroundThread(const uint32_t aPrivateBrowsingId, + nsIEventTarget* aBackgroundThread) { + MOZ_ASSERT(aPrivateBrowsingId <= 1); + + mBackgroundThread[aPrivateBrowsingId] = aBackgroundThread; } nsresult StorageObserver::GetOriginScope(const char16_t* aData, nsACString& aOriginScope) { nsresult rv; NS_ConvertUTF16toUTF8 domain(aData); @@ -193,43 +198,47 @@ StorageObserver::Observe(nsISupports* aS nsCOMPtr<nsITimer> timer = do_QueryInterface(aSubject); if (!timer) { return NS_ERROR_UNEXPECTED; } if (timer == mDBThreadStartDelayTimer) { mDBThreadStartDelayTimer = nullptr; - StorageDBChild* storageChild = StorageDBChild::GetOrCreate(); - if (NS_WARN_IF(!storageChild)) { - return NS_ERROR_FAILURE; + for (const uint32_t id : {0, 1}) { + StorageDBChild* storageChild = StorageDBChild::GetOrCreate(id); + if (NS_WARN_IF(!storageChild)) { + return NS_ERROR_FAILURE; + } + + storageChild->SendStartup(); } - - storageChild->SendStartup(); } return NS_OK; } // Clear everything, caches + database if (!strcmp(aTopic, "cookie-changed")) { if (!u"cleared"_ns.Equals(aData)) { return NS_OK; } if (!NextGenLocalStorageEnabled()) { - StorageDBChild* storageChild = StorageDBChild::GetOrCreate(); - if (NS_WARN_IF(!storageChild)) { - return NS_ERROR_FAILURE; - } + for (const uint32_t id : {0, 1}) { + StorageDBChild* storageChild = StorageDBChild::GetOrCreate(id); + if (NS_WARN_IF(!storageChild)) { + return NS_ERROR_FAILURE; + } - storageChild->AsyncClearAll(); + storageChild->AsyncClearAll(); - if (XRE_IsParentProcess()) { - storageChild->SendClearAll(); + if (XRE_IsParentProcess()) { + storageChild->SendClearAll(); + } } } Notify("cookie-cleared"); return NS_OK; } @@ -292,35 +301,39 @@ StorageObserver::Observe(nsISupports* aS nsCString originScope; rv = GetOriginScope(aData, originScope); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (XRE_IsParentProcess()) { - StorageDBChild* storageChild = StorageDBChild::GetOrCreate(); - if (NS_WARN_IF(!storageChild)) { - return NS_ERROR_FAILURE; + for (const uint32_t id : {0, 1}) { + StorageDBChild* storageChild = StorageDBChild::GetOrCreate(id); + if (NS_WARN_IF(!storageChild)) { + return NS_ERROR_FAILURE; + } + + storageChild->SendClearMatchingOrigin(originScope); } - - storageChild->SendClearMatchingOrigin(originScope); } Notify(topic, u""_ns, originScope); } else { - StorageDBChild* storageChild = StorageDBChild::GetOrCreate(); - if (NS_WARN_IF(!storageChild)) { - return NS_ERROR_FAILURE; - } + for (const uint32_t id : {0, 1}) { + StorageDBChild* storageChild = StorageDBChild::GetOrCreate(id); + if (NS_WARN_IF(!storageChild)) { + return NS_ERROR_FAILURE; + } - storageChild->AsyncClearAll(); + storageChild->AsyncClearAll(); - if (XRE_IsParentProcess()) { - storageChild->SendClearAll(); + if (XRE_IsParentProcess()) { + storageChild->SendClearAll(); + } } Notify(topic); } return NS_OK; } @@ -341,17 +354,43 @@ StorageObserver::Observe(nsISupports* aS } // Clear all private-browsing caches if (!strcmp(aTopic, "last-pb-context-exited")) { if (NextGenLocalStorageEnabled()) { return NS_OK; } - Notify("private-browsing-data-cleared", u"{ \"privateBrowsingId\": 1 }"_ns); + // We get the notification in both processes (parent and content), but the + // clearing of the in-memory database should be triggered from the parent + // process only to avoid creation of redundant clearing operations. + // Also, if we create a new StorageDBChild instance late during content + // process shutdown, then it might be leaked in debug builds because it + // could happen that there is no chance to properly destroy it. + if (XRE_IsParentProcess()) { + // This doesn't use a loop with privateBrowsingId 0 and 1, since we only + // need to clear the in-memory database which is represented by + // privateBrowsingId 1. + static const uint32_t id = 1; + + StorageDBChild* storageChild = StorageDBChild::GetOrCreate(id); + if (NS_WARN_IF(!storageChild)) { + return NS_ERROR_FAILURE; + } + + OriginAttributesPattern pattern; + if (!pattern.Init(kPrivateBrowsingPattern)) { + NS_ERROR("Cannot parse origin attributes pattern"); + return NS_ERROR_FAILURE; + } + + storageChild->SendClearMatchingOriginAttributes(pattern); + } + + Notify("private-browsing-data-cleared", kPrivateBrowsingPattern); return NS_OK; } // Clear data of the origins whose prefixes will match the suffix. if (!strcmp(aTopic, "clear-origin-attributes-data")) { MOZ_ASSERT(XRE_IsParentProcess()); @@ -360,23 +399,25 @@ StorageObserver::Observe(nsISupports* aS } OriginAttributesPattern pattern; if (!pattern.Init(nsDependentString(aData))) { NS_ERROR("Cannot parse origin attributes pattern"); return NS_ERROR_FAILURE; } - StorageDBChild* storageChild = StorageDBChild::GetOrCreate(); - if (NS_WARN_IF(!storageChild)) { - return NS_ERROR_FAILURE; + for (const uint32_t id : {0, 1}) { + StorageDBChild* storageChild = StorageDBChild::GetOrCreate(id); + if (NS_WARN_IF(!storageChild)) { + return NS_ERROR_FAILURE; + } + + storageChild->SendClearMatchingOriginAttributes(pattern); } - storageChild->SendClearMatchingOriginAttributes(pattern); - Notify("origin-attr-pattern-cleared", nsDependentString(aData)); return NS_OK; } if (!strcmp(aTopic, "profile-after-change")) { Notify("profile-change"); @@ -385,45 +426,49 @@ StorageObserver::Observe(nsISupports* aS if (!strcmp(aTopic, "profile-before-change")) { MOZ_ASSERT(XRE_IsParentProcess()); if (NextGenLocalStorageEnabled()) { return NS_OK; } - if (mBackgroundThread) { - bool done = false; + for (const uint32_t id : {0, 1}) { + if (mBackgroundThread[id]) { + bool done = false; - RefPtr<StorageDBThread::ShutdownRunnable> shutdownRunnable = - new StorageDBThread::ShutdownRunnable(done); - MOZ_ALWAYS_SUCCEEDS( - mBackgroundThread->Dispatch(shutdownRunnable, NS_DISPATCH_NORMAL)); + RefPtr<StorageDBThread::ShutdownRunnable> shutdownRunnable = + new StorageDBThread::ShutdownRunnable(id, done); + MOZ_ALWAYS_SUCCEEDS(mBackgroundThread[id]->Dispatch( + shutdownRunnable, NS_DISPATCH_NORMAL)); - MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return done; })); + MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return done; })); - mBackgroundThread = nullptr; + mBackgroundThread[id] = nullptr; + } } return NS_OK; } #ifdef DOM_STORAGE_TESTS if (!strcmp(aTopic, "domstorage-test-flush-force")) { if (NextGenLocalStorageEnabled()) { return NS_OK; } - StorageDBChild* storageChild = StorageDBChild::GetOrCreate(); - if (NS_WARN_IF(!storageChild)) { - return NS_ERROR_FAILURE; + for (const uint32_t id : {0, 1}) { + StorageDBChild* storageChild = StorageDBChild::GetOrCreate(id); + if (NS_WARN_IF(!storageChild)) { + return NS_ERROR_FAILURE; + } + + storageChild->SendAsyncFlush(); } - storageChild->SendAsyncFlush(); - return NS_OK; } if (!strcmp(aTopic, "domstorage-test-flushed")) { if (NextGenLocalStorageEnabled()) { return NS_OK; }
--- a/dom/storage/StorageObserver.h +++ b/dom/storage/StorageObserver.h @@ -45,28 +45,29 @@ class StorageObserver : public nsIObserv static StorageObserver* Self() { return sSelf; } void AddSink(StorageObserverSink* aObs); void RemoveSink(StorageObserverSink* aObs); void Notify(const char* aTopic, const nsAString& aOriginAttributesPattern = u""_ns, const nsACString& aOriginScope = ""_ns); - void NoteBackgroundThread(nsIEventTarget* aBackgroundThread); + void NoteBackgroundThread(uint32_t aPrivateBrowsingId, + nsIEventTarget* aBackgroundThread); private: virtual ~StorageObserver() = default; nsresult GetOriginScope(const char16_t* aData, nsACString& aOriginScope); static void TestingPrefChanged(const char* aPrefName, void* aClosure); static StorageObserver* sSelf; - nsCOMPtr<nsIEventTarget> mBackgroundThread; + nsCOMPtr<nsIEventTarget> mBackgroundThread[2]; // Weak references nsTObserverArray<StorageObserverSink*> mSinks; nsCOMPtr<nsITimer> mDBThreadStartDelayTimer; }; } // namespace dom } // namespace mozilla
--- a/ipc/glue/BackgroundChildImpl.cpp +++ b/ipc/glue/BackgroundChildImpl.cpp @@ -279,17 +279,17 @@ bool BackgroundChildImpl::DeallocPBackgr MOZ_ASSERT(aActor); delete aActor; return true; } BackgroundChildImpl::PBackgroundStorageChild* BackgroundChildImpl::AllocPBackgroundStorageChild( - const nsString& aProfilePath) { + const nsString& aProfilePath, const uint32_t& aPrivateBrowsingId) { MOZ_CRASH("PBackgroundStorageChild actors should be manually constructed!"); } bool BackgroundChildImpl::DeallocPBackgroundStorageChild( PBackgroundStorageChild* aActor) { MOZ_ASSERT(aActor); StorageDBChild* child = static_cast<StorageDBChild*>(aActor);
--- a/ipc/glue/BackgroundChildImpl.h +++ b/ipc/glue/BackgroundChildImpl.h @@ -102,17 +102,18 @@ class BackgroundChildImpl : public PBack AllocPBackgroundLocalStorageCacheChild( const PrincipalInfo& aPrincipalInfo, const nsCString& aOriginKey, const uint32_t& aPrivateBrowsingId) override; virtual bool DeallocPBackgroundLocalStorageCacheChild( PBackgroundLocalStorageCacheChild* aActor) override; virtual PBackgroundStorageChild* AllocPBackgroundStorageChild( - const nsString& aProfilePath) override; + const nsString& aProfilePath, + const uint32_t& aPrivateBrowsingId) override; virtual bool DeallocPBackgroundStorageChild( PBackgroundStorageChild* aActor) override; virtual already_AddRefed<PRemoteLazyInputStreamChild> AllocPRemoteLazyInputStreamChild(const nsID& aID, const uint64_t& aSize) override;
--- a/ipc/glue/BackgroundParentImpl.cpp +++ b/ipc/glue/BackgroundParentImpl.cpp @@ -447,30 +447,34 @@ bool BackgroundParentImpl::DeallocPBackg AssertIsInMainOrSocketProcess(); AssertIsOnBackgroundThread(); MOZ_ASSERT(aActor); return mozilla::dom::DeallocPBackgroundLocalStorageCacheParent(aActor); } auto BackgroundParentImpl::AllocPBackgroundStorageParent( - const nsString& aProfilePath) -> PBackgroundStorageParent* { + const nsString& aProfilePath, const uint32_t& aPrivateBrowsingId) + -> PBackgroundStorageParent* { AssertIsInMainOrSocketProcess(); AssertIsOnBackgroundThread(); - return mozilla::dom::AllocPBackgroundStorageParent(aProfilePath); + return mozilla::dom::AllocPBackgroundStorageParent(aProfilePath, + aPrivateBrowsingId); } mozilla::ipc::IPCResult BackgroundParentImpl::RecvPBackgroundStorageConstructor( - PBackgroundStorageParent* aActor, const nsString& aProfilePath) { + PBackgroundStorageParent* aActor, const nsString& aProfilePath, + const uint32_t& aPrivateBrowsingId) { AssertIsInMainOrSocketProcess(); AssertIsOnBackgroundThread(); MOZ_ASSERT(aActor); - return mozilla::dom::RecvPBackgroundStorageConstructor(aActor, aProfilePath); + return mozilla::dom::RecvPBackgroundStorageConstructor(aActor, aProfilePath, + aPrivateBrowsingId); } bool BackgroundParentImpl::DeallocPBackgroundStorageParent( PBackgroundStorageParent* aActor) { AssertIsInMainOrSocketProcess(); AssertIsOnBackgroundThread(); MOZ_ASSERT(aActor);
--- a/ipc/glue/BackgroundParentImpl.h +++ b/ipc/glue/BackgroundParentImpl.h @@ -125,20 +125,22 @@ class BackgroundParentImpl : public PBac PBackgroundLocalStorageCacheParent* aActor, const PrincipalInfo& aPrincipalInfo, const nsCString& aOriginKey, const uint32_t& aPrivateBrowsingId) override; bool DeallocPBackgroundLocalStorageCacheParent( PBackgroundLocalStorageCacheParent* aActor) override; PBackgroundStorageParent* AllocPBackgroundStorageParent( - const nsString& aProfilePath) override; + const nsString& aProfilePath, + const uint32_t& aPrivateBrowsingId) override; mozilla::ipc::IPCResult RecvPBackgroundStorageConstructor( - PBackgroundStorageParent* aActor, const nsString& aProfilePath) override; + PBackgroundStorageParent* aActor, const nsString& aProfilePath, + const uint32_t& aPrivateBrowsingId) override; bool DeallocPBackgroundStorageParent( PBackgroundStorageParent* aActor) override; already_AddRefed<PBackgroundSessionStorageManagerParent> AllocPBackgroundSessionStorageManagerParent( const uint64_t& aTopContextId) override;
--- a/ipc/glue/PBackground.ipdl +++ b/ipc/glue/PBackground.ipdl @@ -170,17 +170,17 @@ parent: async LSClearPrivateBrowsing(); async PBackgroundLocalStorageCache(PrincipalInfo principalInfo, nsCString originKey, uint32_t privateBrowsingId); async PBackgroundSessionStorageManager(uint64_t aTopContextId); - async PBackgroundStorage(nsString profilePath); + async PBackgroundStorage(nsString profilePath, uint32_t privateBrowsingId); async PVsync(); async PCameras(); async PUDPSocket(PrincipalInfo? pInfo, nsCString filter); async PBroadcastChannel(PrincipalInfo pInfo, nsCString origin, nsString channel);
--- a/security/manager/ssl/tests/unit/test_sts_preloadlist_perwindowpb.js +++ b/security/manager/ssl/tests/unit/test_sts_preloadlist_perwindowpb.js @@ -19,16 +19,18 @@ var secInfo = Cc[ ].createInstance(Ci.nsITransportSecurityInfo); function cleanup() { Services.obs.removeObserver(gObserver, "last-pb-context-exited"); gSSService.clearAll(); } function run_test() { + do_get_profile(); + registerCleanupFunction(cleanup); Services.obs.addObserver(gObserver, "last-pb-context-exited"); add_test(test_part1); add_test(test_private_browsing1); add_test(test_private_browsing2); run_next_test();