diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp index 6fba9121ee5d..25bcc79cec06 100644 --- a/ipc/glue/GeckoChildProcessHost.cpp +++ b/ipc/glue/GeckoChildProcessHost.cpp @@ -63,6 +63,7 @@ #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; @@ -122,6 +123,16 @@ GeckoChildProcessHost::~GeckoChildProcessHost() 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 @@ -621,6 +632,12 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector& aExt 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 @@ -769,6 +786,10 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector& aExt #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. @@ -1007,6 +1028,14 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector& aExt cmdLine.AppendLooseValue( UTF8ToWide(CrashReporter::GetChildNotificationPipe())); + PROsfd h = PR_FileDesc2NativeHandle(crashAnnotationWritePipe); +# if defined(MOZ_SANDBOX) + mSandboxBroker.AddHandleToShare(reinterpret_cast(h)); +# endif // defined(MOZ_SANDBOX) + mLaunchOptions->handles_to_inherit.push_back(reinterpret_cast(h)); + std::string hStr = std::to_string(h); + cmdLine.AppendLooseValue(UTF8ToWide(hStr)); + // Process type cmdLine.AppendLooseValue(UTF8ToWide(childProcessType)); @@ -1069,6 +1098,15 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector& aExt ) { 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(); @@ -1140,7 +1178,7 @@ GeckoChildProcessHost::LaunchAndroidService(const char* type, 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); @@ -1154,7 +1192,8 @@ GeckoChildProcessHost::LaunchAndroidService(const char* type, 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; diff --git 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 index 7dd7808f33f0..36da57c53957 100644 --- 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 @@ -10,5 +10,5 @@ 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); } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java index 3dcb4fba67be..a4c9662fd20a 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java @@ -127,6 +127,7 @@ public class GeckoThread extends Thread { // Child process parameters private int mCrashFileDescriptor = -1; private int mIPCFileDescriptor = -1; + private int mCrashAnnotationFileDescriptor = -1; GeckoThread() { setName("Gecko"); @@ -139,7 +140,8 @@ public class GeckoThread extends Thread { 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(); @@ -153,6 +155,7 @@ public class GeckoThread extends Thread { mFlags = flags; mCrashFileDescriptor = crashFd; mIPCFileDescriptor = ipcFd; + mCrashAnnotationFileDescriptor = crashAnnotationFd; mInitialized = true; notifyAll(); @@ -162,13 +165,15 @@ public class GeckoThread extends Thread { 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, @@ -404,7 +409,7 @@ public class GeckoThread extends Thread { } // And go. - GeckoLoader.nativeRun(args, mCrashFileDescriptor, mIPCFileDescriptor); + GeckoLoader.nativeRun(args, mCrashFileDescriptor, mIPCFileDescriptor, mCrashAnnotationFileDescriptor); // And... we're done. final boolean restarting = isState(State.RESTARTING); diff --git 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 index 77eacdf434aa..ca01fd3cb749 100644 --- 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 @@ -493,7 +493,7 @@ public final class GeckoLoader { 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); diff --git 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 index ad9e22c27907..a2ade7b97a08 100644 --- 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 @@ -168,12 +168,14 @@ public final class GeckoProcessManager extends IProcessManager.Stub { @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) { @@ -182,9 +184,11 @@ public final class GeckoProcessManager extends IProcessManager.Stub { 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; @@ -192,7 +196,7 @@ public final class GeckoProcessManager extends IProcessManager.Stub { boolean started = false; try { - started = child.start(this, args, crashPfd, ipcPfd); + started = child.start(this, args, crashPfd, ipcPfd, crashAnnotationPfd); } catch (final RemoteException e) { } @@ -203,7 +207,7 @@ public final class GeckoProcessManager extends IProcessManager.Stub { } 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 { diff --git 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 index c29663611ef2..913aa9d1e2d7 100644 --- 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 @@ -62,7 +62,8 @@ public class GeckoServiceChildProcess extends Service { 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"); @@ -74,11 +75,12 @@ public class GeckoServiceChildProcess extends Service { 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(); } } diff --git a/mozglue/android/APKOpen.cpp b/mozglue/android/APKOpen.cpp index a88b138f7d6f..4c95e3512e72 100644 --- a/mozglue/android/APKOpen.cpp +++ b/mozglue/android/APKOpen.cpp @@ -408,7 +408,7 @@ FreeArgv(char** argv, int argc) } 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); @@ -423,7 +423,7 @@ Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jo 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; @@ -592,4 +592,4 @@ Java_org_mozilla_gecko_mozglue_GeckoLoader_suppressCrashDialog(JNIEnv *jenv, jcl sigaction(SIGSTKFLT, &action, nullptr); #endif sigaction(SIGTRAP, &action, nullptr); -} \ No newline at end of file +} diff --git a/toolkit/crashreporter/nsDummyExceptionHandler.cpp b/toolkit/crashreporter/nsDummyExceptionHandler.cpp index 83451c99c982..f4eef3f04239 100644 --- a/toolkit/crashreporter/nsDummyExceptionHandler.cpp +++ b/toolkit/crashreporter/nsDummyExceptionHandler.cpp @@ -141,6 +141,24 @@ 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) @@ -298,16 +316,10 @@ 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; } @@ -391,6 +403,11 @@ SetNotificationPipeForChild(int childCrashFd) { } +void +SetCrashAnnotationPipeForChild(int childCrashAnnotationFd) +{ +} + void AddLibraryMapping(const char* library_name, uintptr_t start_address, diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index 468b48542134..7e155d5ec600 100644 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -25,6 +25,7 @@ #include "nsXULAppAPI.h" #include "jsfriendapi.h" #include "ThreadAnnotation.h" +#include "private/pprio.h" #if defined(XP_WIN32) #ifdef WIN32_LEAN_AND_MEAN @@ -242,6 +243,7 @@ static bool sIncludeContextHeap = false; // OOP crash reporting static CrashGenerationServer* crashServer; // chrome process has this +static std::map processToCrashFd; static std::terminate_handler oldTerminateHandler = nullptr; @@ -269,6 +271,10 @@ static int gMagicChildCrashReportFd = ; # 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 @@ -579,6 +585,8 @@ public: nullptr); } + void OpenHandle(HANDLE aHandle) { mHandle = aHandle; } + bool Valid() { return mHandle != INVALID_HANDLE_VALUE; } @@ -625,6 +633,8 @@ public: mFD = sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600); } + void OpenHandle(int aFd) { mFD = aFd; } + bool Valid() { return mFD != -1; } @@ -1261,45 +1271,18 @@ BuildTempPath(PathStringT& aResult) } 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(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). @@ -1395,7 +1378,7 @@ ChildFPEFilter(void* context, EXCEPTION_POINTERS* exinfo, { bool result = FPEFilter(context, exinfo, assertion); if (result) { - PrepareChildExceptionTimeAnnotations(); + PrepareChildExceptionTimeAnnotations(context); } return result; } @@ -1461,7 +1444,7 @@ ChildFilter(void* context) { bool result = Filter(context); if (result) { - PrepareChildExceptionTimeAnnotations(); + PrepareChildExceptionTimeAnnotations(context); } return result; } @@ -3056,50 +3039,6 @@ AppendExtraData(nsIFile* extraFile, const AnnotationTable& data) return WriteExtraData(extraFile, data, Blacklist()); } -static bool -GetExtraFileForChildPid(uint32_t aPid, nsIFile** aExtraFile) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - - nsCOMPtr 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) { @@ -3174,19 +3113,27 @@ WriteExtraForMinidump(nsIFile* minidump, return false; } - nsCOMPtr 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); @@ -3538,30 +3485,39 @@ UnregisterInjectorCallback(DWORD 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; - } +#if defined(MOZ_WIDGET_ANDROID) + return gChildCrashAnnotationReportFd; +#else + return 7; +#endif // defined(MOZ_WIDGET_ANDROID) +} +#endif - // When retrieved by the child process, this will always resolve to the - // correct directory regardless of sandbox level. - nsCOMPtr tmpDir; - nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpDir)); - if (NS_SUCCEEDED(rv)) { - childProcessTmpDir = CreatePathFromFile(tmpDir); +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)) @@ -3569,15 +3525,15 @@ SetRemoteExceptionHandler(const nsACString& crashPipe) 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(aCrashTimeAnnotationFile), + google_breakpad::ExceptionHandler::HANDLER_ALL, + GetMinidumpType(), + NS_ConvertASCIItoUTF16(crashPipe).get(), + nullptr); gExceptionHandler->set_handle_debug_exceptions(true); RunAndCleanUpDelayedNotes(); @@ -4081,6 +4037,11 @@ 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, diff --git a/toolkit/crashreporter/nsExceptionHandler.h b/toolkit/crashreporter/nsExceptionHandler.h index 4a272ece2a84..9c5d4c26ec52 100644 --- a/toolkit/crashreporter/nsExceptionHandler.h +++ b/toolkit/crashreporter/nsExceptionHandler.h @@ -19,6 +19,7 @@ #include #include "nsError.h" #include "nsString.h" +#include "prio.h" #if defined(XP_WIN32) #ifdef WIN32_LEAN_AND_MEAN @@ -176,15 +177,30 @@ bool TakeMinidumpForChild(uint32_t childPid, #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 @@ -264,8 +280,13 @@ 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 @@ -291,6 +312,7 @@ bool UnsetRemoteExceptionHandler(); // 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//maps // will just show anonymous mappings for all the non-system diff --git a/toolkit/xre/Bootstrap.cpp b/toolkit/xre/Bootstrap.cpp index c19f0498d08f..ba8400b08deb 100644 --- a/toolkit/xre/Bootstrap.cpp +++ b/toolkit/xre/Bootstrap.cpp @@ -78,8 +78,8 @@ public: ::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 diff --git a/toolkit/xre/Bootstrap.h b/toolkit/xre/Bootstrap.h index be454f84b8fb..150583feb2ea 100644 --- a/toolkit/xre/Bootstrap.h +++ b/toolkit/xre/Bootstrap.h @@ -113,7 +113,7 @@ public: #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 diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index 272e86923b2a..2acb2c5618ff 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -243,10 +243,11 @@ GeckoProcessType sChildProcessType = GeckoProcessType_Default; #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) @@ -282,9 +283,17 @@ XRE_TakeMinidumpForChild(uint32_t aChildPid, nsIFile** aDump, } 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(); @@ -479,13 +488,20 @@ XRE_InitChildProcess(int aArgc, 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(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. @@ -494,6 +510,13 @@ XRE_InitChildProcess(int aArgc, // 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 @@ -672,10 +695,6 @@ XRE_InitChildProcess(int aArgc, 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 diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index 85f977821b2a..f4d3cf5ce7b5 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -2401,9 +2401,9 @@ 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::Call(GeckoProcessManager::Context(), nullptr, a0, a1, a2, a3); + return mozilla::jni::Method::Call(GeckoProcessManager::Context(), nullptr, a0, a1, a2, a3, a4); } const char GeckoServiceChildProcess::name[] = diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index f00477c88230..535f1369c06b 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -6921,10 +6921,11 @@ public: 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"; + "(Ljava/lang/String;[Ljava/lang/String;III)I"; static const bool isStatic = true; static const mozilla::jni::ExceptionMode exceptionMode = mozilla::jni::ExceptionMode::ABORT; @@ -6934,7 +6935,7 @@ public: mozilla::jni::DispatchTarget::CURRENT; }; - static auto Start(mozilla::jni::String::Param, mozilla::jni::ObjectArray::Param, int32_t, int32_t) -> int32_t; + 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; diff --git a/xpcom/build/nsXULAppAPI.h b/xpcom/build/nsXULAppAPI.h index 6493e08ed754..4d695948aee2 100644 --- a/xpcom/build/nsXULAppAPI.h +++ b/xpcom/build/nsXULAppAPI.h @@ -398,7 +398,7 @@ XRE_API(const char*, #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, @@ -410,8 +410,16 @@ XRE_API(bool, uint32_t* aSequence)) // Used in child processes. +#if defined(XP_WIN) +// Uses uintptr_t, even though it's really a HANDLE, because including +// 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 {