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:
Benjamin Smedberg
2012-07-03 07:49:23 -04:00
parent 464433c541
commit b8a18a817d
3 changed files with 162 additions and 20 deletions

View File

@@ -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, &notes)) {
if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
crashReporter->GenerateHangCrashReport(&notes);
}
else if (!mPluginDumpID.IsEmpty()) {
// Nothing to do, we've already written this minidump in
// PluginModuleParent::OnCrash
}
else if (crashReporter->GenerateCrashReport(this, &notes)) {
mPluginDumpID = crashReporter->ChildDumpID();
PLUGIN_LOG_DEBUG(("got child minidump: %s",
NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
}
else if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
crashReporter->GenerateHangCrashReport(&notes);
}
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