--- 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,