Backed out Bug 771251 -- changeset 95c9bc0e63f7 due to red.
authorJustin Wood <Callek@gmail.com>
Tue, 10 Jul 2012 22:50:33 -0400
changeset 98830 d75c06f195d2086537f439583350d41172d63a79
parent 98829 95c9bc0e63f72caace325087cd87e238e57f5eb7
child 98896 8495e311226f6f5f92473008e561b3b9a4c7537e
push id23087
push userCallek@gmail.com
push dateWed, 11 Jul 2012 02:51:10 +0000
treeherdermozilla-central@d75c06f195d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs771251
milestone16.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
Backed out Bug 771251 -- changeset 95c9bc0e63f7 due to red.
dom/ipc/CrashReporterParent.cpp
dom/ipc/CrashReporterParent.h
dom/plugins/ipc/PluginModuleParent.cpp
dom/plugins/ipc/PluginModuleParent.h
ipc/glue/GeckoChildProcessHost.cpp
ipc/ipdl/ipdl/cxx/ast.py
ipc/ipdl/ipdl/lower.py
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/crashreporter/nsExceptionHandler.h
toolkit/xre/nsEmbedFunctions.cpp
xpcom/build/nsXULAppAPI.h
--- a/dom/ipc/CrashReporterParent.cpp
+++ b/dom/ipc/CrashReporterParent.cpp
@@ -94,25 +94,16 @@ CrashReporterParent::GenerateHangCrashRe
     notes.Init(4);
     notes.Put(nsDependentCString("HangID"), NS_ConvertUTF16toUTF8(mHangID));
     if (!CrashReporter::AppendExtraData(mParentDumpID, notes))
         NS_WARNING("problem appending parent data to .extra");
     return true;
 }
 
 bool
-CrashReporterParent::GenerateCrashReportForMinidump(nsIFile* minidump,
-    const AnnotationTable* processNotes)
-{
-    if (!CrashReporter::GetIDFromMinidump(minidump, mChildDumpID))
-        return false;
-    return GenerateChildData(processNotes);
-}
-
-bool
 CrashReporterParent::GenerateChildData(const AnnotationTable* processNotes)
 {
     MOZ_ASSERT(mInitialized);
 
     nsCAutoString type;
     switch (mProcessType) {
         case GeckoProcessType_Content:
             type = NS_LITERAL_CSTRING("content");
--- a/dom/ipc/CrashReporterParent.h
+++ b/dom/ipc/CrashReporterParent.h
@@ -44,20 +44,16 @@ public:
   /* Attempt to create a bare-bones crash report, along with extra process-
      specific annotations present in the given AnnotationTable. Returns true if
      successful, false otherwise.
   */
   template<class Toplevel>
   bool
   GenerateCrashReport(Toplevel* t, const AnnotationTable* processNotes);
 
-  bool
-  GenerateCrashReportForMinidump(nsIFile* minidump,
-                                 const AnnotationTable* processNotes);
-
   /* Instantiate a new crash reporter actor from a given parent that manages
      the protocol.
   */
   template<class Toplevel>
   static bool CreateCrashReporter(Toplevel* actor);
 #endif
   /* Initialize this reporter with data from the child process */
   void
@@ -134,17 +130,17 @@ CrashReporterParent::GeneratePairedMinid
 }
 
 template<class Toplevel>
 inline bool
 CrashReporterParent::GenerateCrashReport(Toplevel* t,
                                          const AnnotationTable* processNotes)
 {
   nsCOMPtr<nsIFile> crashDump;
-  if (t->TakeMinidump(getter_AddRefs(crashDump), NULL) &&
+  if (t->TakeMinidump(getter_AddRefs(crashDump)) &&
       CrashReporter::GetIDFromMinidump(crashDump, mChildDumpID)) {
     return GenerateChildData(processNotes);
   }
   return false;
 }
 
 template<class Toplevel>
 /* static */ bool
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -22,16 +22,19 @@
 #include "mozilla/ipc/SyncChannel.h"
 #include "mozilla/plugins/PluginModuleParent.h"
 #include "mozilla/plugins/BrowserStreamParent.h"
 #include "mozilla/dom/PCrashReporterParent.h"
 #include "PluginIdentifierParent.h"
 
 #include "nsAutoPtr.h"
 #include "nsCRT.h"
+#ifdef MOZ_CRASHREPORTER
+#include "mozilla/dom/CrashReporterParent.h"
+#endif
 #include "nsNPAPIPlugin.h"
 #include "nsIFile.h"
 
 #ifdef XP_WIN
 #include "mozilla/widget/AudioSession.h"
 #endif
 #include "sampler.h"
 
@@ -41,22 +44,16 @@ using mozilla::PluginLibrary;
 using mozilla::ipc::SyncChannel;
 using mozilla::dom::PCrashReporterParent;
 using mozilla::dom::CrashReporterParent;
 
 using namespace mozilla;
 using namespace mozilla::plugins;
 using namespace mozilla::plugins::parent;
 
-#ifdef MOZ_CRASHREPORTER
-#include "mozilla/dom/CrashReporterParent.h"
-
-using namespace CrashReporter;
-#endif
-
 static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
 static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs";
 static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs";
 
 template<>
 struct RunnableMethodTraits<mozilla::plugins::PluginModuleParent>
 {
     typedef mozilla::plugins::PluginModuleParent Class;
@@ -131,28 +128,28 @@ PluginModuleParent::~PluginModuleParent(
 
     if (mSubprocess) {
         mSubprocess->Delete();
         mSubprocess = nsnull;
     }
 
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     if (mFlashProcess1)
-        UnregisterInjectorCallback(mFlashProcess1);
+        CrashReporter::UnregisterInjectorCallback(mFlashProcess1);
     if (mFlashProcess2)
-        UnregisterInjectorCallback(mFlashProcess2);
+        CrashReporter::UnregisterInjectorCallback(mFlashProcess2);
 #endif
 
     Preferences::UnregisterCallback(TimeoutChanged, kChildTimeoutPref, this);
     Preferences::UnregisterCallback(TimeoutChanged, kParentTimeoutPref, this);
 }
 
 #ifdef MOZ_CRASHREPORTER
 void
-PluginModuleParent::WriteExtraDataForMinidump(AnnotationTable& notes)
+PluginModuleParent::WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes)
 {
     typedef nsDependentCString CS;
 
     // Get the plugin filename, try to get just the file leafname
     const std::string& pluginFile = mSubprocess->GetPluginFilePath();
     size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR);
     if (filePos == std::string::npos)
         filePos = 0;
@@ -198,27 +195,29 @@ PluginModuleParent::CleanupFromTimeout()
     if (!mShutdown && OkToCleanup())
         Close();
 }
 
 bool
 PluginModuleParent::ShouldContinueFromReplyTimeout()
 {
 #ifdef MOZ_CRASHREPORTER
-    CrashReporterParent* crashReporter = CrashReporter();
-    if (crashReporter->GeneratePairedMinidump(this)) {
-        mBrowserDumpID = crashReporter->ParentDumpID();
-        mPluginDumpID = crashReporter->ChildDumpID();
-        PLUGIN_LOG_DEBUG(
-                ("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
-                 NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
-                 NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
-                 NS_ConvertUTF16toUTF8(crashReporter->HangID()).get()));
-    } else {
-        NS_WARNING("failed to capture paired minidumps from hang");
+    if (mPluginDumpID.IsEmpty()) {
+        CrashReporterParent* crashReporter = CrashReporter();
+        if (crashReporter->GeneratePairedMinidump(this)) {
+            mBrowserDumpID = crashReporter->ParentDumpID();
+            mPluginDumpID = crashReporter->ChildDumpID();
+            PLUGIN_LOG_DEBUG(
+                    ("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
+                     NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
+                     NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
+                     NS_ConvertUTF16toUTF8(crashReporter->HangID()).get()));
+        } else {
+            NS_WARNING("failed to capture paired minidumps from hang");
+        }
     }
 #endif
 
     // this must run before the error notification from the channel,
     // or not at all
     MessageLoop::current()->PostTask(
         FROM_HERE,
         mTaskFactory.NewRunnableMethod(
@@ -233,109 +232,43 @@ PluginModuleParent::ShouldContinueFromRe
 #ifdef MOZ_CRASHREPORTER
 CrashReporterParent*
 PluginModuleParent::CrashReporter()
 {
     return static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
 }
 #endif
 
-#ifdef MOZ_CRASHREPORTER
-static void
-RemoveMinidump(nsIFile* minidump)
-{
-    if (!minidump)
-        return;
-
-    minidump->Remove(false);
-    nsCOMPtr<nsIFile> extraFile;
-    if (GetExtraFileForMinidump(minidump,
-                                getter_AddRefs(extraFile))) {
-        extraFile->Remove(true);
-    }
-}
-
-void
-PluginModuleParent::ProcessFirstMinidump()
-{
-    CrashReporterParent* crashReporter = CrashReporter();
-    if (!crashReporter)
-        return;
-
-    AnnotationTable notes;
-    notes.Init(4);
-    WriteExtraDataForMinidump(notes);
-        
-    if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
-        crashReporter->GenerateHangCrashReport(&notes);
-        return;
-    }
-
-    PRUint32 sequence = PR_UINT32_MAX;
-    nsCOMPtr<nsIFile> dumpFile;
-    nsCAutoString flashProcessType;
-    TakeMinidump(getter_AddRefs(dumpFile), &sequence);
-
-#ifdef MOZ_CRASHREPORTER_INJECTOR
-    nsCOMPtr<nsIFile> childDumpFile;
-    PRUint32 childSequence;
-
-    if (mFlashProcess1 &&
-        TakeMinidumpForChild(mFlashProcess1,
-                             getter_AddRefs(childDumpFile),
-                             &childSequence)) {
-        if (childSequence < sequence) {
-            RemoveMinidump(dumpFile);
-            dumpFile = childDumpFile;
-            sequence = childSequence;
-            flashProcessType.AssignLiteral("Broker");
-        }
-        else {
-            RemoveMinidump(childDumpFile);
-        }
-    }
-    if (mFlashProcess2 &&
-        TakeMinidumpForChild(mFlashProcess2,
-                             getter_AddRefs(childDumpFile),
-                             &childSequence)) {
-        if (childSequence < sequence) {
-            RemoveMinidump(dumpFile);
-            dumpFile = childDumpFile;
-            sequence = childSequence;
-            flashProcessType.AssignLiteral("Sandbox");
-        }
-        else {
-            RemoveMinidump(childDumpFile);
-        }
-    }
-#endif
-
-    if (!dumpFile) {
-        NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
-        return;
-    }
-
-    PLUGIN_LOG_DEBUG(("got child minidump: %s",
-                      NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
-
-    GetIDFromMinidump(dumpFile, mPluginDumpID);
-    if (!flashProcessType.IsEmpty()) {
-        notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"), flashProcessType);
-        crashReporter->GenerateCrashReportForMinidump(dumpFile, &notes);
-    }
-}
-#endif
-
 void
 PluginModuleParent::ActorDestroy(ActorDestroyReason why)
 {
     switch (why) {
     case AbnormalShutdown: {
 #ifdef MOZ_CRASHREPORTER
-        ProcessFirstMinidump();
+        CrashReporterParent* crashReporter = CrashReporter();
+
+        CrashReporter::AnnotationTable notes;
+        notes.Init(4);
+        WriteExtraDataForMinidump(notes);
+        
+        if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
+            crashReporter->GenerateHangCrashReport(&notes);
+        }
+        else if (!mPluginDumpID.IsEmpty()) {
+            // Nothing to do, we've already written this minidump in
+            // PluginModuleParent::OnCrash
+        }
+        else if (crashReporter->GenerateCrashReport(this, &notes)) {
+            mPluginDumpID = crashReporter->ChildDumpID();
+            PLUGIN_LOG_DEBUG(("got child minidump: %s",
+                              NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
+        }
+        else {
+            NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
+        }
 #endif
 
         mShutdown = true;
         // Defer the PluginCrashed method so that we don't re-enter
         // and potentially modify the actor child list while enumerating it.
         if (mPlugin)
             MessageLoop::current()->PostTask(
                 FROM_HERE,
@@ -1310,15 +1243,40 @@ PluginModuleParent::InitializeInjector()
         mFlashProcess2 = GetFlashChildOfPID(mFlashProcess1, snapshot);
         if (mFlashProcess2) {
             InjectCrashReporterIntoProcess(mFlashProcess2, this);
         }
     }
 }
 
 void
-PluginModuleParent::OnCrash(DWORD processID)
+PluginModuleParent::OnCrash(DWORD processID, const nsAString& aDumpID)
 {
+    if (!mPluginDumpID.IsEmpty()) {
+        // One process has already crashed: we assume that the first-to-crash
+        // is the interesting one
+        return;
+    }
+
+    mPluginDumpID = aDumpID;
+
+    CrashReporter::AnnotationTable notes;
+    notes.Init(4);
+    WriteExtraDataForMinidump(notes);
+    notes.Put(NS_LITERAL_CSTRING("ProcessType"), NS_LITERAL_CSTRING("plugin"));
+    if (processID == mFlashProcess1) {
+        notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"),
+                  NS_LITERAL_CSTRING("Broker"));
+    }
+    else if (processID == mFlashProcess2) {
+        notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"),
+                  NS_LITERAL_CSTRING("Sandbox"));
+    }
+    else {
+        NS_ERROR("Got minidump for Flash process neither broker nor sandbox.");
+    }
+    CrashReporter::AppendExtraData(aDumpID, notes);
+
     GetIPCChannel()->CloseWithError();
     KillProcess(OtherProcess(), 1, false);
 }
 
 #endif // MOZ_CRASHREPORTER_INJECTOR
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -283,17 +283,16 @@ private:
     virtual nsresult HandleGUIEvent(NPP instance, const nsGUIEvent& anEvent,
                                     bool* handled);
 #endif
 
 private:
     CrashReporterParent* CrashReporter();
 
 #ifdef MOZ_CRASHREPORTER
-    void ProcessFirstMinidump();
     void WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes);
 #endif
     void CleanupFromTimeout();
     static int TimeoutChanged(const char* aPref, void* aModule);
     void NotifyPluginCrashed();
 
     PluginProcessParent* mSubprocess;
     // the plugin thread in mSubprocess
@@ -315,17 +314,17 @@ private:
     ScopedClose mPluginXSocketFdDup;
 #endif
 
     friend class mozilla::dom::CrashReporterParent;
 
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     void InitializeInjector();
     
-    NS_OVERRIDE void OnCrash(DWORD processID);
+    NS_OVERRIDE void OnCrash(DWORD processID, const nsAString& aDumpID);
 
     DWORD mFlashProcess1;
     DWORD mFlashProcess2;
 #endif
 };
 
 } // namespace plugins
 } // namespace mozilla
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -245,20 +245,16 @@ void GeckoChildProcessHost::InitWindowsG
     }
   }
 }
 #endif
 
 bool
 GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts, int aTimeoutMs, base::ProcessArchitecture arch)
 {
-#ifdef MOZ_CRASHREPORTER
-  CrashReporter::OOPInit();
-#endif
-
 #ifdef XP_WIN
   InitWindowsGroupID();
 #endif
 
   PRIntervalTime timeoutTicks = (aTimeoutMs > 0) ? 
     PR_MillisecondsToInterval(aTimeoutMs) : PR_INTERVAL_NO_TIMEOUT;
   MessageLoop* ioLoop = XRE_GetIOMessageLoop();
   NS_ASSERTION(MessageLoop::current() != ioLoop, "sync launch from the IO thread NYI");
@@ -290,20 +286,16 @@ GeckoChildProcessHost::SyncLaunch(std::v
   }
 
   return mLaunched;
 }
 
 bool
 GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts)
 {
-#ifdef MOZ_CRASHREPORTER
-  CrashReporter::OOPInit();
-#endif
-
 #ifdef XP_WIN
   InitWindowsGroupID();
 #endif
 
   MessageLoop* ioLoop = XRE_GetIOMessageLoop();
   ioLoop->PostTask(FROM_HERE,
                    NewRunnableMethod(this,
                                      &GeckoChildProcessHost::PerformAsyncLaunch,
--- a/ipc/ipdl/ipdl/cxx/ast.py
+++ b/ipc/ipdl/ipdl/cxx/ast.py
@@ -325,17 +325,16 @@ Any type, naked or pointer, can be const
                     ptrptr=self.ptrptr, ptrconstptr=self.ptrconstptr,
                     ref=self.ref,
                     T=copy.deepcopy(self.T, memo))
 Type.BOOL = Type('bool')
 Type.INT = Type('int')
 Type.INT32 = Type('int32')
 Type.INTPTR = Type('intptr_t')
 Type.UINT32 = Type('uint32')
-Type.UINT32PTR = Type('uint32', ptr=1)
 Type.SIZE = Type('size_t')
 Type.VOID = Type('void')
 Type.VOIDPTR = Type('void', ptr=1)
 
 class TypeArray(Node):
     def __init__(self, basetype, nmemb):
         '''the type |basetype DECLNAME[nmemb]|.  |nmemb| is an Expr'''
         self.basetype = basetype
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -3081,28 +3081,26 @@ class _GenerateProtocolActorCode(ipdl.as
                 const=1))
             otherpid.addstmts([
                 StmtReturn(ExprCall(
                     ExprVar('base::GetProcId'),
                     args=[ p.otherProcessVar() ])),
             ])
 
             dumpvar = ExprVar('aDump')
-            seqvar = ExprVar('aSequence')
             getdump = MethodDefn(MethodDecl(
                 'TakeMinidump',
-                params=[ Decl(Type('nsIFile', ptrptr=1), dumpvar.name),
-                         Decl(Type.UINT32PTR, seqvar.name)],
+                params=[ Decl(Type('nsIFile', ptrptr=1), dumpvar.name) ],
                 ret=Type.BOOL,
                 const=1))
             getdump.addstmts([
                 CppDirective('ifdef', 'MOZ_CRASHREPORTER'),
                 StmtReturn(ExprCall(
                     ExprVar('XRE_TakeMinidumpForChild'),
-                    args=[ ExprCall(otherpidvar), dumpvar, seqvar ])),
+                    args=[ ExprCall(otherpidvar), dumpvar ])),
                 CppDirective('else'),
                 StmtReturn.FALSE,
                 CppDirective('endif')
             ])
             self.cls.addstmts([ otherpid, Whitespace.NL,
                                 getdump, Whitespace.NL ])
 
         if (ptype.isToplevel() and self.side is 'parent'
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -18,17 +18,16 @@
 #undef WIN32_LEAN_AND_MEAN
 #endif
 
 #include "nsIWindowsRegKey.h"
 #include "client/windows/crash_generation/crash_generation_server.h"
 #include "client/windows/handler/exception_handler.h"
 #include <DbgHelp.h>
 #include <string.h>
-#include "nsDirectoryServiceUtils.h"
 
 #include "nsWindowsDllInterceptor.h"
 #elif defined(XP_MACOSX)
 #include "client/mac/crash_generation/client_info.h"
 #include "client/mac/crash_generation/crash_generation_server.h"
 #include "client/mac/handler/exception_handler.h"
 #include <string>
 #include <Carbon/Carbon.h>
@@ -36,16 +35,17 @@
 #include <crt_externs.h>
 #include <fcntl.h>
 #include <mach/mach.h>
 #include <sys/types.h>
 #include <spawn.h>
 #include <unistd.h>
 #include "mac_utils.h"
 #elif defined(XP_LINUX)
+#include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIINIParser.h"
 #include "common/linux/linux_libc_support.h"
 #include "common/linux/linux_syscall_support.h"
 #include "client/linux/crash_generation/client_info.h"
 #include "client/linux/crash_generation/crash_generation_server.h"
 #include "client/linux/handler/exception_handler.h"
 #include "client/linux/minidump_writer/linux_dumper.h"
@@ -147,17 +147,16 @@ typedef std::string xpstring;
 
 static const XP_CHAR dumpFileExtension[] = {'.', 'd', 'm', 'p',
                                             '\0'}; // .dmp
 static const XP_CHAR extraFileExtension[] = {'.', 'e', 'x', 't',
                                              'r', 'a', '\0'}; // .extra
 
 static google_breakpad::ExceptionHandler* gExceptionHandler = nsnull;
 
-static XP_CHAR* pendingDirectory;
 static XP_CHAR* crashReporterPath;
 
 // if this is false, we don't launch the crash reporter
 static bool doReport = true;
 
 // if this is true, we pass the exception on to the OS crash reporter
 static bool showOSCrashReporter = false;
 
@@ -217,41 +216,23 @@ static char* childCrashNotifyPipe;
 static int serverSocketFd = -1;
 static int clientSocketFd = -1;
 static const int kMagicChildCrashReportFd = 4;
 
 #  endif
 
 // |dumpMapLock| must protect all access to |pidToMinidump|.
 static Mutex* dumpMapLock;
-struct ChildProcessData : public nsUint32HashKey
-{
-  ChildProcessData(KeyTypePointer aKey)
-    : nsUint32HashKey(aKey)
-    , sequence(0)
-#ifdef MOZ_CRASHREPORTER_INJECTOR
-    , callback(NULL)
-#endif
-  { }
-
-  nsCOMPtr<nsIFile> minidump;
-  // Each crashing process is assigned an increasing sequence number to
-  // indicate which process crashed first.
-  PRUint32 sequence;
-#ifdef MOZ_CRASHREPORTER_INJECTOR
-  InjectorCrashCallback* callback;
-#endif
-};
-
-typedef nsTHashtable<ChildProcessData> ChildMinidumpMap;
+typedef nsInterfaceHashtable<nsUint32HashKey, nsIFile> ChildMinidumpMap;
 static ChildMinidumpMap* pidToMinidump;
-static PRUint32 crashSequence;
 
 #ifdef MOZ_CRASHREPORTER_INJECTOR
 static nsIThread* sInjectorThread;
+typedef nsDataHashtable<nsUint32HashKey, InjectorCrashCallback*> InjectorPIDMap;
+static InjectorPIDMap* pidToInjectorCallback;
 
 class ReportInjectedCrash : public nsRunnable
 {
 public:
   ReportInjectedCrash(PRUint32 pid) : mPID(pid) { }
 
   NS_IMETHOD Run();
 
@@ -728,23 +709,23 @@ nsresult SetExceptionHandler(nsIFile* aX
   exePath->Append(NS_LITERAL_STRING("Contents"));
   exePath->Append(NS_LITERAL_STRING("MacOS"));
 #endif
 
   exePath->AppendNative(NS_LITERAL_CSTRING(CRASH_REPORTER_FILENAME));
 
 #ifdef XP_WIN32
   nsString crashReporterPath_temp;
+  exePath->GetPath(crashReporterPath_temp);
 
-  exePath->GetPath(crashReporterPath_temp);
   crashReporterPath = ToNewUnicode(crashReporterPath_temp);
 #elif !defined(__ANDROID__)
   nsCString crashReporterPath_temp;
+  exePath->GetNativePath(crashReporterPath_temp);
 
-  exePath->GetNativePath(crashReporterPath_temp);
   crashReporterPath = ToNewCString(crashReporterPath_temp);
 #else
   // On Android, we launch using the application package name
   // instead of a filename, so use ANDROID_PACKAGE_NAME to do that here.
   //TODO: don't hardcode org.mozilla here, so other vendors can
   // ship XUL apps with different package names on Android?
   nsCString package(ANDROID_PACKAGE_NAME "/.CrashReporter");
   crashReporterPath = ToNewCString(package);
@@ -1147,21 +1128,16 @@ nsresult UnsetExceptionHandler()
   notesFieldLock = nsnull;
 
   delete crashReporterAPIData;
   crashReporterAPIData = nsnull;
 
   delete notesField;
   notesField = nsnull;
 
-  if (pendingDirectory) {
-    NS_Free(pendingDirectory);
-    pendingDirectory = nsnull;
-  }
-
   if (crashReporterPath) {
     NS_Free(crashReporterPath);
     crashReporterPath = nsnull;
   }
 
 #ifdef XP_MACOSX
   posix_spawnattr_destroy(&spawnattr);
 #endif
@@ -1671,33 +1647,33 @@ nsresult SetSubmitReports(bool aSubmitRe
       return rv;
     }
 
     obsServ->NotifyObservers(nsnull, "submit-reports-pref-changed", nsnull);
     return NS_OK;
 }
 
 // The "pending" dir is Crash Reports/pending, from which minidumps
-// can be submitted. Because this method may be called off the main thread,
-// we store the pending directory as a path.
+// can be submitted
 static bool
 GetPendingDir(nsIFile** dir)
 {
-  if (!pendingDirectory) {
-    NS_ERROR("Not initialized");
+  nsCOMPtr<nsIProperties> dirSvc =
+    do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
+  if (!dirSvc)
     return false;
-  }
-
-  nsCOMPtr<nsIFile> pending = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
-#ifdef XP_WIN
-  pending->InitWithPath(nsDependentString(pendingDirectory));
-#else
-  pending->InitWithNativePath(nsDependentCString(pendingDirectory));
-#endif
-  pending.swap(*dir);
+  nsCOMPtr<nsIFile> pendingDir;
+  if (NS_FAILED(dirSvc->Get("UAppData",
+                            NS_GET_IID(nsIFile),
+                            getter_AddRefs(pendingDir))) ||
+      NS_FAILED(pendingDir->Append(NS_LITERAL_STRING("Crash Reports"))) ||
+      NS_FAILED(pendingDir->Append(NS_LITERAL_STRING("pending"))))
+    return false;
+  *dir = NULL;
+  pendingDir.swap(*dir);
   return true;
 }
 
 // The "limbo" dir is where minidumps go to wait for something else to
 // use them.  If we're |ShouldReport()|, then the "something else" is
 // a minidump submitter, and they're coming from the 
 // Crash Reports/pending/ dir.  Otherwise, we don't know what the
 // "somthing else" is, but the minidumps stay in [profile]/minidumps/
@@ -1952,55 +1928,42 @@ OnChildProcessDumpRequested(void* aConte
   {
     PRUint32 pid =
 #ifdef XP_MACOSX
       aClientInfo.pid();
 #else
       aClientInfo->pid();
 #endif
 
-#ifdef MOZ_CRASHREPORTER_INJECTOR
-    bool runCallback;
-#endif
     {
       MutexAutoLock lock(*dumpMapLock);
-      ChildProcessData* pd = pidToMinidump->PutEntry(pid);
-      MOZ_ASSERT(!pd->minidump);
-      pd->minidump = minidump;
-      pd->sequence = ++crashSequence;
-#ifdef MOZ_CRASHREPORTER_INJECTOR
-      runCallback = NULL != pd->callback;
-#endif
+      pidToMinidump->Put(pid, minidump);
     }
 #ifdef MOZ_CRASHREPORTER_INJECTOR
-    if (runCallback)
-      NS_DispatchToMainThread(new ReportInjectedCrash(pid));
+    NS_DispatchToMainThread(new ReportInjectedCrash(pid));
 #endif
   }
 }
 
 static bool
 OOPInitialized()
 {
   return pidToMinidump != NULL;
 }
 
 static bool ChildFilter(void *context) {
   mozilla::DisableWritePoisoning();
   return true;
 }
 
-void
+static void
 OOPInit()
 {
-  if (OOPInitialized())
-    return;
-
-  MOZ_ASSERT(NS_IsMainThread());
-
+  NS_ABORT_IF_FALSE(!OOPInitialized(),
+                    "OOP crash reporter initialized more than once!");
   NS_ABORT_IF_FALSE(gExceptionHandler != NULL,
                     "attempt to initialize OOP crash reporter before in-process crashreporter!");
 
 #if defined(XP_WIN)
   childCrashNotifyPipe =
     PR_smprintf("\\\\.\\pipe\\gecko-crash-server-pipe.%i",
                 static_cast<int>(::GetCurrentProcessId()));
 
@@ -2051,51 +2014,34 @@ OOPInit()
 
   if (!crashServer->Start())
     NS_RUNTIMEABORT("can't start crash reporter server()");
 
   pidToMinidump = new ChildMinidumpMap();
   pidToMinidump->Init();
 
   dumpMapLock = new Mutex("CrashReporter::dumpMapLock");
-
-  nsCOMPtr<nsIFile> pendingDir;
-  nsresult rv = NS_GetSpecialDirectory("UAppData", getter_AddRefs(pendingDir));
-  if (NS_FAILED(rv)) {
-    NS_ERROR("Couldn't get the user appdata directory!");
-    return;
-  }
-
-  pendingDir->Append(NS_LITERAL_STRING("Crash Reports"));
-  pendingDir->Append(NS_LITERAL_STRING("pending"));
-
-#ifdef XP_WIN
-  nsString path;
-  pendingDir->GetPath(path);
-  pendingDirectory = ToNewUnicode(path);
-#else
-  nsCString path;
-  pendingDir->GetNativePath(path);
-  pendingDirectory = ToNewUnicode(path);
-#endif  
 }
 
 static void
 OOPDeinit()
 {
   if (!OOPInitialized()) {
     NS_WARNING("OOPDeinit() without successful OOPInit()");
     return;
   }
 
 #ifdef MOZ_CRASHREPORTER_INJECTOR
   if (sInjectorThread) {
     sInjectorThread->Shutdown();
     NS_RELEASE(sInjectorThread);
   }
+
+  delete pidToInjectorCallback;
+  pidToInjectorCallback = NULL;
 #endif
 
   delete crashServer;
   crashServer = NULL;
 
   delete dumpMapLock;
   dumpMapLock = NULL;
 
@@ -2111,79 +2057,80 @@ OOPDeinit()
 #if defined(XP_WIN) || defined(XP_MACOSX)
 // Parent-side API for children
 const char*
 GetChildNotificationPipe()
 {
   if (!GetEnabled())
     return kNullNotifyPipe;
 
-  MOZ_ASSERT(OOPInitialized());
+  if (!OOPInitialized())
+    OOPInit();
 
   return childCrashNotifyPipe;
 }
 #endif
 
 #ifdef MOZ_CRASHREPORTER_INJECTOR
 void
 InjectCrashReporterIntoProcess(DWORD processID, InjectorCrashCallback* cb)
 {
   if (!GetEnabled())
     return;
 
   if (!OOPInitialized())
     OOPInit();
 
+  if (!pidToInjectorCallback) {
+    pidToInjectorCallback = new InjectorPIDMap;
+    pidToInjectorCallback->Init();
+  }
+
   if (!sInjectorThread) {
     if (NS_FAILED(NS_NewThread(&sInjectorThread)))
       return;
   }
 
-  {
-    MutexAutoLock lock(*dumpMapLock);
-    ChildProcessData* pd = pidToMinidump->PutEntry(processID);
-    MOZ_ASSERT(!pd->minidump && !pd->callback);
-    pd->callback = cb;
-  }
+  pidToInjectorCallback->Put(processID, cb);
 
   nsCOMPtr<nsIRunnable> r = new InjectCrashRunnable(processID);
   sInjectorThread->Dispatch(r, nsIEventTarget::DISPATCH_NORMAL);
 }
 
 NS_IMETHODIMP
 ReportInjectedCrash::Run()
 {
   // Crash reporting may have been disabled after this method was dispatched
-  if (!OOPInitialized())
+  if (!pidToInjectorCallback)
+    return NS_OK;
+
+  InjectorCrashCallback* cb = pidToInjectorCallback->Get(mPID);
+  if (!cb)
     return NS_OK;
 
-  InjectorCrashCallback* cb;
-  {
-    MutexAutoLock lock(*dumpMapLock);
-    ChildProcessData* pd = pidToMinidump->GetEntry(mPID);
-    if (!pd || !pd->callback)
-      return NS_OK;
-
-    MOZ_ASSERT(pd->minidump);
-
-    cb = pd->callback;
+  nsCOMPtr<nsIFile> minidump;
+  if (!TakeMinidumpForChild(mPID, getter_AddRefs(minidump))) {
+    NS_WARNING("No minidump for crash notification.");
+    return NS_OK;
   }
 
-  cb->OnCrash(mPID);
+  nsString id;
+  GetIDFromMinidump(minidump, id);
+
+  cb->OnCrash(mPID, id);
   return NS_OK;
 }
 
 void
 UnregisterInjectorCallback(DWORD processID)
 {
   if (!OOPInitialized())
     return;
 
-  MutexAutoLock lock(*dumpMapLock);
-  pidToMinidump->RemoveEntry(processID);
+  pidToInjectorCallback->Remove(processID);
 }
 
 #endif // MOZ_CRASHREPORTER_INJECTOR
 
 #if defined(XP_WIN)
 // Child-side API
 bool
 SetRemoteExceptionHandler(const nsACString& crashPipe)
@@ -2219,17 +2166,18 @@ bool
 CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd)
 {
   if (!GetEnabled()) {
     *childCrashFd = -1;
     *childCrashRemapFd = -1;
     return true;
   }
 
-  MOZ_ASSERT(OOPInitialized());
+  if (!OOPInitialized())
+    OOPInit();
 
   *childCrashFd = clientSocketFd;
   *childCrashRemapFd = kMagicChildCrashReportFd;
 
   return true;
 }
 
 // Child-side API
@@ -2279,35 +2227,32 @@ SetRemoteExceptionHandler(const nsACStri
 
   // we either do remote or nothing, no fallback to regular crash reporting
   return gExceptionHandler->IsOutOfProcess();
 }
 #endif  // XP_WIN
 
 
 bool
-TakeMinidumpForChild(PRUint32 childPid, nsIFile** dump, PRUint32* aSequence)
+TakeMinidumpForChild(PRUint32 childPid, nsIFile** dump)
 {
   if (!GetEnabled())
     return false;
 
   MutexAutoLock lock(*dumpMapLock);
 
-  ChildProcessData* pd = pidToMinidump->GetEntry(childPid);
-  if (!pd)
-    return false;
+  nsCOMPtr<nsIFile> d;
+  bool found = pidToMinidump->Get(childPid, getter_AddRefs(d));
+  if (found)
+    pidToMinidump->Remove(childPid);
 
-  NS_IF_ADDREF(*dump = pd->minidump);
-  if (aSequence) {
-    *aSequence = pd->sequence;
-  }
-  
-  pidToMinidump->RemoveEntry(childPid);
+  *dump = NULL;
+  d.swap(*dump);
 
-  return !!*dump;
+  return found;
 }
 
 //-----------------------------------------------------------------------------
 // CreatePairedMinidumps() and helpers
 //
 struct PairedDumpContext {
   nsCOMPtr<nsIFile>* minidump;
   nsCOMPtr<nsIFile>* extra;
--- a/toolkit/crashreporter/nsExceptionHandler.h
+++ b/toolkit/crashreporter/nsExceptionHandler.h
@@ -64,27 +64,21 @@ bool AppendExtraData(nsIFile* extraFile,
 #ifdef XP_MACOSX
   nsresult AppendObjCExceptionInfoToAppNotes(void *inException);
 #endif
 nsresult GetSubmitReports(bool* aSubmitReport);
 nsresult SetSubmitReports(bool aSubmitReport);
 
 // Out-of-process crash reporter API.
 
-// Initializes out-of-process crash reporting. This method must be called
-// before the platform-specifi notificationpipe APIs are called.
-void OOPInit();
-
-// Return true if a dump was found for |childPid|, and return the
+// Return true iff a dump was found for |childPid|, and return the
 // path in |dump|.  The caller owns the last reference to |dump| if it
-// is non-NULL. The sequence parameter will be filled with an ordinal
-// indicating which remote process crashed first.
+// is non-NULL.
 bool TakeMinidumpForChild(PRUint32 childPid,
-                          nsIFile** dump NS_OUTPARAM,
-                          PRUint32* aSequence = NULL);
+                          nsIFile** dump NS_OUTPARAM);
 
 #if defined(XP_WIN)
 typedef HANDLE ProcessHandle;
 typedef DWORD ThreadId;
 #elif defined(XP_MACOSX)
 typedef task_t ProcessHandle;
 typedef mach_port_t ThreadId;
 #else
@@ -121,27 +115,19 @@ const char* GetChildNotificationPipe();
 // Inject a crash report client into an arbitrary process, and inform the
 // callback object when it crashes. Parent process only.
 
 class InjectorCrashCallback
 {
 public:
   InjectorCrashCallback() { }
 
-  /**
-   * Inform the callback of a crash. The client code should call
-   * TakeMinidumpForChild to remove it from the PID mapping table.
-   *
-   * The callback will not be fired if the client has already called
-   * TakeMinidumpForChild for this process ID.
-   */
-  virtual void OnCrash(DWORD processID) = 0;
+  virtual void OnCrash(DWORD processID, const nsAString& aDumpID) = 0;
 };
 
-// This method implies OOPInit
 void InjectCrashReporterIntoProcess(DWORD processID, InjectorCrashCallback* cb);
 void UnregisterInjectorCallback(DWORD processID);
 #endif
 
 // Child-side API
 bool SetRemoteExceptionHandler(const nsACString& crashPipe);
 
 #  elif defined(XP_LINUX)
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -221,20 +221,19 @@ GeckoProcessType sChildProcessType = Gec
 }
 }
 
 #if defined(MOZ_CRASHREPORTER)
 // FIXME/bug 539522: this out-of-place function is stuck here because
 // IPDL wants access to this crashreporter interface, and
 // crashreporter is built in such a way to make that awkward
 bool
-XRE_TakeMinidumpForChild(PRUint32 aChildPid, nsIFile** aDump,
-                         PRUint32* aSequence)
+XRE_TakeMinidumpForChild(PRUint32 aChildPid, nsIFile** aDump)
 {
-  return CrashReporter::TakeMinidumpForChild(aChildPid, aDump, aSequence);
+  return CrashReporter::TakeMinidumpForChild(aChildPid, aDump);
 }
 
 bool
 XRE_SetRemoteExceptionHandler(const char* aPipe/*= 0*/)
 {
 #if defined(XP_WIN) || defined(XP_MACOSX)
   return CrashReporter::SetRemoteExceptionHandler(nsDependentCString(aPipe));
 #elif defined(OS_LINUX)
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -362,18 +362,17 @@ XRE_API(const char*,
         XRE_ChildProcessTypeToString, (GeckoProcessType aProcessType))
 
 XRE_API(GeckoProcessType,
         XRE_StringToChildProcessType, (const char* aProcessTypeString))
 
 #if defined(MOZ_CRASHREPORTER)
 // Used in the "master" parent process hosting the crash server
 XRE_API(bool,
-        XRE_TakeMinidumpForChild, (PRUint32 aChildPid, nsIFile** aDump,
-                                   PRUint32* aSequence))
+        XRE_TakeMinidumpForChild, (PRUint32 aChildPid, nsIFile** aDump))
 
 // Used in child processes.
 XRE_API(bool,
         XRE_SetRemoteExceptionHandler, (const char* aPipe))
 #endif
 
 XRE_API(nsresult,
         XRE_InitChildProcess, (int aArgc,