Bug 1436911 - Avoid the early/late prefs split. r=glandium draft
authorNicholas Nethercote <nnethercote@mozilla.com>
Thu, 08 Mar 2018 15:47:24 +1100
changeset 766586 699b8dafb2df18a731506bae82554839f6990f3b
parent 766585 67daf50687c446e95f13cd41d511da64c5c6928a
push id102360
push usernnethercote@mozilla.com
push dateTue, 13 Mar 2018 01:59:25 +0000
reviewersglandium
bugs1436911, 1432979, 1439406, 1419432
milestone61.0a1
Bug 1436911 - Avoid the early/late prefs split. r=glandium All prefs that need to be sent to a new content process are now put into the shared memory segment, and they are identified by the pref name instead of an index into a list. The old IPC used at process startup (in XPCOMInitData) is removed. Benefits: - It removes the need for the early prefs list (dom/ipc/ContentProcesses.{h,cpp}) and the associated checking, which is ugly and often trips people up (e.g. bug 1432979, bug 1439406). - Using prefnames instead of indices fixes some fragility (fixing bug 1419432). - It fixes the problem of early prefs being installed as unlocked default values even if they are locked and/or have user values. MozReview-Commit-ID: FRIzHF8Tjd
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
dom/ipc/ContentPrefs.cpp
dom/ipc/ContentPrefs.h
dom/ipc/ContentProcess.cpp
dom/ipc/PContent.ipdl
dom/ipc/moz.build
layout/style/nsCSSProps.h
modules/libpref/Preferences.cpp
modules/libpref/Preferences.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1176,18 +1176,16 @@ ContentChild::InitGraphicsDeviceData(con
 {
   gfxPlatform::InitChild(aData);
 }
 
 void
 ContentChild::InitXPCOM(const XPCOMInitData& aXPCOMInit,
                         const mozilla::dom::ipc::StructuredCloneData& aInitialData)
 {
-  Preferences::SetLatePreferences(&aXPCOMInit.prefs());
-
   // Do this as early as possible to get the parent process to initialize the
   // background thread since we'll likely need database information very soon.
   BackgroundChild::Startup();
 
   PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
   if (NS_WARN_IF(!actorChild)) {
     MOZ_ASSERT_UNREACHABLE("PBackground init can't fail at this point");
     return;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -192,17 +192,16 @@
 #include "nsHostObjectProtocolHandler.h"
 #include "nsICaptivePortalService.h"
 #include "nsIObjectLoadingContent.h"
 
 #include "nsIBidiKeyboard.h"
 
 #include "nsLayoutStylesheetCache.h"
 
-#include "ContentPrefs.h"
 #include "mozilla/Sprintf.h"
 
 #ifdef MOZ_WEBRTC
 #include "signaling/src/peerconnection/WebrtcGlobalParent.h"
 #endif
 
 #if defined(ANDROID) || defined(LINUX)
 #include "nsSystemInfo.h"
@@ -1999,17 +1998,17 @@ ContentParent::LaunchSubprocess(ProcessP
   extraArgs.push_back(idStr);
   extraArgs.push_back(IsForBrowser() ? "-isForBrowser" : "-notForBrowser");
 
   // Prefs information is passed via anonymous shared memory to avoid bloating
   // the command line.
 
   // Serialize the early prefs.
   nsAutoCStringN<1024> prefs;
-  Preferences::SerializeEarlyPreferences(prefs);
+  Preferences::SerializePreferences(prefs);
 
   // Set up the shared memory.
   base::SharedMemory shm;
   if (!shm.Create("", /* read_only */ false, /* open_existing */ false,
                   prefs.Length())) {
     NS_ERROR("failed to create shared memory in the parent");
     MarkAsDead();
     return false;
@@ -2167,17 +2166,16 @@ void
 ContentParent::InitInternal(ProcessPriority aInitialPriority)
 {
   Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_TIME_MS,
                         static_cast<uint32_t>((TimeStamp::Now() - mLaunchTS)
                                               .ToMilliseconds()));
 
   XPCOMInitData xpcomInit;
 
-  Preferences::GetPreferences(&xpcomInit.prefs());
   nsCOMPtr<nsIIOService> io(do_GetIOService());
   MOZ_ASSERT(io, "No IO service?");
   DebugOnly<nsresult> rv = io->GetOffline(&xpcomInit.isOffline());
   MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
 
   rv = io->GetConnectivity(&xpcomInit.isConnected());
   MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?");
 
deleted file mode 100644
--- a/dom/ipc/ContentPrefs.cpp
+++ /dev/null
@@ -1,360 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "ContentPrefs.h"
-
-/******************************************************************************
- *
- *           DO NOT ADD PREFS TO THIS LIST WITHOUT DOM PEER REVIEW
- *
- * This is the list of preferences that are sent to the content process on
- * startup. Only prefs that are required immediately upon startup should be
- * listed here. The first IPC message received in the content process will
- * contain all the other prefs. Prefs should only be listed here if they must be
- * read before the first IPC message is received.
- *
- ******************************************************************************/
-
-const char* mozilla::dom::ContentPrefs::gEarlyPrefs[] = {
-  "accessibility.monoaudio.enable",
-  "accessibility.mouse_focuses_formcontrol",
-  "accessibility.tabfocus_applies_to_xul",
-  "app.update.channel",
-  "browser.autofocus",
-  "browser.dom.window.dump.enabled",
-  "browser.sessionhistory.max_entries",
-  "browser.sessionhistory.max_total_viewers",
-#if defined(NIGHTLY_BUILD) || defined(DEBUG)
-  "browser.startup.record",
-#endif
-#if defined(ANDROID)
-  "consoleservice.logcat",
-#endif
-  "content.cors.disable",
-  "content.cors.no_private_data",
-  "content.notify.backoffcount",
-  "content.notify.interval",
-  "content.notify.ontimer",
-  "content.sink.enable_perf_mode",
-  "content.sink.event_probe_rate",
-  "content.sink.initial_perf_time",
-  "content.sink.interactive_deflect_count",
-  "content.sink.interactive_parse_time",
-  "content.sink.interactive_time",
-  "content.sink.pending_event_mode",
-  "content.sink.perf_deflect_count",
-  "content.sink.perf_parse_time",
-  "device.storage.prompt.testing",
-  "device.storage.writable.name",
-  "devtools.enabled",
-  "dom.allow_XUL_XBL_for_file",
-  "dom.allow_cut_copy",
-  "dom.animations-api.core.enabled",
-  "dom.animations-api.element-animate.enabled",
-  "dom.animations-api.pending-member.enabled",
-  "dom.enable_frame_timing",
-  "dom.enable_performance",
-  "dom.enable_performance_navigation_timing",
-  "dom.enable_resource_timing",
-  "dom.event.handling-user-input-time-limit",
-  "dom.event.touch.coalescing.enabled",
-  "dom.forms.autocomplete.formautofill",
-  "dom.forms.inputmode",
-  "dom.input.skip_cursor_move_for_same_value_set",
-  "dom.ipc.processPriorityManager.backgroundGracePeriodMS",
-  "dom.ipc.processPriorityManager.backgroundPerceivableGracePeriodMS",
-  "dom.ipc.useNativeEventProcessing.content",
-  "dom.max_chrome_script_run_time",
-  "dom.max_ext_content_script_run_time",
-  "dom.max_script_run_time",
-  "dom.mozBrowserFramesEnabled",
-  "dom.performance.enable_notify_performance_timing",
-  "dom.performance.enable_user_timing_logging",
-  "dom.placeholder.show_on_focus",
-  "dom.requestIdleCallback.enabled",
-  "dom.script_loader.bytecode_cache.enabled",
-  "dom.script_loader.bytecode_cache.strategy",
-  "dom.storage.testing",
-  "dom.url.encode_decode_hash",
-  "dom.url.getters_decode_hash",
-  "dom.use_watchdog",
-  "dom.vibrator.enabled",
-  "dom.vibrator.max_vibrate_list_len",
-  "dom.vibrator.max_vibrate_ms",
-  "dom.webcomponents.customelements.enabled",
-  "dom.webcomponents.shadowdom.enabled",
-  "focusmanager.testmode",
-  "font.size.inflation.disabledInMasterProcess",
-  "font.size.inflation.emPerLine",
-  "font.size.inflation.forceEnabled",
-  "font.size.inflation.lineThreshold",
-  "font.size.inflation.mappingIntercept",
-  "font.size.inflation.maxRatio",
-  "font.size.inflation.minTwips",
-  "font.size.systemFontScale",
-  "full-screen-api.allow-trusted-requests-only",
-  "full-screen-api.enabled",
-  "full-screen-api.unprefix.enabled",
-#ifdef FUZZING
-  "fuzzing.enabled",
-#endif
-  "gfx.font_rendering.opentype_svg.enabled",
-  "hangmonitor.timeout",
-  "html5.flushtimer.initialdelay",
-  "html5.flushtimer.subsequentdelay",
-  "html5.offmainthread",
-  "intl.charset.fallback.tld",
-  "intl.charset.fallback.utf8_for_file",
-  "intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition",
-  "javascript.enabled",
-  "javascript.options.array_prototype_values",
-  "javascript.options.asmjs",
-  "javascript.options.asyncstack",
-  "javascript.options.baselinejit",
-  "javascript.options.baselinejit.threshold",
-  "javascript.options.baselinejit.unsafe_eager_compilation",
-  "javascript.options.discardSystemSource",
-  "javascript.options.dump_stack_on_debuggee_would_run",
-  "javascript.options.gczeal",
-  "javascript.options.gczeal.frequency",
-  "javascript.options.ion",
-  "javascript.options.ion.offthread_compilation",
-  "javascript.options.ion.threshold",
-  "javascript.options.ion.unsafe_eager_compilation",
-  "javascript.options.jit.full_debug_checks",
-  "javascript.options.native_regexp",
-  "javascript.options.parallel_parsing",
-  "javascript.options.shared_memory",
-  "javascript.options.spectre.index_masking",
-  "javascript.options.spectre.jit_to_C++_calls",
-  "javascript.options.spectre.object_mitigations.barriers",
-  "javascript.options.spectre.object_mitigations.misc",
-  "javascript.options.spectre.string_mitigations",
-  "javascript.options.spectre.value_masking",
-  "javascript.options.streams",
-  "javascript.options.strict",
-  "javascript.options.strict.debug",
-  "javascript.options.throw_on_asmjs_validation_failure",
-  "javascript.options.throw_on_debuggee_would_run",
-  "javascript.options.wasm",
-  "javascript.options.wasm_baselinejit",
-  "javascript.options.wasm_ionjit",
-  "javascript.options.werror",
-  "javascript.use_us_english_locale",
-  "jsloader.shareGlobal",
-  "layout.css.all-shorthand.enabled",
-  "layout.css.background-blend-mode.enabled",
-  "layout.css.box-decoration-break.enabled",
-  "layout.css.color-adjust.enabled",
-  "layout.css.column-span.enabled",
-  "layout.css.contain.enabled",
-  "layout.css.control-characters.visible",
-  "layout.css.emulate-moz-box-with-flex",
-  "layout.css.expensive-style-struct-assertions.enabled",
-  "layout.css.float-logical-values.enabled",
-  "layout.css.font-display.enabled",
-  "layout.css.font-variations.enabled",
-  "layout.css.frames-timing.enabled",
-  "layout.css.getBoxQuads.enabled",
-  "layout.css.grid-template-subgrid-value.enabled",
-  "layout.css.grid.enabled",
-  "layout.css.image-orientation.enabled",
-  "layout.css.individual-transform.enabled",
-  "layout.css.initial-letter.enabled",
-  "layout.css.isolation.enabled",
-  "layout.css.mix-blend-mode.enabled",
-  "layout.css.moz-document.content.enabled",
-  "layout.css.osx-font-smoothing.enabled",
-  "layout.css.overflow-clip-box.enabled",
-  "layout.css.overscroll-behavior.enabled",
-  "layout.css.prefixes.animations",
-  "layout.css.prefixes.border-image",
-  "layout.css.prefixes.box-sizing",
-  "layout.css.prefixes.device-pixel-ratio-webkit",
-  "layout.css.prefixes.font-features",
-  "layout.css.prefixes.gradients",
-  "layout.css.prefixes.transforms",
-  "layout.css.prefixes.transitions",
-  "layout.css.prefixes.webkit",
-  "layout.css.scope-pseudo.enabled",
-  "layout.css.scoped-style.enabled",
-  "layout.css.scroll-behavior.property-enabled",
-  "layout.css.scroll-snap.enabled",
-#ifdef MOZ_STYLO
-  "layout.css.servo.chrome.enabled",
-  "layout.css.servo.enabled",
-#endif
-  "layout.css.shape-outside.enabled",
-  "layout.css.text-align-unsafe-value.enabled",
-  "layout.css.text-combine-upright-digits.enabled",
-  "layout.css.text-combine-upright.enabled",
-  "layout.css.text-justify.enabled",
-  "layout.css.touch_action.enabled",
-  "layout.css.visited_links_enabled",
-  "layout.idle_period.required_quiescent_frames",
-  "layout.idle_period.time_limit",
-  "layout.interruptible-reflow.enabled",
-  "mathml.disabled",
-  "media.audio-max-decode-error",
-  "media.cache_readahead_limit",
-  "media.cache_resume_threshold",
-  "media.cache_size",
-  "media.clearkey.persistent-license.enabled",
-  "media.cubeb.backend",
-  "media.cubeb.sandbox",
-  "media.cubeb_latency_msg_frames",
-  "media.cubeb_latency_playback_ms",
-  "media.decoder-doctor.wmf-disabled-is-failure",
-  "media.decoder.recycle.enabled",
-  "media.decoder.skip-to-next-key-frame.enabled",
-  "media.dormant-on-pause-timeout-ms",
-  "media.eme.audio.blank",
-  "media.eme.chromium-api.video-shmems",
-  "media.eme.enabled",
-  "media.eme.video.blank",
-  "media.ffmpeg.enabled",
-  "media.ffmpeg.low-latency.enabled",
-  "media.ffvpx.enabled",
-  "media.ffvpx.low-latency.enabled",
-  "media.flac.enabled",
-  "media.forcestereo.enabled",
-  "media.gmp.decoder.enabled",
-  "media.gmp.insecure.allow",
-  "media.gpu-process-decoder",
-  "media.hls.enabled",
-  "media.libavcodec.allow-obsolete",
-  "media.memory_cache_max_size",
-  "media.memory_caches_combined_limit_kb",
-  "media.memory_caches_combined_limit_pc_sysmem",
-  "media.mp4.enabled",
-  "media.navigator.mediadatadecoder_enabled",
-  "media.ogg.enabled",
-  "media.ogg.flac.enabled",
-  "media.playback.warnings-as-errors",
-  "media.playback.warnings-as-errors.stagefright-vs-rust",
-  "media.resampling.enabled",
-  "media.resume-bkgnd-video-on-tabhover",
-  "media.ruin-av-sync.enabled",
-  "media.rust.mp4parser",
-  "media.rust.test_mode",
-  "media.seamless-looping",
-  "media.suspend-bkgnd-video.delay-ms",
-  "media.suspend-bkgnd-video.enabled",
-  "media.use-blank-decoder",
-  "media.video-max-decode-error",
-  "media.video_stats.enabled",
-  "media.videocontrols.lock-video-orientation",
-  "media.volume_scale",
-  "media.webspeech.recognition.enable",
-  "media.webspeech.recognition.force_enable",
-  "media.webspeech.synth.force_global_queue",
-  "media.webspeech.test.enable",
-  "media.webspeech.test.fake_fsm_events",
-  "media.webspeech.test.fake_recognition_service",
-  "media.wmf.allow-unsupported-resolutions",
-  "media.wmf.enabled",
-  "media.wmf.skip-blacklist",
-  "media.wmf.vp9.enabled",
-  "network.IDN.blacklist_chars",
-  "network.IDN.restriction_profile",
-  "network.IDN.use_whitelist",
-  "network.IDN_show_punycode",
-  "network.buffer.cache.count",
-  "network.buffer.cache.size",
-  "network.captive-portal-service.enabled",
-  "network.cookie.cookieBehavior",
-  "network.cookie.lifetimePolicy",
-  "network.dns.disablePrefetch",
-  "network.dns.disablePrefetchFromHTTPS",
-  "network.http.tailing.enabled",
-  "network.jar.block-remote-files",
-  "network.loadinfo.skip_type_assertion",
-  "network.notify.changed",
-  "network.offline-mirrors-connectivity",
-  "network.protocol-handler.external.jar",
-  "network.proxy.type",
-  "network.security.ports.banned",
-  "network.security.ports.banned.override",
-  "network.standard-url.enable-rust",
-  "network.standard-url.max-length",
-  "network.standard-url.punycode-host",
-  "network.sts.max_time_for_events_between_two_polls",
-  "network.sts.max_time_for_pr_close_during_shutdown",
-  "network.tcp.keepalive.enabled",
-  "network.tcp.keepalive.idle_time",
-  "network.tcp.keepalive.probe_count",
-  "network.tcp.keepalive.retry_interval",
-  "network.tcp.sendbuffer",
-  "nglayout.debug.invalidation",
-  "privacy.donottrackheader.enabled",
-  "privacy.firstparty.isolate",
-  "privacy.firstparty.isolate.restrict_opener_access",
-  "privacy.reduceTimerPrecision",
-  "privacy.resistFingerprinting",
-  "privacy.resistFingerprinting.autoDeclineNoUserInputCanvasPrompts",
-  "privacy.resistFingerprinting.reduceTimerPrecision.jitter",
-  "privacy.resistFingerprinting.reduceTimerPrecision.microseconds",
-  "privacy.resistFingerprinting.target_video_res",
-  "privacy.resistFingerprinting.video_dropped_ratio",
-  "privacy.resistFingerprinting.video_frames_per_sec",
-  "privacy.trackingprotection.lower_network_priority",
-  "privacy.window.maxInnerHeight",
-  "privacy.window.maxInnerWidth",
-  "security.csp.enable",
-  "security.data_uri.block_toplevel_data_uri_navigations",
-  "security.data_uri.unique_opaque_origin",
-  "security.fileuri.strict_origin_policy",
-  "security.mixed_content.block_active_content",
-  "security.mixed_content.block_display_content",
-  "security.mixed_content.block_object_subrequest",
-  "security.mixed_content.hsts_priming_cache_timeout",
-  "security.mixed_content.send_hsts_priming",
-  "security.mixed_content.upgrade_display_content",
-  "security.mixed_content.use_hsts",
-  "security.sandbox.content.level",
-  "security.sandbox.content.tempDirSuffix",
-  "security.sandbox.logging.enabled",
-  "security.sandbox.mac.track.violations",
-  "security.sandbox.windows.log.stackTraceDepth",
-  "svg.disabled",
-  "svg.display-lists.hit-testing.enabled",
-  "svg.display-lists.painting.enabled",
-  "svg.new-getBBox.enabled",
-  "svg.path-caching.enabled",
-  "svg.transform-box.enabled",
-  "toolkit.asyncshutdown.crash_timeout",
-  "toolkit.asyncshutdown.log",
-  "toolkit.osfile.log",
-  "toolkit.osfile.log.redirect",
-  "toolkit.telemetry.enabled",
-  "toolkit.telemetry.idleTimeout",
-  "toolkit.telemetry.initDelay",
-  "toolkit.telemetry.log.dump",
-  "toolkit.telemetry.log.level",
-  "toolkit.telemetry.minSubsessionLength",
-  "toolkit.telemetry.scheduler.idleTickInterval",
-  "toolkit.telemetry.scheduler.tickInterval",
-  "toolkit.telemetry.testing.overridePreRelease",
-  "toolkit.telemetry.unified",
-  "ui.key.menuAccessKeyFocuses",
-  "ui.popup.disable_autohide",
-  "ui.use_activity_cursor",
-  "view_source.editor.external",
-  "zoom.maxPercent",
-  "zoom.minPercent"
-};
-
-const char** mozilla::dom::ContentPrefs::GetEarlyPrefs(size_t* aCount)
-{
-  *aCount = ArrayLength(ContentPrefs::gEarlyPrefs);
-  return gEarlyPrefs;
-}
-
-const char* mozilla::dom::ContentPrefs::GetEarlyPref(size_t aIndex)
-{
-  MOZ_ASSERT(aIndex < ArrayLength(ContentPrefs::gEarlyPrefs));
-  return gEarlyPrefs[aIndex];
-}
deleted file mode 100644
--- a/dom/ipc/ContentPrefs.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* -*- 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 mozilla_dom_ContentPrefs_h
-#define mozilla_dom_ContentPrefs_h
-
-// See the comment in ContentPrefs.cpp for more information.
-
-namespace mozilla {
-namespace dom {
-
-class ContentPrefs {
-public:
-  static const char** GetEarlyPrefs(size_t* aCount);
-  static const char* GetEarlyPref(size_t aIndex);
-
-private:
-  static const char* gEarlyPrefs[];
-};
-
-}
-}
-
-#endif
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -2,17 +2,16 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ipc/IOThreadChild.h"
 
 #include "ContentProcess.h"
-#include "ContentPrefs.h"
 #include "base/shared_memory.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Scheduler.h"
 
 #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
 #include <stdlib.h>
 #endif
 
@@ -221,18 +220,18 @@ ContentProcess::Init(int aArgc, char* aA
   if (!shm.SetHandle(prefsHandle, /* read_only */ true)) {
     NS_ERROR("failed to open shared memory in the child");
     return false;
   }
   if (!shm.Map(prefsLen)) {
     NS_ERROR("failed to map shared memory in the child");
     return false;
   }
-  Preferences::DeserializeEarlyPreferences(static_cast<char*>(shm.memory()),
-                                           prefsLen);
+  Preferences::DeserializePreferences(static_cast<char*>(shm.memory()),
+                                      prefsLen);
 
   Scheduler::SetPrefs(schedulerPrefs);
   mContent.Init(IOThreadChild::message_loop(),
                 ParentPid(),
                 IOThreadChild::channel(),
                 childID,
                 isForBrowser);
   mXREEmbed.Start();
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -150,16 +150,22 @@ union PrefValue {
   bool;
 };
 
 union MaybePrefValue {
   PrefValue;
   null_t;
 };
 
+// This serialization form mirrors that used in mozilla::Pref in
+// Preferences.cpp. The two should be kept in sync, e.g. if something is added
+// to one it should also be added to the other.
+//
+// Note: there is no need to pass the isSticky attribute because that's an
+// immutable attribute obtained from file at startup.
 struct Pref {
   nsCString name;
   bool isLocked;
   MaybePrefValue defaultValue;
   MaybePrefValue userValue;
 };
 
 struct DataStorageItem {
@@ -268,17 +274,16 @@ struct XPCOMInitData
     bool isConnected;
     int32_t captivePortalState;
     bool isLangRTL;
     bool haveBidiKeyboards;
     nsString[] dictionaries;
     ClipboardCapabilities clipboardCaps;
     DomainPolicyClone domainPolicy;
     OptionalURIParams userContentSheetURL;
-    Pref[] prefs;
     GfxVarUpdate[] gfxNonDefaultVarUpdates;
     ContentDeviceData contentDeviceData;
     GfxInfoFeatureStatus[] gfxFeatureStatus;
     DataStorageEntry[] dataStorage;
     nsCString[] appLocales;
     nsCString[] requestedLocales;
     DynamicScalarDefinition[] dynamicScalarDefs;
 };
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -21,17 +21,16 @@ EXPORTS.mozilla.dom.ipc += [
 EXPORTS.mozilla.dom += [
     'CoalescedInputData.h',
     'CoalescedMouseData.h',
     'CoalescedWheelData.h',
     'ContentBridgeChild.h',
     'ContentBridgeParent.h',
     'ContentChild.h',
     'ContentParent.h',
-    'ContentPrefs.h',
     'ContentProcess.h',
     'ContentProcessManager.h',
     'CPOWManagerGetter.h',
     'FilePickerParent.h',
     'MemoryReportRequest.h',
     'nsIContentChild.h',
     'nsIContentParent.h',
     'PermissionMessageUtils.h',
@@ -53,17 +52,16 @@ EXPORTS.mozilla += [
 
 UNIFIED_SOURCES += [
     'CoalescedMouseData.cpp',
     'CoalescedWheelData.cpp',
     'ColorPickerParent.cpp',
     'ContentBridgeChild.cpp',
     'ContentBridgeParent.cpp',
     'ContentParent.cpp',
-    'ContentPrefs.cpp',
     'ContentProcess.cpp',
     'ContentProcessManager.cpp',
     'FilePickerParent.cpp',
     'MemoryReportRequest.cpp',
     'nsIContentChild.cpp',
     'nsIContentParent.cpp',
     'PermissionMessageUtils.cpp',
     'PreallocatedProcessManager.cpp',
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -640,17 +640,17 @@ public:
   }
 
   static bool IsEnabled(nsCSSPropertyID aProperty) {
     MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_with_aliases,
                "out of range");
     // In the child process, assert that we're not trying to parse stylesheets
     // before we've gotten all our prefs.
     MOZ_ASSERT_IF(!XRE_IsParentProcess(),
-                  mozilla::Preferences::AreAllPrefsSetInContentProcess());
+                  mozilla::Preferences::ArePrefsInitedInContentProcess());
     return gPropertyEnabled[aProperty];
   }
 
   // A table for the use counter associated with each CSS property.  If a
   // property does not have a use counter defined in UseCounters.conf, then
   // its associated entry is |eUseCounter_UNKNOWN|.
   static const mozilla::UseCounter gPropertyUseCounter[eCSSProperty_COUNT_no_shorthands];
 
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -10,17 +10,16 @@
 
 #include "base/basictypes.h"
 #include "GeckoProfiler.h"
 #include "MainThreadUtils.h"
 #include "mozilla/ArenaAllocatorExtensions.h"
 #include "mozilla/ArenaAllocator.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
-#include "mozilla/dom/ContentPrefs.h"
 #include "mozilla/dom/PContent.h"
 #include "mozilla/HashFunctions.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ModuleUtils.h"
 #include "mozilla/Omnijar.h"
 #include "mozilla/Preferences.h"
@@ -126,16 +125,39 @@ static const uint32_t MAX_ADVISABLE_PREF
 enum class PrefType : uint8_t
 {
   None = 0, // only used when neither the default nor user value is set
   String = 1,
   Int = 2,
   Bool = 3,
 };
 
+// This is used for pref names and string pref values. We encode the string
+// length, then a '/', then the string chars. This encoding means there are no
+// special chars that are forbidden or require escaping.
+static void
+SerializeAndAppendString(const char* aChars, nsCString& aStr)
+{
+  aStr.AppendInt(uint32_t(strlen(aChars)));
+  aStr.Append('/');
+  aStr.Append(aChars);
+}
+
+static char*
+DeserializeString(char* aChars, nsCString& aStr)
+{
+  char* p = aChars;
+  uint32_t length = strtol(p, &p, 10);
+  MOZ_ASSERT(p[0] == '/');
+  p++; // move past the '/'
+  aStr.Assign(p, length);
+  p += length; // move past the string itself
+  return p;
+}
+
 // Keep this in sync with PrefValue in prefs_parser/src/lib.rs.
 union PrefValue {
   const char* mStringVal;
   int32_t mIntVal;
   bool mBoolVal;
 
   bool Equals(PrefType aType, PrefValue aValue)
   {
@@ -218,16 +240,74 @@ union PrefValue {
       case dom::PrefValue::Tbool:
         mBoolVal = aDomValue.get_bool();
         return PrefType::Bool;
 
       default:
         MOZ_CRASH();
     }
   }
+
+  void SerializeAndAppend(PrefType aType, nsCString& aStr)
+  {
+    switch (aType) {
+      case PrefType::Bool:
+        aStr.Append(mBoolVal ? 'T' : 'F');
+        break;
+
+      case PrefType::Int:
+        aStr.AppendInt(mIntVal);
+        break;
+
+      case PrefType::String: {
+        SerializeAndAppendString(mStringVal, aStr);
+        break;
+      }
+
+      case PrefType::None:
+      default:
+        MOZ_CRASH();
+    }
+  }
+
+  static char* Deserialize(PrefType aType,
+                           char* aStr,
+                           dom::MaybePrefValue* aDomValue)
+  {
+    char* p = aStr;
+
+    switch (aType) {
+      case PrefType::Bool:
+        if (*p == 'T') {
+          *aDomValue = true;
+        } else if (*p == 'F') {
+          *aDomValue = false;
+        } else {
+          *aDomValue = false;
+          NS_ERROR("bad bool pref value");
+        }
+        p++;
+        return p;
+
+      case PrefType::Int: {
+        *aDomValue = int32_t(strtol(p, &p, 10));
+        return p;
+      }
+
+      case PrefType::String: {
+        nsCString str;
+        p = DeserializeString(p, str);
+        *aDomValue = str;
+        return p;
+      }
+
+      default:
+        MOZ_CRASH();
+    }
+  }
 };
 
 #ifdef DEBUG
 const char*
 PrefTypeToString(PrefType aType)
 {
   switch (aType) {
     case PrefType::None:
@@ -689,16 +769,169 @@ public:
       }
       return true;
     }
 
     // Do not save default prefs that haven't changed.
     return false;
   }
 
+  // Prefs are serialized in a manner that mirrors dom::Pref. The two should be
+  // kept in sync. E.g. if something is added to one it should also be added to
+  // the other. (It would be nice to be able to use the code generated from
+  // IPDL for serializing dom::Pref here instead of writing by hand this
+  // serialization/deserialization. Unfortunately, that generated code is
+  // difficult to use directly, outside of the IPDL IPC code.)
+  //
+  // The grammar for the serialized prefs has the following form.
+  //
+  // <pref>         = <type> <locked> ':' <name> ':' <value>? ':' <value>? '\n'
+  // <type>         = 'B' | 'I' | 'S'
+  // <locked>       = 'L' | '-'
+  // <name>         = <string-value>
+  // <value>        = <bool-value> | <int-value> | <string-value>
+  // <bool-value>   = 'T' | 'F'
+  // <int-value>    = an integer literal accepted by strtol()
+  // <string-value> = <int-value> '/' <chars>
+  // <chars>        = any char sequence of length dictated by the preceding
+  //                  <int-value>.
+  //
+  // No whitespace is tolerated between tokens. <type> must match the types of
+  // the values.
+  //
+  // The serialization is text-based, rather than binary, for the following
+  // reasons.
+  //
+  // - The size difference wouldn't be much different between text-based and
+  //   binary. Most of the space is for strings (pref names and string pref
+  //   values), which would be the same in both styles. And other differences
+  //   would be minimal, e.g. small integers are shorter in text but long
+  //   integers are longer in text.
+  //
+  // - Likewise, speed differences should be negligible.
+  //
+  // - It's much easier to debug a text-based serialization. E.g. you can
+  //   print it and inspect it easily in a debugger.
+  //
+  // Examples of unlocked boolean prefs:
+  // - "B-:8/my.bool1:F:T\n"
+  // - "B-:8/my.bool2:F:\n"
+  // - "B-:8/my.bool3::T\n"
+  //
+  // Examples of locked integer prefs:
+  // - "IL:7/my.int1:0:1\n"
+  // - "IL:7/my.int2:123:\n"
+  // - "IL:7/my.int3::-99\n"
+  //
+  // Examples of unlocked string prefs:
+  // - "S-:10/my.string1:3/abc:4/wxyz\n"
+  // - "S-:10/my.string2:5/1.234:\n"
+  // - "S-:10/my.string3::7/string!\n"
+
+  void SerializeAndAppend(nsCString& aStr)
+  {
+    switch (Type()) {
+      case PrefType::Bool:
+        aStr.Append('B');
+        break;
+
+      case PrefType::Int:
+        aStr.Append('I');
+        break;
+
+      case PrefType::String: {
+        aStr.Append('S');
+        break;
+      }
+
+      case PrefType::None:
+      default:
+        MOZ_CRASH();
+    }
+
+    aStr.Append(mIsLocked ? 'L' : '-');
+    aStr.Append(':');
+
+    SerializeAndAppendString(mName, aStr);
+    aStr.Append(':');
+
+    if (mHasDefaultValue) {
+      mDefaultValue.SerializeAndAppend(Type(), aStr);
+    }
+    aStr.Append(':');
+
+    if (mHasUserValue) {
+      mUserValue.SerializeAndAppend(Type(), aStr);
+    }
+    aStr.Append('\n');
+  }
+
+  static char* Deserialize(char* aStr, dom::Pref* aDomPref)
+  {
+    char* p = aStr;
+
+    // The type.
+    PrefType type;
+    if (*p == 'B') {
+      type = PrefType::Bool;
+    } else if (*p == 'I') {
+      type = PrefType::Int;
+    } else if (*p == 'S') {
+      type = PrefType::String;
+    } else {
+      NS_ERROR("bad pref type");
+      type = PrefType::None;
+    }
+    p++; // move past the type char
+
+    // Locked?
+    bool isLocked;
+    if (*p == 'L') {
+      isLocked = true;
+    } else if (*p == '-') {
+      isLocked = false;
+    } else {
+      NS_ERROR("bad pref locked status");
+      isLocked = false;
+    }
+    p++; // move past the isLocked char
+
+    MOZ_ASSERT(*p == ':');
+    p++; // move past the ':'
+
+    // The pref name.
+    nsCString name;
+    p = DeserializeString(p, name);
+
+    MOZ_ASSERT(*p == ':');
+    p++; // move past the ':' preceding the default value
+
+    dom::MaybePrefValue maybeDefaultValue;
+    if (*p != ':') {
+      dom::PrefValue defaultValue;
+      p = PrefValue::Deserialize(type, p, &maybeDefaultValue);
+    }
+
+    MOZ_ASSERT(*p == ':');
+    p++; // move past the ':' between the default and user values
+
+    dom::MaybePrefValue maybeUserValue;
+    if (*p != '\n') {
+      dom::PrefValue userValue;
+      p = PrefValue::Deserialize(type, p, &maybeUserValue);
+    }
+
+    MOZ_ASSERT(*p == '\n');
+    p++; // move past the '\n' following the user value
+
+    *aDomPref = dom::Pref(name, isLocked, maybeDefaultValue, maybeUserValue);
+
+    return p;
+  }
+
   void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes)
   {
     // Note: mName is allocated in gPrefNameArena, measured elsewhere.
     aSizes.mPrefValues += aMallocSizeOf(this);
     if (IsTypeString()) {
       if (mHasDefaultValue) {
         aSizes.mStringValues += aMallocSizeOf(mDefaultValue.mStringVal);
       }
@@ -868,76 +1101,28 @@ pref_savePrefs()
     savedPrefs.AppendElement(str);
   }
 
   return savedPrefs;
 }
 
 #ifdef DEBUG
 
-// For content processes, what prefs have been initialized?
-enum class ContentProcessPhase
-{
-  eNoPrefsSet,
-  eEarlyPrefsSet,
-  eEarlyAndLatePrefsSet,
-};
-
 // Note that this never changes in the parent process, and is only read in
 // content processes.
-static ContentProcessPhase gPhase = ContentProcessPhase::eNoPrefsSet;
-
-struct StringComparator
-{
-  const char* mPrefName;
-
-  explicit StringComparator(const char* aPrefName)
-    : mPrefName(aPrefName)
-  {
-  }
-
-  int operator()(const char* aPrefName) const
-  {
-    return strcmp(mPrefName, aPrefName);
-  }
-};
-
-static bool
-IsEarlyPref(const char* aPrefName)
-{
-  size_t prefsLen;
-  size_t found;
-  const char** list = mozilla::dom::ContentPrefs::GetEarlyPrefs(&prefsLen);
-  return BinarySearchIf(list, 0, prefsLen, StringComparator(aPrefName), &found);
-}
+static bool gContentProcessPrefsAreInited = false;
 
 #endif // DEBUG
 
 static PrefEntry*
 pref_HashTableLookupInner(const char* aPrefName)
 {
   MOZ_ASSERT(NS_IsMainThread() || mozilla::ServoStyleSet::IsInServoTraversal());
 
-#ifdef DEBUG
-  if (!XRE_IsParentProcess()) {
-    if (gPhase == ContentProcessPhase::eNoPrefsSet) {
-      MOZ_CRASH_UNSAFE_PRINTF("accessing pref %s before early prefs are set",
-                              aPrefName);
-    }
-
-    if (gPhase == ContentProcessPhase::eEarlyPrefsSet &&
-        !IsEarlyPref(aPrefName)) {
-      // If you hit this crash, you have an early access of a non-early pref.
-      // Consider moving the access later or add the pref to the whitelist of
-      // early prefs in ContentPrefs.cpp and get review from a DOM peer.
-      MOZ_CRASH_UNSAFE_PRINTF(
-        "accessing non-early pref %s before late prefs are set", aPrefName);
-    }
-  }
-#endif
+  MOZ_ASSERT_IF(!XRE_IsParentProcess(), gContentProcessPrefsAreInited);
 
   return static_cast<PrefEntry*>(gHashTable->Search(aPrefName));
 }
 
 static Pref*
 pref_HashTableLookup(const char* aPrefName)
 {
   PrefEntry* entry = pref_HashTableLookupInner(aPrefName);
@@ -2915,18 +3100,18 @@ public:
   NS_IMETHOD Run() override
   {
     return RegisterStrongMemoryReporter(new PreferenceServiceReporter());
   }
 };
 
 } // namespace
 
-// A list of prefs sent early from the parent, via shared memory.
-static InfallibleTArray<dom::Pref>* gEarlyDomPrefs;
+// A list of changed prefs sent from the parent via shared memory.
+static InfallibleTArray<dom::Pref>* gChangedDomPrefs;
 
 /* static */ already_AddRefed<Preferences>
 Preferences::GetInstanceForService()
 {
   if (sPreferences) {
     return do_AddRef(sPreferences);
   }
 
@@ -2947,22 +3132,22 @@ Preferences::GetInstanceForService()
   Result<Ok, const char*> res = InitInitialObjects();
   if (res.isErr()) {
     sPreferences = nullptr;
     gCacheDataDesc = res.unwrapErr();
     return nullptr;
   }
 
   if (!XRE_IsParentProcess()) {
-    MOZ_ASSERT(gEarlyDomPrefs);
-    for (unsigned int i = 0; i < gEarlyDomPrefs->Length(); i++) {
-      Preferences::SetPreference(gEarlyDomPrefs->ElementAt(i));
+    MOZ_ASSERT(gChangedDomPrefs);
+    for (unsigned int i = 0; i < gChangedDomPrefs->Length(); i++) {
+      Preferences::SetPreference(gChangedDomPrefs->ElementAt(i));
     }
-    delete gEarlyDomPrefs;
-    gEarlyDomPrefs = nullptr;
+    delete gChangedDomPrefs;
+    gChangedDomPrefs = nullptr;
 
   } else {
     // Check if there is a deployment configuration file. If so, set up the
     // pref config machinery, which will actually read the file.
     nsAutoCString lockFileName;
     nsresult rv = Preferences::GetCString(
       "general.config.filename", lockFileName, PrefValueKind::User);
     if (NS_SUCCEEDED(rv)) {
@@ -3076,159 +3261,54 @@ Preferences::~Preferences()
 
 NS_IMPL_ISUPPORTS(Preferences,
                   nsIPrefService,
                   nsIObserver,
                   nsIPrefBranch,
                   nsISupportsWeakReference)
 
 /* static */ void
-Preferences::SerializeEarlyPreferences(nsCString& aStr)
+Preferences::SerializePreferences(nsCString& aStr)
 {
   MOZ_RELEASE_ASSERT(InitStaticMembers());
 
-  nsAutoCStringN<256> boolPrefs, intPrefs, stringPrefs;
-  size_t numEarlyPrefs;
-  dom::ContentPrefs::GetEarlyPrefs(&numEarlyPrefs);
-
-  for (unsigned int i = 0; i < numEarlyPrefs; i++) {
-    const char* prefName = dom::ContentPrefs::GetEarlyPref(i);
-    MOZ_ASSERT_IF(i > 0,
-                  strcmp(prefName, dom::ContentPrefs::GetEarlyPref(i - 1)) > 0);
-
-    Pref* pref = pref_HashTableLookup(prefName);
-    if (!pref || !pref->MustSendToContentProcesses()) {
-      continue;
-    }
-
-    switch (pref->Type()) {
-      case PrefType::Bool:
-        boolPrefs.Append(
-          nsPrintfCString("%u:%d|", i, Preferences::GetBool(prefName)));
-        break;
-      case PrefType::Int:
-        intPrefs.Append(
-          nsPrintfCString("%u:%d|", i, Preferences::GetInt(prefName)));
-        break;
-      case PrefType::String: {
-        nsAutoCString value;
-        Preferences::GetCString(prefName, value);
-        stringPrefs.Append(
-          nsPrintfCString("%u:%d;%s|", i, value.Length(), value.get()));
-      } break;
-      case PrefType::None:
-        break;
-      default:
-        printf_stderr("preference type: %d\n", int(pref->Type()));
-        MOZ_CRASH();
+  aStr.Truncate();
+
+  for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
+    Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
+    if (pref->MustSendToContentProcesses() && pref->HasAdvisablySizedValues()) {
+      pref->SerializeAndAppend(aStr);
     }
   }
 
-  aStr.Truncate();
-  aStr.Append(boolPrefs);
-  aStr.Append('\n');
-  aStr.Append(intPrefs);
-  aStr.Append('\n');
-  aStr.Append(stringPrefs);
-  aStr.Append('\n');
   aStr.Append('\0');
 }
 
 /* static */ void
-Preferences::DeserializeEarlyPreferences(char* aStr, size_t aStrLen)
+Preferences::DeserializePreferences(char* aStr, size_t aPrefsLen)
 {
   MOZ_ASSERT(!XRE_IsParentProcess());
 
-  MOZ_ASSERT(!gEarlyDomPrefs);
-  gEarlyDomPrefs = new InfallibleTArray<dom::Pref>();
+  MOZ_ASSERT(!gChangedDomPrefs);
+  gChangedDomPrefs = new InfallibleTArray<dom::Pref>();
 
   char* p = aStr;
-
-  // XXX: we assume these pref values are default values, which may not be
-  // true. We also assume they are unlocked. Fortunately, these prefs get reset
-  // properly by the first IPC message.
-
-  // Get the bool prefs.
-  while (*p != '\n') {
-    int32_t index = strtol(p, &p, 10);
-    MOZ_ASSERT(p[0] == ':');
-    p++;
-    int v = strtol(p, &p, 10);
-    MOZ_ASSERT(v == 0 || v == 1);
-    dom::MaybePrefValue value(dom::PrefValue(!!v));
-    MOZ_ASSERT(p[0] == '|');
-    p++;
-    dom::Pref pref(nsCString(dom::ContentPrefs::GetEarlyPref(index)),
-                   /* isLocked */ false,
-                   value,
-                   dom::MaybePrefValue());
-    gEarlyDomPrefs->AppendElement(pref);
+  while (*p != '\0') {
+    dom::Pref pref;
+    p = Pref::Deserialize(p, &pref);
+    gChangedDomPrefs->AppendElement(pref);
   }
-  p++;
-
-  // Get the int prefs.
-  while (*p != '\n') {
-    int32_t index = strtol(p, &p, 10);
-    MOZ_ASSERT(p[0] == ':');
-    p++;
-    dom::MaybePrefValue value(
-      dom::PrefValue(static_cast<int32_t>(strtol(p, &p, 10))));
-    MOZ_ASSERT(p[0] == '|');
-    p++;
-    dom::Pref pref(nsCString(dom::ContentPrefs::GetEarlyPref(index)),
-                   /* isLocked */ false,
-                   value,
-                   dom::MaybePrefValue());
-    gEarlyDomPrefs->AppendElement(pref);
-  }
-  p++;
-
-  // Get the string prefs.
-  while (*p != '\n') {
-    int32_t index = strtol(p, &p, 10);
-    MOZ_ASSERT(p[0] == ':');
-    p++;
-    int32_t length = strtol(p, &p, 10);
-    MOZ_ASSERT(p[0] == ';');
-    p++;
-    dom::MaybePrefValue value(dom::PrefValue(nsCString(p, length)));
-    dom::Pref pref(nsCString(dom::ContentPrefs::GetEarlyPref(index)),
-                   /* isLocked */ false,
-                   value,
-                   dom::MaybePrefValue());
-    gEarlyDomPrefs->AppendElement(pref);
-    p += length + 1;
-    MOZ_ASSERT(*(p - 1) == '|');
-  }
-  p++;
-
-  MOZ_ASSERT(*p == '\0');
 
   // We finished parsing on a '\0'. That should be the last char in the shared
-  // memory.
-  MOZ_ASSERT(aStr + aStrLen - 1 == p);
+  // memory. (aPrefsLen includes the '\0'.)
+  MOZ_ASSERT(p == aStr + aPrefsLen - 1);
 
 #ifdef DEBUG
-  MOZ_ASSERT(gPhase == ContentProcessPhase::eNoPrefsSet);
-  gPhase = ContentProcessPhase::eEarlyPrefsSet;
-#endif
-}
-
-/* static */ void
-Preferences::SetLatePreferences(const nsTArray<dom::Pref>* aDomPrefs)
-{
-  MOZ_ASSERT(!XRE_IsParentProcess());
-
-  for (unsigned int i = 0; i < aDomPrefs->Length(); i++) {
-    Preferences::SetPreference(aDomPrefs->ElementAt(i));
-  }
-
-#ifdef DEBUG
-  MOZ_ASSERT(gPhase == ContentProcessPhase::eEarlyPrefsSet);
-  gPhase = ContentProcessPhase::eEarlyAndLatePrefsSet;
+  MOZ_ASSERT(!gContentProcessPrefsAreInited);
+  gContentProcessPrefsAreInited = true;
 #endif
 }
 
 /* static */ void
 Preferences::InitializeUserPrefs()
 {
   MOZ_ASSERT(XRE_IsParentProcess());
   MOZ_ASSERT(!sPreferences->mCurrentFile, "Should only initialize prefs once");
@@ -3455,46 +3535,22 @@ Preferences::GetPreference(dom::Pref* aD
   MOZ_ASSERT(XRE_IsParentProcess());
 
   Pref* pref = pref_HashTableLookup(aDomPref->name().get());
   if (pref && pref->HasAdvisablySizedValues()) {
     pref->ToDomPref(aDomPref);
   }
 }
 
-void
-Preferences::GetPreferences(InfallibleTArray<dom::Pref>* aDomPrefs)
-{
-  MOZ_ASSERT(XRE_IsParentProcess());
-  MOZ_ASSERT(NS_IsMainThread());
-
-  aDomPrefs->SetCapacity(gHashTable->EntryCount());
-  for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
-    Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
-
-    if (!pref->MustSendToContentProcesses()) {
-      // The pref value hasn't changed since it was initialized at startup.
-      // Don't bother sending it, because the content process will initialize
-      // it the same way.
-      continue;
-    }
-
-    if (pref->HasAdvisablySizedValues()) {
-      dom::Pref* setting = aDomPrefs->AppendElement();
-      pref->ToDomPref(setting);
-    }
-  }
-}
-
 #ifdef DEBUG
 bool
-Preferences::AreAllPrefsSetInContentProcess()
+Preferences::ArePrefsInitedInContentProcess()
 {
   MOZ_ASSERT(!XRE_IsParentProcess());
-  return gPhase == ContentProcessPhase::eEarlyAndLatePrefsSet;
+  return gContentProcessPrefsAreInited;
 }
 #endif
 
 NS_IMETHODIMP
 Preferences::GetBranch(const char* aPrefRoot, nsIPrefBranch** aRetVal)
 {
   if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) {
     // TODO: Cache this stuff and allow consumers to share branches (hold weak
--- a/modules/libpref/Preferences.h
+++ b/modules/libpref/Preferences.h
@@ -323,33 +323,28 @@ public:
   template<MemoryOrdering Order>
   static nsresult AddAtomicUintVarCache(Atomic<uint32_t, Order>* aVariable,
                                         const char* aPref,
                                         uint32_t aDefault = 0);
   static nsresult AddFloatVarCache(float* aVariable,
                                    const char* aPref,
                                    float aDefault = 0.0f);
 
-  // When a content process is created these methods are used to pass prefs in
-  // bulk from the parent process. "Early" preferences are ones that are needed
-  // very early on in the content process's lifetime; they are passed via a
-  // special shared memory segment. "Late" preferences are the remainder, which
-  // are passed via a standard IPC message.
-  static void SerializeEarlyPreferences(nsCString& aStr);
-  static void DeserializeEarlyPreferences(char* aStr, size_t aStrLen);
-  static void GetPreferences(InfallibleTArray<dom::Pref>* aSettings);
-  static void SetLatePreferences(const nsTArray<dom::Pref>* aSettings);
+  // When a content process is created these methods are used to pass changed
+  // prefs in bulk from the parent process, via shared memory.
+  static void SerializePreferences(nsCString& aStr);
+  static void DeserializePreferences(char* aStr, size_t aPrefsLen);
 
   // When a single pref is changed in the parent process, these methods are
   // used to pass the update to content processes.
   static void GetPreference(dom::Pref* aPref);
   static void SetPreference(const dom::Pref& aPref);
 
 #ifdef DEBUG
-  static bool AreAllPrefsSetInContentProcess();
+  static bool ArePrefsInitedInContentProcess();
 #endif
 
   static void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                      PrefsSizes& aSizes);
 
   static void HandleDirty();
 
   // Explicitly choosing synchronous or asynchronous (if allowed) preferences