void PluginModuleParent::WriteExtraDataForMinidump(AnnotationTable& notes) { typedef nsDependentCString CS; // Get the plugin filename, try to get just the file leafname const std::string& pluginFile = mSubprocess->GetPluginFilePath(); size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR); if (filePos == std::string::npos) filePos = 0; else filePos++; notes.Put(CS("PluginFilename"), CS(pluginFile.substr(filePos).c_str())); //TODO: add plugin name and version: bug 539841 // (as PluginName, PluginVersion) notes.Put(CS("PluginName"), CS("")); notes.Put(CS("PluginVersion"), CS("")); CrashReporterParent* crashReporter = CrashReporter(); if (crashReporter) { const nsString& hangID = crashReporter->HangID(); if (!hangID.IsEmpty()) notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(hangID)); } }
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"); } #endif // this must run before the error notification from the channel, // or not at all MessageLoop::current()->PostTask( FROM_HERE, mTaskFactory.NewRunnableMethod( &PluginModuleParent::CleanupFromTimeout)); if (!KillProcess(OtherProcess(), 1, false)) NS_WARNING("failed to kill subprocess!"); return false; }
bool PluginModuleParent::ShouldContinueFromReplyTimeout() { #ifdef MOZ_CRASHREPORTER CrashReporterParent* crashReporter = CrashReporter(); crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("PluginHang"), NS_LITERAL_CSTRING("1")); if (crashReporter->GeneratePairedMinidump(this)) { mPluginDumpID = crashReporter->ChildDumpID(); PLUGIN_LOG_DEBUG( ("generated paired browser/plugin minidumps: %s)", NS_ConvertUTF16toUTF8(mPluginDumpID).get())); crashReporter->AnnotateCrashReport( NS_LITERAL_CSTRING("additional_minidumps"), NS_LITERAL_CSTRING("browser")); // TODO: collect Flash minidumps here } else { NS_WARNING("failed to capture paired minidumps from hang"); } #endif #ifdef XP_WIN // collect cpu usage for plugin processes InfallibleTArray<base::ProcessHandle> processHandles; base::ProcessHandle handle; processHandles.AppendElement(OtherProcess()); #ifdef MOZ_CRASHREPORTER_INJECTOR if (mFlashProcess1 && base::OpenProcessHandle(mFlashProcess1, &handle)) { processHandles.AppendElement(handle); } if (mFlashProcess2 && base::OpenProcessHandle(mFlashProcess2, &handle)) { processHandles.AppendElement(handle); } #endif if (!GetProcessCpuUsage(processHandles, mPluginCpuUsageOnHang)) { mPluginCpuUsageOnHang.Clear(); } #endif // this must run before the error notification from the channel, // or not at all MessageLoop::current()->PostTask( FROM_HERE, mTaskFactory.NewRunnableMethod( &PluginModuleParent::CleanupFromTimeout)); if (!KillProcess(OtherProcess(), 1, false)) NS_WARNING("failed to kill subprocess!"); return false; }
mozilla::dom::PCrashReporterParent* GMPParent::AllocPCrashReporterParent(const NativeThreadId& aThread) { #ifndef MOZ_CRASHREPORTER MOZ_ASSERT(false, "Should only be sent if crash reporting is enabled."); #endif CrashReporterParent* cr = new CrashReporterParent(); cr->SetChildData(aThread, GeckoProcessType_GMPlugin); return cr; }
void PluginModuleParent::ActorDestroy(ActorDestroyReason why) { switch (why) { case AbnormalShutdown: { #ifdef MOZ_CRASHREPORTER CrashReporterParent* crashReporter = CrashReporter(); CrashReporter::AnnotationTable notes; notes.Init(4); WriteExtraDataForMinidump(notes); 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 { NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!"); } #endif mShutdown = true; // Defer the PluginCrashed method so that we don't re-enter // and potentially modify the actor child list while enumerating it. if (mPlugin) MessageLoop::current()->PostTask( FROM_HERE, mTaskFactory.NewRunnableMethod( &PluginModuleParent::NotifyPluginCrashed)); break; } case NormalShutdown: mShutdown = true; break; default: NS_ERROR("Unexpected shutdown reason for toplevel actor."); } }
void PluginModuleParent::WriteExtraDataForMinidump(AnnotationTable& notes) { typedef nsDependentCString CS; // Get the plugin filename, try to get just the file leafname const std::string& pluginFile = mSubprocess->GetPluginFilePath(); size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR); if (filePos == std::string::npos) filePos = 0; else filePos++; notes.Put(CS("PluginFilename"), CS(pluginFile.substr(filePos).c_str())); //TODO: add plugin name and version: bug 539841 // (as PluginName, PluginVersion) notes.Put(CS("PluginName"), CS("")); notes.Put(CS("PluginVersion"), CS("")); CrashReporterParent* crashReporter = CrashReporter(); if (crashReporter) { const nsString& hangID = crashReporter->HangID(); if (!hangID.IsEmpty()) { notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(hangID)); #ifdef XP_WIN if (mPluginCpuUsageOnHang.Length() > 0) { notes.Put(CS("NumberOfProcessors"), nsPrintfCString("%d", PR_GetNumberOfProcessors())); nsCString cpuUsageStr; cpuUsageStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[0] * 100) / 100); notes.Put(CS("PluginCpuUsage"), cpuUsageStr); #ifdef MOZ_CRASHREPORTER_INJECTOR for (uint32_t i=1; i<mPluginCpuUsageOnHang.Length(); ++i) { nsCString tempStr; tempStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[i] * 100) / 100); notes.Put(nsPrintfCString("CpuUsageFlashProcess%d", i), tempStr); } #endif } #endif } } }
void GMPParent::GetCrashID(nsString& aResult) { CrashReporterParent* cr = nullptr; if (ManagedPCrashReporterParent().Length() > 0) { cr = static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]); } if (NS_WARN_IF(!cr)) { return; } AnnotationTable notes(4); WriteExtraDataForMinidump(notes); nsCOMPtr<nsIFile> dumpFile; TakeMinidump(getter_AddRefs(dumpFile), nullptr); if (!dumpFile) { NS_WARNING("GMP crash without crash report"); return; } GetIDFromMinidump(dumpFile, aResult); cr->GenerateCrashReportForMinidump(dumpFile, ¬es); }
void ContentParent::ActorDestroy(ActorDestroyReason why) { nsCOMPtr<nsIThreadObserver> kungFuDeathGrip(static_cast<nsIThreadObserver*>(this)); nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); if (obs) { obs->RemoveObserver(static_cast<nsIObserver*>(this), "xpcom-shutdown"); obs->RemoveObserver(static_cast<nsIObserver*>(this), "memory-pressure"); obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-memory-reporter-request"); obs->RemoveObserver(static_cast<nsIObserver*>(this), NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC); obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-gc-request"); obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-cc-request"); #ifdef ACCESSIBILITY obs->RemoveObserver(static_cast<nsIObserver*>(this), "a11y-init-or-shutdown"); #endif } mMessageManager->Disconnect(); // clear the child memory reporters InfallibleTArray<MemoryReport> empty; SetChildMemoryReporters(empty); // remove the global remote preferences observers nsCOMPtr<nsIPrefBranch2> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID)); if (prefs) { prefs->RemoveObserver("", this); } RecvRemoveGeolocationListener(); RecvRemoveDeviceMotionListener(); nsCOMPtr<nsIThreadInternal> threadInt(do_QueryInterface(NS_GetCurrentThread())); if (threadInt) threadInt->RemoveObserver(this); if (mRunToCompletionDepth) mRunToCompletionDepth = 0; if (gContentParents) { gContentParents->RemoveElement(this); if (!gContentParents->Length()) { delete gContentParents; gContentParents = NULL; } } mIsAlive = false; if (obs) { nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag(); props->Init(); if (AbnormalShutdown == why) { props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), true); #ifdef MOZ_CRASHREPORTER MOZ_ASSERT(ManagedPCrashReporterParent().Length() > 0); CrashReporterParent* crashReporter = static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]); crashReporter->GenerateCrashReport(this, NULL); nsAutoString dumpID(crashReporter->ChildDumpID()); props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID); #endif obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nsnull); } } MessageLoop::current()-> PostTask(FROM_HERE, NewRunnableFunction(DelayedDeleteSubprocess, mSubprocess)); mSubprocess = NULL; // IPDL rules require actors to live on past ActorDestroy, but it // may be that the kungFuDeathGrip above is the last reference to // |this|. If so, when we go out of scope here, we're deleted and // all hell breaks loose. // // This runnable ensures that a reference to |this| lives on at // least until after the current task finishes running. NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this)); }
void PluginModuleParent::ProcessFirstMinidump() { CrashReporterParent* crashReporter = CrashReporter(); if (!crashReporter) return; AnnotationTable notes; notes.Init(4); WriteExtraDataForMinidump(notes); if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) { crashReporter->GenerateHangCrashReport(¬es); return; } uint32_t sequence = PR_UINT32_MAX; nsCOMPtr<nsIFile> dumpFile; nsAutoCString flashProcessType; TakeMinidump(getter_AddRefs(dumpFile), &sequence); #ifdef MOZ_CRASHREPORTER_INJECTOR nsCOMPtr<nsIFile> childDumpFile; uint32_t childSequence; if (mFlashProcess1 && TakeMinidumpForChild(mFlashProcess1, getter_AddRefs(childDumpFile), &childSequence)) { if (childSequence < sequence) { RemoveMinidump(dumpFile); dumpFile = childDumpFile; sequence = childSequence; flashProcessType.AssignLiteral("Broker"); } else { RemoveMinidump(childDumpFile); } } if (mFlashProcess2 && TakeMinidumpForChild(mFlashProcess2, getter_AddRefs(childDumpFile), &childSequence)) { if (childSequence < sequence) { RemoveMinidump(dumpFile); dumpFile = childDumpFile; sequence = childSequence; flashProcessType.AssignLiteral("Sandbox"); } else { RemoveMinidump(childDumpFile); } } #endif if (!dumpFile) { NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!"); return; } PLUGIN_LOG_DEBUG(("got child minidump: %s", NS_ConvertUTF16toUTF8(mPluginDumpID).get())); GetIDFromMinidump(dumpFile, mPluginDumpID); if (!flashProcessType.IsEmpty()) { notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"), flashProcessType); } crashReporter->GenerateCrashReportForMinidump(dumpFile, ¬es); }