Bug 1215723 - Part 2: Initialize DataStorage items in the content process from the data in the parent; r=keeler

This commit is contained in:
Ehsan Akhgari 2015-10-30 15:30:00 -04:00
parent d32e5b3c64
commit 49884777a4
7 changed files with 161 additions and 28 deletions

View File

@ -35,6 +35,7 @@
#include "imgIContainer.h"
#include "mozIApplication.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/DataStorage.h"
#include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h"
#include "mozilla/docshell/OfflineCacheUpdateParent.h"
#include "mozilla/dom/DataStoreService.h"
@ -2673,6 +2674,15 @@ ContentParent::RecvReadFontList(InfallibleTArray<FontListEntry>* retValue)
return true;
}
bool
ContentParent::RecvReadDataStorageArray(const nsString& aFilename,
InfallibleTArray<DataStorageItem>* aValues)
{
RefPtr<DataStorage> storage = DataStorage::Get(aFilename);
storage->GetAll(aValues);
return true;
}
bool
ContentParent::RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions)
{

View File

@ -742,6 +742,9 @@ private:
virtual bool RecvReadPrefsArray(InfallibleTArray<PrefSetting>* aPrefs) override;
virtual bool RecvReadFontList(InfallibleTArray<FontListEntry>* retValue) override;
virtual bool RecvReadDataStorageArray(const nsString& aFilename,
InfallibleTArray<DataStorageItem>* aValues) override;
virtual bool RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions) override;
virtual bool RecvSetClipboard(const IPCDataTransfer& aDataTransfer,

View File

@ -91,6 +91,7 @@ using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h";
using class mozilla::dom::ipc::StructuredCloneData from "ipc/IPCMessageUtils.h";
using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h";
union ChromeRegistryItem
{
@ -324,6 +325,12 @@ struct PrefSetting {
MaybePrefValue userValue;
};
struct DataStorageItem {
nsCString key;
nsCString value;
DataStorageType type;
};
struct DataStoreSetting {
nsString name;
nsString originURL;
@ -829,6 +836,9 @@ parent:
sync ReadFontList() returns (FontListEntry[] retValue);
sync ReadDataStorageArray(nsString aFilename)
returns (DataStorageItem[] retValue);
sync SyncMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal)
returns (StructuredCloneData[] retval);

View File

@ -7,6 +7,8 @@
#include "DataStorage.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/PContent.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/Telemetry.h"
@ -42,6 +44,7 @@ DataStorage::DataStorage(const nsString& aFilename)
: mMutex("DataStorage::mMutex")
, mPendingWrite(false)
, mShuttingDown(false)
, mInitCalled(false)
, mReadyMonitor("DataStorage::mReadyMonitor")
, mReady(false)
, mFilename(aFilename)
@ -80,15 +83,41 @@ DataStorage::Init(bool& aDataWillPersist)
MutexAutoLock lock(mMutex);
nsresult rv;
rv = NS_NewThread(getter_AddRefs(mWorkerThread));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
// Ignore attempts to initialize several times.
if (mInitCalled) {
return NS_OK;
}
rv = AsyncReadData(aDataWillPersist, lock);
if (NS_FAILED(rv)) {
return rv;
mInitCalled = true;
nsresult rv;
if (XRE_IsParentProcess()) {
rv = NS_NewThread(getter_AddRefs(mWorkerThread));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = AsyncReadData(aDataWillPersist, lock);
if (NS_FAILED(rv)) {
return rv;
}
} else {
// In the child process, we ask the parent process for the data.
MOZ_ASSERT(XRE_IsContentProcess());
aDataWillPersist = false;
InfallibleTArray<DataStorageItem> items;
dom::ContentChild::GetSingleton()->
SendReadDataStorageArray(mFilename, &items);
for (auto& item : items) {
Entry entry;
entry.mValue = item.value();
rv = PutInternal(item.key(), entry, item.type(), lock);
if (NS_FAILED(rv)) {
return rv;
}
}
mReady = true;
NotifyObservers("data-storage-ready");
}
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
@ -337,6 +366,7 @@ nsresult
DataStorage::AsyncReadData(bool& aHaveProfileDir,
const MutexAutoLock& /*aProofOfLock*/)
{
MOZ_ASSERT(XRE_IsParentProcess());
aHaveProfileDir = false;
// Allocate a Reader so that even if it isn't dispatched,
// the data-storage-ready notification will be fired and Get
@ -425,6 +455,34 @@ DataStorage::GetTableForType(DataStorageType aType,
MOZ_CRASH("given bad DataStorage storage type");
}
void
DataStorage::ReadAllFromTable(DataStorageType aType,
InfallibleTArray<dom::DataStorageItem>* aItems,
const MutexAutoLock& aProofOfLock)
{
for (auto iter = GetTableForType(aType, aProofOfLock).Iter();
!iter.Done(); iter.Next()) {
DataStorageItem* item = aItems->AppendElement();
item->key() = iter.Key();
item->value() = iter.Data().mValue;
item->type() = aType;
}
}
void
DataStorage::GetAll(InfallibleTArray<dom::DataStorageItem>* aItems)
{
WaitForReady();
MutexAutoLock lock(mMutex);
aItems->SetCapacity(mPersistentDataTable.Count() +
mTemporaryDataTable.Count() +
mPrivateDataTable.Count());
ReadAllFromTable(DataStorage_Persistent, aItems, lock);
ReadAllFromTable(DataStorage_Temporary, aItems, lock);
ReadAllFromTable(DataStorage_Private, aItems, lock);
}
// Limit the number of entries per table. This is to prevent unbounded
// resource use. The eviction strategy is as follows:
// - An entry's score is incremented once for every day it is accessed.
@ -591,6 +649,8 @@ DataStorage::Writer::Run()
nsresult
DataStorage::AsyncWriteData(const MutexAutoLock& /*aProofOfLock*/)
{
MOZ_ASSERT(XRE_IsParentProcess());
if (mShuttingDown || !mBackingFile) {
return NS_OK;
}
@ -627,12 +687,14 @@ DataStorage::Clear()
mTemporaryDataTable.Clear();
mPrivateDataTable.Clear();
// Asynchronously clear the file. This is similar to the permission manager
// in that it doesn't wait to synchronously remove the data from its backing
// storage either.
nsresult rv = AsyncWriteData(lock);
if (NS_FAILED(rv)) {
return rv;
if (XRE_IsParentProcess()) {
// Asynchronously clear the file. This is similar to the permission manager
// in that it doesn't wait to synchronously remove the data from its backing
// storage either.
nsresult rv = AsyncWriteData(lock);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
@ -641,6 +703,8 @@ DataStorage::Clear()
void
DataStorage::TimerCallback(nsITimer* aTimer, void* aClosure)
{
MOZ_ASSERT(XRE_IsParentProcess());
RefPtr<DataStorage> aDataStorage = (DataStorage*)aClosure;
MutexAutoLock lock(aDataStorage->mMutex);
Unused << aDataStorage->AsyncWriteData(lock);
@ -651,7 +715,7 @@ DataStorage::TimerCallback(nsITimer* aTimer, void* aClosure)
nsresult
DataStorage::AsyncSetTimer(const MutexAutoLock& /*aProofOfLock*/)
{
if (mShuttingDown) {
if (mShuttingDown || !XRE_IsParentProcess()) {
return NS_OK;
}
@ -669,6 +733,8 @@ void
DataStorage::SetTimer()
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(XRE_IsParentProcess());
MutexAutoLock lock(mMutex);
nsresult rv;
@ -702,6 +768,8 @@ DataStorage::NotifyObservers(const char* aTopic)
nsresult
DataStorage::DispatchShutdownTimer(const MutexAutoLock& /*aProofOfLock*/)
{
MOZ_ASSERT(XRE_IsParentProcess());
nsCOMPtr<nsIRunnable> job =
NS_NewRunnableMethod(this, &DataStorage::ShutdownTimer);
nsresult rv = mWorkerThread->Dispatch(job, NS_DISPATCH_NORMAL);
@ -714,6 +782,7 @@ DataStorage::DispatchShutdownTimer(const MutexAutoLock& /*aProofOfLock*/)
void
DataStorage::ShutdownTimer()
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(!NS_IsMainThread());
MutexAutoLock lock(mMutex);
nsresult rv = mTimer->Cancel();
@ -740,22 +809,24 @@ DataStorage::Observe(nsISupports* aSubject, const char* aTopic,
MutexAutoLock lock(mMutex);
mPrivateDataTable.Clear();
} else if (strcmp(aTopic, "profile-before-change") == 0) {
{
MutexAutoLock lock(mMutex);
rv = AsyncWriteData(lock);
mShuttingDown = true;
Unused << NS_WARN_IF(NS_FAILED(rv));
if (mTimer) {
rv = DispatchShutdownTimer(lock);
if (XRE_IsParentProcess()) {
{
MutexAutoLock lock(mMutex);
rv = AsyncWriteData(lock);
mShuttingDown = true;
Unused << NS_WARN_IF(NS_FAILED(rv));
if (mTimer) {
rv = DispatchShutdownTimer(lock);
Unused << NS_WARN_IF(NS_FAILED(rv));
}
}
// Run the thread to completion and prevent any further events
// being scheduled to it. The thread may need the lock, so we can't
// hold it here.
rv = mWorkerThread->Shutdown();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
// Run the thread to completion and prevent any further events
// being scheduled to it. The thread may need the lock, so we can't
// hold it here.
rv = mWorkerThread->Shutdown();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
sDataStorages->Clear();

View File

@ -20,6 +20,10 @@
namespace mozilla {
namespace dom {
class DataStorageItem;
}
/**
* DataStorage is a threadsafe, generic, narrow string-based hash map that
* persists data on disk and additionally handles temporary and private data.
@ -83,6 +87,8 @@ enum DataStorageType {
class DataStorage : public nsIObserver
{
typedef dom::DataStorageItem DataStorageItem;
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER
@ -109,6 +115,9 @@ public:
// Removes all entries of all types of data.
nsresult Clear();
// Read all of the data items.
void GetAll(InfallibleTArray<DataStorageItem>* aItems);
private:
explicit DataStorage(const nsString& aFilename);
virtual ~DataStorage();
@ -162,6 +171,10 @@ private:
DataStorageTable& GetTableForType(DataStorageType aType,
const MutexAutoLock& aProofOfLock);
void ReadAllFromTable(DataStorageType aType,
InfallibleTArray<DataStorageItem>* aItems,
const MutexAutoLock& aProofOfLock);
Mutex mMutex; // This mutex protects access to the following members:
DataStorageTable mPersistentDataTable;
DataStorageTable mTemporaryDataTable;
@ -172,6 +185,7 @@ private:
uint32_t mTimerDelay; // in milliseconds
bool mPendingWrite; // true if a write is needed but hasn't been dispatched
bool mShuttingDown;
bool mInitCalled; // Indicates that Init() has been called.
// (End list of members protected by mMutex)
Monitor mReadyMonitor; // Do not acquire this at the same time as mMutex.

View File

@ -0,0 +1,21 @@
/* -*- 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/. */
#ifndef ipc_DataStorageIPCUtils_h
#define ipc_DataStorageIPCUtils_h
#include "ipc/IPCMessageUtils.h"
#include "mozilla/DataStorage.h"
namespace IPC {
template<>
struct ParamTraits<mozilla::DataStorageType> :
public ContiguousEnumSerializer<mozilla::DataStorageType,
mozilla::DataStorage_Persistent,
mozilla::DataStorageType(mozilla::DataStorage_Private + 1)> {};
} // namespace IPC
#endif // mozilla_DataStorageIPCUtils_hh

View File

@ -75,6 +75,10 @@ EXPORTS.mozilla.psm += [
'PSMContentListener.h',
]
EXPORTS.ipc += [
'DataStorageIPCUtils.h',
]
UNIFIED_SOURCES += [
'CertBlocklist.cpp',
'CryptoTask.cpp',