Bug 1287178 - Move unsubmitted crash report handling into ContentCrashHandlers.jsm. r=Felipe

MozReview-Commit-ID: 8lsv6zxLc9x

--HG--
extra : rebase_source : c94f2939ec35e3f2357761fd13eaba856c7c1a59
This commit is contained in:
Mike Conley 2016-09-02 13:16:28 -04:00
Родитель 15dc33fbae
Коммит 0c1ba21a69
4 изменённых файлов: 205 добавлений и 64 удалений

Просмотреть файл

@ -1507,3 +1507,12 @@ pref("print.use_simplify_page", true);
// Space separated list of URLS that are allowed to send objects (instead of
// only strings) through webchannels. This list is duplicated in mobile/android/app/mobile.js
pref("webchannel.allowObject.urlWhitelist", "https://accounts.firefox.com https://content.cdn.mozilla.net https://input.mozilla.org https://support.mozilla.org https://install.mozilla.org");
// Whether or not the browser should scan for unsubmitted
// crash reports, and then show a notification for submitting
// those reports.
#ifdef RELEASE_BUILD
pref("browser.crashReports.unsubmittedCheck.enabled", false);
#else
pref("browser.crashReports.unsubmittedCheck.enabled", true);
#endif

Просмотреть файл

@ -71,6 +71,8 @@ XPCOMUtils.defineLazyServiceGetter(this, "AlertsService", "@mozilla.org/alerts-s
if (AppConstants.MOZ_CRASHREPORTER) {
XPCOMUtils.defineLazyModuleGetter(this, "PluginCrashReporter",
"resource:///modules/ContentCrashHandlers.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UnsubmittedCrashHandler",
"resource:///modules/ContentCrashHandlers.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CrashSubmit",
"resource://gre/modules/CrashSubmit.jsm");
}
@ -714,6 +716,7 @@ BrowserGlue.prototype = {
TabCrashHandler.init();
if (AppConstants.MOZ_CRASHREPORTER) {
PluginCrashReporter.init();
UnsubmittedCrashHandler.init();
}
Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
@ -744,64 +747,6 @@ BrowserGlue.prototype = {
}
},
checkForPendingCrashReports: function() {
// We don't process crash reports older than 28 days, so don't bother submitting them
const PENDING_CRASH_REPORT_DAYS = 28;
if (AppConstants.MOZ_CRASHREPORTER) {
let dateLimit = new Date();
dateLimit.setDate(dateLimit.getDate() - PENDING_CRASH_REPORT_DAYS);
CrashSubmit.pendingIDsAsync(dateLimit).then(
function onSuccess(ids) {
let count = ids.length;
if (count) {
let win = RecentWindow.getMostRecentBrowserWindow();
if (!win) {
return;
}
let nb = win.document.getElementById("global-notificationbox");
let notification = nb.getNotificationWithValue("pending-crash-reports");
if (notification) {
return;
}
let buttons = [
{
label: win.gNavigatorBundle.getString("pendingCrashReports.submitAll"),
callback: function() {
ids.forEach(function(id) {
CrashSubmit.submit(id, {extraExtraKeyVals: {"SubmittedFromInfobar": true}});
});
}
},
{
label: win.gNavigatorBundle.getString("pendingCrashReports.ignoreAll"),
callback: function() {
ids.forEach(function(id) {
CrashSubmit.ignore(id);
});
}
},
{
label: win.gNavigatorBundle.getString("pendingCrashReports.viewAll"),
callback: function() {
win.openUILinkIn("about:crashes", "tab");
return true;
}
}
];
nb.appendNotification(PluralForm.get(count,
win.gNavigatorBundle.getString("pendingCrashReports.label")).replace("#1", count),
"pending-crash-reports",
"chrome://browser/skin/tab-crashed.svg",
nb.PRIORITY_INFO_HIGH, buttons);
}
},
function onError(err) {
Cu.reportError(err);
}
);
}
},
_onSafeModeRestart: function BG_onSafeModeRestart() {
// prompt the user to confirm
let strings = gBrowserBundle;
@ -1070,10 +1015,6 @@ BrowserGlue.prototype = {
this._checkForOldBuildUpdates();
if (!AppConstants.RELEASE_BUILD) {
this.checkForPendingCrashReports();
}
CaptivePortalWatcher.init();
AutoCompletePopup.init();

Просмотреть файл

@ -733,7 +733,6 @@ tabgroups.migration.tabGroupBookmarkFolderName = Bookmarked Tab Groups
pendingCrashReports.label = You have an unsubmitted crash report;You have #1 unsubmitted crash reports
pendingCrashReports.viewAll = View
pendingCrashReports.submitAll = Submit
pendingCrashReports.ignoreAll = Ignore
decoder.noCodecs.button = Learn how
decoder.noCodecs.accesskey = L

Просмотреть файл

@ -8,7 +8,9 @@ var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
this.EXPORTED_SYMBOLS = [ "TabCrashHandler", "PluginCrashReporter" ];
this.EXPORTED_SYMBOLS = [ "TabCrashHandler",
"PluginCrashReporter",
"UnsubmittedCrashHandler" ];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@ -21,6 +23,21 @@ XPCOMUtils.defineLazyModuleGetter(this, "RemotePages",
"resource://gre/modules/RemotePageManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
"resource:///modules/sessionstore/SessionStore.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
"resource:///modules/RecentWindow.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
XPCOMUtils.defineLazyGetter(this, "gNavigatorBundle", function() {
const url = "chrome://browser/locale/browser.properties";
return Services.strings.createBundle(url);
});
// We don't process crash reports older than 28 days, so don't bother
// submitting them
const PENDING_CRASH_REPORT_DAYS = 28;
this.TabCrashHandler = {
_crashedTabCount: 0,
@ -319,6 +336,181 @@ this.TabCrashHandler = {
},
}
/**
* This component is responsible for scanning the pending
* crash report directory for reports, and (if enabled), to
* prompt the user to submit those reports.
*/
this.UnsubmittedCrashHandler = {
init() {
if (this.initialized) {
return;
}
this.initialized = true;
let pref = "browser.crashReports.unsubmittedCheck.enabled";
let shouldCheck = Services.prefs.getBoolPref(pref);
if (shouldCheck) {
Services.obs.addObserver(this, "browser-delayed-startup-finished",
false);
}
},
observe(subject, topic, data) {
if (topic != "browser-delayed-startup-finished") {
return;
}
Services.obs.removeObserver(this, topic);
this.checkForUnsubmittedCrashReports();
},
/**
* Scans the profile directory for unsubmitted crash reports
* within the past PENDING_CRASH_REPORT_DAYS days. If it
* finds any, it will, if necessary, attempt to open a notification
* bar to prompt the user to submit them.
*
* @returns Promise
* Resolves after it tries to append a notification on
* the most recent browser window. If a notification
* cannot be shown, will resolve anyways.
*/
checkForUnsubmittedCrashReports: Task.async(function*() {
let dateLimit = new Date();
dateLimit.setDate(dateLimit.getDate() - PENDING_CRASH_REPORT_DAYS);
let reportIDs = [];
try {
reportIDs = yield CrashSubmit.pendingIDsAsync(dateLimit);
} catch (e) {
Cu.reportError(e);
return;
}
if (reportIDs.length) {
this.showPendingSubmissionsNotification(reportIDs);
}
}),
/**
* Given an array of unsubmitted crash report IDs, try to open
* up a notification asking the user to submit them.
*
* @param reportIDs (Array<string>)
* The Array of report IDs to offer the user to send.
*/
showPendingSubmissionsNotification(reportIDs) {
let count = reportIDs.length;
if (!count) {
return;
}
let messageTemplate =
gNavigatorBundle.GetStringFromName("pendingCrashReports.label");
let message = PluralForm.get(count, messageTemplate).replace("#1", count);
CrashNotificationBar.show({
notificationID: "pending-crash-reports",
message,
reportIDs,
});
},
};
this.CrashNotificationBar = {
/**
* Attempts to show a notification bar to the user in the most
* recent browser window asking them to submit some crash report
* IDs. If a notification cannot be shown (for example, there
* is no browser window), this method exits silently.
*
* The notification will allow the user to submit their crash
* reports. If the user dismissed the notification, the crash
* reports will be marked to be ignored (though they can
* still be manually submitted via about:crashes).
*
* @param JS Object
* An Object with the following properties:
*
* notificationID (string)
* The ID for the notification to be opened.
*
* message (string)
* The message to be displayed in the notification.
*
* reportIDs (Array<string>)
* The array of report IDs to offer to the user.
*/
show({ notificationID, message, reportIDs }) {
let chromeWin = RecentWindow.getMostRecentBrowserWindow();
if (!chromeWin) {
// Can't show a notification in this case. We'll hopefully
// get another opportunity to have the user submit their
// crash reports later.
return;
}
let nb = chromeWin.document.getElementById("global-notificationbox");
let notification = nb.getNotificationWithValue(notificationID);
if (notification) {
return;
}
let buttons = [{
label: gNavigatorBundle.GetStringFromName("pendingCrashReports.submitAll"),
callback: () => {
this.submitReports(reportIDs);
},
},
{
label: gNavigatorBundle.GetStringFromName("pendingCrashReports.viewAll"),
callback: function() {
chromeWin.openUILinkIn("about:crashes", "tab");
return true;
},
}];
let eventCallback = (eventType) => {
if (eventType == "dismissed") {
// The user intentionally dismissed the notification,
// which we interpret as meaning that they don't care
// to submit the reports. We'll ignore these particular
// reports going forward.
reportIDs.forEach(function(reportID) {
CrashSubmit.ignore(reportID);
});
}
};
nb.appendNotification(message, notificationID,
"chrome://browser/skin/tab-crashed.svg",
nb.PRIORITY_INFO_HIGH, buttons,
eventCallback);
},
/**
* Attempt to submit reports to the crash report server. Each
* report will have the "SubmittedFromInfobar" extra key set
* to true.
*
* @param reportIDs (Array<string>)
* The array of reportIDs to submit.
*/
submitReports(reportIDs) {
for (let reportID of reportIDs) {
CrashSubmit.submit(reportID, {
extraExtraKeyVals: {
"SubmittedFromInfobar": true,
},
});
}
},
};
this.PluginCrashReporter = {
/**
* Makes the PluginCrashReporter ready to hear about and