зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1463048 - Remove asynchronous minidump generation r=ted
This reverts the changes in bug 1360308, bug 1390143 and bug 1469603. Minidump generation will now only happen on the main process' main thread which might lead to hangs but is known to be fairly robust. Asynchronous generation proved too brittle and enormously increased the complexity of this already hard-to-read code. Differential Revision: https://phabricator.services.mozilla.com/D5147 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
e361f7ef17
Коммит
a1f6255102
|
@ -3381,34 +3381,17 @@ ContentParent::KillHard(const char* aReason)
|
|||
mCrashReporter->AddAnnotation(CrashReporter::Annotation::ipc_channel_error,
|
||||
reason);
|
||||
|
||||
Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1);
|
||||
|
||||
RefPtr<ContentParent> self = this;
|
||||
std::function<void(bool)> callback = [self](bool aResult) {
|
||||
self->OnGenerateMinidumpComplete(aResult);
|
||||
};
|
||||
// Generate the report and insert into the queue for submittal.
|
||||
mCrashReporter->GenerateMinidumpAndPair(Process(),
|
||||
nullptr,
|
||||
NS_LITERAL_CSTRING("browser"),
|
||||
std::move(callback),
|
||||
true);
|
||||
return;
|
||||
if (mCrashReporter->GenerateMinidumpAndPair(this,
|
||||
nullptr,
|
||||
NS_LITERAL_CSTRING("browser")))
|
||||
{
|
||||
mCreatedPairedMinidumps = mCrashReporter->FinalizeCrashReport();
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1);
|
||||
}
|
||||
|
||||
OnGenerateMinidumpComplete(false);
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::OnGenerateMinidumpComplete(bool aDumpResult)
|
||||
{
|
||||
if (mCrashReporter && aDumpResult) {
|
||||
// CrashReporterHost::GenerateMinidumpAndPair() is successful.
|
||||
mCreatedPairedMinidumps = mCrashReporter->FinalizeCrashReport();
|
||||
}
|
||||
|
||||
Unused << aDumpResult; // Don't care about result if no minidump was requested.
|
||||
|
||||
ProcessHandle otherProcessHandle;
|
||||
if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle)) {
|
||||
NS_ERROR("Failed to open child process when attempting kill.");
|
||||
|
|
|
@ -862,8 +862,6 @@ private:
|
|||
// Start the force-kill timer on shutdown.
|
||||
void StartForceKillTimer();
|
||||
|
||||
void OnGenerateMinidumpComplete(bool aDumpResult);
|
||||
|
||||
// Ensure that the permissions for the giben Permission key are set in the
|
||||
// content process.
|
||||
//
|
||||
|
|
|
@ -264,8 +264,6 @@ private:
|
|||
void SendHangNotification(const HangData& aHangData,
|
||||
const nsString& aBrowserDumpId,
|
||||
bool aTakeMinidump);
|
||||
void OnTakeFullMinidumpComplete(const HangData& aHangData,
|
||||
const nsString& aDumpId);
|
||||
|
||||
void ClearHangNotification();
|
||||
|
||||
|
@ -738,48 +736,25 @@ HangMonitorParent::SendHangNotification(const HangData& aHangData,
|
|||
// chrome process, main thread
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsString dumpId;
|
||||
if ((aHangData.type() == HangData::TPluginHangData) && aTakeMinidump) {
|
||||
// We've been handed a partial minidump; complete it with plugin and
|
||||
// content process dumps.
|
||||
const PluginHangData& phd = aHangData.get_PluginHangData();
|
||||
|
||||
WeakPtr<HangMonitorParent> self = this;
|
||||
std::function<void(nsString)> callback =
|
||||
[self, aHangData](nsString aResult) {
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!self) {
|
||||
// Don't report hang since the process has already shut down.
|
||||
return;
|
||||
}
|
||||
|
||||
self->UpdateMinidump(aHangData.get_PluginHangData().pluginId(),
|
||||
aResult);
|
||||
self->OnTakeFullMinidumpComplete(aHangData, aResult);
|
||||
};
|
||||
|
||||
plugins::TakeFullMinidump(phd.pluginId(),
|
||||
phd.contentProcessId(),
|
||||
aBrowserDumpId,
|
||||
std::move(callback),
|
||||
true);
|
||||
plugins::TakeFullMinidump(phd.pluginId(), phd.contentProcessId(),
|
||||
aBrowserDumpId, dumpId);
|
||||
UpdateMinidump(phd.pluginId(), dumpId);
|
||||
} else {
|
||||
// We already have a full minidump; go ahead and use it.
|
||||
OnTakeFullMinidumpComplete(aHangData, aBrowserDumpId);
|
||||
dumpId = aBrowserDumpId;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HangMonitorParent::OnTakeFullMinidumpComplete(const HangData& aHangData,
|
||||
const nsString& aDumpId)
|
||||
{
|
||||
mProcess->SetHangData(aHangData, aDumpId);
|
||||
mProcess->SetHangData(aHangData, dumpId);
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
observerService->NotifyObservers(mProcess,
|
||||
"process-hang-report",
|
||||
nullptr);
|
||||
observerService->NotifyObservers(mProcess, "process-hang-report", nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1117,20 +1092,12 @@ HangMonitoredProcess::TerminatePlugin()
|
|||
// Use the multi-process crash report generated earlier.
|
||||
uint32_t id = mHangData.get_PluginHangData().pluginId();
|
||||
base::ProcessId contentPid = mHangData.get_PluginHangData().contentProcessId();
|
||||
plugins::TerminatePlugin(id, contentPid, NS_LITERAL_CSTRING("HangMonitor"),
|
||||
mDumpId);
|
||||
|
||||
RefPtr<HangMonitoredProcess> self{this};
|
||||
std::function<void(bool)> callback =
|
||||
[self, id](bool aResult) {
|
||||
if (self->mActor) {
|
||||
self->mActor->CleanupPluginHang(id, false);
|
||||
}
|
||||
};
|
||||
|
||||
plugins::TerminatePlugin(id,
|
||||
contentPid,
|
||||
NS_LITERAL_CSTRING("HangMonitor"),
|
||||
mDumpId,
|
||||
std::move(callback));
|
||||
if (mActor) {
|
||||
mActor->CleanupPluginHang(id, false);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
#ifndef mozilla_plugins_PluginBridge_h
|
||||
#define mozilla_plugins_PluginBridge_h
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "base/process.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -41,15 +39,14 @@ void
|
|||
TakeFullMinidump(uint32_t aPluginId,
|
||||
base::ProcessId aContentProcessId,
|
||||
const nsAString& aBrowserDumpId,
|
||||
std::function<void(nsString)>&& aCallback,
|
||||
bool aAsync);
|
||||
nsString& aDumpId);
|
||||
|
||||
void
|
||||
TerminatePlugin(uint32_t aPluginId,
|
||||
base::ProcessId aContentProcessId,
|
||||
const nsCString& aMonitorDescription,
|
||||
const nsAString& aDumpId,
|
||||
std::function<void(bool)>&& aCallback);
|
||||
const nsAString& aDumpId);
|
||||
|
||||
} // namespace plugins
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -355,13 +355,10 @@ PluginHangUIParent::RecvUserResponse(const unsigned int& aResponse)
|
|||
int responseCode;
|
||||
if (aResponse & HANGUI_USER_RESPONSE_STOP) {
|
||||
// User clicked Stop
|
||||
std::function<void(bool)> callback = [](bool aResult) { };
|
||||
mModule->TerminateChildProcess(mMainThreadMessageLoop,
|
||||
mozilla::ipc::kInvalidProcessId,
|
||||
NS_LITERAL_CSTRING("ModalHangUI"),
|
||||
EmptyString(),
|
||||
mModule->DummyCallback<bool>(),
|
||||
/* aAsync = */ false);
|
||||
EmptyString());
|
||||
responseCode = 1;
|
||||
} else if(aResponse & HANGUI_USER_RESPONSE_CONTINUE) {
|
||||
mModule->OnHangUIContinue();
|
||||
|
|
|
@ -357,19 +357,13 @@ void
|
|||
mozilla::plugins::TakeFullMinidump(uint32_t aPluginId,
|
||||
base::ProcessId aContentProcessId,
|
||||
const nsAString& aBrowserDumpId,
|
||||
std::function<void(nsString)>&& aCallback,
|
||||
bool aAsync)
|
||||
nsString& aDumpId)
|
||||
{
|
||||
PluginModuleChromeParent* chromeParent =
|
||||
PluginModuleChromeParentForId(aPluginId);
|
||||
|
||||
if (chromeParent) {
|
||||
chromeParent->TakeFullMinidump(aContentProcessId,
|
||||
aBrowserDumpId,
|
||||
std::move(aCallback),
|
||||
aAsync);
|
||||
} else {
|
||||
aCallback(EmptyString());
|
||||
chromeParent->TakeFullMinidump(aContentProcessId, aBrowserDumpId, aDumpId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,8 +371,7 @@ void
|
|||
mozilla::plugins::TerminatePlugin(uint32_t aPluginId,
|
||||
base::ProcessId aContentProcessId,
|
||||
const nsCString& aMonitorDescription,
|
||||
const nsAString& aDumpId,
|
||||
std::function<void(bool)>&& aCallback)
|
||||
const nsAString& aDumpId)
|
||||
{
|
||||
PluginModuleChromeParent* chromeParent =
|
||||
PluginModuleChromeParentForId(aPluginId);
|
||||
|
@ -387,11 +380,7 @@ mozilla::plugins::TerminatePlugin(uint32_t aPluginId,
|
|||
chromeParent->TerminateChildProcess(MessageLoop::current(),
|
||||
aContentProcessId,
|
||||
aMonitorDescription,
|
||||
aDumpId,
|
||||
std::move(aCallback),
|
||||
true); // Always runs asynchronously.
|
||||
} else {
|
||||
aCallback(true);
|
||||
aDumpId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -587,7 +576,7 @@ PluginModuleChromeParent::InitCrashReporter()
|
|||
}
|
||||
|
||||
{
|
||||
mozilla::RecursiveMutexAutoLock lock(mCrashReporterMutex);
|
||||
mozilla::MutexAutoLock lock(mCrashReporterMutex);
|
||||
mCrashReporter = MakeUnique<ipc::CrashReporterHost>(
|
||||
GeckoProcessType_Plugin,
|
||||
shmem,
|
||||
|
@ -727,7 +716,7 @@ void
|
|||
PluginModuleChromeParent::WriteExtraDataForMinidump()
|
||||
{
|
||||
// mCrashReporterMutex is already held by the caller
|
||||
mCrashReporterMutex.AssertCurrentThreadIn();
|
||||
mCrashReporterMutex.AssertCurrentThreadOwns();
|
||||
|
||||
typedef nsDependentCString cstring;
|
||||
|
||||
|
@ -1066,14 +1055,10 @@ PluginModuleChromeParent::ShouldContinueFromReplyTimeout()
|
|||
FinishHangUI();
|
||||
#endif // XP_WIN
|
||||
|
||||
// Terminate the child process synchronously because this function can be
|
||||
// called in sync IPC.
|
||||
TerminateChildProcess(MessageLoop::current(),
|
||||
mozilla::ipc::kInvalidProcessId,
|
||||
NS_LITERAL_CSTRING("ModalHangUI"),
|
||||
EmptyString(),
|
||||
DummyCallback<bool>(),
|
||||
/* aAsync = */ false);
|
||||
EmptyString());
|
||||
GetIPCChannel()->CloseWithTimeout();
|
||||
return false;
|
||||
}
|
||||
|
@ -1098,141 +1083,55 @@ PluginModuleContentParent::OnExitedSyncSend()
|
|||
void
|
||||
PluginModuleChromeParent::TakeFullMinidump(base::ProcessId aContentPid,
|
||||
const nsAString& aBrowserDumpId,
|
||||
std::function<void(nsString)>&& aCallback,
|
||||
bool aAsync)
|
||||
nsString& aDumpId)
|
||||
{
|
||||
mozilla::RecursiveMutexAutoLock lock(mCrashReporterMutex);
|
||||
mozilla::MutexAutoLock lock(mCrashReporterMutex);
|
||||
|
||||
if (!mCrashReporter || !mTakeFullMinidumpCallback.IsEmpty()) {
|
||||
aCallback(EmptyString());
|
||||
if (!mCrashReporter) {
|
||||
return;
|
||||
}
|
||||
mTakeFullMinidumpCallback.Init(std::move(aCallback), aAsync);
|
||||
|
||||
nsString browserDumpId{aBrowserDumpId};
|
||||
bool reportsReady = false;
|
||||
|
||||
// Check to see if we already have a browser dump id - with e10s plugin
|
||||
// hangs we take this earlier (see ProcessHangMonitor) from a background
|
||||
// thread. We do this before we message the main thread about the hang
|
||||
// since the posted message will trash our browser stack state.
|
||||
nsCOMPtr<nsIFile> browserDumpFile;
|
||||
if (CrashReporter::GetMinidumpForID(aBrowserDumpId,
|
||||
getter_AddRefs(mBrowserDumpFile))) {
|
||||
|
||||
// Hold a ref to mPlugin to keep *this* alive until the callback runs.
|
||||
RetainPluginRef();
|
||||
std::function<void(bool)> callback =
|
||||
[this, aContentPid, browserDumpId, aAsync](bool aResult) {
|
||||
if (aAsync) {
|
||||
this->mCrashReporterMutex.Lock();
|
||||
}
|
||||
|
||||
this->TakeBrowserAndPluginMinidumps(aResult,
|
||||
aContentPid,
|
||||
browserDumpId,
|
||||
aAsync);
|
||||
if (aAsync) {
|
||||
this->mCrashReporterMutex.Unlock();
|
||||
}
|
||||
|
||||
this->ReleasePluginRef();
|
||||
};
|
||||
getter_AddRefs(browserDumpFile))) {
|
||||
// We have a single browser report, generate a new plugin process parent
|
||||
// report and pair it up with the browser report handed in.
|
||||
mCrashReporter->GenerateMinidumpAndPair(Process(), mBrowserDumpFile,
|
||||
NS_LITERAL_CSTRING("browser"),
|
||||
std::move(callback), aAsync);
|
||||
} else {
|
||||
TakeBrowserAndPluginMinidumps(false, aContentPid, browserDumpId, aAsync);
|
||||
}
|
||||
}
|
||||
reportsReady = mCrashReporter->GenerateMinidumpAndPair(
|
||||
this,
|
||||
browserDumpFile,
|
||||
NS_LITERAL_CSTRING("browser"));
|
||||
|
||||
void
|
||||
PluginModuleChromeParent::RetainPluginRef()
|
||||
{
|
||||
if (!mPlugin) {
|
||||
return;
|
||||
if (!reportsReady) {
|
||||
browserDumpFile = nullptr;
|
||||
CrashReporter::DeleteMinidumpFilesForID(aBrowserDumpId);
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
mPlugin->AddRef();
|
||||
} else {
|
||||
// XXX We can't sync-dispatch to the main thread because doing that
|
||||
// deadlocks when we are called from
|
||||
// PluginHangUIParent::RecvUserResponse().
|
||||
Unused << NS_DispatchToMainThread(
|
||||
NewNonOwningRunnableMethod("nsNPAPIPlugin::AddRef",
|
||||
mPlugin, &nsNPAPIPlugin::AddRef));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleChromeParent::ReleasePluginRef()
|
||||
{
|
||||
if (!mPlugin) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
mPlugin->Release();
|
||||
} else {
|
||||
// Async release the reference to mPlugin.
|
||||
Unused << NS_DispatchToMainThread(
|
||||
NewNonOwningRunnableMethod("nsNPAPIPlugin::Release",
|
||||
mPlugin, &nsNPAPIPlugin::Release));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleChromeParent::TakeBrowserAndPluginMinidumps(bool aReportsReady,
|
||||
base::ProcessId aContentPid,
|
||||
const nsAString& aBrowserDumpId,
|
||||
bool aAsync)
|
||||
{
|
||||
mCrashReporterMutex.AssertCurrentThreadIn();
|
||||
|
||||
// Generate crash report including plugin and browser process minidumps.
|
||||
// The plugin process is the parent report with additional dumps including
|
||||
// the browser process, content process when running under e10s, and
|
||||
// various flash subprocesses if we're the flash module.
|
||||
if (!aReportsReady) {
|
||||
mBrowserDumpFile = nullptr;
|
||||
CrashReporter::DeleteMinidumpFilesForID(aBrowserDumpId);
|
||||
|
||||
nsString browserDumpId{aBrowserDumpId};
|
||||
|
||||
RetainPluginRef();
|
||||
std::function<void(bool)> callback =
|
||||
[this, aContentPid, browserDumpId](bool aResult) {
|
||||
this->OnTakeFullMinidumpComplete(aResult,
|
||||
aContentPid,
|
||||
browserDumpId);
|
||||
this->ReleasePluginRef();
|
||||
};
|
||||
mCrashReporter->GenerateMinidumpAndPair(Process(),
|
||||
nullptr, // Pair with a dump of this process and thread.
|
||||
NS_LITERAL_CSTRING("browser"),
|
||||
std::move(callback),
|
||||
aAsync);
|
||||
} else {
|
||||
OnTakeFullMinidumpComplete(aReportsReady, aContentPid, aBrowserDumpId);
|
||||
if (!reportsReady) {
|
||||
reportsReady = mCrashReporter->GenerateMinidumpAndPair(
|
||||
this,
|
||||
nullptr, // Pair with a dump of this process and thread.
|
||||
NS_LITERAL_CSTRING("browser"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleChromeParent::OnTakeFullMinidumpComplete(bool aReportsReady,
|
||||
base::ProcessId aContentPid,
|
||||
const nsAString& aBrowserDumpId)
|
||||
{
|
||||
mCrashReporterMutex.AssertCurrentThreadIn();
|
||||
|
||||
if (aReportsReady) {
|
||||
nsString dumpId = mCrashReporter->MinidumpID();
|
||||
if (reportsReady) {
|
||||
aDumpId = mCrashReporter->MinidumpID();
|
||||
PLUGIN_LOG_DEBUG(
|
||||
("generated paired browser/plugin minidumps: %s)",
|
||||
NS_ConvertUTF16toUTF8(dumpId).get()));
|
||||
("generated paired browser/plugin minidumps: %s)",
|
||||
NS_ConvertUTF16toUTF8(aDumpId).get()));
|
||||
nsAutoCString additionalDumps("browser");
|
||||
nsCOMPtr<nsIFile> pluginDumpFile;
|
||||
if (GetMinidumpForID(dumpId, getter_AddRefs(pluginDumpFile))) {
|
||||
if (GetMinidumpForID(aDumpId, getter_AddRefs(pluginDumpFile))) {
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
// If we have handles to the flash sandbox processes on Windows,
|
||||
// include those minidumps as well.
|
||||
|
@ -1256,10 +1155,7 @@ PluginModuleChromeParent::OnTakeFullMinidumpComplete(bool aReportsReady,
|
|||
}
|
||||
mCrashReporter->AddAnnotation(Annotation::additional_minidumps,
|
||||
additionalDumps);
|
||||
|
||||
mTakeFullMinidumpCallback.Invoke(mCrashReporter->MinidumpID());
|
||||
} else {
|
||||
mTakeFullMinidumpCallback.Invoke(EmptyString());
|
||||
NS_WARNING("failed to capture paired minidumps from hang");
|
||||
}
|
||||
}
|
||||
|
@ -1268,52 +1164,20 @@ void
|
|||
PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop,
|
||||
base::ProcessId aContentPid,
|
||||
const nsCString& aMonitorDescription,
|
||||
const nsAString& aDumpId,
|
||||
std::function<void(bool)>&& aCallback,
|
||||
bool aAsync)
|
||||
const nsAString& aDumpId)
|
||||
{
|
||||
if (!mTerminateChildProcessCallback.IsEmpty()) {
|
||||
aCallback(false);
|
||||
return;
|
||||
}
|
||||
mTerminateChildProcessCallback.Init(std::move(aCallback), aAsync);
|
||||
|
||||
// Start by taking a full minidump if necessary, this is done early
|
||||
// because it also needs to lock the mCrashReporterMutex and Mutex doesn't
|
||||
// support recursive locking.
|
||||
nsAutoString dumpId;
|
||||
if (aDumpId.IsEmpty()) {
|
||||
|
||||
RetainPluginRef();
|
||||
std::function<void(nsString)> callback =
|
||||
[this, aMsgLoop, aMonitorDescription, aAsync](nsString aResult) {
|
||||
if (aAsync) {
|
||||
this->mCrashReporterMutex.Lock();
|
||||
}
|
||||
this->TerminateChildProcessOnDumpComplete(aMsgLoop,
|
||||
aMonitorDescription);
|
||||
if (aAsync) {
|
||||
this->mCrashReporterMutex.Unlock();
|
||||
}
|
||||
|
||||
this->ReleasePluginRef();
|
||||
};
|
||||
|
||||
TakeFullMinidump(aContentPid, EmptyString(), std::move(callback), aAsync);
|
||||
} else {
|
||||
TerminateChildProcessOnDumpComplete(aMsgLoop, aMonitorDescription);
|
||||
TakeFullMinidump(aContentPid, EmptyString(), dumpId);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleChromeParent::TerminateChildProcessOnDumpComplete(MessageLoop* aMsgLoop,
|
||||
const nsCString& aMonitorDescription)
|
||||
{
|
||||
mCrashReporterMutex.AssertCurrentThreadIn();
|
||||
|
||||
mozilla::MutexAutoLock lock(mCrashReporterMutex);
|
||||
if (!mCrashReporter) {
|
||||
// If mCrashReporter is null then the hang has ended, the plugin module
|
||||
// is shutting down. There's nothing to do here.
|
||||
mTerminateChildProcessCallback.Invoke(true);
|
||||
return;
|
||||
}
|
||||
mCrashReporter->AddAnnotation(Annotation::PluginHang, true);
|
||||
|
@ -1370,8 +1234,6 @@ PluginModuleChromeParent::TerminateChildProcessOnDumpComplete(MessageLoop* aMsgL
|
|||
if (!childOpened || !KillProcess(geckoChildProcess, 1, false)) {
|
||||
NS_WARNING("failed to kill subprocess!");
|
||||
}
|
||||
|
||||
mTerminateChildProcessCallback.Invoke(true);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1522,7 +1384,7 @@ RemoveMinidump(nsIFile* minidump)
|
|||
void
|
||||
PluginModuleChromeParent::ProcessFirstMinidump()
|
||||
{
|
||||
mozilla::RecursiveMutexAutoLock lock(mCrashReporterMutex);
|
||||
mozilla::MutexAutoLock lock(mCrashReporterMutex);
|
||||
|
||||
if (!mCrashReporter)
|
||||
return;
|
||||
|
|
|
@ -11,13 +11,11 @@
|
|||
#include "mozilla/FileUtils.h"
|
||||
#include "mozilla/HangAnnotations.h"
|
||||
#include "mozilla/PluginLibrary.h"
|
||||
#include "mozilla/ipc/CrashReporterHost.h"
|
||||
#include "mozilla/plugins/PluginProcessParent.h"
|
||||
#include "mozilla/plugins/PPluginModuleParent.h"
|
||||
#include "mozilla/plugins/PluginMessageUtils.h"
|
||||
#include "mozilla/plugins/PluginTypes.h"
|
||||
#include "mozilla/ipc/TaskFactory.h"
|
||||
#include "mozilla/RecursiveMutex.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "npapi.h"
|
||||
|
@ -34,6 +32,9 @@ class nsPluginTag;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
namespace ipc {
|
||||
class CrashReporterHost;
|
||||
} // namespace ipc
|
||||
namespace layers {
|
||||
class TextureClientRecycleAllocator;
|
||||
} // namespace layers
|
||||
|
@ -318,11 +319,9 @@ protected:
|
|||
* This mutex protects the crash reporter when the Plugin Hang UI event
|
||||
* handler is executing off main thread. It is intended to protect both
|
||||
* the mCrashReporter variable in addition to the CrashReporterHost object
|
||||
* that mCrashReporter refers to. Sometimes asynchronous crash reporter
|
||||
* callbacks are dispatched synchronously while the caller is still holding
|
||||
* the mutex. This requires recursive locking support in the mutex.
|
||||
* that mCrashReporter refers to.
|
||||
*/
|
||||
mozilla::RecursiveMutex mCrashReporterMutex;
|
||||
mozilla::Mutex mCrashReporterMutex;
|
||||
UniquePtr<ipc::CrashReporterHost> mCrashReporter;
|
||||
};
|
||||
|
||||
|
@ -359,10 +358,6 @@ class PluginModuleChromeParent
|
|||
, public mozilla::BackgroundHangAnnotator
|
||||
{
|
||||
friend class mozilla::ipc::CrashReporterHost;
|
||||
using TerminateChildProcessCallback =
|
||||
mozilla::ipc::CrashReporterHost::CallbackWrapper<bool>;
|
||||
using TakeFullMinidumpCallback =
|
||||
mozilla::ipc::CrashReporterHost::CallbackWrapper<nsString>;
|
||||
public:
|
||||
/**
|
||||
* LoadModule
|
||||
|
@ -387,16 +382,12 @@ class PluginModuleChromeParent
|
|||
* provided TakeFullMinidump will use this dump file instead of
|
||||
* generating a new one. If not provided a browser dump will be taken at
|
||||
* the time of this call.
|
||||
* @param aCallback a callback invoked when the operation completes. The ID
|
||||
* of the newly generated crash dump is provided in the callback argument.
|
||||
* An empty string will be provided upon failure.
|
||||
* @param aAsync whether to perform the dump asynchronously.
|
||||
* @param aDumpId Returns the ID of the newly generated crash dump. Left
|
||||
* untouched upon failure.
|
||||
*/
|
||||
void
|
||||
TakeFullMinidump(base::ProcessId aContentPid,
|
||||
const nsAString& aBrowserDumpId,
|
||||
std::function<void(nsString)>&& aCallback,
|
||||
bool aAsync);
|
||||
void TakeFullMinidump(base::ProcessId aContentPid,
|
||||
const nsAString& aBrowserDumpId,
|
||||
nsString& aDumpId);
|
||||
|
||||
/*
|
||||
* Terminates the plugin process associated with this plugin module. Also
|
||||
|
@ -414,46 +405,11 @@ class PluginModuleChromeParent
|
|||
* TerminateChildProcess will use this dump file instead of generating a
|
||||
* multi-process crash report. If not provided a multi-process dump will
|
||||
* be taken at the time of this call.
|
||||
* @param aCallback a callback invoked when the operation completes. The
|
||||
* argument denotes whether the operation succeeded.
|
||||
* @param aAsync whether to perform the operation asynchronously.
|
||||
*/
|
||||
void
|
||||
TerminateChildProcess(MessageLoop* aMsgLoop,
|
||||
base::ProcessId aContentPid,
|
||||
const nsCString& aMonitorDescription,
|
||||
const nsAString& aDumpId,
|
||||
std::function<void(bool)>&& aCallback,
|
||||
bool aAsync);
|
||||
|
||||
/**
|
||||
* Helper for passing a dummy callback in calling the above function if it
|
||||
* is called synchronously and the caller doesn't care about the callback
|
||||
* result.
|
||||
*/
|
||||
template<typename T>
|
||||
static std::function<void(T)> DummyCallback()
|
||||
{
|
||||
return std::function<void(T)>([](T aResult) { });
|
||||
}
|
||||
|
||||
private:
|
||||
// The following methods are callbacks invoked after calling
|
||||
// TakeFullMinidump(). The methods are invoked in the following order:
|
||||
void TakeBrowserAndPluginMinidumps(bool aReportsReady,
|
||||
base::ProcessId aContentPid,
|
||||
const nsAString& aBrowserDumpId,
|
||||
bool aAsync);
|
||||
void OnTakeFullMinidumpComplete(bool aReportsReady,
|
||||
base::ProcessId aContentPid,
|
||||
const nsAString& aBrowserDumpId);
|
||||
|
||||
|
||||
// The following method is the callback invoked after calling
|
||||
// TerminateChidlProcess().
|
||||
void TerminateChildProcessOnDumpComplete(MessageLoop* aMsgLoop,
|
||||
const nsCString& aMonitorDescription);
|
||||
public:
|
||||
void TerminateChildProcess(MessageLoop* aMsgLoop,
|
||||
base::ProcessId aContentPid,
|
||||
const nsCString& aMonitorDescription,
|
||||
const nsAString& aDumpId);
|
||||
|
||||
#ifdef XP_WIN
|
||||
/**
|
||||
|
@ -486,8 +442,6 @@ private:
|
|||
|
||||
void ProcessFirstMinidump();
|
||||
void WriteExtraDataForMinidump();
|
||||
void RetainPluginRef();
|
||||
void ReleasePluginRef();
|
||||
|
||||
PluginProcessParent* Process() const { return mSubprocess; }
|
||||
base::ProcessHandle ChildProcessHandle() { return mSubprocess->GetChildProcessHandle(); }
|
||||
|
@ -603,12 +557,6 @@ private:
|
|||
|
||||
nsCOMPtr<nsIObserver> mPluginOfflineObserver;
|
||||
bool mIsBlocklisted;
|
||||
|
||||
nsCOMPtr<nsIFile> mBrowserDumpFile;
|
||||
TakeFullMinidumpCallback mTakeFullMinidumpCallback;
|
||||
|
||||
TerminateChildProcessCallback mTerminateChildProcessCallback;
|
||||
|
||||
bool mIsCleaningFromTimeout;
|
||||
};
|
||||
|
||||
|
|
|
@ -7,12 +7,10 @@
|
|||
#include "CrashReporterHost.h"
|
||||
#include "CrashReporterMetadataShmem.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
#include "mozilla/recordreplay/ParentIPC.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsIAsyncShutdown.h"
|
||||
#include "nsICrashService.h"
|
||||
|
||||
|
@ -21,7 +19,7 @@ namespace ipc {
|
|||
|
||||
CrashReporterHost::CrashReporterHost(GeckoProcessType aProcessType,
|
||||
const Shmem& aShmem,
|
||||
ThreadId aThreadId)
|
||||
CrashReporter::ThreadId aThreadId)
|
||||
: mProcessType(aProcessType),
|
||||
mShmem(aShmem),
|
||||
mThreadId(aThreadId),
|
||||
|
@ -121,120 +119,6 @@ CrashReporterHost::FinalizeCrashReport()
|
|||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class GenerateMinidumpShutdownBlocker : public nsIAsyncShutdownBlocker {
|
||||
public:
|
||||
GenerateMinidumpShutdownBlocker() = default;
|
||||
|
||||
NS_IMETHOD BlockShutdown(nsIAsyncShutdownClient* aBarrierClient) override
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetName(nsAString& aName) override
|
||||
{
|
||||
aName = NS_LITERAL_STRING("Crash Reporter: blocking on minidump"
|
||||
"generation.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetState(nsIPropertyBag**) override
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
private:
|
||||
virtual ~GenerateMinidumpShutdownBlocker() = default;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(GenerateMinidumpShutdownBlocker, nsIAsyncShutdownBlocker)
|
||||
}
|
||||
|
||||
static nsCOMPtr<nsIAsyncShutdownClient> GetShutdownBarrier()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
|
||||
nsCOMPtr<nsIAsyncShutdownClient> barrier;
|
||||
nsresult rv = svc->GetProfileBeforeChange(getter_AddRefs(barrier));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return barrier.forget();
|
||||
}
|
||||
|
||||
void
|
||||
CrashReporterHost::GenerateMinidumpAndPair(GeckoChildProcessHost* aChildProcess,
|
||||
nsIFile* aMinidumpToPair,
|
||||
const nsACString& aPairName,
|
||||
std::function<void(bool)>&& aCallback,
|
||||
bool aAsync)
|
||||
{
|
||||
base::ProcessHandle childHandle;
|
||||
#ifdef XP_MACOSX
|
||||
childHandle = aChildProcess->GetChildTask();
|
||||
#else
|
||||
childHandle = aChildProcess->GetChildProcessHandle();
|
||||
#endif
|
||||
|
||||
if (!mCreateMinidumpCallback.IsEmpty()) {
|
||||
aCallback(false);
|
||||
return;
|
||||
}
|
||||
mCreateMinidumpCallback.Init(std::move(aCallback), aAsync);
|
||||
|
||||
if (!childHandle) {
|
||||
NS_WARNING("Failed to get child process handle.");
|
||||
mCreateMinidumpCallback.Invoke(false);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAsyncShutdownBlocker> shutdownBlocker;
|
||||
if (aAsync && NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIAsyncShutdownClient> barrier = GetShutdownBarrier();
|
||||
if (!barrier) {
|
||||
mCreateMinidumpCallback.Invoke(false);
|
||||
return;
|
||||
}
|
||||
|
||||
shutdownBlocker = new GenerateMinidumpShutdownBlocker();
|
||||
|
||||
nsresult rv = barrier->AddBlocker(shutdownBlocker,
|
||||
NS_LITERAL_STRING(__FILE__), __LINE__,
|
||||
NS_LITERAL_STRING("Minidump generation"));
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
std::function<void(bool)> callback =
|
||||
[this, shutdownBlocker](bool aResult) {
|
||||
if (aResult &&
|
||||
CrashReporter::GetIDFromMinidump(this->mTargetDump, this->mDumpID)) {
|
||||
this->mCreateMinidumpCallback.Invoke(true);
|
||||
} else {
|
||||
this->mCreateMinidumpCallback.Invoke(false);
|
||||
}
|
||||
|
||||
if (shutdownBlocker) {
|
||||
nsCOMPtr<nsIAsyncShutdownClient> barrier = GetShutdownBarrier();
|
||||
if (barrier) {
|
||||
barrier->RemoveBlocker(shutdownBlocker);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CrashReporter::CreateMinidumpsAndPair(childHandle,
|
||||
mThreadId,
|
||||
aPairName,
|
||||
aMinidumpToPair,
|
||||
getter_AddRefs(mTargetDump),
|
||||
std::move(callback),
|
||||
aAsync);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
CrashReporterHost::NotifyCrashService(GeckoProcessType aProcessType,
|
||||
int32_t aCrashType,
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class GeckoChildProcessHost;
|
||||
|
||||
// This is the newer replacement for CrashReporterParent. It is created in
|
||||
// response to a InitCrashReporter message on a top-level actor, and simply
|
||||
// holds the metadata shmem alive until the process ends. When the process
|
||||
|
@ -29,68 +27,12 @@ class CrashReporterHost
|
|||
{
|
||||
typedef mozilla::ipc::Shmem Shmem;
|
||||
typedef CrashReporter::AnnotationTable AnnotationTable;
|
||||
typedef CrashReporter::ThreadId ThreadId;
|
||||
|
||||
public:
|
||||
|
||||
template <typename T>
|
||||
class CallbackWrapper {
|
||||
public:
|
||||
void Init(std::function<void(T)>&& aCallback, bool aAsync)
|
||||
{
|
||||
mCallback = std::move(aCallback);
|
||||
mAsync = aAsync;
|
||||
if (IsAsync()) {
|
||||
// Don't call do_GetCurrentThread() if this is called synchronously
|
||||
// because 1. it's unnecessary, and 2. more importantly, it might create
|
||||
// one if called from a native thread, and the thread will be leaked.
|
||||
mTargetThread = do_GetCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsEmpty()
|
||||
{
|
||||
return !mCallback;
|
||||
}
|
||||
|
||||
bool IsAsync()
|
||||
{
|
||||
return mAsync;
|
||||
}
|
||||
|
||||
void Invoke(T aResult)
|
||||
{
|
||||
if (IsAsync()) {
|
||||
decltype(mCallback) callback = std::move(mCallback);
|
||||
mTargetThread->
|
||||
Dispatch(NS_NewRunnableFunction("ipc::CrashReporterHost::CallbackWrapper::Invoke",
|
||||
[callback, aResult](){
|
||||
callback(aResult);
|
||||
}), NS_DISPATCH_NORMAL);
|
||||
} else {
|
||||
MOZ_ASSERT(!mTargetThread);
|
||||
mCallback(aResult);
|
||||
}
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
private:
|
||||
void Clear()
|
||||
{
|
||||
mCallback = nullptr;
|
||||
mTargetThread = nullptr;
|
||||
mAsync = false;
|
||||
}
|
||||
|
||||
bool mAsync;
|
||||
std::function<void(T)> mCallback;
|
||||
nsCOMPtr<nsIThread> mTargetThread;
|
||||
};
|
||||
|
||||
CrashReporterHost(GeckoProcessType aProcessType,
|
||||
const Shmem& aShmem,
|
||||
ThreadId aThreadId);
|
||||
CrashReporter::ThreadId aThreadId);
|
||||
|
||||
// Helper function for generating a crash report for a process that probably
|
||||
// crashed (i.e., had an AbnormalShutdown in ActorDestroy). Returns true if
|
||||
|
@ -112,15 +54,37 @@ public:
|
|||
|
||||
// Generate a paired minidump. This does not take the crash report, as
|
||||
// GenerateCrashReport does. After this, FinalizeCrashReport may be called.
|
||||
// Minidump(s) can be generated synchronously or asynchronously, specified in
|
||||
// argument aAsync. When the operation completes, aCallback is invoked, where
|
||||
// the callback argument denotes whether the operation succeeded.
|
||||
void
|
||||
GenerateMinidumpAndPair(GeckoChildProcessHost* aChildProcess,
|
||||
nsIFile* aMinidumpToPair,
|
||||
const nsACString& aPairName,
|
||||
std::function<void(bool)>&& aCallback,
|
||||
bool aAsync);
|
||||
//
|
||||
// This calls TakeCrashedChildMinidump and FinalizeCrashReport.
|
||||
template <typename Toplevel>
|
||||
bool GenerateMinidumpAndPair(Toplevel* aToplevelProtocol,
|
||||
nsIFile* aMinidumpToPair,
|
||||
const nsACString& aPairName)
|
||||
{
|
||||
ScopedProcessHandle childHandle;
|
||||
#ifdef XP_MACOSX
|
||||
childHandle = aToplevelProtocol->Process()->GetChildTask();
|
||||
#else
|
||||
if (!base::OpenPrivilegedProcessHandle(aToplevelProtocol->OtherPid(),
|
||||
&childHandle.rwget()))
|
||||
{
|
||||
NS_WARNING("Failed to open child process handle.");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIFile> targetDump;
|
||||
if (!CrashReporter::CreateMinidumpsAndPair(childHandle,
|
||||
mThreadId,
|
||||
aPairName,
|
||||
aMinidumpToPair,
|
||||
getter_AddRefs(targetDump)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return CrashReporter::GetIDFromMinidump(targetDump, mDumpID);
|
||||
}
|
||||
|
||||
void AddAnnotation(CrashReporter::Annotation aKey, bool aValue);
|
||||
void AddAnnotation(CrashReporter::Annotation aKey, int aValue);
|
||||
|
@ -152,15 +116,13 @@ private:
|
|||
const nsString& aChildDumpID);
|
||||
|
||||
private:
|
||||
CallbackWrapper<bool> mCreateMinidumpCallback;
|
||||
GeckoProcessType mProcessType;
|
||||
Shmem mShmem;
|
||||
ThreadId mThreadId;
|
||||
CrashReporter::ThreadId mThreadId;
|
||||
time_t mStartTime;
|
||||
AnnotationTable mExtraAnnotations;
|
||||
nsString mDumpID;
|
||||
bool mFinalized;
|
||||
nsCOMPtr<nsIFile> mTargetDump;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsExceptionHandlerUtils.h"
|
||||
|
||||
|
@ -393,15 +395,14 @@ TakeMinidump(nsIFile** aResult, bool aMoveToPending)
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
CreateMinidumpsAndPair(ProcessHandle aTargetPid,
|
||||
ThreadId aTargetBlamedThread,
|
||||
const nsACString& aIncomingPairName,
|
||||
nsIFile* aIncomingDumpToPair,
|
||||
nsIFile** aMainDumpOut,
|
||||
std::function<void(bool)>&& aCallback,
|
||||
bool aAsync)
|
||||
nsIFile** aTargetDumpOut)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -306,8 +306,6 @@ static ChildMinidumpMap* pidToMinidump;
|
|||
static uint32_t crashSequence;
|
||||
static bool OOPInitialized();
|
||||
|
||||
static nsIThread* sMinidumpWriterThread;
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
static nsIThread* sInjectorThread;
|
||||
|
||||
|
@ -3408,11 +3406,6 @@ OOPDeinit()
|
|||
}
|
||||
#endif
|
||||
|
||||
if (sMinidumpWriterThread) {
|
||||
sMinidumpWriterThread->Shutdown();
|
||||
NS_RELEASE(sMinidumpWriterThread);
|
||||
}
|
||||
|
||||
delete crashServer;
|
||||
crashServer = nullptr;
|
||||
|
||||
|
@ -3851,37 +3844,17 @@ bool TakeMinidump(nsIFile** aResult, bool aMoveToPending)
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline void
|
||||
NotifyDumpResult(bool aResult,
|
||||
bool aAsync,
|
||||
std::function<void(bool)>&& aCallback,
|
||||
RefPtr<nsIThread>&& aCallbackThread)
|
||||
bool
|
||||
CreateMinidumpsAndPair(ProcessHandle aTargetPid,
|
||||
ThreadId aTargetBlamedThread,
|
||||
const nsACString& aIncomingPairName,
|
||||
nsIFile* aIncomingDumpToPair,
|
||||
nsIFile** aMainDumpOut)
|
||||
{
|
||||
std::function<void()> runnable = [&](){
|
||||
aCallback(aResult);
|
||||
};
|
||||
|
||||
if (aAsync) {
|
||||
MOZ_ASSERT(!!aCallbackThread);
|
||||
Unused << aCallbackThread->Dispatch(NS_NewRunnableFunction("CrashReporter::InvokeCallback",
|
||||
std::move(runnable)),
|
||||
NS_DISPATCH_SYNC);
|
||||
} else {
|
||||
runnable();
|
||||
if (!GetEnabled()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
CreatePairedChildMinidumpAsync(ProcessHandle aTargetPid,
|
||||
ThreadId aTargetBlamedThread,
|
||||
nsCString aIncomingPairName,
|
||||
nsCOMPtr<nsIFile> aIncomingDumpToPair,
|
||||
nsIFile** aMainDumpOut,
|
||||
xpstring aDumpPath,
|
||||
std::function<void(bool)>&& aCallback,
|
||||
RefPtr<nsIThread>&& aCallbackThread,
|
||||
bool aAsync)
|
||||
{
|
||||
AutoIOInterposerDisable disableIOInterposition;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
|
@ -3890,64 +3863,6 @@ CreatePairedChildMinidumpAsync(ProcessHandle aTargetPid,
|
|||
ThreadId targetThread = aTargetBlamedThread;
|
||||
#endif
|
||||
|
||||
// dump the target
|
||||
nsCOMPtr<nsIFile> targetMinidump;
|
||||
if (!google_breakpad::ExceptionHandler::WriteMinidumpForChild(
|
||||
aTargetPid,
|
||||
targetThread,
|
||||
aDumpPath,
|
||||
PairedDumpCallbackExtra,
|
||||
static_cast<void*>(&targetMinidump)
|
||||
#ifdef XP_WIN32
|
||||
, GetMinidumpType()
|
||||
#endif
|
||||
)) {
|
||||
NotifyDumpResult(false, aAsync, std::move(aCallback), std::move(aCallbackThread));
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> targetExtra;
|
||||
GetExtraFileForMinidump(targetMinidump, getter_AddRefs(targetExtra));
|
||||
if (!targetExtra) {
|
||||
targetMinidump->Remove(false);
|
||||
|
||||
NotifyDumpResult(false, aAsync, std::move(aCallback), std::move(aCallbackThread));
|
||||
return;
|
||||
}
|
||||
|
||||
RenameAdditionalHangMinidump(aIncomingDumpToPair,
|
||||
targetMinidump,
|
||||
aIncomingPairName);
|
||||
|
||||
if (ShouldReport()) {
|
||||
MoveToPending(targetMinidump, targetExtra, nullptr);
|
||||
MoveToPending(aIncomingDumpToPair, nullptr, nullptr);
|
||||
}
|
||||
|
||||
targetMinidump.forget(aMainDumpOut);
|
||||
|
||||
NotifyDumpResult(true, aAsync, std::move(aCallback), std::move(aCallbackThread));
|
||||
}
|
||||
|
||||
void
|
||||
CreateMinidumpsAndPair(ProcessHandle aTargetPid,
|
||||
ThreadId aTargetBlamedThread,
|
||||
const nsACString& aIncomingPairName,
|
||||
nsIFile* aIncomingDumpToPair,
|
||||
nsIFile** aMainDumpOut,
|
||||
std::function<void(bool)>&& aCallback,
|
||||
bool aAsync)
|
||||
{
|
||||
if (!GetEnabled()) {
|
||||
aCallback(false);
|
||||
return;
|
||||
}
|
||||
#if defined(DEBUG) && defined(HAS_DLL_BLOCKLIST)
|
||||
DllBlocklist_Shutdown();
|
||||
#endif
|
||||
|
||||
AutoIOInterposerDisable disableIOInterposition;
|
||||
|
||||
xpstring dump_path;
|
||||
#ifndef XP_LINUX
|
||||
dump_path = gExceptionHandler->dump_path();
|
||||
|
@ -3955,10 +3870,26 @@ CreateMinidumpsAndPair(ProcessHandle aTargetPid,
|
|||
dump_path = gExceptionHandler->minidump_descriptor().directory();
|
||||
#endif
|
||||
|
||||
// dump the target
|
||||
nsCOMPtr<nsIFile> targetMinidump;
|
||||
if (!google_breakpad::ExceptionHandler::WriteMinidumpForChild(
|
||||
aTargetPid,
|
||||
targetThread,
|
||||
dump_path,
|
||||
PairedDumpCallbackExtra,
|
||||
static_cast<void*>(&targetMinidump)
|
||||
#ifdef XP_WIN32
|
||||
, GetMinidumpType()
|
||||
#endif
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> targetExtra;
|
||||
GetExtraFileForMinidump(targetMinidump, getter_AddRefs(targetExtra));
|
||||
|
||||
// If aIncomingDumpToPair isn't valid, create a dump of this process.
|
||||
// This part needs to be synchronous, unfortunately, so that the parent dump
|
||||
// contains the stack symmetrical with the child dump.
|
||||
nsCOMPtr<nsIFile> incomingDumpToPair;
|
||||
nsCOMPtr<nsIFile> incomingDump;
|
||||
if (aIncomingDumpToPair == nullptr) {
|
||||
if (!google_breakpad::ExceptionHandler::WriteMinidump(
|
||||
dump_path,
|
||||
|
@ -3966,52 +3897,32 @@ CreateMinidumpsAndPair(ProcessHandle aTargetPid,
|
|||
true,
|
||||
#endif
|
||||
PairedDumpCallback,
|
||||
static_cast<void*>(&incomingDumpToPair)
|
||||
static_cast<void*>(&incomingDump)
|
||||
#ifdef XP_WIN32
|
||||
, GetMinidumpType()
|
||||
#endif
|
||||
)) {
|
||||
aCallback(false);
|
||||
return;
|
||||
} // else incomingDump is assigned in PairedDumpCallback().
|
||||
targetMinidump->Remove(false);
|
||||
targetExtra->Remove(false);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
incomingDumpToPair = aIncomingDumpToPair;
|
||||
}
|
||||
MOZ_ASSERT(!!incomingDumpToPair);
|
||||
|
||||
if (aAsync &&
|
||||
!sMinidumpWriterThread &&
|
||||
NS_FAILED(NS_NewNamedThread("Minidump Writer", &sMinidumpWriterThread))) {
|
||||
aCallback(false);
|
||||
return;
|
||||
incomingDump = aIncomingDumpToPair;
|
||||
}
|
||||
|
||||
nsCString incomingPairName(aIncomingPairName);
|
||||
std::function<void(bool)> callback = std::move(aCallback);
|
||||
// Don't call do_GetCurrentThread() if this is called synchronously because
|
||||
// 1. it's unnecessary, and 2. more importantly, it might create one if called
|
||||
// from a native thread, and the thread will be leaked.
|
||||
RefPtr<nsIThread> callbackThread = aAsync ? do_GetCurrentThread() : nullptr;
|
||||
RenameAdditionalHangMinidump(incomingDump, targetMinidump, aIncomingPairName);
|
||||
|
||||
std::function<void()> doDump = [=]() mutable {
|
||||
CreatePairedChildMinidumpAsync(aTargetPid,
|
||||
aTargetBlamedThread,
|
||||
incomingPairName,
|
||||
incomingDumpToPair,
|
||||
aMainDumpOut,
|
||||
dump_path,
|
||||
std::move(callback),
|
||||
std::move(callbackThread),
|
||||
aAsync);
|
||||
};
|
||||
|
||||
if (aAsync) {
|
||||
sMinidumpWriterThread->Dispatch(NS_NewRunnableFunction("CrashReporter::CreateMinidumpsAndPair",
|
||||
std::move(doDump)),
|
||||
nsIEventTarget::DISPATCH_NORMAL);
|
||||
} else {
|
||||
doDump();
|
||||
if (ShouldReport()) {
|
||||
MoveToPending(targetMinidump, targetExtra, nullptr);
|
||||
MoveToPending(incomingDump, nullptr, nullptr);
|
||||
}
|
||||
#if defined(DEBUG) && defined(HAS_DLL_BLOCKLIST)
|
||||
DllBlocklist_Shutdown();
|
||||
#endif
|
||||
|
||||
targetMinidump.forget(aMainDumpOut);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include "CrashAnnotations.h"
|
||||
|
||||
#include <functional>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "nsError.h"
|
||||
|
@ -238,14 +237,11 @@ ThreadId CurrentThreadId();
|
|||
* aIncomingDumpToPair.
|
||||
* @return bool indicating success or failure
|
||||
*/
|
||||
void
|
||||
CreateMinidumpsAndPair(ProcessHandle aTargetPid,
|
||||
ThreadId aTargetBlamedThread,
|
||||
const nsACString& aIncomingPairName,
|
||||
nsIFile* aIncomingDumpToPair,
|
||||
nsIFile** aTargetDumpOut,
|
||||
std::function<void(bool)>&& aCallback,
|
||||
bool aAsync);
|
||||
bool CreateMinidumpsAndPair(ProcessHandle aTargetPid,
|
||||
ThreadId aTargetBlamedThread,
|
||||
const nsACString& aIncomingPairName,
|
||||
nsIFile* aIncomingDumpToPair,
|
||||
nsIFile** aTargetDumpOut);
|
||||
|
||||
// Create an additional minidump for a child of a process which already has
|
||||
// a minidump (|parentMinidump|).
|
||||
|
|
Загрузка…
Ссылка в новой задаче