Bug 538910 - Plugins: Need a "plugin crashed" UI. r=gavin, ui-r=faaborg, icon=shorlander

This commit is contained in:
Justin Dolske 2010-02-09 17:05:32 -08:00
parent 43603428aa
commit 1f895f93b6
16 changed files with 194 additions and 103 deletions

View File

@ -1101,14 +1101,18 @@ function HandleAppCommandEvent(evt) {
}
function prepareForStartup() {
var os = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver.onUpdatePageReport, false);
// Note: we need to listen to untrusted events, because the pluginfinder XBL
// binding can't fire trusted ones (runs with page privileges).
gBrowser.addEventListener("PluginNotFound", gMissingPluginInstaller.newMissingPlugin, true, true);
gBrowser.addEventListener("PluginCrashed", gMissingPluginInstaller.pluginInstanceCrashed, true, true);
gBrowser.addEventListener("PluginBlocklisted", gMissingPluginInstaller.newMissingPlugin, true, true);
gBrowser.addEventListener("PluginOutdated", gMissingPluginInstaller.newMissingPlugin, true, true);
gBrowser.addEventListener("PluginDisabled", gMissingPluginInstaller.newDisabledPlugin, true, true);
gBrowser.addEventListener("NewPluginInstalled", gMissingPluginInstaller.refreshBrowser, false);
os.addObserver(gMissingPluginInstaller.pluginCrashed, "plugin-crashed", false);
window.addEventListener("AppCommand", HandleAppCommandEvent, true);
var webNavigation;
@ -1152,7 +1156,6 @@ function prepareForStartup() {
// progress notifications for back/forward button updating
webNavigation.sessionHistory = Components.classes["@mozilla.org/browser/shistory;1"]
.createInstance(Components.interfaces.nsISHistory);
var os = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
os.addObserver(gBrowser.browsers[0], "browser:purge-session-history", false);
// remove the disablehistory attribute so the browser cleans up, as
@ -5993,6 +5996,20 @@ function getPluginInfo(pluginElement)
var gMissingPluginInstaller = {
get CrashSubmit() {
delete this.CrashSubmit;
Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
return this.CrashSubmit;
},
get crashReportHelpURL() {
delete this.crashReportHelpURL;
let url = formatURL("app.support.baseURL", true);
url += "plugin-crashed";
this.crashReportHelpURL = url;
return this.crashReportHelpURL;
},
installSinglePlugin: function (aEvent) {
if (!aEvent.isTrusted)
return;
@ -6168,6 +6185,129 @@ var gMissingPluginInstaller = {
true);
},
// Crashed-plugin observer. Notified once per plugin crash, before events
// are dispatched to individual plugin instances.
pluginCrashed : function(subject, topic, data) {
let propertyBag = subject;
if (!(propertyBag instanceof Ci.nsIPropertyBag2) ||
!(propertyBag instanceof Ci.nsIWritablePropertyBag2))
return;
#ifdef MOZ_CRASHREPORTER
let minidumpID = subject.getPropertyAsAString("minidumpID");
let submitReports = gCrashReporter.submitReports;
// The crash reporter wants a DOM element it can append an IFRAME to,
// which it uses to submit a form. Let's just give it gBrowser.
if (submitReports)
gMissingPluginInstaller.CrashSubmit.submit(minidumpID, gBrowser, null, null);
propertyBag.setPropertyAsBool("submittedCrashReport", submitReports);
#endif
},
pluginInstanceCrashed: function (aEvent) {
// Evil content could fire a fake event at us, ignore them.
if (!aEvent.isTrusted)
return;
if (!(aEvent instanceof Ci.nsIDOMDataContainerEvent))
return;
let submittedReport = aEvent.getData("submittedCrashReport");
let pluginName = aEvent.getData("pluginName");
// We're expecting this to be a plugin.
let plugin = aEvent.target;
if (!(plugin instanceof Ci.nsIObjectLoadingContent))
return;
// Force a style flush, so that we ensure our binding is attached.
plugin.clientTop;
let messageString = gNavigatorBundle.getFormattedString("crashedpluginsMessage.title", [pluginName]);
//
// Configure the crashed-plugin placeholder.
//
let doc = plugin.ownerDocument;
let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
// The binding has role="link" here, since missing/disabled/blocked
// plugin UI has a onclick handler on the whole thing. This isn't needed
// for the plugin-crashed UI, because we use actual HTML links in the text.
overlay.removeAttribute("role");
#ifdef MOZ_CRASHREPORTER
let helpClass = submittedReport ? "submitLink" : "notSubmitLink";
let helpLink = doc.getAnonymousElementByAttribute(plugin, "class", helpClass);
helpLink.href = gMissingPluginInstaller.crashReportHelpURL;
let showClass = submittedReport ? "msg msgSubmitted" : "msg msgNotSubmitted";
let textToShow = doc.getAnonymousElementByAttribute(plugin, "class", showClass);
textToShow.style.display = "block";
#endif
let crashText = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgCrashed");
crashText.textContent = messageString;
let link = doc.getAnonymousElementByAttribute(plugin, "class", "reloadLink");
link.addEventListener("click", function(e) { if (e.isTrusted) browser.reload(); }, true);
let browser = gBrowser.getBrowserForDocument(plugin.ownerDocument
.defaultView.top.document);
let notificationBox = gBrowser.getNotificationBox(browser);
// Is the <object>'s size too small to hold what we want to show?
let pluginRect = plugin.getBoundingClientRect();
// XXX bug 446693. The text-shadow on the submitted-report text at
// the bottom causes scrollHeight to be larger than it should be.
let isObjectTooSmall = (overlay.scrollWidth > pluginRect.width) ||
(overlay.scrollHeight - 5 > pluginRect.height);
if (isObjectTooSmall) {
// Hide the overlay's contents. Use visibility style, so that it
// doesn't collapse down to 0x0.
overlay.style.visibility = "hidden";
// If another plugin on the page was large enough to show our UI, we
// don't want to show a notification bar.
if (!doc.mozNoPluginCrashedNotification)
showNotificationBar();
} else {
// If a previous plugin on the page was too small and resulted in
// adding a notification bar, then remove it because this plugin
// instance it big enough to serve as in-content notification.
hideNotificationBar();
doc.mozNoPluginCrashedNotification = true;
}
function hideNotificationBar() {
let notification = notificationBox.getNotificationWithValue("plugin-crashed");
if (notification)
notificationBox.removeNotification(notification, true);
}
function showNotificationBar() {
// If there's already an existing notification bar, don't do anything.
let notification = notificationBox.getNotificationWithValue("plugin-crashed");
if (notification)
return;
// Configure the notification bar
let priority = notificationBox.PRIORITY_WARNING_MEDIUM;
let iconURL = "chrome://mozapps/skin/plugins/pluginGeneric-16.png";
let label = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.label");
let accessKey = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.accesskey");
let buttons = [{
label: label,
accessKey: accessKey,
popup: null,
callback: function() { browser.reload(); },
}];
let notification = notificationBox.appendNotification(messageString, "plugin-crashed",
iconURL, priority, buttons);
}
},
refreshBrowser: function (aEvent) {
// browser elements are anonymous so we can't just use target.
var browser = aEvent.originalTarget;

View File

@ -74,6 +74,9 @@ blockedpluginsMessage.infoButton.label=Details…
blockedpluginsMessage.infoButton.accesskey=D
blockedpluginsMessage.searchButton.label=Update Plugins…
blockedpluginsMessage.searchButton.accesskey=U
crashedpluginsMessage.title=The %S plugin has crashed.
crashedpluginsMessage.reloadButton.label=Reload page
crashedpluginsMessage.reloadButton.accesskey=R
# Sanitize
# LOCALIZATION NOTE (sanitizeDialog2.everything.title): When "Time range to

View File

@ -1,33 +0,0 @@
// This code is TEMPORARY for submitting crashes via an ugly popup dialog:
// bug 525849 tracks the real implementation.
const Cc = Components.classes;
const Ci = Components.interfaces;
Components.utils.import("resource://gre/modules/CrashSubmit.jsm");
var id;
function collectData() {
let directoryService = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
let dumpFile = window.arguments[0].QueryInterface(Ci.nsIFile);
id = dumpFile.leafName.replace(/.dmp$/, "");
}
function submitDone()
{
// we don't currently distinguish between success or failure here
window.close();
}
function onSubmit()
{
document.documentElement.getButton('accept').disabled = true;
document.documentElement.getButton('accept').label = 'Sending';
document.getElementById('throbber').src = 'chrome://global/skin/icons/loading_16.png';
CrashSubmit.submit(id, document.getElementById('iframe-holder'),
submitDone, submitDone);
return false;
}

View File

@ -1,32 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="oopCrashDialog"
buttons="accept,cancel"
buttonlabelaccept="Send"
ondialogaccept="return onSubmit()"
onload="collectData()">
<style xmlns="http://www.w3.org/1999/xhtml" type="text/css">
#iframe-holder {
visibility: hidden;
height: 1px;
overflow: hidden;
}
</style>
<script type="application/javascript;version=1.8" src="chrome://global/content/oopcrashdialog.js"/>
<dialogheader title="A Plugin Crashed" />
<hbox align="center">
<description>A plugin crashed while Firefox was running. Please choose to send a crash report
to Mozilla. Reloading should cause your plugin to restart.</description>
<image width="16" height="16" id="throbber" />
</hbox>
<hbox id="iframe-holder" height="1"/>
</dialog>

View File

@ -2,5 +2,3 @@ toolkit.jar:
content/global/crashes.xhtml (content/crashes.xhtml)
content/global/crashes.js (content/crashes.js)
content/global/crash-submit-form.xhtml (content/crash-submit-form.xhtml)
content/global/oopcrashdialog.xul (content/oopcrashdialog.xul)
content/global/oopcrashdialog.js (content/oopcrashdialog.js)

View File

@ -101,10 +101,6 @@ using google_breakpad::ClientInfo;
using mozilla::Mutex;
using mozilla::MutexAutoLock;
#include "nsThreadUtils.h"
#include "nsIWindowWatcher.h"
#include "nsIDOMWindow.h"
#endif
namespace CrashReporter {
@ -1139,29 +1135,6 @@ nsresult SetSubmitReports(PRBool aSubmitReports)
#if defined(MOZ_IPC)
//-----------------------------------------------------------------------------
// Out-of-process crash reporting API wrappers
class SubmitCrashReport : public nsRunnable
{
public:
SubmitCrashReport(nsIFile* dumpFile) : mDumpFile(dumpFile) { }
NS_IMETHOD Run() {
nsCOMPtr<nsIWindowWatcher> windowWatcher =
do_GetService(NS_WINDOWWATCHER_CONTRACTID);
nsCOMPtr<nsIDOMWindow> newWindow;
windowWatcher->OpenWindow(nsnull,
"chrome://global/content/oopcrashdialog.xul",
"_blank",
"centerscreen,chrome,titlebar",
mDumpFile, getter_AddRefs(newWindow));
return NS_OK;
}
private:
nsCOMPtr<nsIFile> mDumpFile;
};
static PLDHashOperator EnumerateChildAnnotations(const nsACString& key,
nsCString entry,
void* userData)
@ -1283,11 +1256,6 @@ OnChildProcessDumpRequested(void* aContext,
MutexAutoLock lock(*dumpMapLock);
pidToMinidump->Put(pid, lf);
}
if (doReport) {
nsCOMPtr<nsIRunnable> r = new SubmitCrashReport(lf);
NS_DispatchToMainThread(r);
}
}
static bool

View File

@ -23,3 +23,21 @@
<!ENTITY missingPlugin.label "Click here to download plugin.">
<!ENTITY disabledPlugin.label "The plugin for this content has been disabled. Click here to manage your plugins.">
<!ENTITY blockedPlugin.label "This plugin has been blocked for your protection.">
<!-- LOCALIZATION NOTE (reloadPlugin.pre): include a trailing space as needed -->
<!-- LOCALIZATION NOTE (reloadPlugin.middle): avoid leading/trailing spaces, this text is a link -->
<!-- LOCALIZATION NOTE (reloadPlugin.post): include a starting space as needed -->
<!ENTITY reloadPlugin.pre "">
<!ENTITY reloadPlugin.middle "Reload the page">
<!ENTITY reloadPlugin.post " to try again.">
<!-- LOCALIZATION NOTE (submittedCrashReport.pre): include a trailing space as needed -->
<!-- LOCALIZATION NOTE (submittedCrashReport.middle): avoid leading/trailing spaces, this text is a link -->
<!-- LOCALIZATION NOTE (submittedCrashReport.post): include a starting space as needed -->
<!ENTITY submittedCrashReport.pre "A ">
<!ENTITY submittedCrashReport.middle "crash report">
<!ENTITY submittedCrashReport.post " was submitted.">
<!-- LOCALIZATION NOTE (notSubmittedCrashReport.pre): include a trailing space as needed -->
<!-- LOCALIZATION NOTE (notSubmittedCrashReport.middle): avoid leading/trailing spaces, this text is a link -->
<!-- LOCALIZATION NOTE (notSubmittedCrashReport.post): include a starting space as needed -->
<!ENTITY notSubmittedCrashReport.pre "You have disabled ">
<!ENTITY notSubmittedCrashReport.middle "crash report">
<!ENTITY notSubmittedCrashReport.post " submission.">

View File

@ -54,7 +54,12 @@
<html:div class="msg msgUnsupported">&missingPlugin.label;</html:div>
<html:div class="msg msgDisabled">&disabledPlugin.label;</html:div>
<html:div class="msg msgBlocked">&blockedPlugin.label;</html:div>
<html:div class="msg msgCrashed"><!-- set at runtime --></html:div>
<html:div class="msg msgReload">&reloadPlugin.pre;<html:a class="reloadLink" href="">&reloadPlugin.middle;</html:a>&reloadPlugin.post;</html:div>
<xul:spacer flex="1"/>
<!-- link hrefs set at runtime -->
<html:div class="msg msgSubmitted">&submittedCrashReport.pre;<html:a class="submitLink" href="">&submittedCrashReport.middle;</html:a>&submittedCrashReport.post;</html:div>
<html:div class="msg msgNotSubmitted">&notSubmittedCrashReport.pre;<html:a class="notSubmitLink" href="">&notSubmittedCrashReport.middle;</html:a>&notSubmittedCrashReport.post;</html:div>
</xul:vbox>
<html:div style="display:none;"><children/></html:div>
</content>

View File

@ -41,11 +41,14 @@
embed:-moz-type-unsupported,
embed:-moz-handler-disabled,
embed:-moz-handler-blocked,
embed:-moz-handler-crashed,
applet:-moz-type-unsupported,
applet:-moz-handler-disabled,
applet:-moz-handler-blocked,
applet:-moz-handler-crashed,
object:-moz-has-handlerref:-moz-type-unsupported,
object:-moz-has-handlerref:-moz-handler-disabled,
object:-moz-has-handlerref:-moz-handler-blocked {
object:-moz-has-handlerref:-moz-handler-blocked,
object:-moz-has-handlerref:-moz-handler-crashed {
-moz-binding: url('chrome://mozapps/content/plugins/pluginProblem.xml#pluginProblem') !important;
}

View File

@ -24,6 +24,7 @@ toolkit.jar:
skin/classic/mozapps/plugins/pluginGeneric.png (plugins/pluginGeneric.png)
skin/classic/mozapps/plugins/pluginDisabled.png (plugins/pluginDisabled.png)
skin/classic/mozapps/plugins/pluginBlocked.png (plugins/pluginBlocked.png)
skin/classic/mozapps/plugins/pluginCrashed.png (plugins/pluginCrashed.png)
skin/classic/mozapps/plugins/pluginGeneric-16.png (plugins/pluginGeneric-16.png)
skin/classic/mozapps/plugins/pluginBlocked-16.png (plugins/pluginBlocked-16.png)
skin/classic/mozapps/plugins/pluginOutdated-16.png (plugins/pluginOutdated-16.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -54,6 +54,9 @@ html|applet:not([height]), html|applet[height=""] {
:-moz-handler-blocked .icon {
background-image: url(chrome://mozapps/skin/plugins/pluginBlocked.png);
}
:-moz-handler-crashed .icon {
background-image: url(chrome://mozapps/skin/plugins/pluginCrashed.png);
}
.msg {
display: none;
@ -65,6 +68,12 @@ html|applet:not([height]), html|applet[height=""] {
}
:-moz-type-unsupported .msgUnsupported,
:-moz-handler-disabled .msgDisabled,
:-moz-handler-blocked .msgBlocked {
:-moz-handler-blocked .msgBlocked,
:-moz-handler-crashed .msgCrashed,
:-moz-handler-crashed .msgReload {
display: block;
}
html|A {
color: white;
}

View File

@ -30,6 +30,7 @@ toolkit.jar:
skin/classic/mozapps/plugins/pluginGeneric.png (plugins/pluginGeneric.png)
skin/classic/mozapps/plugins/pluginDisabled.png (plugins/pluginDisabled.png)
skin/classic/mozapps/plugins/pluginBlocked.png (plugins/pluginBlocked.png)
skin/classic/mozapps/plugins/pluginCrashed.png (plugins/pluginCrashed.png)
skin/classic/mozapps/plugins/pluginGeneric-16.png (plugins/pluginGeneric-16.png)
skin/classic/mozapps/plugins/pluginBlocked-16.png (plugins/pluginBlocked-16.png)
skin/classic/mozapps/plugins/pluginOutdated-16.png (plugins/pluginOutdated-16.png)
@ -73,6 +74,7 @@ toolkit.jar:
skin/classic/aero/mozapps/plugins/pluginGeneric.png (plugins/pluginGeneric-aero.png)
skin/classic/aero/mozapps/plugins/pluginDisabled.png (plugins/pluginDisabled-aero.png)
skin/classic/aero/mozapps/plugins/pluginBlocked.png (plugins/pluginBlocked-aero.png)
skin/classic/aero/mozapps/plugins/pluginCrashed.png (plugins/pluginCrashed-aero.png)
skin/classic/aero/mozapps/plugins/pluginGeneric-16.png (plugins/pluginGeneric-16-aero.png)
skin/classic/aero/mozapps/plugins/pluginBlocked-16.png (plugins/pluginBlocked-16-aero.png)
skin/classic/aero/mozapps/plugins/pluginOutdated-16.png (plugins/pluginOutdated-16-aero.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -54,6 +54,9 @@ html|applet:not([height]), html|applet[height=""] {
:-moz-handler-blocked .icon {
background-image: url(chrome://mozapps/skin/plugins/pluginBlocked.png);
}
:-moz-handler-crashed .icon {
background-image: url(chrome://mozapps/skin/plugins/pluginCrashed.png);
}
.msg {
display: none;
@ -65,6 +68,12 @@ html|applet:not([height]), html|applet[height=""] {
}
:-moz-type-unsupported .msgUnsupported,
:-moz-handler-disabled .msgDisabled,
:-moz-handler-blocked .msgBlocked {
:-moz-handler-blocked .msgBlocked,
:-moz-handler-crashed .msgCrashed,
:-moz-handler-crashed .msgReload {
display: block;
}
html|A {
color: white;
}