--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2,16 +2,17 @@
/* 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/DebugOnly.h"
#include "base/basictypes.h"
+#include "base/shared_memory.h"
#include "ContentParent.h"
#include "TabParent.h"
#if defined(ANDROID) || defined(LINUX)
# include <sys/time.h>
# include <sys/resource.h>
#endif
@@ -1992,79 +1993,75 @@ ContentParent::LaunchSubprocess(ProcessP
std::vector<std::string> extraArgs;
extraArgs.push_back("-childID");
char idStr[21];
SprintfLiteral(idStr, "%" PRId64, static_cast<uint64_t>(mChildID));
extraArgs.push_back(idStr);
extraArgs.push_back(IsForBrowser() ? "-isForBrowser" : "-notForBrowser");
- nsAutoCStringN<1024> boolPrefs;
- nsAutoCStringN<1024> intPrefs;
- nsAutoCStringN<1024> stringPrefs;
-
- size_t prefsLen;
- ContentPrefs::GetEarlyPrefs(&prefsLen);
-
- for (unsigned int i = 0; i < prefsLen; i++) {
- const char* prefName = ContentPrefs::GetEarlyPref(i);
- MOZ_ASSERT_IF(i > 0,
- strcmp(prefName, ContentPrefs::GetEarlyPref(i - 1)) > 0);
-
- 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();
- }
- }
-
- nsCString schedulerPrefs = Scheduler::GetPrefs();
-
- // 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());
- }
+ // Prefs information is passed via anonymous shared memory to avoid bloating
+ // the command line.
+
+ // Serialize the early prefs.
+ nsAutoCStringN<1024> prefs;
+ Preferences::SerializeEarlyPreferences(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;
+ }
+ if (!shm.Map(prefs.Length())) {
+ NS_ERROR("failed to map shared memory in the parent");
+ MarkAsDead();
+ return false;
+ }
+
+ // Copy the serialized prefs into the shared memory.
+ memcpy(static_cast<char*>(shm.memory()), prefs.get(), prefs.Length());
+
+#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());
if (gSafeMode) {
extraArgs.push_back("-safeMode");
}
if (!mSubprocess->LaunchAndWaitForProcessHandle(extraArgs)) {
+ NS_ERROR("failed to launch child in the parent");
MarkAsDead();
return false;
}
base::ProcessId procId = base::GetProcId(mSubprocess->GetChildProcessHandle());
Open(mSubprocess->GetChannel(), procId);
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -3,24 +3,25 @@
/* 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
#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"
#include "nsDirectoryServiceDefs.h"
#endif
using mozilla::ipc::IOThreadChild;
@@ -76,39 +77,51 @@ SetUpSandboxEnvironment()
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
SetTmpEnvironmentVariable(sandboxedContentTemp);
}
#endif
+#ifdef ANDROID
+static int gPrefsFd = -1;
+
+void
+SetPrefsFd(int aFd)
+{
+ gPrefsFd = aFd;
+}
+#endif
+
bool
ContentProcess::Init(int aArgc, char* aArgv[])
{
// If passed in grab the application path for xpcom init
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;
bool isForBrowser;
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
// If passed in grab the profile path for sandboxing
bool foundProfile = false;
nsCOMPtr<nsIFile> profileDir;
#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;
}
if (!strcmp(aArgv[idx], "-appdir")) {
MOZ_ASSERT(!foundAppdir);
if (foundAppdir) {
@@ -129,64 +142,34 @@ ContentProcess::Init(int aArgc, char* aA
}
} else if (!strcmp(aArgv[idx], "-isForBrowser") || !strcmp(aArgv[idx], "-notForBrowser")) {
MOZ_ASSERT(!foundIsForBrowser);
if (foundIsForBrowser) {
continue;
}
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;
} else if (!strcmp(aArgv[idx], "-safeMode")) {
gSafeMode = true;
}
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
@@ -204,31 +187,53 @@ ContentProcess::Init(int aArgc, char* aA
}
foundProfile = true;
}
#endif /* XP_MACOSX && MOZ_CONTENT_SANDBOX */
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(),
IOThreadChild::channel(),
childID,
isForBrowser);
mXREEmbed.Start();
#if (defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
--- a/dom/ipc/ContentProcess.h
+++ b/dom/ipc/ContentProcess.h
@@ -44,12 +44,17 @@ private:
#if defined(XP_WIN)
// This object initializes and configures COM.
mozilla::mscom::MainThreadRuntime mCOMRuntime;
#endif
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
#endif // ifndef dom_tabs_ContentThread_h
--- a/ipc/chromium/src/base/process_util_win.cc
+++ b/ipc/chromium/src/base/process_util_win.cc
@@ -349,16 +349,20 @@ bool LaunchApp(const std::wstring& cmdli
startup_info.dwFlags = STARTF_USESHOWWINDOW;
startup_info.wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW;
// Per the comment in CreateThreadAttributeList, lpAttributeList will contain
// a pointer to handlesToInherit, so make sure they have the same lifetime.
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);
}
// setup our handle array first - if we end up with no handles that can
// be inherited we can avoid trying to do the ThreadAttributeList dance...
HANDLE stdOut = ::GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE stdErr = ::GetStdHandle(STD_ERROR_HANDLE);
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -1025,29 +1025,31 @@ GeckoChildProcessHost::PerformAsyncLaunc
// Process id
cmdLine.AppendLooseValue(UTF8ToWide(pidstring));
cmdLine.AppendLooseValue(
UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
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));
}
// Process type
cmdLine.AppendLooseValue(UTF8ToWide(childProcessType));
# 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,
mProcessType,
mEnableSandboxLogging,
&process)) {
EnvironmentLog("MOZ_PROCESS_LOG").print(
"==> process %d launched child process %d (%S)\n",
@@ -1175,38 +1177,42 @@ bool GeckoChildProcessHost::sRunSelfAsCo
#ifdef MOZ_WIDGET_ANDROID
void
GeckoChildProcessHost::LaunchAndroidService(const char* type,
const std::vector<std::string>& argv,
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);
const int argvSize = argv.size();
jni::ObjectArray::LocalRef jargs = jni::ObjectArray::New<jni::String>(argvSize);
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, crashFd, ipcFd, crashAnnotationFd);
+
+ int32_t handle = java::GeckoProcessManager::Start(type, jargs, prefsFd, ipcFd, crashFd, crashAnnotationFd);
if (process_handle) {
*process_handle = handle;
}
}
#endif
--- a/ipc/glue/GeckoChildProcessHost.h
+++ b/ipc/glue/GeckoChildProcessHost.h
@@ -98,16 +98,26 @@ public:
}
#ifdef XP_MACOSX
task_t GetChildTask() {
return mChildTask;
}
#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.
*/
void Join();
// For bug 943174: Skip the EnsureProcessTerminated call in the destructor.
void SetAlreadyDead();
--- a/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl
+++ b/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl
@@ -5,10 +5,10 @@
package org.mozilla.gecko.process;
import org.mozilla.gecko.process.IProcessManager;
import android.os.ParcelFileDescriptor;
interface IChildProcess {
int getPid();
- boolean start(in IProcessManager procMan, in String[] args, in ParcelFileDescriptor crashReporterPfd, in ParcelFileDescriptor ipcPfd, in ParcelFileDescriptor crashAnnotationPfd);
+ boolean start(in IProcessManager procMan, in String[] args, in ParcelFileDescriptor prefsPfd, in ParcelFileDescriptor ipcPfd, in ParcelFileDescriptor crashReporterPfd, in ParcelFileDescriptor crashAnnotationPfd);
}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
@@ -127,65 +127,71 @@ public class GeckoThread extends Thread
public static final int FLAG_DEBUGGING = 1; // Debugging mode.
public static final int FLAG_PRELOAD_CHILD = 2; // Preload child during main thread start.
private GeckoProfile mProfile;
private String mExtraArgs;
private int mFlags;
// Child process parameters
+ private int mPrefsFileDescriptor = -1;
+ private int mIPCFileDescriptor = -1;
private int mCrashFileDescriptor = -1;
- private int mIPCFileDescriptor = -1;
private int mCrashAnnotationFileDescriptor = -1;
GeckoThread() {
setName("Gecko");
}
@WrapForJNI
private static boolean isChildProcess() {
return INSTANCE.mIPCFileDescriptor != -1;
}
private synchronized boolean init(final GeckoProfile profile, final String[] args,
final String extraArgs, final int flags,
- final int crashFd, final int ipcFd,
+ final int prefsFd, final int ipcFd,
+ final int crashFd,
final int crashAnnotationFd) {
ThreadUtils.assertOnUiThread();
uiThreadId = android.os.Process.myTid();
if (mInitialized) {
return false;
}
mProfile = profile;
mArgs = args;
mExtraArgs = extraArgs;
mFlags = flags;
+ mPrefsFileDescriptor = prefsFd;
+ mIPCFileDescriptor = ipcFd;
mCrashFileDescriptor = crashFd;
- mIPCFileDescriptor = ipcFd;
mCrashAnnotationFileDescriptor = crashAnnotationFd;
mInitialized = true;
notifyAll();
return true;
}
public static boolean initMainProcess(final GeckoProfile profile, final String extraArgs,
final int flags) {
return INSTANCE.init(profile, /* args */ null, extraArgs, flags,
- /* crashFd */ -1, /* ipcFd */ -1,
- /* crashAnnotationFd */ -1);
+ /* prefsFd */ -1, /* ipcFd */ -1,
+ /* crashFd */ -1, /* crashAnnotationFd */ -1);
}
- public static boolean initChildProcess(final String[] args, final int crashFd,
+ public static boolean initChildProcess(final String[] args,
+ final int prefsFd,
final int ipcFd,
+ final int crashFd,
final int crashAnnotationFd) {
return INSTANCE.init(/* profile */ null, args, /* extraArgs */ null,
- /* flags */ 0, crashFd, ipcFd, crashAnnotationFd);
+ /* flags */ 0, prefsFd, ipcFd, crashFd,
+ crashAnnotationFd);
}
private static boolean canUseProfile(final Context context, final GeckoProfile profile,
final String profileName, final File profileDir) {
if (profileDir != null && !profileDir.isDirectory()) {
return false;
}
@@ -417,17 +423,19 @@ public class GeckoThread extends Thread
Log.w(LOGTAG, "zerdatime " + SystemClock.elapsedRealtime() + " - runGecko");
if ((mFlags & FLAG_DEBUGGING) != 0) {
Log.i(LOGTAG, "RunGecko - args = " + TextUtils.join(" ", args));
}
// And go.
- GeckoLoader.nativeRun(args, mCrashFileDescriptor, mIPCFileDescriptor, mCrashAnnotationFileDescriptor);
+ GeckoLoader.nativeRun(args, mPrefsFileDescriptor, mIPCFileDescriptor,
+ mCrashFileDescriptor,
+ mCrashAnnotationFileDescriptor);
// And... we're done.
final boolean restarting = isState(State.RESTARTING);
setState(State.EXITED);
final GeckoBundle data = new GeckoBundle(1);
data.putBoolean("restart", restarting);
EventDispatcher.getInstance().dispatch("Gecko:Exited", data);
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java
@@ -489,15 +489,15 @@ public final class GeckoLoader {
}
}
// These methods are implemented in mozglue/android/nsGeckoUtils.cpp
private static native void putenv(String map);
public static native boolean verifyCRCs(String apkName);
// These methods are implemented in mozglue/android/APKOpen.cpp
- public static native void nativeRun(String[] args, int crashFd, int ipcFd, 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);
public static native boolean neonCompatible();
public static native void suppressCrashDialog();
}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java
@@ -163,56 +163,58 @@ public final class GeckoProcessManager e
final ChildConnection connection = getConnection(type);
connection.bind();
connection.getPid();
}
}
@WrapForJNI
private static int start(final String type, final String[] args,
- final int crashFd, final int ipcFd,
- final int crashAnnotationFd) {
- return INSTANCE.start(type, args, crashFd, ipcFd, 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 crashFd,
- final int ipcFd, 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) {
return 0;
}
+ final ParcelFileDescriptor prefsPfd;
+ final ParcelFileDescriptor ipcPfd;
final ParcelFileDescriptor crashPfd;
- final ParcelFileDescriptor ipcPfd;
final ParcelFileDescriptor crashAnnotationPfd;
try {
+ prefsPfd = ParcelFileDescriptor.fromFd(prefsFd);
+ ipcPfd = ParcelFileDescriptor.fromFd(ipcFd);
crashPfd = (crashFd >= 0) ? ParcelFileDescriptor.fromFd(crashFd) : null;
- ipcPfd = ParcelFileDescriptor.fromFd(ipcFd);
crashAnnotationPfd = (crashAnnotationFd >= 0) ? ParcelFileDescriptor.fromFd(crashAnnotationFd) : null;
} catch (final IOException e) {
Log.e(LOGTAG, "Cannot create fd for " + type, e);
return 0;
}
boolean started = false;
try {
- started = child.start(this, args, crashPfd, ipcPfd, crashAnnotationPfd);
+ started = child.start(this, args, prefsPfd, ipcPfd, crashPfd, crashAnnotationPfd);
} catch (final RemoteException e) {
}
if (!started) {
if (retry) {
Log.e(LOGTAG, "Cannot restart child " + type);
return 0;
}
Log.w(LOGTAG, "Attempting to kill running child " + type);
connection.unbind();
- return start(type, args, crashFd, ipcFd, crashAnnotationFd, /* retry */ true);
+ return start(type, args, prefsFd, ipcFd, crashFd, crashAnnotationFd, /* retry */ true);
}
try {
if (crashPfd != null) {
crashPfd.close();
}
ipcPfd.close();
} catch (final IOException e) {
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java
@@ -56,36 +56,38 @@ public class GeckoServiceChildProcess ex
@Override
public int getPid() {
return Process.myPid();
}
@Override
public boolean start(final IProcessManager procMan,
final String[] args,
+ final ParcelFileDescriptor prefsPfd,
+ final ParcelFileDescriptor ipcPfd,
final ParcelFileDescriptor crashReporterPfd,
- final ParcelFileDescriptor ipcPfd,
final ParcelFileDescriptor crashAnnotationPfd) {
synchronized (GeckoServiceChildProcess.class) {
if (sProcessManager != null) {
Log.e(LOGTAG, "Child process already started");
return false;
}
sProcessManager = procMan;
}
+ final int prefsFd = prefsPfd != null ? prefsPfd.detachFd() : -1;
+ final int ipcFd = ipcPfd != null ? ipcPfd.detachFd() : -1;
final int crashReporterFd = crashReporterPfd != null ?
crashReporterPfd.detachFd() : -1;
- final int ipcFd = ipcPfd != null ? ipcPfd.detachFd() : -1;
final int crashAnnotationFd = crashAnnotationPfd != null ? crashAnnotationPfd.detachFd() : -1;
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
- if (GeckoThread.initChildProcess(args, crashReporterFd, ipcFd, crashAnnotationFd)) {
+ if (GeckoThread.initChildProcess(args, prefsFd, ipcFd, crashReporterFd, crashAnnotationFd)) {
GeckoThread.launch();
}
}
});
return true;
}
};
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -2898,17 +2898,17 @@ public:
NS_IMETHOD Run() override
{
return RegisterStrongMemoryReporter(new PreferenceServiceReporter());
}
};
} // 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>
Preferences::GetInstanceForService()
{
if (sPreferences) {
return do_AddRef(sPreferences);
}
@@ -3059,21 +3059,140 @@ Preferences::~Preferences()
NS_IMPL_ISUPPORTS(Preferences,
nsIPrefService,
nsIObserver,
nsIPrefBranch,
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);
gPhase = ContentProcessPhase::eEarlyPrefsSet;
#endif
}
/* static */ void
@@ -4264,25 +4383,16 @@ Preferences::ClearUser(const char* aPref
Preferences::HasUserValue(const char* aPrefName)
{
NS_ENSURE_TRUE(InitStaticMembers(), false);
Pref* pref = pref_HashTableLookup(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)
{
NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID);
Pref* pref;
if (!gHashTable || !(pref = pref_HashTableLookup(aPrefName))) {
return PREF_INVALID;
--- a/modules/libpref/Preferences.h
+++ b/modules/libpref/Preferences.h
@@ -36,16 +36,21 @@ namespace mozilla {
namespace dom {
class Pref;
class PrefValue;
} // namespace dom
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
{
Default,
User
};
class Preferences final
@@ -225,19 +230,16 @@ public:
static bool IsLocked(const char* aPrefName);
// Clears user set pref. Fails if run outside the parent process.
static nsresult ClearUser(const char* aPrefName);
// 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);
static nsresult AddWeakObserver(nsIObserver* aObserver, const char* aPref);
static nsresult RemoveObserver(nsIObserver* aObserver, const char* aPref);
// Adds/Removes two or more observers for the root pref branch. Pass to
// aPrefs an array of const char* whose last item is nullptr.
@@ -323,21 +325,22 @@ public:
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 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
// used to pass the update to content processes.
static void GetPreference(dom::Pref* aPref);
static void SetPreference(const dom::Pref& aPref);
#ifdef DEBUG
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -387,32 +387,32 @@ FreeArgv(char** argv, int argc)
for (int ix=0; ix < argc; ix++) {
// String was allocated with strndup, so need to use free to deallocate.
free(argv[ix]);
}
delete[](argv);
}
extern "C" APKOPEN_EXPORT void MOZ_JNICALL
-Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jobjectArray jargs, int crashFd, int ipcFd, 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);
if (ipcFd < 0) {
if (gBootstrap == nullptr) {
FreeArgv(argv, argc);
return;
}
ElfLoader::Singleton.ExpectShutdown(false);
gBootstrap->GeckoStart(jenv, argv, argc, sAppData);
ElfLoader::Singleton.ExpectShutdown(true);
} else {
- gBootstrap->XRE_SetAndroidChildFds(jenv, crashFd, ipcFd, crashAnnotationFd);
+ gBootstrap->XRE_SetAndroidChildFds(jenv, prefsFd, ipcFd, crashFd, crashAnnotationFd);
gBootstrap->XRE_SetProcessType(argv[argc - 1]);
XREChildData childData;
gBootstrap->XRE_InitChildProcess(argc - 1, argv, &childData);
}
gBootstrap.reset();
FreeArgv(argv, argc);
--- a/toolkit/xre/Bootstrap.cpp
+++ b/toolkit/xre/Bootstrap.cpp
@@ -73,18 +73,18 @@ public:
::XRE_EnableSameExecutableForContentProc();
}
#ifdef MOZ_WIDGET_ANDROID
virtual void GeckoStart(JNIEnv* aEnv, char** argv, int argc, const StaticXREAppData& aAppData) override {
::GeckoStart(aEnv, argv, argc, aAppData);
}
- virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aCrashFd, int aIPCFd, int aCrashAnnotationFd) override {
- ::XRE_SetAndroidChildFds(aEnv, aCrashFd, aIPCFd, aCrashAnnotationFd);
+ virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aPrefsFd, int aIPCFd, int aCrashFd, int aCrashAnnotationFd) override {
+ ::XRE_SetAndroidChildFds(aEnv, aPrefsFd, aIPCFd, aCrashFd, aCrashAnnotationFd);
}
#endif
#ifdef LIBFUZZER
virtual void XRE_LibFuzzerSetDriver(LibFuzzerDriver aDriver) override {
::XRE_LibFuzzerSetDriver(aDriver);
}
#endif
--- a/toolkit/xre/Bootstrap.h
+++ b/toolkit/xre/Bootstrap.h
@@ -108,17 +108,17 @@ public:
virtual nsresult XRE_InitChildProcess(int argc, char* argv[], const XREChildData* aChildData) = 0;
virtual void XRE_EnableSameExecutableForContentProc() = 0;
#ifdef MOZ_WIDGET_ANDROID
virtual void GeckoStart(JNIEnv* aEnv, char** argv, int argc, const StaticXREAppData& aAppData) = 0;
- virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aCrashFd, int aIPCFd, int aCrashAnnotationFd) = 0;
+ virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aPrefsFd, int aIPCFd, int aCrashFd, int aCrashAnnotationFd) = 0;
#endif
#ifdef LIBFUZZER
virtual void XRE_LibFuzzerSetDriver(LibFuzzerDriver aDriver) = 0;
#endif
#ifdef MOZ_IPDL_TESTS
virtual int XRE_RunIPDLTest(int argc, char **argv) = 0;
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -238,22 +238,23 @@ XRE_ChildProcessTypeToString(GeckoProces
namespace mozilla {
namespace startup {
GeckoProcessType sChildProcessType = GeckoProcessType_Default;
} // namespace startup
} // namespace mozilla
#if defined(MOZ_WIDGET_ANDROID)
void
-XRE_SetAndroidChildFds (JNIEnv* env, int crashFd, int ipcFd, 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);
- IPC::Channel::SetClientChannelFd(ipcFd);
}
#endif // defined(MOZ_WIDGET_ANDROID)
void
XRE_SetProcessType(const char* aProcessTypeString)
{
static bool called = false;
if (called) {
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -2350,19 +2350,19 @@ const char GeckoProcessManager::name[] =
"org/mozilla/gecko/process/GeckoProcessManager";
constexpr char GeckoProcessManager::GetEditableParent_t::name[];
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[] =
"org/mozilla/gecko/process/GeckoServiceChildProcess";
constexpr char GeckoServiceChildProcess::GetEditableParent_t::name[];
constexpr char GeckoServiceChildProcess::GetEditableParent_t::signature[];
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -6691,30 +6691,31 @@ public:
typedef GeckoProcessManager Owner;
typedef int32_t ReturnType;
typedef int32_t SetterType;
typedef mozilla::jni::Args<
mozilla::jni::String::Param,
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";
- static const bool isStatic = true;
- static const mozilla::jni::ExceptionMode exceptionMode =
- mozilla::jni::ExceptionMode::ABORT;
- static const mozilla::jni::CallingThread callingThread =
- mozilla::jni::CallingThread::ANY;
- static const mozilla::jni::DispatchTarget dispatchTarget =
- mozilla::jni::DispatchTarget::CURRENT;
- };
-
- static auto Start(mozilla::jni::String::Param, mozilla::jni::ObjectArray::Param, int32_t, int32_t, int32_t) -> int32_t;
+ "(Ljava/lang/String;[Ljava/lang/String;IIII)I";
+ static const bool isStatic = true;
+ static const mozilla::jni::ExceptionMode exceptionMode =
+ mozilla::jni::ExceptionMode::ABORT;
+ static const mozilla::jni::CallingThread callingThread =
+ mozilla::jni::CallingThread::ANY;
+ static const mozilla::jni::DispatchTarget dispatchTarget =
+ mozilla::jni::DispatchTarget::CURRENT;
+ };
+
+ 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;
template<class Impl> class Natives;
};
class GeckoServiceChildProcess : public mozilla::jni::ObjectBase<GeckoServiceChildProcess>
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -393,17 +393,17 @@ static_assert(MOZ_ARRAY_LENGTH(kGeckoPro
GeckoProcessType_End,
"Array length mismatch");
XRE_API(const char*,
XRE_ChildProcessTypeToString, (GeckoProcessType aProcessType))
#if defined(MOZ_WIDGET_ANDROID)
XRE_API(void,
- XRE_SetAndroidChildFds, (JNIEnv* env, int crashFd, int ipcFd, int crashAnnotationFd))
+ XRE_SetAndroidChildFds, (JNIEnv* env, int prefsFd, int ipcFd, int crashFd, int crashAnnotationFd))
#endif // defined(MOZ_WIDGET_ANDROID)
XRE_API(void,
XRE_SetProcessType, (const char* aProcessTypeString))
// Used in the "master" parent process hosting the crash server
XRE_API(bool,
XRE_TakeMinidumpForChild, (uint32_t aChildPid, nsIFile** aDump,