зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to b2g-inbound
This commit is contained in:
Коммит
b355a3895d
|
@ -319,6 +319,26 @@
|
|||
orient="horizontal"
|
||||
hidden="true"/>
|
||||
|
||||
<menupopup id="processHangOptions"
|
||||
onpopupshowing="ProcessHangMonitor.refreshMenu(window);">
|
||||
<menuitem id="processHangTerminateScript"
|
||||
oncommand="ProcessHangMonitor.terminateScript(window)"
|
||||
accesskey="&processHang.terminateScript.accessKey;"
|
||||
label="&processHang.terminateScript.label;"/>
|
||||
<menuitem id="processHangDebugScript"
|
||||
oncommand="ProcessHangMonitor.debugScript(window)"
|
||||
accesskey="&processHang.debugScript.accessKey;"
|
||||
label="&processHang.debugScript.label;"/>
|
||||
<menuitem id="processHangTerminatePlugin"
|
||||
oncommand="ProcessHangMonitor.terminatePlugin(window)"
|
||||
accesskey="&processHang.terminatePlugin.accessKey;"
|
||||
label="&processHang.terminatePlugin.label;"/>
|
||||
<menuitem id="processHangTerminateProcess"
|
||||
oncommand="ProcessHangMonitor.terminateProcess(window)"
|
||||
accesskey="&processHang.terminateProcess.accessKey;"
|
||||
label="&processHang.terminateProcess.label;"/>
|
||||
</menupopup>
|
||||
|
||||
<menupopup id="toolbar-context-menu"
|
||||
onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('viewToolbarsMenuSeparator'));">
|
||||
<menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode)"
|
||||
|
|
|
@ -925,6 +925,15 @@ you can use these alternative items. Otherwise, their values should be empty. -
|
|||
<!ENTITY panicButton.thankyou.msg2 "Safe browsing!">
|
||||
<!ENTITY panicButton.thankyou.buttonlabel "Thanks!">
|
||||
|
||||
<!ENTITY processHang.terminateScript.label "Stop Script">
|
||||
<!ENTITY processHang.terminateScript.accessKey "S">
|
||||
<!ENTITY processHang.debugScript.label "Debug Script">
|
||||
<!ENTITY processHang.debugScript.accessKey "D">
|
||||
<!ENTITY processHang.terminatePlugin.label "Kill Plugin">
|
||||
<!ENTITY processHang.terminatePlugin.accessKey "P">
|
||||
<!ENTITY processHang.terminateProcess.label "Kill Web Process">
|
||||
<!ENTITY processHang.terminateProcess.accessKey "K">
|
||||
|
||||
<!ENTITY emeLearnMoreContextMenu.label "Learn more about DRM…">
|
||||
<!ENTITY emeLearnMoreContextMenu.accesskey "D">
|
||||
<!ENTITY emeNotificationsNotNow.label "Not now">
|
||||
|
|
|
@ -472,13 +472,9 @@ dataReportingNotification.button.label = Choose What I Share
|
|||
dataReportingNotification.button.accessKey = C
|
||||
|
||||
# Process hang reporter
|
||||
processHang.label = A web page is slowing down your browser. What would you like to do?
|
||||
processHang.button_stop.label = Stop It
|
||||
processHang.button_stop.accessKey = S
|
||||
processHang.button_wait.label = Wait
|
||||
processHang.button_wait.accessKey = W
|
||||
processHang.button_debug.label = Debug Script
|
||||
processHang.button_debug.accessKey = D
|
||||
processHang.message = A web page is causing %1$S to run slowly. What would you like to do?
|
||||
processHang.button.label = Options
|
||||
processHang.button.accessKey = O
|
||||
|
||||
# Webapps notification popup
|
||||
webapps.install = Install
|
||||
|
|
|
@ -19,31 +19,13 @@ Cu.import("resource://gre/modules/Services.jsm");
|
|||
* the platform interface.
|
||||
*/
|
||||
|
||||
/**
|
||||
* If a hang hasn't been reported for more than 10 seconds, assume the
|
||||
* content process has gotten unstuck (and hide the hang notification).
|
||||
*/
|
||||
const HANG_EXPIRATION_TIME = 10000;
|
||||
|
||||
var ProcessHangMonitor = {
|
||||
/**
|
||||
* If a hang hasn't been reported for more than 10 seconds, assume the
|
||||
* content process has gotten unstuck (and hide the hang notification).
|
||||
*/
|
||||
get HANG_EXPIRATION_TIME() {
|
||||
try {
|
||||
return Services.prefs.getIntPref("browser.hangNotification.expiration");
|
||||
} catch (ex) {
|
||||
return 10000;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This timeout is the wait period applied after a user selects "Wait" in
|
||||
* an existing notification.
|
||||
*/
|
||||
get WAIT_EXPIRATION_TIME() {
|
||||
try {
|
||||
return Services.prefs.getIntPref("browser.hangNotification.waitPeriod");
|
||||
} catch (ex) {
|
||||
return 10000;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Collection of hang reports that haven't expired or been dismissed
|
||||
* by the user. The keys are nsIHangReports and values keys are
|
||||
|
@ -52,12 +34,6 @@ var ProcessHangMonitor = {
|
|||
*/
|
||||
_activeReports: new Map(),
|
||||
|
||||
/**
|
||||
* Collection of hang reports that have been suppressed for a
|
||||
* short period of time.
|
||||
*/
|
||||
_pausedReports: new Map(),
|
||||
|
||||
/**
|
||||
* Initialize hang reporting. Called once in the parent process.
|
||||
*/
|
||||
|
@ -94,78 +70,46 @@ var ProcessHangMonitor = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Terminate the plugin process associated with a hang being reported
|
||||
* for the selected browser in |win|. Will attempt to generate a combined
|
||||
* crash report for all processes.
|
||||
* Kill the plugin process causing the hang being reported for the
|
||||
* selected browser in |win|.
|
||||
*/
|
||||
terminatePlugin: function(win) {
|
||||
this.handleUserInput(win, report => report.terminatePlugin());
|
||||
},
|
||||
|
||||
/**
|
||||
* Dismiss the browser notification and invoke an appropriate action based on
|
||||
* the hang type.
|
||||
* Kill the content process causing the hang being reported for the selected
|
||||
* browser in |win|.
|
||||
*/
|
||||
stopIt: function (win) {
|
||||
let report = this.findActiveReport(win.gBrowser.selectedBrowser);
|
||||
if (!report) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (report.hangType) {
|
||||
case report.SLOW_SCRIPT:
|
||||
this.terminateScript(win);
|
||||
break;
|
||||
case report.PLUGIN_HANG:
|
||||
this.terminatePlugin(win);
|
||||
break;
|
||||
}
|
||||
terminateProcess: function(win) {
|
||||
this.handleUserInput(win, report => report.terminateProcess());
|
||||
},
|
||||
|
||||
/**
|
||||
* Dismiss the notification, clear the report from the active list and set up
|
||||
* a new timer to track a wait period during which we won't notify.
|
||||
* Update the "Options" pop-up menu for the hang notification
|
||||
* associated with the selected browser in |win|. The menu should
|
||||
* display only options that are relevant to the given report.
|
||||
*/
|
||||
waitLonger: function(win) {
|
||||
let report = this.findActiveReport(win.gBrowser.selectedBrowser);
|
||||
refreshMenu: function(win) {
|
||||
let report = this.findReport(win.gBrowser.selectedBrowser);
|
||||
if (!report) {
|
||||
return;
|
||||
}
|
||||
// Remove the report from the active list and cancel its timer.
|
||||
this.removeActiveReport(report);
|
||||
|
||||
// NOTE, we didn't call userCanceled on nsIHangReport here. This insures
|
||||
// we don't repeatedly generate and cache crash report data for this hang
|
||||
// in the process hang reporter. It already has one report for the browser
|
||||
// process we want it hold onto.
|
||||
function setVisible(id, visible) {
|
||||
let item = win.document.getElementById(id);
|
||||
item.hidden = !visible;
|
||||
}
|
||||
|
||||
// Create a new wait timer with notify callback
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(() => {
|
||||
for (let [stashedReport, otherTimer] of this._pausedReports) {
|
||||
if (otherTimer === timer) {
|
||||
this.removePausedReport(stashedReport);
|
||||
|
||||
// Create a new notification display timeout timer
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(this, this.HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
|
||||
|
||||
// Store the timer in the active reports map. If we receive a new
|
||||
// observer notification for this hang, we'll redisplay the browser
|
||||
// notification in reportHang below. If we do not receive a new
|
||||
// observer, timer will take care of cleaning up resources associated
|
||||
// with this hang. The observer for active hangs fires about once
|
||||
// a second.
|
||||
this._activeReports.set(report, timer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, this.WAIT_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
|
||||
|
||||
this._pausedReports.set(report, timer);
|
||||
|
||||
// remove the browser notification associated with this hang
|
||||
this.updateWindows();
|
||||
if (report.hangType == report.SLOW_SCRIPT) {
|
||||
setVisible("processHangTerminateScript", true);
|
||||
setVisible("processHangDebugScript", true);
|
||||
setVisible("processHangTerminatePlugin", false);
|
||||
} else if (report.hangType == report.PLUGIN_HANG) {
|
||||
setVisible("processHangTerminateScript", false);
|
||||
setVisible("processHangDebugScript", false);
|
||||
setVisible("processHangTerminatePlugin", true);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -174,11 +118,11 @@ var ProcessHangMonitor = {
|
|||
* about it.
|
||||
*/
|
||||
handleUserInput: function(win, func) {
|
||||
let report = this.findActiveReport(win.gBrowser.selectedBrowser);
|
||||
let report = this.findReport(win.gBrowser.selectedBrowser);
|
||||
if (!report) {
|
||||
return;
|
||||
}
|
||||
this.removeActiveReport(report);
|
||||
this.removeReport(report);
|
||||
|
||||
return func(report);
|
||||
},
|
||||
|
@ -209,9 +153,9 @@ var ProcessHangMonitor = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Find a active hang report for the given <browser> element.
|
||||
* Find any active hang reports for the given <browser> element.
|
||||
*/
|
||||
findActiveReport: function(browser) {
|
||||
findReport: function(browser) {
|
||||
let frameLoader = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
|
||||
for (let [report, timer] of this._activeReports) {
|
||||
if (report.isReportForBrowser(frameLoader)) {
|
||||
|
@ -221,44 +165,6 @@ var ProcessHangMonitor = {
|
|||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Find a paused hang report for the given <browser> element.
|
||||
*/
|
||||
findPausedReport: function(browser) {
|
||||
let frameLoader = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
|
||||
for (let [report, timer] of this._pausedReports) {
|
||||
if (report.isReportForBrowser(frameLoader)) {
|
||||
return report;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove an active hang report from the active list and cancel the timer
|
||||
* associated with it.
|
||||
*/
|
||||
removeActiveReport: function(report) {
|
||||
let timer = this._activeReports.get(report);
|
||||
if (timer) {
|
||||
timer.cancel();
|
||||
}
|
||||
this._activeReports.delete(report);
|
||||
this.updateWindows();
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a paused hang report from the paused list and cancel the timer
|
||||
* associated with it.
|
||||
*/
|
||||
removePausedReport: function(report) {
|
||||
let timer = this._pausedReports.get(report);
|
||||
if (timer) {
|
||||
timer.cancel();
|
||||
}
|
||||
this._pausedReports.delete(report);
|
||||
},
|
||||
|
||||
/**
|
||||
* Iterate over all XUL windows and ensure that the proper hang
|
||||
* reports are shown for each one. Also install event handlers in
|
||||
|
@ -285,7 +191,7 @@ var ProcessHangMonitor = {
|
|||
* If there is a hang report for the current tab in |win|, display it.
|
||||
*/
|
||||
updateWindow: function(win) {
|
||||
let report = this.findActiveReport(win.gBrowser.selectedBrowser);
|
||||
let report = this.findReport(win.gBrowser.selectedBrowser);
|
||||
|
||||
if (report) {
|
||||
this.showNotification(win, report);
|
||||
|
@ -306,36 +212,19 @@ var ProcessHangMonitor = {
|
|||
|
||||
let bundle = win.gNavigatorBundle;
|
||||
let brandBundle = win.document.getElementById("bundle_brand");
|
||||
let appName = brandBundle.getString("brandShortName");
|
||||
let message = bundle.getFormattedString(
|
||||
"processHang.message",
|
||||
[appName]);
|
||||
|
||||
let buttons = [{
|
||||
label: bundle.getString("processHang.button_stop.label"),
|
||||
accessKey: bundle.getString("processHang.button_stop.accessKey"),
|
||||
callback: function() {
|
||||
ProcessHangMonitor.stopIt(win);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: bundle.getString("processHang.button_wait.label"),
|
||||
accessKey: bundle.getString("processHang.button_wait.accessKey"),
|
||||
callback: function() {
|
||||
ProcessHangMonitor.waitLonger(win);
|
||||
}
|
||||
}];
|
||||
label: bundle.getString("processHang.button.label"),
|
||||
accessKey: bundle.getString("processHang.button.accessKey"),
|
||||
popup: "processHangOptions",
|
||||
callback: null,
|
||||
}];
|
||||
|
||||
#ifdef MOZ_DEV_EDITION
|
||||
if (report.hangType == report.SLOW_SCRIPT) {
|
||||
buttons.push({
|
||||
label: bundle.getString("processHang.button_debug.label"),
|
||||
accessKey: bundle.getString("processHang.button_debug.accessKey"),
|
||||
callback: function() {
|
||||
ProcessHangMonitor.debugScript(win);
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
nb.appendNotification(bundle.getString("processHang.label"),
|
||||
"process-hang",
|
||||
nb.appendNotification(message, "process-hang",
|
||||
"chrome://browser/content/aboutRobots-icon.png",
|
||||
nb.PRIORITY_WARNING_HIGH, buttons);
|
||||
},
|
||||
|
@ -381,19 +270,11 @@ var ProcessHangMonitor = {
|
|||
* before, show a notification for it in all open XUL windows.
|
||||
*/
|
||||
reportHang: function(report) {
|
||||
// If this hang was already reported reset the timer for it.
|
||||
// If this hang was already reported, then reset the timer for it.
|
||||
if (this._activeReports.has(report)) {
|
||||
let timer = this._activeReports.get(report);
|
||||
timer.cancel();
|
||||
timer.initWithCallback(this, this.HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
|
||||
// if this report is in active but doesn't have a notification associated
|
||||
// with it, display a notification.
|
||||
this.updateWindows();
|
||||
return;
|
||||
}
|
||||
|
||||
// If this hang was already reported and paused by the user ignore it.
|
||||
if (this._pausedReports.has(report)) {
|
||||
timer.initWithCallback(this, HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -410,19 +291,28 @@ var ProcessHangMonitor = {
|
|||
|
||||
// Otherwise create a new timer and display the report.
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(this, this.HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
|
||||
timer.initWithCallback(this, HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
|
||||
|
||||
this._activeReports.set(report, timer);
|
||||
this.updateWindows();
|
||||
},
|
||||
|
||||
/**
|
||||
* Dismiss a hang report because the user closed the notification
|
||||
* for it or the report expired.
|
||||
*/
|
||||
removeReport: function(report) {
|
||||
this._activeReports.delete(report);
|
||||
this.updateWindows();
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for when HANG_EXPIRATION_TIME has elapsed.
|
||||
*/
|
||||
notify: function(timer) {
|
||||
for (let [otherReport, otherTimer] of this._activeReports) {
|
||||
if (otherTimer === timer) {
|
||||
this.removeActiveReport(otherReport);
|
||||
this.removeReport(otherReport);
|
||||
otherReport.userCanceled();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ EXTRA_JS_MODULES += [
|
|||
'offlineAppCache.jsm',
|
||||
'PanelFrame.jsm',
|
||||
'PluginContent.jsm',
|
||||
'ProcessHangMonitor.jsm',
|
||||
'ReaderParent.jsm',
|
||||
'RecentWindow.jsm',
|
||||
'RemotePrompt.jsm',
|
||||
|
@ -45,10 +46,6 @@ EXTRA_JS_MODULES += [
|
|||
'webrtcUI.jsm',
|
||||
]
|
||||
|
||||
EXTRA_PP_JS_MODULES += [
|
||||
'ProcessHangMonitor.jsm'
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
EXTRA_JS_MODULES += [
|
||||
'Windows8WindowFrameColor.jsm',
|
||||
|
|
|
@ -3,8 +3,6 @@ support-files =
|
|||
head.js
|
||||
|
||||
[browser_BrowserUITelemetry_buckets.js]
|
||||
[browser_ProcessHangNotifications.js]
|
||||
skip-if = !e10s
|
||||
[browser_ContentSearch.js]
|
||||
skip-if = e10s
|
||||
support-files =
|
||||
|
|
|
@ -1,185 +0,0 @@
|
|||
|
||||
Cu.import("resource://gre/modules/UpdateUtils.jsm");
|
||||
|
||||
function getNotificationBox(aWindow) {
|
||||
return aWindow.document.getElementById("high-priority-global-notificationbox");
|
||||
}
|
||||
|
||||
function promiseNotificationShown(aWindow, aName) {
|
||||
return new Promise((resolve) => {
|
||||
let notification = getNotificationBox(aWindow);
|
||||
notification.addEventListener("AlertActive", function active() {
|
||||
notification.removeEventListener("AlertActive", active, true);
|
||||
is(notification.allNotifications.length, 1, "Notification Displayed.");
|
||||
resolve(notification);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function promiseReportCallMade(aValue) {
|
||||
return new Promise((resolve) => {
|
||||
let old = gTestHangReport.testCallback;
|
||||
gTestHangReport.testCallback = function (val) {
|
||||
gTestHangReport.testCallback = old;
|
||||
is(aValue, val, "was the correct method call made on the hang report object?");
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function pushPrefs(...aPrefs) {
|
||||
return new Promise((resolve) => {
|
||||
SpecialPowers.pushPrefEnv({"set": aPrefs}, resolve);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function popPrefs() {
|
||||
return new Promise((resolve) => {
|
||||
SpecialPowers.popPrefEnv(resolve);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
let gTestHangReport = {
|
||||
SLOW_SCRIPT: 1,
|
||||
PLUGIN_HANG: 2,
|
||||
|
||||
TEST_CALLBACK_CANCELED: 1,
|
||||
TEST_CALLBACK_TERMSCRIPT: 2,
|
||||
TEST_CALLBACK_TERMPLUGIN: 3,
|
||||
|
||||
_hangType: 1,
|
||||
_tcb: function (aCallbackType) {},
|
||||
|
||||
get hangType() {
|
||||
return this._hangType;
|
||||
},
|
||||
|
||||
set hangType(aValue) {
|
||||
this._hangType = aValue;
|
||||
},
|
||||
|
||||
set testCallback(aValue) {
|
||||
this._tcb = aValue;
|
||||
},
|
||||
|
||||
QueryInterface: function (aIID) {
|
||||
if (aIID.equals(Components.interfaces.nsIHangReport) ||
|
||||
aIID.equals(Components.interfaces.nsISupports))
|
||||
return this;
|
||||
throw Components.results.NS_NOINTERFACE;
|
||||
},
|
||||
|
||||
userCanceled: function () {
|
||||
this._tcb(this.TEST_CALLBACK_CANCELED);
|
||||
},
|
||||
|
||||
terminateScript: function () {
|
||||
this._tcb(this.TEST_CALLBACK_TERMSCRIPT);
|
||||
},
|
||||
|
||||
terminatePlugin: function () {
|
||||
this._tcb(this.TEST_CALLBACK_TERMPLUGIN);
|
||||
},
|
||||
|
||||
isReportForBrowser: function(aFrameLoader) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// on dev edition we add a button for js debugging of hung scripts.
|
||||
let buttonCount = (UpdateUtils.UpdateChannel == "aurora" ? 3 : 2);
|
||||
|
||||
/**
|
||||
* Test if hang reports receive a terminate script callback when the user selects
|
||||
* stop in response to a script hang.
|
||||
*/
|
||||
|
||||
add_task(function* terminateScriptTest() {
|
||||
let promise = promiseNotificationShown(window, "process-hang");
|
||||
Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
|
||||
let notification = yield promise;
|
||||
|
||||
let buttons = notification.currentNotification.getElementsByTagName("button");
|
||||
is(buttons.length, buttonCount, "proper number of buttons");
|
||||
|
||||
// Click the "Stop It" button, we should get a terminate script callback
|
||||
gTestHangReport.hangType = gTestHangReport.SLOW_SCRIPT;
|
||||
promise = promiseReportCallMade(gTestHangReport.TEST_CALLBACK_TERMSCRIPT);
|
||||
buttons[0].click();
|
||||
yield promise;
|
||||
});
|
||||
|
||||
/**
|
||||
* Test if hang reports receive user canceled callbacks after a user selects wait
|
||||
* and the browser frees up from a script hang on its own.
|
||||
*/
|
||||
|
||||
add_task(function* waitForScriptTest() {
|
||||
let promise = promiseNotificationShown(window, "process-hang");
|
||||
Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
|
||||
let notification = yield promise;
|
||||
|
||||
let buttons = notification.currentNotification.getElementsByTagName("button");
|
||||
is(buttons.length, buttonCount, "proper number of buttons");
|
||||
|
||||
yield pushPrefs(["browser.hangNotification.waitPeriod", 1000],
|
||||
["browser.hangNotification.expiration", 2000]);
|
||||
|
||||
function nocbcheck() {
|
||||
ok(false, "received a callback?");
|
||||
}
|
||||
let oldcb = gTestHangReport.testCallback;
|
||||
gTestHangReport.testCallback = nocbcheck;
|
||||
// Click the "Wait" button this time, we shouldn't get a callback at all.
|
||||
buttons[1].click();
|
||||
gTestHangReport.testCallback = oldcb;
|
||||
|
||||
// send another hang pulse, we should not get a notification here
|
||||
Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
|
||||
is(notification.currentNotification, null, "no notification should be visible");
|
||||
|
||||
// After selecting Wait, we should get a userCanceled callback after
|
||||
// HANG_EXPIRATION_TIME.
|
||||
yield promiseReportCallMade(gTestHangReport.TEST_CALLBACK_CANCELED);
|
||||
|
||||
yield popPrefs();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test if hang reports receive user canceled callbacks after the content
|
||||
* process stops sending hang notifications.
|
||||
*/
|
||||
|
||||
add_task(function* hangGoesAwayTest() {
|
||||
yield pushPrefs(["browser.hangNotification.expiration", 1000]);
|
||||
|
||||
let promise = promiseNotificationShown(window, "process-hang");
|
||||
Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
|
||||
yield promise;
|
||||
|
||||
yield promiseReportCallMade(gTestHangReport.TEST_CALLBACK_CANCELED);
|
||||
|
||||
yield popPrefs();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests if hang reports receive a terminate plugin callback when the user selects
|
||||
* stop in response to a plugin hang.
|
||||
*/
|
||||
|
||||
add_task(function* terminatePluginTest() {
|
||||
let promise = promiseNotificationShown(window, "process-hang");
|
||||
Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
|
||||
let notification = yield promise;
|
||||
|
||||
let buttons = notification.currentNotification.getElementsByTagName("button");
|
||||
is(buttons.length, buttonCount, "proper number of buttons");
|
||||
|
||||
// Click the "Stop It" button, we should get a terminate script callback
|
||||
gTestHangReport.hangType = gTestHangReport.PLUGIN_HANG;
|
||||
promise = promiseReportCallMade(gTestHangReport.TEST_CALLBACK_TERMPLUGIN);
|
||||
buttons[0].click();
|
||||
yield promise;
|
||||
});
|
|
@ -151,6 +151,7 @@ public:
|
|||
NS_IMETHOD BeginStartingDebugger() override;
|
||||
NS_IMETHOD EndStartingDebugger() override;
|
||||
NS_IMETHOD TerminatePlugin() override;
|
||||
NS_IMETHOD TerminateProcess() override;
|
||||
NS_IMETHOD UserCanceled() override;
|
||||
|
||||
NS_IMETHOD IsReportForBrowser(nsIFrameLoader* aFrameLoader, bool* aResult) override;
|
||||
|
@ -819,8 +820,6 @@ HangMonitoredProcess::TerminatePlugin()
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// generates a crash report that includes a browser report taken here
|
||||
// earlier, the content process, and any plugin process(es).
|
||||
uint32_t id = mHangData.get_PluginHangData().pluginId();
|
||||
plugins::TerminatePlugin(id, NS_LITERAL_CSTRING("HangMonitor"),
|
||||
mBrowserDumpId);
|
||||
|
@ -831,6 +830,24 @@ HangMonitoredProcess::TerminatePlugin()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HangMonitoredProcess::TerminateProcess()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mContentParent) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (mActor && mHangData.type() == HangData::TPluginHangData) {
|
||||
uint32_t id = mHangData.get_PluginHangData().pluginId();
|
||||
mActor->CleanupPluginHang(id, true);
|
||||
}
|
||||
|
||||
mContentParent->KillHard("HangMonitor");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HangMonitoredProcess::IsReportForBrowser(nsIFrameLoader* aFrameLoader, bool* aResult)
|
||||
{
|
||||
|
|
|
@ -18,7 +18,7 @@ interface nsIFrameLoader;
|
|||
* process will continue to run uninhibitedly during this time.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(5fcffbb9-be62-49b1-b8a1-36e820787a74)]
|
||||
[scriptable, uuid(90cea731-dd3e-459e-b017-f9a14697b56e)]
|
||||
interface nsIHangReport : nsISupports
|
||||
{
|
||||
const unsigned long SLOW_SCRIPT = 1;
|
||||
|
@ -50,6 +50,10 @@ interface nsIHangReport : nsISupports
|
|||
// Only valid for PLUGIN_HANG reports.
|
||||
void terminatePlugin();
|
||||
|
||||
// Terminate the hung content process unconditionally.
|
||||
// Valid for any type of hang.
|
||||
void terminateProcess();
|
||||
|
||||
// Ask the content process to start up the slow script debugger.
|
||||
// Only valid for SLOW_SCRIPT reports.
|
||||
void beginStartingDebugger();
|
||||
|
|
Загрузка…
Ссылка в новой задаче