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 draft
authorAlex Gaynor <agaynor@mozilla.com>
Mon, 27 Nov 2017 14:37:34 -0600
changeset 752768 6487b70f321b241b2535f66bf2f89b63446b45e8
parent 752767 90893c1c2cd3e20a35954c8c22011548b47f446f
push id98368
push userbmo:agaynor@mozilla.com
push dateThu, 08 Feb 2018 22:01:20 +0000
reviewersgsvelto
bugs1407693
milestone60.0a1
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 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,