summaryrefslogtreecommitdiff
path: root/www/firefox/files/patch-bug1438678
diff options
context:
space:
mode:
Diffstat (limited to 'www/firefox/files/patch-bug1438678')
-rw-r--r--www/firefox/files/patch-bug14386781000
1 files changed, 1000 insertions, 0 deletions
diff --git a/www/firefox/files/patch-bug1438678 b/www/firefox/files/patch-bug1438678
new file mode 100644
index 000000000000..47e8dec9ad5b
--- /dev/null
+++ b/www/firefox/files/patch-bug1438678
@@ -0,0 +1,1000 @@
+commit 68124009fc5a
+Author: Nicholas Nethercote <nnethercote@mozilla.com>
+Date: Fri Feb 16 17:54:16 2018 +1100
+
+ Bug 1438678 - Pass early prefs via shared memory instead of the command line. r=bobowen,jld,glandium.
+
+ This patch replaces the large -intPrefs/-boolPrefs/-stringPrefs flags with
+ a short-lived, anonymous, shared memory segment that is used to pass the early
+ prefs.
+
+ Removing the bloat from the command line is nice, but more important is the
+ fact that this will let us pass more prefs at content process start-up, which
+ will allow us to remove the early/late prefs split (bug 1436911).
+
+ Although this mechanism is only used for prefs, it's conceivable that it could
+ be used for other data that must be received very early by children, and for
+ which the command line isn't ideal.
+
+ Notable details:
+
+ - Much of the patch deals with the various platform-specific ways of passing
+ handles/fds to children.
+
+ - Linux and Mac: we use a fixed fd (8) in combination with the new
+ GeckoChildProcessHost::AddFdToRemap() function (which ensures the child
+ won't close the fd).
+
+ - Android: like Linux and Mac, but the handles get passed via "parcels" and
+ we use the new SetPrefsFd() function instead of the fixed fd.
+
+ - Windows: there is no need to duplicate the handle because Windows handles
+ are system-wide. But we do use the new
+ GeckoChildProcessHost::AddHandleToShare() function to add it to the list of
+ inheritable handles. We also ensure that list is processed on all paths
+ (MOZ_SANDBOX with sandbox, MOZ_SANDBOX without sandbox, non-MOZ_SANDBOX) so
+ that the handles are marked as inheritable. The handle is passed via the
+ -prefsHandle flag.
+
+ The -prefsLen flag is used on all platforms to indicate the size of the
+ shared memory segment.
+
+ - The patch also moves the serialization/deserialization of the prefs in/out of
+ the shared memory into libpref, which is a better spot for it. (This means
+ Preferences::MustSendToContentProcesses() can be removed.)
+
+ MozReview-Commit-ID: 8fREEBiYFvc
+
+ --HG--
+ extra : rebase_source : 7e4c8ebdbcd7d74d6bd2ab3c9e75a6a17dbd8dfe
+---
+ dom/ipc/ContentParent.cpp | 91 +++++++-------
+ dom/ipc/ContentProcess.cpp | 121 ++++++++++---------
+ dom/ipc/ContentProcess.h | 5 +
+ ipc/chromium/src/base/process_util_win.cc | 4 +
+ ipc/glue/GeckoChildProcessHost.cpp | 36 +++---
+ ipc/glue/GeckoChildProcessHost.h | 10 ++
+ .../org/mozilla/gecko/process/IChildProcess.aidl | 3 +-
+ .../main/java/org/mozilla/gecko/GeckoThread.java | 13 +-
+ .../org/mozilla/gecko/mozglue/GeckoLoader.java | 2 +-
+ .../mozilla/gecko/process/GeckoProcessManager.java | 19 +--
+ .../gecko/process/GeckoServiceChildProcess.java | 4 +-
+ modules/libpref/Preferences.cpp | 134 +++++++++++++++++++--
+ modules/libpref/Preferences.h | 17 +--
+ mozglue/android/APKOpen.cpp | 4 +-
+ toolkit/xre/Bootstrap.cpp | 4 +-
+ toolkit/xre/Bootstrap.h | 2 +-
+ toolkit/xre/nsEmbedFunctions.cpp | 3 +-
+ widget/android/GeneratedJNIWrappers.cpp | 4 +-
+ widget/android/GeneratedJNIWrappers.h | 5 +-
+ xpcom/build/nsXULAppAPI.h | 2 +-
+ 20 files changed, 318 insertions(+), 165 deletions(-)
+
+diff --git dom/ipc/ContentParent.cpp dom/ipc/ContentParent.cpp
+index e27f3eedc1b1..60be7005354b 100644
+--- dom/ipc/ContentParent.cpp
++++ dom/ipc/ContentParent.cpp
+@@ -7,6 +7,7 @@
+ #include "mozilla/DebugOnly.h"
+
+ #include "base/basictypes.h"
++#include "base/shared_memory.h"
+
+ #include "ContentParent.h"
+ #include "TabParent.h"
+@@ -1998,61 +1999,56 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
+ extraArgs.push_back(idStr);
+ extraArgs.push_back(IsForBrowser() ? "-isForBrowser" : "-notForBrowser");
+
+- nsAutoCStringN<1024> boolPrefs;
+- nsAutoCStringN<1024> intPrefs;
+- nsAutoCStringN<1024> stringPrefs;
++ // Prefs information is passed via anonymous shared memory to avoid bloating
++ // the command line.
+
+- size_t prefsLen;
+- ContentPrefs::GetEarlyPrefs(&prefsLen);
++ // Serialize the early prefs.
++ nsAutoCStringN<1024> prefs;
++ Preferences::SerializeEarlyPreferences(prefs);
+
+- for (unsigned int i = 0; i < prefsLen; i++) {
+- const char* prefName = ContentPrefs::GetEarlyPref(i);
+- MOZ_ASSERT(i == 0 || strcmp(prefName, ContentPrefs::GetEarlyPref(i - 1)) > 0,
+- "Content process preferences should be sorted alphabetically.");
+-
+- if (!Preferences::MustSendToContentProcesses(prefName)) {
+- continue;
+- }
+-
+- switch (Preferences::GetType(prefName)) {
+- case nsIPrefBranch::PREF_INT:
+- intPrefs.Append(nsPrintfCString("%u:%d|", i, Preferences::GetInt(prefName)));
+- break;
+- case nsIPrefBranch::PREF_BOOL:
+- boolPrefs.Append(nsPrintfCString("%u:%d|", i, Preferences::GetBool(prefName)));
+- break;
+- case nsIPrefBranch::PREF_STRING: {
+- nsAutoCString value;
+- Preferences::GetCString(prefName, value);
+- stringPrefs.Append(nsPrintfCString("%u:%d;%s|", i, value.Length(), value.get()));
+- }
+- break;
+- case nsIPrefBranch::PREF_INVALID:
+- break;
+- default:
+- printf("preference type: %x\n", Preferences::GetType(prefName));
+- MOZ_CRASH();
+- }
++ // 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;
++ }
++ if (!shm.Map(prefs.Length())) {
++ NS_ERROR("failed to map shared memory in the parent");
++ MarkAsDead();
++ return false;
+ }
+
+- nsCString schedulerPrefs = Scheduler::GetPrefs();
++ // Copy the serialized prefs into the shared memory.
++ memcpy(static_cast<char*>(shm.memory()), prefs.get(), prefs.Length());
+
+- // Only do these ones if they're non-empty.
+- if (!intPrefs.IsEmpty()) {
+- extraArgs.push_back("-intPrefs");
+- extraArgs.push_back(intPrefs.get());
+- }
+- if (!boolPrefs.IsEmpty()) {
+- extraArgs.push_back("-boolPrefs");
+- extraArgs.push_back(boolPrefs.get());
+- }
+- if (!stringPrefs.IsEmpty()) {
+- extraArgs.push_back("-stringPrefs");
+- extraArgs.push_back(stringPrefs.get());
+- }
++#if defined(XP_WIN)
++ // Record the handle as to-be-shared, and pass it via a command flag. This
++ // works because Windows handles are system-wide.
++ HANDLE prefsHandle = shm.handle();
++ mSubprocess->AddHandleToShare(prefsHandle);
++ extraArgs.push_back("-prefsHandle");
++ extraArgs.push_back(
++ nsPrintfCString("%zu", reinterpret_cast<uintptr_t>(prefsHandle)).get());
++#else
++ // In contrast, Unix fds are per-process. So remap the fd to a fixed one that
++ // will be used in the child.
++ // XXX: bug 1440207 is about improving how fixed fds are used.
++ //
++ // Note: on Android, AddFdToRemap() sets up the fd to be passed via a Parcel,
++ // and the fixed fd isn't used. However, we still need to mark it for
++ // remapping so it doesn't get closed in the child.
++ mSubprocess->AddFdToRemap(shm.handle().fd, kPrefsFileDescriptor);
++#endif
++
++ // Pass the length via a command flag.
++ extraArgs.push_back("-prefsLen");
++ extraArgs.push_back(nsPrintfCString("%zu", uintptr_t(prefs.Length())).get());
+
+ // Scheduler prefs need to be handled differently because the scheduler needs
+ // to start up in the content process before the normal preferences service.
++ nsCString schedulerPrefs = Scheduler::GetPrefs();
+ extraArgs.push_back("-schedulerPrefs");
+ extraArgs.push_back(schedulerPrefs.get());
+
+@@ -2061,6 +2057,7 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
+ }
+
+ if (!mSubprocess->LaunchAndWaitForProcessHandle(extraArgs)) {
++ NS_ERROR("failed to launch child in the parent");
+ MarkAsDead();
+ return false;
+ }
+diff --git dom/ipc/ContentProcess.cpp dom/ipc/ContentProcess.cpp
+index e3c1f16910c6..2441c8cb9224 100644
+--- dom/ipc/ContentProcess.cpp
++++ dom/ipc/ContentProcess.cpp
+@@ -8,6 +8,8 @@
+
+ #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)
+@@ -15,7 +17,6 @@
+ #endif
+
+ #if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
+-#include "mozilla/Preferences.h"
+ #include "mozilla/SandboxSettings.h"
+ #include "nsAppDirectoryServiceDefs.h"
+ #include "nsDirectoryService.h"
+@@ -81,6 +82,16 @@ SetUpSandboxEnvironment()
+ }
+ #endif
+
++#ifdef ANDROID
++static int gPrefsFd = -1;
++
++void
++SetPrefsFd(int aFd)
++{
++ gPrefsFd = aFd;
++}
++#endif
++
+ bool
+ ContentProcess::Init(int aArgc, char* aArgv[])
+ {
+@@ -88,9 +99,10 @@ ContentProcess::Init(int aArgc, char* aArgv[])
+ bool foundAppdir = false;
+ bool foundChildID = false;
+ bool foundIsForBrowser = false;
+- bool foundIntPrefs = false;
+- bool foundBoolPrefs = false;
+- bool foundStringPrefs = false;
++#ifdef XP_WIN
++ bool foundPrefsHandle = false;
++#endif
++ bool foundPrefsLen = false;
+ bool foundSchedulerPrefs = false;
+
+ uint64_t childID;
+@@ -103,7 +115,8 @@ ContentProcess::Init(int aArgc, char* aArgv[])
+ #endif
+
+ char* schedulerPrefs = nullptr;
+- InfallibleTArray<Pref> prefsArray;
++ base::SharedMemoryHandle prefsHandle = base::SharedMemory::NULLHandle();
++ size_t prefsLen = 0;
+ for (int idx = aArgc; idx > 0; idx--) {
+ if (!aArgv[idx]) {
+ continue;
+@@ -134,54 +147,24 @@ ContentProcess::Init(int aArgc, char* aArgv[])
+ }
+ isForBrowser = strcmp(aArgv[idx], "-notForBrowser");
+ foundIsForBrowser = true;
+- } else if (!strcmp(aArgv[idx], "-intPrefs")) {
+- char* str = aArgv[idx + 1];
+- while (*str) {
+- int32_t index = strtol(str, &str, 10);
+- MOZ_ASSERT(str[0] == ':');
+- str++;
+- MaybePrefValue value(PrefValue(static_cast<int32_t>(strtol(str, &str, 10))));
+- MOZ_ASSERT(str[0] == '|');
+- str++;
+- // XXX: we assume these values as default values, which may not be
+- // true. We also assume they are unlocked. Fortunately, these prefs
+- // get reset properly by the first IPC message.
+- Pref pref(nsCString(ContentPrefs::GetEarlyPref(index)),
+- /* isLocked */ false, value, MaybePrefValue());
+- prefsArray.AppendElement(pref);
+- }
+- foundIntPrefs = true;
+- } else if (!strcmp(aArgv[idx], "-boolPrefs")) {
++#ifdef XP_WIN
++ } else if (!strcmp(aArgv[idx], "-prefsHandle")) {
+ char* str = aArgv[idx + 1];
+- while (*str) {
+- int32_t index = strtol(str, &str, 10);
+- MOZ_ASSERT(str[0] == ':');
+- str++;
+- MaybePrefValue value(PrefValue(!!strtol(str, &str, 10)));
+- MOZ_ASSERT(str[0] == '|');
+- str++;
+- Pref pref(nsCString(ContentPrefs::GetEarlyPref(index)),
+- /* isLocked */ false, value, MaybePrefValue());
+- prefsArray.AppendElement(pref);
+- }
+- foundBoolPrefs = true;
+- } else if (!strcmp(aArgv[idx], "-stringPrefs")) {
++ MOZ_ASSERT(str[0] != '\0');
++ // ContentParent uses %zu to print a word-sized unsigned integer. So even
++ // though strtoull() returns a long long int, it will fit in a uintptr_t.
++ prefsHandle = reinterpret_cast<HANDLE>(strtoull(str, &str, 10));
++ MOZ_ASSERT(str[0] == '\0');
++ foundPrefsHandle = true;
++#endif
++ } else if (!strcmp(aArgv[idx], "-prefsLen")) {
+ char* str = aArgv[idx + 1];
+- while (*str) {
+- int32_t index = strtol(str, &str, 10);
+- MOZ_ASSERT(str[0] == ':');
+- str++;
+- int32_t length = strtol(str, &str, 10);
+- MOZ_ASSERT(str[0] == ';');
+- str++;
+- MaybePrefValue value(PrefValue(nsCString(str, length)));
+- Pref pref(nsCString(ContentPrefs::GetEarlyPref(index)),
+- /* isLocked */ false, value, MaybePrefValue());
+- prefsArray.AppendElement(pref);
+- str += length + 1;
+- MOZ_ASSERT(*(str - 1) == '|');
+- }
+- foundStringPrefs = true;
++ MOZ_ASSERT(str[0] != '\0');
++ // ContentParent uses %zu to print a word-sized unsigned integer. So even
++ // though strtoull() returns a long long int, it will fit in a uintptr_t.
++ prefsLen = strtoull(str, &str, 10);
++ MOZ_ASSERT(str[0] == '\0');
++ foundPrefsLen = true;
+ } else if (!strcmp(aArgv[idx], "-schedulerPrefs")) {
+ schedulerPrefs = aArgv[idx + 1];
+ foundSchedulerPrefs = true;
+@@ -209,21 +192,43 @@ ContentProcess::Init(int aArgc, char* aArgv[])
+ bool allFound = foundAppdir
+ && foundChildID
+ && foundIsForBrowser
+- && foundIntPrefs
+- && foundBoolPrefs
+- && foundStringPrefs
+- && foundSchedulerPrefs;
+-
++ && foundPrefsLen
++ && foundSchedulerPrefs
++#ifdef XP_WIN
++ && foundPrefsHandle
++#endif
+ #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+- allFound &= foundProfile;
++ && foundProfile
+ #endif
++ && true;
+
+ if (allFound) {
+ break;
+ }
+ }
+
+- Preferences::SetEarlyPreferences(&prefsArray);
++#ifdef ANDROID
++ // Android is different; get the FD via gPrefsFd instead of a fixed fd.
++ MOZ_RELEASE_ASSERT(gPrefsFd != -1);
++ prefsHandle = base::FileDescriptor(gPrefsFd, /* auto_close */ true);
++#elif XP_UNIX
++ prefsHandle = base::FileDescriptor(kPrefsFileDescriptor,
++ /* auto_close */ true);
++#endif
++
++ // Set up early prefs from the shared memory.
++ base::SharedMemory shm;
++ 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);
++
+ Scheduler::SetPrefs(schedulerPrefs);
+ mContent.Init(IOThreadChild::message_loop(),
+ ParentPid(),
+diff --git dom/ipc/ContentProcess.h dom/ipc/ContentProcess.h
+index a3854c761e10..6582c94da496 100644
+--- dom/ipc/ContentProcess.h
++++ dom/ipc/ContentProcess.h
+@@ -49,6 +49,11 @@ private:
+ DISALLOW_EVIL_CONSTRUCTORS(ContentProcess);
+ };
+
++#ifdef ANDROID
++// Android doesn't use -prefsHandle, it gets that FD another way.
++void SetPrefsFd(int aFd);
++#endif
++
+ } // namespace dom
+ } // namespace mozilla
+
+diff --git ipc/chromium/src/base/process_util_win.cc ipc/chromium/src/base/process_util_win.cc
+index 3ed54cd744ac..46667985cd71 100644
+--- ipc/chromium/src/base/process_util_win.cc
++++ ipc/chromium/src/base/process_util_win.cc
+@@ -354,6 +354,10 @@ bool LaunchApp(const std::wstring& cmdline,
+ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = NULL;
+ std::vector<HANDLE> handlesToInherit;
+ for (HANDLE h : options.handles_to_inherit) {
++ if (SetHandleInformation(h, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) == 0) {
++ MOZ_DIAGNOSTIC_ASSERT(false, "SetHandleInformation failed");
++ return false;
++ }
+ handlesToInherit.push_back(h);
+ }
+
+diff --git ipc/glue/GeckoChildProcessHost.cpp ipc/glue/GeckoChildProcessHost.cpp
+index d18ed9edd4ca..3be1c51d10bb 100644
+--- ipc/glue/GeckoChildProcessHost.cpp
++++ ipc/glue/GeckoChildProcessHost.cpp
+@@ -1030,9 +1030,6 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
+
+ if (!CrashReporter::IsDummy()) {
+ PROsfd h = PR_FileDesc2NativeHandle(crashAnnotationWritePipe);
+-# if defined(MOZ_SANDBOX)
+- mSandboxBroker.AddHandleToShare(reinterpret_cast<HANDLE>(h));
+-# endif // defined(MOZ_SANDBOX)
+ mLaunchOptions->handles_to_inherit.push_back(reinterpret_cast<HANDLE>(h));
+ std::string hStr = std::to_string(h);
+ cmdLine.AppendLooseValue(UTF8ToWide(hStr));
+@@ -1043,6 +1040,11 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
+
+ # if defined(MOZ_SANDBOX)
+ if (shouldSandboxCurrentProcess) {
++ // Mark the handles to inherit as inheritable.
++ for (HANDLE h : mLaunchOptions->handles_to_inherit) {
++ mSandboxBroker.AddHandleToShare(h);
++ }
++
+ if (mSandboxBroker.LaunchApp(cmdLine.program().c_str(),
+ cmdLine.command_line_string().c_str(),
+ mLaunchOptions->env_map,
+@@ -1180,7 +1182,7 @@ GeckoChildProcessHost::LaunchAndroidService(const char* type,
+ const base::file_handle_mapping_vector& fds_to_remap,
+ ProcessHandle* process_handle)
+ {
+- MOZ_ASSERT((fds_to_remap.size() > 0) && (fds_to_remap.size() <= 3));
++ MOZ_RELEASE_ASSERT((2 <= fds_to_remap.size()) && (fds_to_remap.size() <= 4));
+ JNIEnv* const env = mozilla::jni::GetEnvForThread();
+ MOZ_ASSERT(env);
+
+@@ -1189,21 +1191,25 @@ GeckoChildProcessHost::LaunchAndroidService(const char* type,
+ for (int ix = 0; ix < argvSize; ix++) {
+ jargs->SetElement(ix, jni::StringParam(argv[ix].c_str(), env));
+ }
+- base::file_handle_mapping_vector::const_iterator it = fds_to_remap.begin();
+- int32_t ipcFd = it->first;
+- it++;
+- // If the Crash Reporter is disabled, there will not be a second file descriptor.
++
++ // XXX: this processing depends entirely on the internals of
++ // ContentParent::LaunchSubprocess()
++ // GeckoChildProcessHost::PerformAsyncLaunchInternal(), and the order in
++ // which they append to fds_to_remap. There must be a better way to do it.
++ // See bug 1440207.
++ int32_t prefsFd = fds_to_remap[0].first;
++ int32_t ipcFd = fds_to_remap[1].first;
+ int32_t crashFd = -1;
+ int32_t crashAnnotationFd = -1;
+- if (it != fds_to_remap.end() && !CrashReporter::IsDummy()) {
+- crashFd = it->first;
+- it++;
++ if (fds_to_remap.size() == 3) {
++ crashAnnotationFd = fds_to_remap[2].first;
+ }
+- if (it != fds_to_remap.end()) {
+- crashAnnotationFd = it->first;
+- it++;
++ if (fds_to_remap.size() == 4) {
++ crashFd = fds_to_remap[2].first;
++ crashAnnotationFd = fds_to_remap[3].first;
+ }
+- int32_t handle = java::GeckoProcessManager::Start(type, jargs, ipcFd, crashFd, crashAnnotationFd);
++
++ int32_t handle = java::GeckoProcessManager::Start(type, jargs, prefsFd, ipcFd, crashFd, crashAnnotationFd);
+
+ if (process_handle) {
+ *process_handle = handle;
+diff --git ipc/glue/GeckoChildProcessHost.h ipc/glue/GeckoChildProcessHost.h
+index 631c42066bc7..0345e221abcc 100644
+--- ipc/glue/GeckoChildProcessHost.h
++++ ipc/glue/GeckoChildProcessHost.h
+@@ -103,6 +103,16 @@ public:
+ }
+ #endif
+
++#ifdef XP_WIN
++ void AddHandleToShare(HANDLE aHandle) {
++ mLaunchOptions->handles_to_inherit.push_back(aHandle);
++ }
++#else
++ void AddFdToRemap(int aSrcFd, int aDstFd) {
++ mLaunchOptions->fds_to_remap.push_back(std::make_pair(aSrcFd, aDstFd));
++ }
++#endif
++
+ /**
+ * Must run on the IO thread. Cause the OS process to exit and
+ * ensure its OS resources are cleaned up.
+diff --git mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl
+index ba26ae1ba06b..a2535f44c72b 100644
+--- mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl
++++ mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl
+@@ -12,6 +12,7 @@ import android.os.ParcelFileDescriptor;
+ interface IChildProcess {
+ int getPid();
+ boolean start(in IProcessManager procMan, in String[] args, in Bundle extras,
+- in ParcelFileDescriptor ipcPfd, in ParcelFileDescriptor crashReporterPfd,
++ in ParcelFileDescriptor prefsPfd, in ParcelFileDescriptor ipcPfd,
++ in ParcelFileDescriptor crashReporterPfd,
+ in ParcelFileDescriptor crashAnnotationPfd);
+ }
+diff --git mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
+index dfabfd05daf0..8311920afeec 100644
+--- mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
++++ mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
+@@ -128,6 +128,7 @@ public class GeckoThread extends Thread {
+ public static final int FLAG_PRELOAD_CHILD = 2; // Preload child during main thread start.
+
+ private static final String EXTRA_ARGS = "args";
++ private static final String EXTRA_PREFS_FD = "prefsFd";
+ private static final String EXTRA_IPC_FD = "ipcFd";
+ private static final String EXTRA_CRASH_FD = "crashFd";
+ private static final String EXTRA_CRASH_ANNOTATION_FD = "crashAnnotationFd";
+@@ -149,7 +150,8 @@ public class GeckoThread extends Thread {
+
+ private synchronized boolean init(final GeckoProfile profile, final String[] args,
+ final Bundle extras, final int flags,
+- final int ipcFd, final int crashFd,
++ final int prefsFd, final int ipcFd,
++ final int crashFd,
+ final int crashAnnotationFd) {
+ ThreadUtils.assertOnUiThread();
+ uiThreadId = android.os.Process.myTid();
+@@ -163,6 +165,7 @@ public class GeckoThread extends Thread {
+ mFlags = flags;
+
+ mExtras = (extras != null) ? new Bundle(extras) : new Bundle(3);
++ mExtras.putInt(EXTRA_PREFS_FD, prefsFd);
+ mExtras.putInt(EXTRA_IPC_FD, ipcFd);
+ mExtras.putInt(EXTRA_CRASH_FD, crashFd);
+ mExtras.putInt(EXTRA_CRASH_ANNOTATION_FD, crashAnnotationFd);
+@@ -174,15 +177,16 @@ public class GeckoThread extends Thread {
+
+ public static boolean initMainProcess(final GeckoProfile profile, final String[] args,
+ final Bundle extras, final int flags) {
+- return INSTANCE.init(profile, args, extras, flags,
++ return INSTANCE.init(profile, args, extras, flags, /* fd */ -1,
+ /* fd */ -1, /* fd */ -1, /* fd */ -1);
+ }
+
+ public static boolean initChildProcess(final String[] args, final Bundle extras,
+- final int ipcFd, final int crashFd,
++ final int prefsFd, final int ipcFd,
++ final int crashFd,
+ final int crashAnnotationFd) {
+ return INSTANCE.init(/* profile */ null, args, extras, /* flags */ 0,
+- ipcFd, crashFd, crashAnnotationFd);
++ prefsFd, ipcFd, crashFd, crashAnnotationFd);
+ }
+
+ private static boolean canUseProfile(final Context context, final GeckoProfile profile,
+@@ -442,6 +446,7 @@ public class GeckoThread extends Thread {
+
+ // And go.
+ GeckoLoader.nativeRun(args,
++ mExtras.getInt(EXTRA_PREFS_FD, -1),
+ mExtras.getInt(EXTRA_IPC_FD, -1),
+ mExtras.getInt(EXTRA_CRASH_FD, -1),
+ mExtras.getInt(EXTRA_CRASH_ANNOTATION_FD, -1));
+diff --git mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java
+index b1830fd86945..ac128b651e7b 100644
+--- mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java
++++ mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java
+@@ -463,7 +463,7 @@ public final class GeckoLoader {
+ public static native boolean verifyCRCs(String apkName);
+
+ // These methods are implemented in mozglue/android/APKOpen.cpp
+- public static native void nativeRun(String[] args, int ipcFd, int crashFd, int crashAnnotationFd);
++ public static native void nativeRun(String[] args, int prefsFd, int ipcFd, int crashFd, int crashAnnotationFd);
+ private static native void loadGeckoLibsNative(String apkName);
+ private static native void loadSQLiteLibsNative(String apkName);
+ private static native void loadNSSLibsNative(String apkName);
+diff --git mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java
+index b762e1c9a3eb..dba329ba8f92 100644
+--- mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java
++++ mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java
+@@ -169,14 +169,14 @@ public final class GeckoProcessManager extends IProcessManager.Stub {
+
+ @WrapForJNI
+ private static int start(final String type, final String[] args,
+- final int ipcFd, final int crashFd,
+- final int crashAnnotationFd) {
+- return INSTANCE.start(type, args, ipcFd, crashFd, crashAnnotationFd, /* retry */ false);
++ final int prefsFd, final int ipcFd,
++ final int crashFd, final int crashAnnotationFd) {
++ return INSTANCE.start(type, args, prefsFd, ipcFd, crashFd, crashAnnotationFd, /* retry */ false);
+ }
+
+- private int start(final String type, final String[] args, final int ipcFd,
+- final int crashFd, final int crashAnnotationFd,
+- final boolean retry) {
++ private int start(final String type, final String[] args, final int prefsFd,
++ final int ipcFd, final int crashFd,
++ final int crashAnnotationFd, final boolean retry) {
+ final ChildConnection connection = getConnection(type);
+ final IChildProcess child = connection.bind();
+ if (child == null) {
+@@ -184,10 +184,12 @@ public final class GeckoProcessManager extends IProcessManager.Stub {
+ }
+
+ final Bundle extras = GeckoThread.getActiveExtras();
++ final ParcelFileDescriptor prefsPfd;
+ final ParcelFileDescriptor ipcPfd;
+ final ParcelFileDescriptor crashPfd;
+ final ParcelFileDescriptor crashAnnotationPfd;
+ try {
++ prefsPfd = ParcelFileDescriptor.fromFd(prefsFd);
+ ipcPfd = ParcelFileDescriptor.fromFd(ipcFd);
+ crashPfd = (crashFd >= 0) ? ParcelFileDescriptor.fromFd(crashFd) : null;
+ crashAnnotationPfd = (crashAnnotationFd >= 0) ? ParcelFileDescriptor.fromFd(crashAnnotationFd) : null;
+@@ -198,7 +200,8 @@ public final class GeckoProcessManager extends IProcessManager.Stub {
+
+ boolean started = false;
+ try {
+- started = child.start(this, args, extras, ipcPfd, crashPfd, crashAnnotationPfd);
++ started = child.start(this, args, extras, prefsPfd, ipcPfd, crashPfd,
++ crashAnnotationPfd);
+ } catch (final RemoteException e) {
+ }
+
+@@ -209,7 +212,7 @@ public final class GeckoProcessManager extends IProcessManager.Stub {
+ }
+ Log.w(LOGTAG, "Attempting to kill running child " + type);
+ connection.unbind();
+- return start(type, args, ipcFd, crashFd, crashAnnotationFd, /* retry */ true);
++ return start(type, args, prefsFd, ipcFd, crashFd, crashAnnotationFd, /* retry */ true);
+ }
+
+ try {
+diff --git mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java
+index f1f6ce109fda..6dc19813fc10 100644
+--- mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java
++++ mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java
+@@ -63,6 +63,7 @@ public class GeckoServiceChildProcess extends Service {
+ public boolean start(final IProcessManager procMan,
+ final String[] args,
+ final Bundle extras,
++ final ParcelFileDescriptor prefsPfd,
+ final ParcelFileDescriptor ipcPfd,
+ final ParcelFileDescriptor crashReporterPfd,
+ final ParcelFileDescriptor crashAnnotationPfd) {
+@@ -74,6 +75,7 @@ public class GeckoServiceChildProcess extends Service {
+ sProcessManager = procMan;
+ }
+
++ final int prefsFd = prefsPfd.detachFd();
+ final int ipcFd = ipcPfd.detachFd();
+ final int crashReporterFd = crashReporterPfd != null ?
+ crashReporterPfd.detachFd() : -1;
+@@ -83,7 +85,7 @@ public class GeckoServiceChildProcess extends Service {
+ ThreadUtils.postToUiThread(new Runnable() {
+ @Override
+ public void run() {
+- if (GeckoThread.initChildProcess(args, extras, ipcFd, crashReporterFd,
++ if (GeckoThread.initChildProcess(args, extras, prefsFd, ipcFd, crashReporterFd,
+ crashAnnotationFd)) {
+ GeckoThread.launch();
+ }
+diff --git modules/libpref/Preferences.cpp modules/libpref/Preferences.cpp
+index 330ed4a09b54..b884591c9271 100644
+--- modules/libpref/Preferences.cpp
++++ modules/libpref/Preferences.cpp
+@@ -2920,7 +2920,7 @@ public:
+
+ } // namespace
+
+-// A list of prefs sent early from the parent, via the command line.
++// A list of prefs sent early from the parent, via shared memory.
+ static InfallibleTArray<dom::Pref>* gEarlyDomPrefs;
+
+ /* static */ already_AddRefed<Preferences>
+@@ -3081,11 +3081,130 @@ NS_IMPL_ISUPPORTS(Preferences,
+ nsISupportsWeakReference)
+
+ /* static */ void
+-Preferences::SetEarlyPreferences(const nsTArray<dom::Pref>* aDomPrefs)
++Preferences::SerializeEarlyPreferences(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();
++ 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)
+ {
+ MOZ_ASSERT(!XRE_IsParentProcess());
+
+- gEarlyDomPrefs = new InfallibleTArray<dom::Pref>(mozilla::Move(*aDomPrefs));
++ MOZ_ASSERT(!gEarlyDomPrefs);
++ gEarlyDomPrefs = 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);
++ }
++ 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);
+
+ #ifdef DEBUG
+ MOZ_ASSERT(gPhase == ContentProcessPhase::eNoPrefsSet);
+@@ -4298,15 +4417,6 @@ Preferences::HasUserValue(const char* aPrefName)
+ return pref && pref->HasUserValue();
+ }
+
+-/* static */ bool
+-Preferences::MustSendToContentProcesses(const char* aPrefName)
+-{
+- NS_ENSURE_TRUE(InitStaticMembers(), false);
+-
+- Pref* pref = pref_HashTableLookup(aPrefName);
+- return pref && pref->MustSendToContentProcesses();
+-}
+-
+ /* static */ int32_t
+ Preferences::GetType(const char* aPrefName)
+ {
+diff --git modules/libpref/Preferences.h modules/libpref/Preferences.h
+index 1cb825ecbfe5..c149db62b525 100644
+--- modules/libpref/Preferences.h
++++ modules/libpref/Preferences.h
+@@ -41,6 +41,11 @@ class PrefValue;
+
+ struct PrefsSizes;
+
++#ifdef XP_UNIX
++// XXX: bug 1440207 is about improving how fixed fds such as this are used.
++static const int kPrefsFileDescriptor = 8;
++#endif
++
+ // Keep this in sync with PrefType in parser/src/lib.rs.
+ enum class PrefValueKind : uint8_t
+ {
+@@ -230,9 +235,6 @@ public:
+ // Whether the pref has a user value or not.
+ static bool HasUserValue(const char* aPref);
+
+- // Must the pref be sent to content processes when they start?
+- static bool MustSendToContentProcesses(const char* aPref);
+-
+ // Adds/Removes the observer for the root pref branch. See nsIPrefBranch.idl
+ // for details.
+ static nsresult AddStrongObserver(nsIObserver* aObserver, const char* aPref);
+@@ -328,11 +330,12 @@ public:
+
+ // 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 the
+- // command line. "Late" preferences are the remainder, which are passed via
+- // IPC message.
++ // 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 SetEarlyPreferences(const nsTArray<dom::Pref>* aSettings);
+ static void SetLatePreferences(const nsTArray<dom::Pref>* aSettings);
+
+ // When a single pref is changed in the parent process, these methods are
+diff --git mozglue/android/APKOpen.cpp mozglue/android/APKOpen.cpp
+index 5f1ef55b605e..b57192488725 100644
+--- mozglue/android/APKOpen.cpp
++++ mozglue/android/APKOpen.cpp
+@@ -392,7 +392,7 @@ FreeArgv(char** argv, int argc)
+ }
+
+ extern "C" APKOPEN_EXPORT void MOZ_JNICALL
+-Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jobjectArray jargs, int ipcFd, int crashFd, int crashAnnotationFd)
++Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jobjectArray jargs, int prefsFd, int ipcFd, int crashFd, int crashAnnotationFd)
+ {
+ int argc = 0;
+ char** argv = CreateArgvFromObjectArray(jenv, jargs, &argc);
+@@ -407,7 +407,7 @@ Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jo
+ gBootstrap->GeckoStart(jenv, argv, argc, sAppData);
+ ElfLoader::Singleton.ExpectShutdown(true);
+ } else {
+- gBootstrap->XRE_SetAndroidChildFds(jenv, ipcFd, crashFd, crashAnnotationFd);
++ gBootstrap->XRE_SetAndroidChildFds(jenv, prefsFd, ipcFd, crashFd, crashAnnotationFd);
+ gBootstrap->XRE_SetProcessType(argv[argc - 1]);
+
+ XREChildData childData;
+diff --git toolkit/xre/Bootstrap.cpp toolkit/xre/Bootstrap.cpp
+index 5688519822a9..7e857969a4fb 100644
+--- toolkit/xre/Bootstrap.cpp
++++ toolkit/xre/Bootstrap.cpp
+@@ -78,8 +78,8 @@ public:
+ ::GeckoStart(aEnv, argv, argc, aAppData);
+ }
+
+- virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aIPCFd, int aCrashFd, int aCrashAnnotationFd) override {
+- ::XRE_SetAndroidChildFds(aEnv, aIPCFd, aCrashFd, aCrashAnnotationFd);
++ virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aPrefsFd, int aIPCFd, int aCrashFd, int aCrashAnnotationFd) override {
++ ::XRE_SetAndroidChildFds(aEnv, aPrefsFd, aIPCFd, aCrashFd, aCrashAnnotationFd);
+ }
+ #endif
+
+diff --git toolkit/xre/Bootstrap.h toolkit/xre/Bootstrap.h
+index 686d0a38e324..77adcef80e1f 100644
+--- toolkit/xre/Bootstrap.h
++++ toolkit/xre/Bootstrap.h
+@@ -113,7 +113,7 @@ public:
+ #ifdef MOZ_WIDGET_ANDROID
+ virtual void GeckoStart(JNIEnv* aEnv, char** argv, int argc, const StaticXREAppData& aAppData) = 0;
+
+- virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aIPCFd, int aCrashFd, int aCrashAnnotationFd) = 0;
++ virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aPrefsFd, int aIPCFd, int aCrashFd, int aCrashAnnotationFd) = 0;
+ #endif
+
+ #ifdef LIBFUZZER
+diff --git toolkit/xre/nsEmbedFunctions.cpp toolkit/xre/nsEmbedFunctions.cpp
+index 53bd2bc2eb47..83184e97ba92 100644
+--- toolkit/xre/nsEmbedFunctions.cpp
++++ toolkit/xre/nsEmbedFunctions.cpp
+@@ -243,9 +243,10 @@ GeckoProcessType sChildProcessType = GeckoProcessType_Default;
+
+ #if defined(MOZ_WIDGET_ANDROID)
+ void
+-XRE_SetAndroidChildFds (JNIEnv* env, int ipcFd, int crashFd, int crashAnnotationFd)
++XRE_SetAndroidChildFds (JNIEnv* env, int prefsFd, int ipcFd, int crashFd, int crashAnnotationFd)
+ {
+ mozilla::jni::SetGeckoThreadEnv(env);
++ mozilla::dom::SetPrefsFd(prefsFd);
+ IPC::Channel::SetClientChannelFd(ipcFd);
+ CrashReporter::SetNotificationPipeForChild(crashFd);
+ CrashReporter::SetCrashAnnotationPipeForChild(crashAnnotationFd);
+diff --git widget/android/GeneratedJNIWrappers.cpp widget/android/GeneratedJNIWrappers.cpp
+index e3f6af0cc575..4165df59f0e8 100644
+--- widget/android/GeneratedJNIWrappers.cpp
++++ widget/android/GeneratedJNIWrappers.cpp
+@@ -2355,9 +2355,9 @@ constexpr char GeckoProcessManager::GetEditableParent_t::signature[];
+ constexpr char GeckoProcessManager::Start_t::name[];
+ constexpr char GeckoProcessManager::Start_t::signature[];
+
+-auto GeckoProcessManager::Start(mozilla::jni::String::Param a0, mozilla::jni::ObjectArray::Param a1, int32_t a2, int32_t a3, int32_t a4) -> int32_t
++auto GeckoProcessManager::Start(mozilla::jni::String::Param a0, mozilla::jni::ObjectArray::Param a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5) -> int32_t
+ {
+- return mozilla::jni::Method<Start_t>::Call(GeckoProcessManager::Context(), nullptr, a0, a1, a2, a3, a4);
++ return mozilla::jni::Method<Start_t>::Call(GeckoProcessManager::Context(), nullptr, a0, a1, a2, a3, a4, a5);
+ }
+
+ const char GeckoServiceChildProcess::name[] =
+diff --git widget/android/GeneratedJNIWrappers.h widget/android/GeneratedJNIWrappers.h
+index ece79ac94a71..228affa1e550 100644
+--- widget/android/GeneratedJNIWrappers.h
++++ widget/android/GeneratedJNIWrappers.h
+@@ -6696,10 +6696,11 @@ public:
+ mozilla::jni::ObjectArray::Param,
+ int32_t,
+ int32_t,
++ int32_t,
+ int32_t> Args;
+ static constexpr char name[] = "start";
+ static constexpr char signature[] =
+- "(Ljava/lang/String;[Ljava/lang/String;III)I";
++ "(Ljava/lang/String;[Ljava/lang/String;IIII)I";
+ static const bool isStatic = true;
+ static const mozilla::jni::ExceptionMode exceptionMode =
+ mozilla::jni::ExceptionMode::ABORT;
+@@ -6709,7 +6710,7 @@ public:
+ mozilla::jni::DispatchTarget::CURRENT;
+ };
+
+- static auto Start(mozilla::jni::String::Param, mozilla::jni::ObjectArray::Param, int32_t, int32_t, int32_t) -> int32_t;
++ static auto Start(mozilla::jni::String::Param, mozilla::jni::ObjectArray::Param, int32_t, int32_t, int32_t, int32_t) -> int32_t;
+
+ static const mozilla::jni::CallingThread callingThread =
+ mozilla::jni::CallingThread::ANY;
+diff --git xpcom/build/nsXULAppAPI.h xpcom/build/nsXULAppAPI.h
+index 94f6daf864c9..d6ac10d51d76 100644
+--- xpcom/build/nsXULAppAPI.h
++++ xpcom/build/nsXULAppAPI.h
+@@ -398,7 +398,7 @@ XRE_API(const char*,
+
+ #if defined(MOZ_WIDGET_ANDROID)
+ XRE_API(void,
+- XRE_SetAndroidChildFds, (JNIEnv* env, int ipcFd, int crashFd, int crashAnnotationFd))
++ XRE_SetAndroidChildFds, (JNIEnv* env, int prefsFd, int ipcFd, int crashFd, int crashAnnotationFd))
+ #endif // defined(MOZ_WIDGET_ANDROID)
+
+ XRE_API(void,