Bug 1669437 - Add necessary infrastructure for independent in-memory only local storage database; r=asuth,dom-workers-and-storage-reviewers

The new infrastructure consists of a separate bridge between the content and the
parent process and a separate local storage database in the parent process.
The new infrastructure can be used for storing and sharing of private browsing
data across content processes.
This patch only creates necessary infrastructure, actual enabling of storing and
sharing of data across content processes will be done in a follow-up patch.

Differential Revision: https://phabricator.services.mozilla.com/D96562
This commit is contained in:
Jan Varga 2020-11-11 13:12:57 +00:00
parent adf086b335
commit 03e0a91794
16 changed files with 315 additions and 178 deletions

View file

@ -129,6 +129,7 @@ void LocalStorageCache::Init(LocalStorageManager* aManager, bool aPersistent,
mInitialized = true;
aPrincipal->OriginAttributesRef().CreateSuffix(mOriginSuffix);
mPrivateBrowsingId = aPrincipal->GetPrivateBrowsingId();
mPersistent = aPersistent;
if (aQuotaOriginScope.IsEmpty()) {
mQuotaOriginScope = Origin();
@ -147,7 +148,7 @@ void LocalStorageCache::Init(LocalStorageManager* aManager, bool aPersistent,
MOZ_ASSERT(mOriginSuffix.IsEmpty() !=
StringBeginsWith(mQuotaOriginScope, "^"_ns));
mUsage = aManager->GetOriginUsage(mQuotaOriginScope);
mUsage = aManager->GetOriginUsage(mQuotaOriginScope, mPrivateBrowsingId);
}
void LocalStorageCache::NotifyObservers(const LocalStorage* aStorage,
@ -214,7 +215,8 @@ void LocalStorageCache::Preload() {
return;
}
StorageDBChild* storageChild = StorageDBChild::GetOrCreate();
StorageDBChild* storageChild =
StorageDBChild::GetOrCreate(mPrivateBrowsingId);
if (!storageChild) {
mLoaded = true;
mLoadResult = NS_ERROR_FAILURE;
@ -254,7 +256,7 @@ void LocalStorageCache::WaitForPreload(Telemetry::HistogramID aTelemetryID) {
// 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,
@ -374,7 +376,7 @@ nsresult LocalStorageCache::SetItem(const LocalStorage* aStorage,
#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"
@ -423,7 +425,7 @@ nsresult LocalStorageCache::RemoveItem(const LocalStorage* aStorage,
#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"
@ -474,7 +476,7 @@ nsresult LocalStorageCache::Clear(const LocalStorage* aStorage,
#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"

View file

@ -256,6 +256,9 @@ class LocalStorageCache : public LocalStorageCacheBridge {
// 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;

View file

@ -61,7 +61,9 @@ LocalStorageManager::LocalStorageManager() : mCaches(8) {
// 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);
}
}
}
@ -100,7 +102,7 @@ LocalStorageCache* LocalStorageManager::GetCache(
}
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();
@ -108,7 +110,8 @@ already_AddRefed<StorageUsage> LocalStorageManager::GetOriginUsage(
usage = new StorageUsage(aOriginNoSuffix);
StorageDBChild* storageChild = StorageDBChild::GetOrCreate();
StorageDBChild* storageChild =
StorageDBChild::GetOrCreate(aPrivateBrowsingId);
if (storageChild) {
storageChild->AsyncGetUsage(usage);
}
@ -167,9 +170,12 @@ nsresult LocalStorageManager::GetStorageInternal(
}
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))) {

View file

@ -45,7 +45,7 @@ class LocalStorageManager final : public nsIDOMStorageManager,
// 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);

View file

@ -52,10 +52,10 @@ 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
@ -97,11 +97,14 @@ class StorageDBThread::InitHelper final : public Runnable {
};
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:
@ -110,7 +113,7 @@ class StorageDBThread::NoteBackgroundThreadRunnable final : public Runnable {
NS_DECL_NSIRUNNABLE
};
StorageDBThread::StorageDBThread()
StorageDBThread::StorageDBThread(const uint32_t aPrivateBrowsingId)
: mThread(nullptr),
mThreadObserver(new ThreadObserver()),
mStopIOThread(false),
@ -120,36 +123,43 @@ StorageDBThread::StorageDBThread()
mWorkerStatements(mWorkerConnection),
mReaderStatements(mReaderConnection),
mFlushImmediately(false),
mPriorityCounter(0) {}
// static
StorageDBThread* StorageDBThread::Get() {
::mozilla::ipc::AssertIsOnBackgroundThread();
return sStorageThread;
mPrivateBrowsingId(aPrivateBrowsingId),
mPriorityCounter(0) {
MOZ_ASSERT(aPrivateBrowsingId <= 1);
}
// static
StorageDBThread* StorageDBThread::GetOrCreate(const nsString& aProfilePath) {
StorageDBThread* StorageDBThread::Get(const uint32_t aPrivateBrowsingId) {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(aPrivateBrowsingId <= 1);
if (sStorageThread || sStorageThreadDown) {
return sStorageThread[aPrivateBrowsingId];
}
// static
StorageDBThread* StorageDBThread::GetOrCreate(
const nsString& aProfilePath, const uint32_t aPrivateBrowsingId) {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(aPrivateBrowsingId <= 1);
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
@ -185,33 +195,35 @@ nsresult StorageDBThread::GetProfilePath(nsString& aProfilePath) {
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);
rv = helper->SyncDispatchAndReturnProfilePath(profilePath);
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;
}
} 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->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->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());
@ -224,7 +236,7 @@ nsresult StorageDBThread::Init(const nsString& aProfilePath) {
}
RefPtr<NoteBackgroundThreadRunnable> runnable =
new NoteBackgroundThreadRunnable();
new NoteBackgroundThreadRunnable(mPrivateBrowsingId);
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
return NS_OK;
@ -233,8 +245,6 @@ nsresult StorageDBThread::Init(const nsString& aProfilePath) {
nsresult StorageDBThread::Shutdown() {
::mozilla::ipc::AssertIsOnBackgroundThread();
sStorageThreadDown = true;
if (!mThread) {
return NS_ERROR_NOT_INITIALIZED;
}
@ -522,14 +532,24 @@ nsresult StorageDBThread::OpenDatabaseConnection() {
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);
@ -562,16 +582,18 @@ nsresult StorageDBThread::InitDatabase() {
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);
}
@ -1529,7 +1551,7 @@ StorageDBThread::NoteBackgroundThreadRunnable::Run() {
StorageObserver* observer = StorageObserver::Self();
MOZ_ASSERT(observer);
observer->NoteBackgroundThread(mOwningThread);
observer->NoteBackgroundThread(mPrivateBrowsingId, mOwningThread);
return NS_OK;
}
@ -1544,11 +1566,14 @@ StorageDBThread::ShutdownRunnable::Run() {
::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));

View file

@ -292,12 +292,16 @@ class StorageDBThread final {
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());
}
@ -308,12 +312,13 @@ class StorageDBThread final {
};
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);
@ -429,6 +434,9 @@ class StorageDBThread final {
// 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;

View file

@ -32,10 +32,10 @@ typedef nsClassHashtable<nsCStringHashKey, nsTArray<LocalStorageCacheParent*>>
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
@ -111,8 +111,14 @@ mozilla::ipc::IPCResult LocalStorageCacheChild::RecvObserve(
// ----------------------------------------------------------------------------
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
@ -133,47 +139,55 @@ void StorageDBChild::ReleaseIPDLReference() {
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() {
@ -194,7 +208,7 @@ nsresult StorageDBChild::Init() {
}
nsString profilePath;
if (XRE_IsParentProcess()) {
if (XRE_IsParentProcess() && mPrivateBrowsingId == 0) {
nsresult rv = StorageDBThread::GetProfilePath(profilePath);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -203,12 +217,13 @@ nsresult StorageDBChild::Init() {
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));
@ -380,7 +395,7 @@ mozilla::ipc::IPCResult StorageDBChild::RecvLoadDone(
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();
}
@ -407,13 +422,14 @@ StorageDBChild::ShutdownObserver::Observe(nsISupports* aSubject,
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;
@ -667,8 +683,11 @@ void StorageDBParent::ReleaseIPDLReference() {
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
@ -695,7 +714,7 @@ void StorageDBParent::Init() {
mObserverSink->Start();
}
StorageDBThread* storageThread = StorageDBThread::Get();
StorageDBThread* storageThread = StorageDBThread::Get(mPrivateBrowsingId);
if (storageThread) {
nsTArray<nsCString> scopes;
storageThread->GetOriginsHavingData(&scopes);
@ -725,7 +744,8 @@ mozilla::ipc::IPCResult StorageDBParent::RecvDeleteMe() {
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);
}
@ -738,7 +758,8 @@ mozilla::ipc::IPCResult StorageDBParent::RecvAsyncPreload(
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);
}
@ -833,7 +854,8 @@ 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);
}
@ -850,7 +872,8 @@ mozilla::ipc::IPCResult StorageDBParent::RecvPreload(
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);
}
@ -867,7 +890,8 @@ mozilla::ipc::IPCResult StorageDBParent::RecvAsyncAddItem(
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);
}
@ -884,7 +908,8 @@ mozilla::ipc::IPCResult StorageDBParent::RecvAsyncUpdateItem(
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);
}
@ -900,7 +925,8 @@ mozilla::ipc::IPCResult StorageDBParent::RecvAsyncRemoveItem(
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);
}
@ -915,7 +941,7 @@ mozilla::ipc::IPCResult StorageDBParent::RecvAsyncClear(
}
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncFlush() {
StorageDBThread* storageThread = StorageDBThread::Get();
StorageDBThread* storageThread = StorageDBThread::Get(mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
@ -926,7 +952,8 @@ mozilla::ipc::IPCResult StorageDBParent::RecvAsyncFlush() {
}
mozilla::ipc::IPCResult StorageDBParent::RecvStartup() {
StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
StorageDBThread* storageThread =
StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
@ -935,7 +962,8 @@ mozilla::ipc::IPCResult StorageDBParent::RecvStartup() {
}
mozilla::ipc::IPCResult StorageDBParent::RecvClearAll() {
StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
StorageDBThread* storageThread =
StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
@ -947,7 +975,8 @@ mozilla::ipc::IPCResult StorageDBParent::RecvClearAll() {
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);
}
@ -959,7 +988,8 @@ mozilla::ipc::IPCResult StorageDBParent::RecvClearMatchingOrigin(
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);
}
@ -1459,14 +1489,15 @@ bool DeallocPBackgroundLocalStorageCacheParent(
}
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);

View file

@ -100,11 +100,11 @@ class StorageDBChild final : public PBackgroundStorageChild {
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);
@ -178,6 +178,9 @@ class StorageDBChild final : public PBackgroundStorageChild {
// 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;
@ -332,7 +335,7 @@ class StorageDBParent final : public PBackgroundStorageParent {
virtual ~StorageDBParent();
public:
explicit StorageDBParent(const nsString& aProfilePath);
StorageDBParent(const nsString& aProfilePath, uint32_t aPrivateBrowsingId);
void Init();
@ -469,6 +472,9 @@ class StorageDBParent final : public PBackgroundStorageParent {
// 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
@ -574,10 +580,11 @@ 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);

View file

@ -37,6 +37,8 @@ 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;
@ -129,8 +131,11 @@ void StorageObserver::Notify(const char* aTopic,
}
}
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,
@ -198,12 +203,14 @@ StorageObserver::Observe(nsISupports* aSubject, const char* aTopic,
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;
@ -216,15 +223,17 @@ StorageObserver::Observe(nsISupports* aSubject, const char* aTopic,
}
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();
}
}
}
@ -297,25 +306,29 @@ StorageObserver::Observe(nsISupports* aSubject, const char* aTopic,
}
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);
@ -346,7 +359,33 @@ StorageObserver::Observe(nsISupports* aSubject, const char* aTopic,
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;
}
@ -365,12 +404,14 @@ StorageObserver::Observe(nsISupports* aSubject, const char* aTopic,
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));
@ -390,17 +431,19 @@ StorageObserver::Observe(nsISupports* aSubject, const char* aTopic,
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;
@ -412,12 +455,14 @@ StorageObserver::Observe(nsISupports* aSubject, const char* aTopic,
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;
}

View file

@ -50,7 +50,8 @@ class StorageObserver : public nsIObserver, public nsSupportsWeakReference {
const nsAString& aOriginAttributesPattern = u""_ns,
const nsACString& aOriginScope = ""_ns);
void NoteBackgroundThread(nsIEventTarget* aBackgroundThread);
void NoteBackgroundThread(uint32_t aPrivateBrowsingId,
nsIEventTarget* aBackgroundThread);
private:
virtual ~StorageObserver() = default;
@ -61,7 +62,7 @@ class StorageObserver : public nsIObserver, public nsSupportsWeakReference {
static StorageObserver* sSelf;
nsCOMPtr<nsIEventTarget> mBackgroundThread;
nsCOMPtr<nsIEventTarget> mBackgroundThread[2];
// Weak references
nsTObserverArray<StorageObserverSink*> mSinks;

View file

@ -284,7 +284,7 @@ bool BackgroundChildImpl::DeallocPBackgroundLSSimpleRequestChild(
BackgroundChildImpl::PBackgroundStorageChild*
BackgroundChildImpl::AllocPBackgroundStorageChild(
const nsString& aProfilePath) {
const nsString& aProfilePath, const uint32_t& aPrivateBrowsingId) {
MOZ_CRASH("PBackgroundStorageChild actors should be manually constructed!");
}

View file

@ -107,7 +107,8 @@ class BackgroundChildImpl : public PBackgroundChild,
PBackgroundLocalStorageCacheChild* aActor) override;
virtual PBackgroundStorageChild* AllocPBackgroundStorageChild(
const nsString& aProfilePath) override;
const nsString& aProfilePath,
const uint32_t& aPrivateBrowsingId) override;
virtual bool DeallocPBackgroundStorageChild(
PBackgroundStorageChild* aActor) override;

View file

@ -452,20 +452,24 @@ bool BackgroundParentImpl::DeallocPBackgroundLocalStorageCacheParent(
}
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(

View file

@ -130,10 +130,12 @@ class BackgroundParentImpl : public PBackgroundParent,
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;

View file

@ -175,7 +175,7 @@ parent:
async PBackgroundSessionStorageManager(uint64_t aTopContextId);
async PBackgroundStorage(nsString profilePath);
async PBackgroundStorage(nsString profilePath, uint32_t privateBrowsingId);
async PVsync();

View file

@ -24,6 +24,8 @@ function cleanup() {
}
function run_test() {
do_get_profile();
registerCleanupFunction(cleanup);
Services.obs.addObserver(gObserver, "last-pb-context-exited");