Bug 783184: Ensure that child-process pref state always is the same as its parent's. r=bsmedberg

This commit is contained in:
Chris Jones 2012-08-22 13:00:21 -07:00
parent 5918e55b6e
commit bda301f268
12 changed files with 164 additions and 210 deletions

View File

@ -757,16 +757,9 @@ ContentChild::AddRemoteAlertObserver(const nsString& aData,
}
bool
ContentChild::RecvPreferenceUpdate(const PrefTuple& aPref)
ContentChild::RecvPreferenceUpdate(const PrefSetting& aPref)
{
Preferences::SetPreference(&aPref);
return true;
}
bool
ContentChild::RecvClearUserPreference(const nsCString& aPrefName)
{
Preferences::ClearContentPref(aPrefName.get());
Preferences::SetPreference(aPref);
return true;
}

View File

@ -136,8 +136,7 @@ public:
// auto remove when alertfinished is received.
nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
virtual bool RecvPreferenceUpdate(const PrefTuple& aPref);
virtual bool RecvClearUserPreference(const nsCString& aPrefName);
virtual bool RecvPreferenceUpdate(const PrefSetting& aPref);
virtual bool RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData);

View File

@ -732,9 +732,9 @@ ContentParent::IsForApp()
}
bool
ContentParent::RecvReadPrefsArray(InfallibleTArray<PrefTuple> *prefs)
ContentParent::RecvReadPrefsArray(InfallibleTArray<PrefSetting>* aPrefs)
{
Preferences::MirrorPreferences(prefs);
Preferences::GetPreferences(aPrefs);
return true;
}
@ -954,17 +954,10 @@ ContentParent::Observe(nsISupports* aSubject,
// We know prefs are ASCII here.
NS_LossyConvertUTF16toASCII strData(aData);
PrefTuple pref;
bool prefNeedUpdate = Preferences::MirrorPreference(strData.get(), &pref);
if (prefNeedUpdate) {
if (!SendPreferenceUpdate(pref)) {
return NS_ERROR_NOT_AVAILABLE;
}
} else {
// Pref wasn't found. It was probably removed.
if (!SendClearUserPreference(strData)) {
return NS_ERROR_NOT_AVAILABLE;
}
PrefSetting pref(strData, null_t(), null_t());
Preferences::GetPreference(&pref);
if (!SendPreferenceUpdate(pref)) {
return NS_ERROR_NOT_AVAILABLE;
}
}
else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) {

View File

@ -212,7 +212,7 @@ private:
virtual PStorageParent* AllocPStorage(const StorageConstructData& aData);
virtual bool DeallocPStorage(PStorageParent* aActor);
virtual bool RecvReadPrefsArray(InfallibleTArray<PrefTuple> *retValue);
virtual bool RecvReadPrefsArray(InfallibleTArray<PrefSetting>* aPrefs);
virtual bool RecvReadFontList(InfallibleTArray<FontListEntry>* retValue);
virtual bool RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions);

View File

@ -24,7 +24,6 @@ include "mozilla/net/NeckoMessageUtils.h";
include "mozilla/dom/TabMessageUtils.h";
include "nsGeoPositionIPCSerialiser.h";
include "PPrefTuple.h";
include DOMTypes;
@ -135,6 +134,23 @@ union AppId {
nullable PBrowser;
};
union PrefValue {
nsCString;
int32_t;
bool;
};
union MaybePrefValue {
PrefValue;
null_t;
};
struct PrefSetting {
nsCString name;
MaybePrefValue defaultValue;
MaybePrefValue userValue;
};
rpc protocol PContent
{
parent opens PCompositor;
@ -183,8 +199,7 @@ child:
async NotifyVisited(URI uri);
PreferenceUpdate(PrefTuple pref);
ClearUserPreference(nsCString prefName);
PreferenceUpdate(PrefSetting pref);
NotifyAlertsObserver(nsCString topic, nsString data);
@ -248,7 +263,7 @@ parent:
async LoadURIExternal(URI uri);
// PrefService message
sync ReadPrefsArray() returns (PrefTuple[] retValue);
sync ReadPrefsArray() returns (PrefSetting[] prefs);
sync ReadFontList() returns (FontListEntry[] retValue);

View File

@ -27,11 +27,6 @@ XPIDLSRCS = \
nsIRelativeFilePref.idl \
$(NULL)
EXPORTS = \
PPrefTuple.h \
PrefTuple.h \
$(NULL)
EXPORTS_mozilla = \
Preferences.h \
$(NULL)

View File

@ -1,74 +0,0 @@
/* 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 dom_pref_hash_entry_array_IPC_serialiser
#define dom_pref_hash_entry_array_IPC_serialiser
#include "IPC/IPCMessageUtils.h"
#include "nsTArray.h"
#include "pldhash.h"
#include "nsIPrefService.h"
#include "PrefTuple.h"
namespace IPC {
template <>
struct ParamTraits<PrefTuple>
{
typedef PrefTuple paramType;
// Function to serialize a PrefTuple
static void Write(Message *aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.key);
WriteParam(aMsg, (uint32_t)aParam.type);
switch (aParam.type) {
case PrefTuple::PREF_STRING:
WriteParam(aMsg, aParam.stringVal);
break;
case PrefTuple::PREF_INT:
WriteParam(aMsg, aParam.intVal);
break;
case PrefTuple::PREF_BOOL:
WriteParam(aMsg, aParam.boolVal);
break;
}
}
// Function to de-serialize a PrefTuple
static bool Read(const Message* aMsg, void **aIter, paramType* aResult)
{
uint32_t type;
if (!ReadParam(aMsg, aIter, &(aResult->key)))
return false;
if (!ReadParam(aMsg, aIter, &type))
return false;
switch (type) {
case PrefTuple::PREF_STRING:
aResult->type = PrefTuple::PREF_STRING;
if (!ReadParam(aMsg, aIter, &(aResult->stringVal)))
return false;
break;
case PrefTuple::PREF_INT:
aResult->type = PrefTuple::PREF_INT;
if (!ReadParam(aMsg, aIter, &(aResult->intVal)))
return false;
break;
case PrefTuple::PREF_BOOL:
aResult->type = PrefTuple::PREF_BOOL;
if (!ReadParam(aMsg, aIter, &(aResult->boolVal)))
return false;
break;
}
return true;
}
} ;
}
#endif

View File

@ -1,30 +0,0 @@
/* 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 preftuple_included
#define preftuple_included
#include "nsTArray.h"
#include "nsString.h"
struct PrefTuple
{
nsCAutoString key;
// We don't use a union to avoid allocations when using the string component
// NOTE: Only one field will be valid at any given time, as indicated by the type enum
nsCAutoString stringVal;
int32_t intVal;
bool boolVal;
enum {
PREF_STRING,
PREF_INT,
PREF_BOOL
} type;
};
#endif

View File

@ -15,6 +15,7 @@
#include "nsIPrefBranchInternal.h"
#include "nsIObserver.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "nsWeakReference.h"
class nsIFile;
@ -30,12 +31,18 @@ typedef int (*PR_CALLBACK PrefChangedFunc)(const char *, void *);
namespace mozilla {
namespace dom {
class PrefSetting;
}
class Preferences : public nsIPrefService,
public nsIObserver,
public nsIPrefBranchInternal,
public nsSupportsWeakReference
{
public:
typedef mozilla::dom::PrefSetting PrefSetting;
NS_DECL_ISUPPORTS
NS_DECL_NSIPREFSERVICE
NS_FORWARD_NSIPREFBRANCH(sRootBranch->)
@ -320,11 +327,9 @@ public:
static int32_t GetDefaultType(const char* aPref);
// Used to synchronise preferences between chrome and content processes.
static void MirrorPreferences(nsTArray<PrefTuple,
nsTArrayInfallibleAllocator> *aArray);
static bool MirrorPreference(const char *aPref, PrefTuple *aTuple);
static void ClearContentPref(const char *aPref);
static void SetPreference(const PrefTuple *aTuple);
static void GetPreferences(InfallibleTArray<PrefSetting>* aPrefs);
static void GetPreference(PrefSetting* aPref);
static void SetPreference(const PrefSetting& aPref);
protected:
nsresult NotifyServiceObservers(const char *aSubject);

View File

@ -36,7 +36,6 @@
#include "prefapi.h"
#include "prefread.h"
#include "prefapi_private_data.h"
#include "PrefTuple.h"
#include "mozilla/Omnijar.h"
#include "nsZipArchive.h"
@ -285,13 +284,12 @@ Preferences::Init()
using mozilla::dom::ContentChild;
if (XRE_GetProcessType() == GeckoProcessType_Content) {
InfallibleTArray<PrefTuple> array;
ContentChild::GetSingleton()->SendReadPrefsArray(&array);
InfallibleTArray<PrefSetting> prefs;
ContentChild::GetSingleton()->SendReadPrefsArray(&prefs);
// Store the array
nsTArray<PrefTuple>::size_type index = array.Length();
while (index-- > 0) {
pref_SetPrefTuple(array[index], true);
for (uint32_t i = 0; i < prefs.Length(); ++i) {
pref_SetPref(prefs[i]);
}
return NS_OK;
}
@ -470,34 +468,26 @@ ReadExtensionPrefs(nsIFile *aFile)
}
void
Preferences::SetPreference(const PrefTuple *aPref)
Preferences::SetPreference(const PrefSetting& aPref)
{
pref_SetPrefTuple(*aPref, true);
pref_SetPref(aPref);
}
void
Preferences::ClearContentPref(const char *aPref)
Preferences::GetPreference(PrefSetting* aPref)
{
PREF_ClearUserPref(aPref);
}
bool
Preferences::MirrorPreference(const char *aPref, PrefTuple *aTuple)
{
PrefHashEntry *entry = pref_HashTableLookup(aPref);
PrefHashEntry *entry = pref_HashTableLookup(aPref->name().get());
if (!entry)
return false;
return;
pref_GetTupleFromEntry(entry, aTuple);
return true;
pref_GetPrefFromEntry(entry, aPref);
}
void
Preferences::MirrorPreferences(nsTArray<PrefTuple,
nsTArrayInfallibleAllocator> *aArray)
Preferences::GetPreferences(InfallibleTArray<PrefSetting>* aPrefs)
{
aArray->SetCapacity(PL_DHASH_TABLE_SIZE(&gHashTable));
PL_DHashTableEnumerate(&gHashTable, pref_MirrorPrefs, aArray);
aPrefs->SetCapacity(PL_DHASH_TABLE_SIZE(&gHashTable));
PL_DHashTableEnumerate(&gHashTable, pref_GetPrefs, aPrefs);
}
NS_IMETHODIMP

View File

@ -1,11 +1,12 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "base/basictypes.h"
#include "prefapi.h"
#include "prefapi_private_data.h"
#include "PrefTuple.h"
#include "prefread.h"
#include "nsReadableUtils.h"
#include "nsCRT.h"
@ -26,6 +27,7 @@
#include "prlog.h"
#include "prmem.h"
#include "prprf.h"
#include "mozilla/dom/PContent.h"
#include "nsQuickSort.h"
#include "nsString.h"
#include "nsPrintfCString.h"
@ -36,6 +38,8 @@
#include <os2.h>
#endif
using namespace mozilla;
static void
clearPrefEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
{
@ -121,6 +125,7 @@ static char *ArenaStrDup(const char* str, PLArenaPool* aArena)
/*---------------------------------------------------------------------------*/
#define PREF_IS_LOCKED(pref) ((pref)->flags & PREF_LOCKED)
#define PREF_HAS_DEFAULT_VALUE(pref) ((pref)->flags & PREF_HAS_DEFAULT)
#define PREF_HAS_USER_VALUE(pref) ((pref)->flags & PREF_USERSET)
#define PREF_TYPE(pref) (PrefType)((pref)->flags & PREF_VALUETYPE_MASK)
@ -271,22 +276,53 @@ PREF_SetBoolPref(const char *pref_name, bool value, bool set_default)
return pref_HashPref(pref_name, pref, PREF_BOOL, set_default ? kPrefSetDefault : 0);
}
nsresult
pref_SetPrefTuple(const PrefTuple &aPref, bool set_default)
enum WhichValue { DEFAULT_VALUE, USER_VALUE };
static nsresult
SetPrefValue(const char* aPrefName, const dom::PrefValue& aValue,
WhichValue aWhich)
{
switch (aPref.type) {
case PrefTuple::PREF_STRING:
return PREF_SetCharPref(aPref.key.get(), aPref.stringVal.get(), set_default);
bool setDefault = (aWhich == DEFAULT_VALUE);
switch (aValue.type()) {
case dom::PrefValue::TnsCString:
return PREF_SetCharPref(aPrefName, aValue.get_nsCString().get(),
setDefault);
case dom::PrefValue::Tint32_t:
return PREF_SetIntPref(aPrefName, aValue.get_int32_t(),
setDefault);
case dom::PrefValue::Tbool:
return PREF_SetBoolPref(aPrefName, aValue.get_bool(),
setDefault);
default:
MOZ_NOT_REACHED();
return NS_ERROR_FAILURE;
}
}
case PrefTuple::PREF_INT:
return PREF_SetIntPref(aPref.key.get(), aPref.intVal, set_default);
nsresult
pref_SetPref(const dom::PrefSetting& aPref)
{
const char* prefName = aPref.name().get();
const dom::MaybePrefValue& defaultValue = aPref.defaultValue();
const dom::MaybePrefValue& userValue = aPref.userValue();
case PrefTuple::PREF_BOOL:
return PREF_SetBoolPref(aPref.key.get(), aPref.boolVal, set_default);
nsresult rv;
if (defaultValue.type() == dom::MaybePrefValue::TPrefValue) {
rv = SetPrefValue(prefName, defaultValue.get_PrefValue(), DEFAULT_VALUE);
if (NS_FAILED(rv)) {
return rv;
}
}
NS_NOTREACHED("Unknown type");
return NS_ERROR_INVALID_ARG;
if (userValue.type() == dom::MaybePrefValue::TPrefValue) {
rv = SetPrefValue(prefName, userValue.get_PrefValue(), USER_VALUE);
} else {
rv = PREF_ClearUserPref(prefName);
}
// NB: we should never try to clear a default value, that doesn't
// make sense
return rv;
}
PLDHashOperator
@ -348,47 +384,73 @@ pref_savePref(PLDHashTable *table, PLDHashEntryHdr *heh, uint32_t i, void *arg)
}
PLDHashOperator
pref_MirrorPrefs(PLDHashTable *table,
PLDHashEntryHdr *heh,
uint32_t i,
void *arg)
pref_GetPrefs(PLDHashTable *table,
PLDHashEntryHdr *heh,
uint32_t i,
void *arg)
{
if (heh) {
PrefHashEntry *entry = static_cast<PrefHashEntry *>(heh);
PrefTuple *newEntry =
static_cast<nsTArray<PrefTuple> *>(arg)->AppendElement();
dom::PrefSetting *pref =
static_cast<InfallibleTArray<dom::PrefSetting>*>(arg)->AppendElement();
pref_GetTupleFromEntry(entry, newEntry);
pref_GetPrefFromEntry(entry, pref);
}
return PL_DHASH_NEXT;
}
void
pref_GetTupleFromEntry(PrefHashEntry *aHashEntry, PrefTuple *aTuple)
static void
GetPrefValueFromEntry(PrefHashEntry *aHashEntry, dom::PrefSetting* aPref,
WhichValue aWhich)
{
aTuple->key = aHashEntry->key;
PrefValue *value = PREF_HAS_USER_VALUE(aHashEntry) ?
&(aHashEntry->userPref) : &(aHashEntry->defaultPref);
PrefValue* value;
dom::PrefValue* settingValue;
if (aWhich == USER_VALUE) {
value = &aHashEntry->userPref;
aPref->userValue() = dom::PrefValue();
settingValue = &aPref->userValue().get_PrefValue();
} else {
value = &aHashEntry->defaultPref;
aPref->defaultValue() = dom::PrefValue();
settingValue = &aPref->defaultValue().get_PrefValue();
}
switch (aHashEntry->flags & PREF_VALUETYPE_MASK) {
case PREF_STRING:
aTuple->stringVal = value->stringVal;
aTuple->type = PrefTuple::PREF_STRING;
return;
case PREF_INT:
aTuple->intVal = value->intVal;
aTuple->type = PrefTuple::PREF_INT;
return;
case PREF_BOOL:
aTuple->boolVal = !!value->boolVal;
aTuple->type = PrefTuple::PREF_BOOL;
return;
case PREF_STRING:
*settingValue = nsDependentCString(value->stringVal);
return;
case PREF_INT:
*settingValue = value->intVal;
return;
case PREF_BOOL:
*settingValue = !!value->boolVal;
return;
default:
MOZ_NOT_REACHED();
}
}
void
pref_GetPrefFromEntry(PrefHashEntry *aHashEntry, dom::PrefSetting* aPref)
{
aPref->name() = aHashEntry->key;
if (PREF_HAS_DEFAULT_VALUE(aHashEntry)) {
GetPrefValueFromEntry(aHashEntry, aPref, DEFAULT_VALUE);
} else {
aPref->defaultValue() = null_t();
}
if (PREF_HAS_USER_VALUE(aHashEntry)) {
GetPrefValueFromEntry(aHashEntry, aPref, USER_VALUE);
} else {
aPref->userValue() = null_t();
}
MOZ_ASSERT(aPref->defaultValue().type() == dom::MaybePrefValue::Tnull_t ||
aPref->userValue().type() == dom::MaybePrefValue::Tnull_t ||
(aPref->defaultValue().get_PrefValue().type() ==
aPref->userValue().get_PrefValue().type()));
}
int
pref_CompareStrings(const void *v1, const void *v2, void *unused)

View File

@ -8,7 +8,11 @@
extern PLDHashTable gHashTable;
extern bool gDirty;
struct PrefTuple;
namespace mozilla {
namespace dom {
class PrefSetting;
}
}
enum pref_SaveTypes { SAVE_NONSHARED, SAVE_SHARED, SAVE_ALL, SAVE_ALL_AND_DEFAULTS };
@ -22,12 +26,14 @@ PLDHashOperator
pref_savePref(PLDHashTable *table, PLDHashEntryHdr *heh, uint32_t i, void *arg);
PLDHashOperator
pref_MirrorPrefs(PLDHashTable *table, PLDHashEntryHdr *heh, uint32_t i, void *arg);
pref_GetPrefs(PLDHashTable *table,
PLDHashEntryHdr *heh, uint32_t i, void *arg);
nsresult
pref_SetPrefTuple(const PrefTuple &aPref,bool set_default = false);
pref_SetPref(const mozilla::dom::PrefSetting& aPref);
int pref_CompareStrings(const void *v1, const void *v2, void* unused);
PrefHashEntry* pref_HashTableLookup(const void *key);
void pref_GetTupleFromEntry(PrefHashEntry *aHashEntry, PrefTuple *aTuple);
void pref_GetPrefFromEntry(PrefHashEntry *aHashEntry,
mozilla::dom::PrefSetting* aPref);