Bug 1407693 - Part 2 - when a child process crashes, write extra annotation data to a pre-opened file descriptor instead of creating a new file; r=gsvelto,rbarker
authorAlex Gaynor <agaynor@mozilla.com>
Mon, 27 Nov 2017 14:37:34 -0600
changeset 403385 bcc0a91dd43feae18d4bf04d7db3d146035aa416
parent 403384 202bc739dda8746e28808470a77a3892444e2483
child 403386 af0ba0c0a055d5114ab4ab20b363e95125a6c93e
push id33432
push useraciure@mozilla.com
push dateMon, 12 Feb 2018 22:07:25 +0000
treeherdermozilla-central@a0afa134baa3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgsvelto, rbarker
bugs1407693
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1407693 - Part 2 - when a child process crashes, write extra annotation data to a pre-opened file descriptor instead of creating a new file; r=gsvelto,rbarker This removes the need for the content process to have permissions to create new files on macOS, allowing more aggressive sandboxing. MozReview-Commit-ID: 8agL5jwxDSL
ipc/glue/GeckoChildProcessHost.cpp
mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl
mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java
mozglue/android/APKOpen.cpp
toolkit/crashreporter/nsDummyExceptionHandler.cpp
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/crashreporter/nsExceptionHandler.h
toolkit/xre/Bootstrap.cpp
toolkit/xre/Bootstrap.h
toolkit/xre/nsEmbedFunctions.cpp
widget/android/GeneratedJNIWrappers.cpp
widget/android/GeneratedJNIWrappers.h
xpcom/build/nsXULAppAPI.h
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -58,16 +58,17 @@
 #include "mozilla/SandboxLaunch.h"
 #endif
 
 #include "nsTArray.h"
 #include "nsClassHashtable.h"
 #include "nsHashKeys.h"
 #include "nsNativeCharsetUtils.h"
 #include "nscore.h" // for NS_FREE_PERMANENT_DATA
+#include "private/pprio.h"
 
 using mozilla::MonitorAutoLock;
 using mozilla::ipc::GeckoChildProcessHost;
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #include "GeneratedJNIWrappers.h"
 #include "mozilla/jni/Refs.h"
@@ -117,16 +118,26 @@ GeckoChildProcessHost::~GeckoChildProces
 #endif
     );
   }
 
 #if defined(MOZ_WIDGET_COCOA)
   if (mChildTask != MACH_PORT_NULL)
     mach_port_deallocate(mach_task_self(), mChildTask);
 #endif
+
+  if (mChildProcessHandle != 0) {
+#if defined(XP_WIN)
+    CrashReporter::DeregisterChildCrashAnnotationFileDescriptor(
+      base::GetProcId(mChildProcessHandle));
+#else
+    CrashReporter::DeregisterChildCrashAnnotationFileDescriptor(
+      mChildProcessHandle);
+#endif
+  }
 }
 
 //static
 auto
 GeckoChildProcessHost::GetPathToBinary(FilePath& exePath, GeckoProcessType processType) -> BinaryPathType
 {
   if (sRunSelfAsContentProc &&
       (processType == GeckoProcessType_Content || processType == GeckoProcessType_GPU)) {
@@ -616,16 +627,22 @@ GeckoChildProcessHost::PerformAsyncLaunc
   // send the child the PID so that it can open a ProcessHandle back to us.
   // probably don't want to do this in the long run
   char pidstring[32];
   SprintfLiteral(pidstring, "%d", base::GetCurrentProcId());
 
   const char* const childProcessType =
       XRE_ChildProcessTypeToString(mProcessType);
 
+  PRFileDesc* crashAnnotationReadPipe;
+  PRFileDesc* crashAnnotationWritePipe;
+  if (PR_CreatePipe(&crashAnnotationReadPipe, &crashAnnotationWritePipe) != PR_SUCCESS) {
+    return false;
+  }
+
 //--------------------------------------------------
 #if defined(OS_POSIX)
   // For POSIX, we have to be extremely anal about *not* using
   // std::wstring in code compiled with Mozilla's -fshort-wchar
   // configuration, because chromium is compiled with -fno-short-wchar
   // and passing wstrings from one config to the other is unsafe.  So
   // we split the logic here.
 
@@ -764,16 +781,20 @@ GeckoChildProcessHost::PerformAsyncLaunc
       // "false" == crash reporting disabled
       childArgv.push_back("false");
     }
 #elif defined(MOZ_WIDGET_COCOA) // defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
     childArgv.push_back(CrashReporter::GetChildNotificationPipe());
 #endif  // defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
   }
 
+  int fd = PR_FileDesc2NativeHandle(crashAnnotationWritePipe);
+  mLaunchOptions->fds_to_remap.push_back(
+    std::make_pair(fd, CrashReporter::GetAnnotationTimeCrashFd()));
+
 # ifdef MOZ_WIDGET_COCOA
   // Add a mach port to the command line so the child can communicate its
   // 'task_t' back to the parent.
   //
   // Put a random number into the channel name, so that a compromised renderer
   // can't pretend being the child that's forked off.
   std::string mach_connection_name = StringPrintf("org.mozilla.machname.%d",
                                                   base::RandInt(0, std::numeric_limits<int>::max()));
@@ -1002,16 +1023,24 @@ GeckoChildProcessHost::PerformAsyncLaunc
   }
 
   // Process id
   cmdLine.AppendLooseValue(UTF8ToWide(pidstring));
 
   cmdLine.AppendLooseValue(
     UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
 
+  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) {
     if (mSandboxBroker.LaunchApp(cmdLine.program().c_str(),
                                  cmdLine.command_line_string().c_str(),
                                  mLaunchOptions->env_map,
@@ -1064,16 +1093,25 @@ GeckoChildProcessHost::PerformAsyncLaunc
                             PROCESS_DUP_HANDLE | PROCESS_TERMINATE |
                             PROCESS_QUERY_INFORMATION | PROCESS_VM_READ |
                             SYNCHRONIZE,
                             FALSE, 0)
 #endif // XP_WIN
      ) {
     MOZ_CRASH("cannot open handle to child process");
   }
+#if defined(XP_WIN)
+  CrashReporter::RegisterChildCrashAnnotationFileDescriptor(
+    base::GetProcId(process), crashAnnotationReadPipe);
+#else
+  CrashReporter::RegisterChildCrashAnnotationFileDescriptor(process,
+                                                            crashAnnotationReadPipe);
+#endif
+  PR_Close(crashAnnotationWritePipe);
+
   MonitorAutoLock lock(mMonitor);
   mProcessState = PROCESS_CREATED;
   lock.Notify();
 
   mLaunchOptions = nullptr;
   return true;
 }
 
@@ -1135,29 +1173,30 @@ 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() <= 2));
+  MOZ_ASSERT((fds_to_remap.size() > 0) && (fds_to_remap.size() <= 3));
   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.
   int32_t crashFd = (it != fds_to_remap.end()) ? it->first : -1;
-  int32_t handle = java::GeckoProcessManager::Start(type, jargs, crashFd, ipcFd);
+  int32_t crashAnnotationFd = (it != fds_to_remap.end()) ? it->first : -1;
+  int32_t handle = java::GeckoProcessManager::Start(type, jargs, crashFd, ipcFd, crashAnnotationFd);
 
   if (process_handle) {
     *process_handle = handle;
   }
 }
 #endif
--- 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);
+    boolean start(in IProcessManager procMan, in String[] args, in ParcelFileDescriptor crashReporterPfd, in ParcelFileDescriptor ipcPfd, 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
@@ -122,58 +122,63 @@ public class GeckoThread extends Thread 
 
     private GeckoProfile mProfile;
     private String mExtraArgs;
     private int mFlags;
 
     // Child process parameters
     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 crashFd, final int ipcFd,
+                                      final int crashAnnotationFd) {
         ThreadUtils.assertOnUiThread();
         uiThreadId = android.os.Process.myTid();
 
         if (mInitialized) {
             return false;
         }
 
         mProfile = profile;
         mArgs = args;
         mExtraArgs = extraArgs;
         mFlags = flags;
         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);
+                                 /* crashFd */ -1, /* ipcFd */ -1,
+                                 /* crashAnnotationFd */ -1);
     }
 
     public static boolean initChildProcess(final String[] args, final int crashFd,
-                                           final int ipcFd) {
+                                           final int ipcFd,
+                                           final int crashAnnotationFd) {
         return INSTANCE.init(/* profile */ null, args, /* extraArgs */ null,
-                                 /* flags */ 0, crashFd, ipcFd);
+                                 /* flags */ 0, crashFd, ipcFd, crashAnnotationFd);
     }
 
     private static boolean canUseProfile(final Context context, final GeckoProfile profile,
                                          final String profileName, final File profileDir) {
         if (profileDir != null && !profileDir.isDirectory()) {
             return false;
         }
 
@@ -399,17 +404,17 @@ 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);
+        GeckoLoader.nativeRun(args, mCrashFileDescriptor, mIPCFileDescriptor, 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
@@ -488,15 +488,15 @@ public final class GeckoLoader {
             uncaughtHandler.uncaughtException(thread, new AbortException(msg));
         }
     }
 
     // These methods are implemented in mozglue/android/nsGeckoUtils.cpp
     private static native void putenv(String map);
 
     // These methods are implemented in mozglue/android/APKOpen.cpp
-    public static native void nativeRun(String[] args, int crashFd, int ipcFd);
+    public static native void nativeRun(String[] args, int crashFd, int ipcFd, 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,52 +163,56 @@ 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) {
-        return INSTANCE.start(type, args, crashFd, ipcFd, /* retry */ false);
+                             final int crashFd, final int ipcFd,
+                             final int crashAnnotationFd) {
+        return INSTANCE.start(type, args, crashFd, ipcFd, crashAnnotationFd, /* retry */ false);
     }
 
     private int start(final String type, final String[] args, final int crashFd,
-                      final int ipcFd, final boolean retry) {
+                      final int ipcFd, final int crashAnnotationFd,
+                      final boolean retry) {
         final ChildConnection connection = getConnection(type);
         final IChildProcess child = connection.bind();
         if (child == null) {
             return 0;
         }
 
         final ParcelFileDescriptor crashPfd;
         final ParcelFileDescriptor ipcPfd;
+        final ParcelFileDescriptor crashAnnotationPfd;
         try {
             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);
+            started = child.start(this, args, crashPfd, ipcPfd, 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, /* retry */ true);
+            return start(type, args, crashFd, ipcFd, 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
@@ -57,33 +57,35 @@ public class GeckoServiceChildProcess ex
         public int getPid() {
             return Process.myPid();
         }
 
         @Override
         public boolean start(final IProcessManager procMan,
                              final String[] args,
                              final ParcelFileDescriptor crashReporterPfd,
-                             final ParcelFileDescriptor ipcPfd) {
+                             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 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)) {
+                    if (GeckoThread.initChildProcess(args, crashReporterFd, ipcFd, crashAnnotationFd)) {
                         GeckoThread.launch();
                     }
                 }
             });
             return true;
         }
     };
 
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -403,32 +403,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)
+Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jobjectArray jargs, int crashFd, int ipcFd, 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);
+    gBootstrap->XRE_SetAndroidChildFds(jenv, crashFd, ipcFd, crashAnnotationFd);
     gBootstrap->XRE_SetProcessType(argv[argc - 1]);
 
     XREChildData childData;
     gBootstrap->XRE_InitChildProcess(argc - 1, argv, &childData);
   }
 
   gBootstrap.reset();
   FreeArgv(argv, argc);
@@ -587,9 +587,9 @@ Java_org_mozilla_gecko_mozglue_GeckoLoad
   sigaction(SIGBUS, &action, nullptr);
   sigaction(SIGFPE, &action, nullptr);
   sigaction(SIGILL, &action, nullptr);
   sigaction(SIGSEGV, &action, nullptr);
 #if defined(SIGSTKFLT)
   sigaction(SIGSTKFLT, &action, nullptr);
 #endif
   sigaction(SIGTRAP, &action, nullptr);
-}
\ No newline at end of file
+}
--- a/toolkit/crashreporter/nsDummyExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsDummyExceptionHandler.cpp
@@ -136,16 +136,34 @@ SetServerURL(const nsACString& aServerUR
 }
 
 nsresult
 SetRestartArgs(int argc, char** argv)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+#if !defined(XP_WIN)
+int
+GetAnnotationTimeCrashFd()
+{
+  return 7;
+}
+#endif
+
+void
+RegisterChildCrashAnnotationFileDescriptor(ProcessId aProcess, PRFileDesc* aFd)
+{
+}
+
+void
+DeregisterChildCrashAnnotationFileDescriptor(ProcessId aProcess)
+{
+}
+
 #ifdef XP_WIN32
 nsresult
 WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 #endif
 
@@ -293,26 +311,20 @@ UnregisterInjectorCallback(DWORD process
 #endif // MOZ_CRASHREPORTER_INJECTOR
 
 bool
 GetLastRunCrashID(nsAString& id)
 {
   return false;
 }
 
-#if defined(XP_WIN) || defined(XP_MACOSX)
-void
-InitChildProcessTmpDir(nsIFile* aDirOverride)
-{
-}
-#endif // defined(XP_WIN) || defined(XP_MACOSX)
-
 #if defined(XP_WIN)
 bool
-SetRemoteExceptionHandler(const nsACString& crashPipe)
+SetRemoteExceptionHandler(const nsACString& crashPipe,
+                          uintptr_t aCrashTimeAnnotationFile)
 {
   return false;
 }
 
 #elif defined(XP_MACOSX)
 
 bool
 SetRemoteExceptionHandler(const nsACString& crashPipe)
@@ -387,16 +399,21 @@ UnsetRemoteExceptionHandler()
 
 #if defined(MOZ_WIDGET_ANDROID)
 void
 SetNotificationPipeForChild(int childCrashFd)
 {
 }
 
 void
+SetCrashAnnotationPipeForChild(int childCrashAnnotationFd)
+{
+}
+
+void
 AddLibraryMapping(const char* library_name,
                   uintptr_t   start_address,
                   size_t      mapping_length,
                   size_t      file_offset)
 {
 }
 #endif
 
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -20,16 +20,17 @@
 #include "mozilla/SyncRunnable.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/ipc/CrashReporterClient.h"
 
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "jsfriendapi.h"
 #include "ThreadAnnotation.h"
+#include "private/pprio.h"
 
 #if defined(XP_WIN32)
 #ifdef WIN32_LEAN_AND_MEAN
 #undef WIN32_LEAN_AND_MEAN
 #endif
 
 #include "nsXULAppAPI.h"
 #include "nsIXULAppInfo.h"
@@ -237,16 +238,17 @@ static bool minidumpAnalysisAllThreads =
 static Mutex* dumpSafetyLock;
 static bool isSafeToDump = false;
 
 // Whether to include heap regions of the crash context.
 static bool sIncludeContextHeap = false;
 
 // OOP crash reporting
 static CrashGenerationServer* crashServer; // chrome process has this
+static std::map<ProcessId, PRFileDesc*> processToCrashFd;
 
 static std::terminate_handler oldTerminateHandler = nullptr;
 
 #if (defined(XP_MACOSX) || defined(XP_WIN))
 // This field is valid in both chrome and content processes.
 static xpstring* childProcessTmpDir = nullptr;
 #endif
 
@@ -264,16 +266,20 @@ static int gMagicChildCrashReportFd =
 // On android the fd is set at the time of child creation.
 -1
 #    else
 4
 #    endif // defined(MOZ_WIDGET_ANDROID)
 ;
 #  endif
 
+#if defined(MOZ_WIDGET_ANDROID)
+static int gChildCrashAnnotationReportFd = -1;
+#endif
+
 // |dumpMapLock| must protect all access to |pidToMinidump|.
 static Mutex* dumpMapLock;
 struct ChildProcessData : public nsUint32HashKey
 {
   explicit ChildProcessData(KeyTypePointer aKey)
     : nsUint32HashKey(aKey)
     , sequence(0)
 #ifdef MOZ_CRASHREPORTER_INJECTOR
@@ -574,16 +580,18 @@ public:
   }
 
   void Open(const wchar_t* path) {
     mHandle = CreateFile(path, GENERIC_WRITE, 0,
                          nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
                          nullptr);
   }
 
+  void OpenHandle(HANDLE aHandle) { mHandle = aHandle; }
+
   bool Valid() {
     return mHandle != INVALID_HANDLE_VALUE;
   }
 
   void WriteBuffer(const char* buffer, size_t len)
   {
     if (!Valid()) {
       return;
@@ -620,16 +628,18 @@ public:
       sys_close(mFD);
     }
   }
 
   void Open(const char* path) {
     mFD = sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
   }
 
+  void OpenHandle(int aFd) { mFD = aFd; }
+
   bool Valid() {
     return mFD != -1;
   }
 
   void WriteBuffer(const char* buffer, size_t len) {
     if (!Valid()) {
       return;
     }
@@ -1256,55 +1266,28 @@ BuildTempPath(PathStringT& aResult)
   if (!actualLen) {
     return false;
   }
   aResult.SetLength(actualLen);
   return true;
 }
 
 static void
-PrepareChildExceptionTimeAnnotations()
+PrepareChildExceptionTimeAnnotations(void* context)
 {
   MOZ_ASSERT(!XRE_IsParentProcess());
-  static XP_CHAR tempPath[XP_PATH_MAX] = {0};
-
-  // Get the temp path
-  size_t charsAvailable = XP_PATH_MAX;
-  XP_CHAR* p = tempPath;
-#if (defined(XP_MACOSX) || defined(XP_WIN))
-  if (!childProcessTmpDir || childProcessTmpDir->empty()) {
-    return;
-  }
-  p = Concat(p, childProcessTmpDir->c_str(), &charsAvailable);
-  // Ensure that this path ends with a path separator
-  if (p > tempPath && *(p - 1) != XP_PATH_SEPARATOR_CHAR) {
-    p = Concat(p, XP_PATH_SEPARATOR, &charsAvailable);
-  }
+
+  FileHandle f;
+#ifdef XP_WIN
+  f = static_cast<HANDLE>(context);
 #else
-  size_t tempPathLen = BuildTempPath(tempPath);
-  if (!tempPathLen) {
-    return;
-  }
-  p += tempPathLen;
-  charsAvailable -= tempPathLen;
+  f = GetAnnotationTimeCrashFd();
 #endif
-
-  // Generate and append the file name
-  p = Concat(p, childCrashAnnotationBaseName, &charsAvailable);
-  XP_CHAR pidBuffer[32] = XP_TEXT("");
-#if defined(XP_WIN32)
-  _ui64tow(GetCurrentProcessId(), pidBuffer, 10);
-#else
-  XP_STOA(getpid(), pidBuffer, 10);
-#endif
-  p = Concat(p, pidBuffer, &charsAvailable);
-
-  // Now open the file...
   PlatformWriter apiData;
-  OpenAPIData(apiData, tempPath);
+  apiData.OpenHandle(f);
 
   // ...and write out any annotations. These must be escaped if necessary
   // (but don't call EscapeAnnotation here, because it touches the heap).
 #ifdef XP_WIN
   WriteGlobalMemoryStatus(&apiData, nullptr);
 #endif
 
   char oomAllocationSizeBuffer[32] = "";
@@ -1390,17 +1373,17 @@ static bool FPEFilter(void* context, EXC
 }
 
 static bool
 ChildFPEFilter(void* context, EXCEPTION_POINTERS* exinfo,
                MDRawAssertionInfo* assertion)
 {
   bool result = FPEFilter(context, exinfo, assertion);
   if (result) {
-    PrepareChildExceptionTimeAnnotations();
+    PrepareChildExceptionTimeAnnotations(context);
   }
   return result;
 }
 
 static MINIDUMP_TYPE
 GetMinidumpType()
 {
   MINIDUMP_TYPE minidump_type = MiniDumpWithFullMemoryInfo;
@@ -1456,17 +1439,17 @@ Filter(void* context)
   return true;
 }
 
 static bool
 ChildFilter(void* context)
 {
   bool result = Filter(context);
   if (result) {
-    PrepareChildExceptionTimeAnnotations();
+    PrepareChildExceptionTimeAnnotations(context);
   }
   return result;
 }
 
 static void
 TerminateHandler()
 {
   MOZ_CRASH("Unhandled exception");
@@ -3052,60 +3035,16 @@ WriteExtraData(nsIFile* extraFile,
 
 bool
 AppendExtraData(nsIFile* extraFile, const AnnotationTable& data)
 {
   return WriteExtraData(extraFile, data, Blacklist());
 }
 
 static bool
-GetExtraFileForChildPid(uint32_t aPid, nsIFile** aExtraFile)
-{
-  MOZ_ASSERT(XRE_IsParentProcess());
-
-  nsCOMPtr<nsIFile> extraFile;
-  nsresult rv;
-
-#if defined(XP_WIN) || defined(XP_MACOSX)
-  if (!childProcessTmpDir) {
-    return false;
-  }
-  CreateFileFromPath(*childProcessTmpDir, getter_AddRefs(extraFile));
-  if (!extraFile) {
-    return false;
-  }
-#elif defined(XP_UNIX)
-  rv = NS_NewLocalFile(NS_LITERAL_STRING("/tmp"), false,
-                       getter_AddRefs(extraFile));
-  if (NS_FAILED(rv)) {
-    return false;
-  }
-#else
-#error "Implement this for your platform"
-#endif
-
-  nsAutoString leafName;
-#if defined(XP_WIN)
-  leafName.AppendPrintf("%S%u%S", childCrashAnnotationBaseName, aPid,
-                        extraFileExtension);
-#else
-  leafName.AppendPrintf("%s%u%s", childCrashAnnotationBaseName, aPid,
-                        extraFileExtension);
-#endif
-
-  rv = extraFile->Append(leafName);
-  if (NS_FAILED(rv)) {
-    return false;
-  }
-
-  extraFile.forget(aExtraFile);
-  return true;
-}
-
-static bool
 IsDataEscaped(char* aData)
 {
   if (strchr(aData, '\n')) {
     // There should not be any newlines
     return false;
   }
   char* pos = aData;
   while ((pos = strchr(pos, '\\'))) {
@@ -3169,29 +3108,37 @@ WriteExtraForMinidump(nsIFile* minidump,
 
   if (!WriteExtraData(extra, *crashReporterAPIData_Hash,
                       blacklist,
                       true /*write crash time*/,
                       true /*truncate*/)) {
     return false;
   }
 
-  nsCOMPtr<nsIFile> exceptionTimeExtra;
-  FILE* fd;
-  if (pid && GetExtraFileForChildPid(pid, getter_AddRefs(exceptionTimeExtra)) &&
-      NS_SUCCEEDED(exceptionTimeExtra->OpenANSIFileDesc("r", &fd))) {
-    AnnotationTable exceptionTimeAnnotations;
-    ReadAndValidateExceptionTimeAnnotations(fd, exceptionTimeAnnotations);
-    fclose(fd);
-    if (!AppendExtraData(extra, exceptionTimeAnnotations)) {
+  if (pid && processToCrashFd.count(pid)) {
+    PRFileDesc* prFd = processToCrashFd[pid];
+    processToCrashFd.erase(pid);
+    FILE* fd;
+#if defined(XP_WIN)
+    int nativeFd = _open_osfhandle(PR_FileDesc2NativeHandle(prFd), 0);
+    if (nativeFd == -1) {
       return false;
     }
-  }
-  if (exceptionTimeExtra) {
-    exceptionTimeExtra->Remove(false);
+    fd = fdopen(nativeFd, "r");
+#else
+    fd = fdopen(PR_FileDesc2NativeHandle(prFd), "r");
+#endif
+    if (fd) {
+      AnnotationTable exceptionTimeAnnotations;
+      ReadAndValidateExceptionTimeAnnotations(fd, exceptionTimeAnnotations);
+      PR_Close(prFd);
+      if (!AppendExtraData(extra, exceptionTimeAnnotations)) {
+        return false;
+      }
+    }
   }
 
   extra.forget(extraFile);
 
   return true;
 }
 
 // It really only makes sense to call this function when
@@ -3533,56 +3480,65 @@ UnregisterInjectorCallback(DWORD process
     return;
 
   MutexAutoLock lock(*dumpMapLock);
   pidToMinidump->RemoveEntry(processID);
 }
 
 #endif // MOZ_CRASHREPORTER_INJECTOR
 
-#if defined(XP_WIN) || defined(XP_MACOSX)
-void
-InitChildProcessTmpDir(nsIFile* aDirOverride)
+#if !defined(XP_WIN)
+int
+GetAnnotationTimeCrashFd()
 {
-  MOZ_ASSERT(!XRE_IsParentProcess());
-  if (aDirOverride) {
-    childProcessTmpDir = CreatePathFromFile(aDirOverride);
-    return;
-  }
-
-  // When retrieved by the child process, this will always resolve to the
-  // correct directory regardless of sandbox level.
-  nsCOMPtr<nsIFile> tmpDir;
-  nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpDir));
-  if (NS_SUCCEEDED(rv)) {
-    childProcessTmpDir = CreatePathFromFile(tmpDir);
+#if defined(MOZ_WIDGET_ANDROID)
+  return gChildCrashAnnotationReportFd;
+#else
+  return 7;
+#endif // defined(MOZ_WIDGET_ANDROID)
+}
+#endif
+
+void
+RegisterChildCrashAnnotationFileDescriptor(ProcessId aProcess, PRFileDesc* aFd)
+{
+  processToCrashFd[aProcess] = aFd;
+}
+
+void
+DeregisterChildCrashAnnotationFileDescriptor(ProcessId aProcess)
+{
+  auto it = processToCrashFd.find(aProcess);
+  if (it != processToCrashFd.end()) {
+    PR_Close(it->second);
+    processToCrashFd.erase(it);
   }
 }
-#endif // defined(XP_WIN) || defined(XP_MACOSX)
 
 #if defined(XP_WIN)
 // Child-side API
 bool
-SetRemoteExceptionHandler(const nsACString& crashPipe)
+SetRemoteExceptionHandler(const nsACString& crashPipe,
+                          uintptr_t aCrashTimeAnnotationFile)
 {
   // crash reporting is disabled
   if (crashPipe.Equals(kNullNotifyPipe))
     return true;
 
   MOZ_ASSERT(!gExceptionHandler, "crash client already init'd");
 
-  gExceptionHandler = new google_breakpad::
-    ExceptionHandler(L"",
-                     ChildFPEFilter,
-                     nullptr,    // no minidump callback
-                     nullptr,    // no callback context
-                     google_breakpad::ExceptionHandler::HANDLER_ALL,
-                     GetMinidumpType(),
-                     NS_ConvertASCIItoUTF16(crashPipe).get(),
-                     nullptr);
+  gExceptionHandler = new google_breakpad::ExceptionHandler(
+    L"",
+    ChildFPEFilter,
+    nullptr, // no minidump callback
+    reinterpret_cast<void*>(aCrashTimeAnnotationFile),
+    google_breakpad::ExceptionHandler::HANDLER_ALL,
+    GetMinidumpType(),
+    NS_ConvertASCIItoUTF16(crashPipe).get(),
+    nullptr);
   gExceptionHandler->set_handle_debug_exceptions(true);
   RunAndCleanUpDelayedNotes();
 
 #ifdef _WIN64
   SetJitExceptionHandler();
 #endif
 
   mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);
@@ -4076,16 +4032,21 @@ UnsetRemoteExceptionHandler()
 }
 
 #if defined(MOZ_WIDGET_ANDROID)
 void SetNotificationPipeForChild(int childCrashFd)
 {
   gMagicChildCrashReportFd = childCrashFd;
 }
 
+void SetCrashAnnotationPipeForChild(int childCrashAnnotationFd)
+{
+  gChildCrashAnnotationReportFd = childCrashAnnotationFd;
+}
+
 void AddLibraryMapping(const char* library_name,
                        uintptr_t   start_address,
                        size_t      mapping_length,
                        size_t      file_offset)
 {
   if (!gExceptionHandler) {
     mapping_info info;
     info.name = library_name;
--- a/toolkit/crashreporter/nsExceptionHandler.h
+++ b/toolkit/crashreporter/nsExceptionHandler.h
@@ -14,16 +14,17 @@
 
 #include "mozilla/Assertions.h"
 
 #include <functional>
 #include <stddef.h>
 #include <stdint.h>
 #include "nsError.h"
 #include "nsString.h"
+#include "prio.h"
 
 #if defined(XP_WIN32)
 #ifdef WIN32_LEAN_AND_MEAN
 #undef WIN32_LEAN_AND_MEAN
 #endif
 #include <windows.h>
 #endif
 
@@ -171,25 +172,40 @@ bool TakeMinidump(nsIFile** aResult, boo
 // is non-nullptr. The sequence parameter will be filled with an ordinal
 // indicating which remote process crashed first.
 bool TakeMinidumpForChild(uint32_t childPid,
                           nsIFile** dump,
                           uint32_t* aSequence = nullptr);
 
 #if defined(XP_WIN)
 typedef HANDLE ProcessHandle;
+typedef DWORD ProcessId;
 typedef DWORD ThreadId;
+typedef HANDLE FileHandle;
 #elif defined(XP_MACOSX)
 typedef task_t ProcessHandle;
+typedef pid_t ProcessId;
 typedef mach_port_t ThreadId;
+typedef int FileHandle;
 #else
 typedef int ProcessHandle;
+typedef pid_t ProcessId;
 typedef int ThreadId;
+typedef int FileHandle;
 #endif
 
+#if !defined(XP_WIN)
+int
+GetAnnotationTimeCrashFd();
+#endif
+void
+RegisterChildCrashAnnotationFileDescriptor(ProcessId aProcess, PRFileDesc* aFd);
+void
+DeregisterChildCrashAnnotationFileDescriptor(ProcessId aProcess);
+
 // Return the current thread's ID.
 //
 // XXX: this is a somewhat out-of-place interface to expose through
 // crashreporter, but it takes significant work to call sys_gettid()
 // correctly on Linux and breakpad has already jumped through those
 // hoops for us.
 ThreadId CurrentThreadId();
 
@@ -259,18 +275,23 @@ public:
 };
 
 // This method implies OOPInit
 void InjectCrashReporterIntoProcess(DWORD processID, InjectorCrashCallback* cb);
 void UnregisterInjectorCallback(DWORD processID);
 #endif
 
 // Child-side API
+#if defined(XP_WIN32)
+bool
+SetRemoteExceptionHandler(const nsACString& crashPipe,
+                          uintptr_t aCrashTimeAnnotationFile);
+#else
 bool SetRemoteExceptionHandler(const nsACString& crashPipe);
-void InitChildProcessTmpDir(nsIFile* aDirOverride = nullptr);
+#endif
 
 #  else
 // Parent-side API for children
 
 // Set the outparams for crash reporter server's fd (|childCrashFd|)
 // and the magic fd number it should be remapped to
 // (|childCrashRemapFd|) before exec() in the child process.
 // |SetRemoteExceptionHandler()| in the child process expects to find
@@ -286,16 +307,17 @@ bool SetRemoteExceptionHandler();
 #endif  // XP_WIN32
 
 bool UnsetRemoteExceptionHandler();
 
 #if defined(MOZ_WIDGET_ANDROID)
 // Android creates child process as services so we must explicitly set
 // the handle for the pipe since it can't get remapped to a default value.
 void SetNotificationPipeForChild(int childCrashFd);
+void SetCrashAnnotationPipeForChild(int childCrashAnnotationFd);
 
 // Android builds use a custom library loader, so /proc/<pid>/maps
 // will just show anonymous mappings for all the non-system
 // shared libraries. This API is to work around that by providing
 // info about the shared libraries that are mapped into these anonymous
 // mappings.
 void AddLibraryMapping(const char* library_name,
                        uintptr_t   start_address,
--- 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) override {
-    ::XRE_SetAndroidChildFds(aEnv, aCrashFd, aIPCFd);
+  virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aCrashFd, int aIPCFd, int aCrashAnnotationFd) override {
+    ::XRE_SetAndroidChildFds(aEnv, aCrashFd, aIPCFd, 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) = 0;
+  virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aCrashFd, int aIPCFd, 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,20 +238,21 @@ 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)
+XRE_SetAndroidChildFds (JNIEnv* env, int crashFd, int ipcFd, int crashAnnotationFd)
 {
   mozilla::jni::SetGeckoThreadEnv(env);
   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;
@@ -277,19 +278,27 @@ XRE_SetProcessType(const char* aProcessT
 bool
 XRE_TakeMinidumpForChild(uint32_t aChildPid, nsIFile** aDump,
                          uint32_t* aSequence)
 {
   return CrashReporter::TakeMinidumpForChild(aChildPid, aDump, aSequence);
 }
 
 bool
-XRE_SetRemoteExceptionHandler(const char* aPipe/*= 0*/)
+#if defined(XP_WIN)
+XRE_SetRemoteExceptionHandler(const char* aPipe /*= 0*/,
+                              uintptr_t aCrashTimeAnnotationFile)
+#else
+XRE_SetRemoteExceptionHandler(const char* aPipe /*= 0*/)
+#endif
 {
-#if defined(XP_WIN) || defined(XP_MACOSX)
+#if defined(XP_WIN)
+  return CrashReporter::SetRemoteExceptionHandler(nsDependentCString(aPipe),
+                                                  aCrashTimeAnnotationFile);
+#elif defined(XP_MACOSX)
   return CrashReporter::SetRemoteExceptionHandler(nsDependentCString(aPipe));
 #else
   return CrashReporter::SetRemoteExceptionHandler();
 #endif
 }
 
 #if defined(XP_WIN)
 void
@@ -474,31 +483,45 @@ XRE_InitChildProcess(int aArgc,
     return NS_ERROR_FAILURE;
   }
 
 #endif
 
   SetupErrorHandling(aArgv[0]);
 
   if (!CrashReporter::IsDummy()) {
+#if defined(XP_WIN)
     if (aArgc < 1) {
       return NS_ERROR_FAILURE;
     }
+    const char* const crashTimeAnnotationArg = aArgv[--aArgc];
+    uintptr_t crashTimeAnnotationFile =
+      static_cast<uintptr_t>(std::stoul(std::string(crashTimeAnnotationArg)));
+#endif
 
+    if (aArgc < 1)
+      return NS_ERROR_FAILURE;
     const char* const crashReporterArg = aArgv[--aArgc];
 
-#if defined(XP_WIN) || defined(XP_MACOSX)
+#if defined(XP_MACOSX)
     // on windows and mac, |crashReporterArg| is the named pipe on which the
     // server is listening for requests, or "-" if crash reporting is
     // disabled.
     if (0 != strcmp("-", crashReporterArg) &&
         !XRE_SetRemoteExceptionHandler(crashReporterArg)) {
       // Bug 684322 will add better visibility into this condition
       NS_WARNING("Could not setup crash reporting\n");
     }
+#elif defined(XP_WIN)
+    if (0 != strcmp("-", crashReporterArg) &&
+        !XRE_SetRemoteExceptionHandler(crashReporterArg,
+                                       crashTimeAnnotationFile)) {
+      // Bug 684322 will add better visibility into this condition
+      NS_WARNING("Could not setup crash reporting\n");
+    }
 #else
     // on POSIX, |crashReporterArg| is "true" if crash reporting is
     // enabled, false otherwise
     if (0 != strcmp("false", crashReporterArg) &&
         !XRE_SetRemoteExceptionHandler(nullptr)) {
       // Bug 684322 will add better visibility into this condition
       NS_WARNING("Could not setup crash reporting\n");
     }
@@ -667,20 +690,16 @@ XRE_InitChildProcess(int aArgc,
       default:
         MOZ_CRASH("Unknown main thread class");
       }
 
       if (!process->Init(aArgc, aArgv)) {
         return NS_ERROR_FAILURE;
       }
 
-#if defined(XP_WIN) || defined(XP_MACOSX)
-      CrashReporter::InitChildProcessTmpDir(crashReportTmpDir);
-#endif
-
 #if defined(XP_WIN)
       // Set child processes up such that they will get killed after the
       // chrome process is killed in cases where the user shuts the system
       // down or logs off.
       ::SetProcessShutdownParameters(0x280 - 1, SHUTDOWN_NORETRY);
 #endif
 
 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -2396,19 +2396,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
+auto GeckoProcessManager::Start(mozilla::jni::String::Param a0, mozilla::jni::ObjectArray::Param a1, int32_t a2, int32_t a3, int32_t a4) -> int32_t
 {
-    return mozilla::jni::Method<Start_t>::Call(GeckoProcessManager::Context(), nullptr, a0, a1, a2, a3);
+    return mozilla::jni::Method<Start_t>::Call(GeckoProcessManager::Context(), nullptr, a0, a1, a2, a3, a4);
 }
 
 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
@@ -6916,30 +6916,31 @@ public:
     struct Start_t {
         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> Args;
         static constexpr char name[] = "start";
         static constexpr char signature[] =
-                "(Ljava/lang/String;[Ljava/lang/String;II)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;
+                "(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;
 
     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,30 +393,38 @@ 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))
+        XRE_SetAndroidChildFds, (JNIEnv* env, int crashFd, int ipcFd, 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,
                                    uint32_t* aSequence))
 
 // Used in child processes.
+#if defined(XP_WIN)
+// Uses uintptr_t, even though it's really a HANDLE, because including
+// <windows.h> here caused compilation issues.
+XRE_API(bool,
+        XRE_SetRemoteExceptionHandler,
+        (const char* aPipe, uintptr_t aCrashTimeAnnotationFile))
+#else
 XRE_API(bool,
         XRE_SetRemoteExceptionHandler, (const char* aPipe))
+#endif
 
 namespace mozilla {
 namespace gmp {
 class GMPLoader;
 } // namespace gmp
 } // namespace mozilla
 
 XRE_API(nsresult,