Bug 769048 part F - Add the final bits to PluginModuleParent which watch for new Flash processes and inject a crashreporter into them, r=jimm
This commit is contained in:
@@ -102,6 +102,10 @@ PluginModuleParent::PluginModuleParent(const char* aFilePath)
|
||||
, mNPNIface(NULL)
|
||||
, mPlugin(NULL)
|
||||
, mTaskFactory(this)
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
, mFlashProcess1(0)
|
||||
, mFlashProcess2(0)
|
||||
#endif
|
||||
{
|
||||
NS_ASSERTION(mSubprocess, "Out of memory!");
|
||||
|
||||
@@ -127,6 +131,13 @@ PluginModuleParent::~PluginModuleParent()
|
||||
mSubprocess = nsnull;
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
if (mFlashProcess1)
|
||||
CrashReporter::UnregisterInjectorCallback(mFlashProcess1);
|
||||
if (mFlashProcess2)
|
||||
CrashReporter::UnregisterInjectorCallback(mFlashProcess2);
|
||||
#endif
|
||||
|
||||
Preferences::UnregisterCallback(TimeoutChanged, kChildTimeoutPref, this);
|
||||
Preferences::UnregisterCallback(TimeoutChanged, kParentTimeoutPref, this);
|
||||
}
|
||||
@@ -151,9 +162,12 @@ PluginModuleParent::WriteExtraDataForMinidump(CrashReporter::AnnotationTable& no
|
||||
notes.Put(CS("PluginName"), CS(""));
|
||||
notes.Put(CS("PluginVersion"), CS(""));
|
||||
|
||||
const nsString& hangID = CrashReporter()->HangID();
|
||||
if (!hangID.IsEmpty())
|
||||
notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(hangID));
|
||||
CrashReporterParent* crashReporter = CrashReporter();
|
||||
if (crashReporter) {
|
||||
const nsString& hangID = crashReporter->HangID();
|
||||
if (!hangID.IsEmpty())
|
||||
notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(hangID));
|
||||
}
|
||||
}
|
||||
#endif // MOZ_CRASHREPORTER
|
||||
|
||||
@@ -186,17 +200,19 @@ bool
|
||||
PluginModuleParent::ShouldContinueFromReplyTimeout()
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
CrashReporterParent* crashReporter = CrashReporter();
|
||||
if (crashReporter->GeneratePairedMinidump(this)) {
|
||||
mBrowserDumpID = crashReporter->ParentDumpID();
|
||||
mPluginDumpID = crashReporter->ChildDumpID();
|
||||
PLUGIN_LOG_DEBUG(
|
||||
("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
|
||||
NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
|
||||
NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
|
||||
NS_ConvertUTF16toUTF8(crashReporter->HangID()).get()));
|
||||
} else {
|
||||
NS_WARNING("failed to capture paired minidumps from hang");
|
||||
if (mPluginDumpID.IsEmpty()) {
|
||||
CrashReporterParent* crashReporter = CrashReporter();
|
||||
if (crashReporter->GeneratePairedMinidump(this)) {
|
||||
mBrowserDumpID = crashReporter->ParentDumpID();
|
||||
mPluginDumpID = crashReporter->ChildDumpID();
|
||||
PLUGIN_LOG_DEBUG(
|
||||
("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
|
||||
NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
|
||||
NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
|
||||
NS_ConvertUTF16toUTF8(crashReporter->HangID()).get()));
|
||||
} else {
|
||||
NS_WARNING("failed to capture paired minidumps from hang");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -217,7 +233,6 @@ PluginModuleParent::ShouldContinueFromReplyTimeout()
|
||||
CrashReporterParent*
|
||||
PluginModuleParent::CrashReporter()
|
||||
{
|
||||
MOZ_ASSERT(ManagedPCrashReporterParent().Length() > 0);
|
||||
return static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
|
||||
}
|
||||
#endif
|
||||
@@ -234,14 +249,18 @@ PluginModuleParent::ActorDestroy(ActorDestroyReason why)
|
||||
notes.Init(4);
|
||||
WriteExtraDataForMinidump(notes);
|
||||
|
||||
if (crashReporter->GenerateCrashReport(this, ¬es)) {
|
||||
if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
|
||||
crashReporter->GenerateHangCrashReport(¬es);
|
||||
}
|
||||
else if (!mPluginDumpID.IsEmpty()) {
|
||||
// Nothing to do, we've already written this minidump in
|
||||
// PluginModuleParent::OnCrash
|
||||
}
|
||||
else if (crashReporter->GenerateCrashReport(this, ¬es)) {
|
||||
mPluginDumpID = crashReporter->ChildDumpID();
|
||||
PLUGIN_LOG_DEBUG(("got child minidump: %s",
|
||||
NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
|
||||
}
|
||||
else if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
|
||||
crashReporter->GenerateHangCrashReport(¬es);
|
||||
}
|
||||
else {
|
||||
NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
|
||||
}
|
||||
@@ -761,6 +780,10 @@ PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
|
||||
unused << SendSetAudioSessionData(id, sessionName, iconPath);
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
InitializeInjector();
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
@@ -1162,3 +1185,102 @@ PluginModuleParent::RecvNPN_ReloadPlugins(const bool& aReloadPages)
|
||||
mozilla::plugins::parent::_reloadplugins(aReloadPages);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
|
||||
// We only add the crash reporter to subprocess which have the filename
|
||||
// FlashPlayerPlugin*
|
||||
#define FLASH_PROCESS_PREFIX "FLASHPLAYERPLUGIN"
|
||||
|
||||
static DWORD
|
||||
GetFlashChildOfPID(DWORD pid, HANDLE snapshot)
|
||||
{
|
||||
PROCESSENTRY32 entry = {
|
||||
sizeof(entry)
|
||||
};
|
||||
for (BOOL ok = Process32First(snapshot, &entry);
|
||||
ok;
|
||||
ok = Process32Next(snapshot, &entry)) {
|
||||
if (entry.th32ParentProcessID == pid) {
|
||||
nsString name(entry.szExeFile);
|
||||
ToUpperCase(name);
|
||||
if (StringBeginsWith(name, NS_LITERAL_STRING(FLASH_PROCESS_PREFIX))) {
|
||||
return entry.th32ProcessID;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We only look for child processes of the Flash plugin, NPSWF*
|
||||
#define FLASH_PLUGIN_PREFIX "NPSWF"
|
||||
|
||||
void
|
||||
PluginModuleParent::InitializeInjector()
|
||||
{
|
||||
if (!Preferences::GetBool("dom.ipc.plugins.flash.subprocess.crashreporter.enabled", false))
|
||||
return;
|
||||
|
||||
nsCString path(Process()->GetPluginFilePath().c_str());
|
||||
ToUpperCase(path);
|
||||
PRInt32 lastSlash = path.RFindCharInSet("\\/");
|
||||
if (kNotFound == lastSlash)
|
||||
return;
|
||||
|
||||
if (!StringBeginsWith(Substring(path, lastSlash + 1),
|
||||
NS_LITERAL_CSTRING(FLASH_PLUGIN_PREFIX)))
|
||||
return;
|
||||
|
||||
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (INVALID_HANDLE_VALUE == snapshot)
|
||||
return;
|
||||
|
||||
DWORD pluginProcessPID = GetProcessId(Process()->GetChildProcessHandle());
|
||||
mFlashProcess1 = GetFlashChildOfPID(pluginProcessPID, snapshot);
|
||||
if (mFlashProcess1) {
|
||||
InjectCrashReporterIntoProcess(mFlashProcess1, this);
|
||||
|
||||
mFlashProcess2 = GetFlashChildOfPID(mFlashProcess1, snapshot);
|
||||
if (mFlashProcess2) {
|
||||
InjectCrashReporterIntoProcess(mFlashProcess2, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleParent::OnCrash(DWORD processID, const nsAString& aDumpID)
|
||||
{
|
||||
if (!mPluginDumpID.IsEmpty()) {
|
||||
// One process has already crashed: we assume that the first-to-crash
|
||||
// is the interesting one
|
||||
return;
|
||||
}
|
||||
|
||||
mPluginDumpID = aDumpID;
|
||||
|
||||
CrashReporter::AnnotationTable notes;
|
||||
notes.Init(4);
|
||||
WriteExtraDataForMinidump(notes);
|
||||
notes.Put(NS_LITERAL_CSTRING("ProcessType"), NS_LITERAL_CSTRING("plugin"));
|
||||
if (processID == mFlashProcess1) {
|
||||
notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"),
|
||||
NS_LITERAL_CSTRING("Broker"));
|
||||
}
|
||||
else if (processID == mFlashProcess2) {
|
||||
notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"),
|
||||
NS_LITERAL_CSTRING("Sandbox"));
|
||||
}
|
||||
else {
|
||||
NS_ERROR("Got minidump for Flash process neither broker nor sandbox.");
|
||||
}
|
||||
|
||||
CrashReporter::AppendExtraData(aDumpID, notes);
|
||||
MessageLoop::current()->PostTask(
|
||||
FROM_HERE,
|
||||
mTaskFactory.NewRunnableMethod(
|
||||
&PluginModuleParent::CleanupFromTimeout));
|
||||
|
||||
KillProcess(OtherProcess(), 1, false);
|
||||
}
|
||||
|
||||
#endif // MOZ_CRASHREPORTER_INJECTOR
|
||||
|
||||
Reference in New Issue
Block a user