mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backout bug 1118618 on a CLOSED TREE
This commit is contained in:
parent
81c4309842
commit
7b3fe0714a
@ -1803,11 +1803,5 @@ pref("extensions.interposition.prefetching", true);
|
|||||||
|
|
||||||
pref("browser.defaultbrowser.notificationbar", false);
|
pref("browser.defaultbrowser.notificationbar", false);
|
||||||
|
|
||||||
// How often to check for CPOW timeouts. CPOWs are only timed out by
|
// How many milliseconds to wait for a CPOW response from the child process.
|
||||||
// the hang monitor.
|
pref("dom.ipc.cpow.timeout", 0);
|
||||||
pref("dom.ipc.cpow.timeout", 500);
|
|
||||||
|
|
||||||
// Enable e10s hang monitoring (slow script checking and plugin hang
|
|
||||||
// detection).
|
|
||||||
pref("dom.ipc.processHangMonitor", true);
|
|
||||||
pref("dom.ipc.reportProcessHangs", true);
|
|
||||||
|
@ -149,9 +149,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "Social",
|
|||||||
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
|
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
|
||||||
"resource://gre/modules/PageThumbs.jsm");
|
"resource://gre/modules/PageThumbs.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "ProcessHangMonitor",
|
|
||||||
"resource:///modules/ProcessHangMonitor.jsm");
|
|
||||||
|
|
||||||
#ifdef MOZ_SAFE_BROWSING
|
#ifdef MOZ_SAFE_BROWSING
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
|
XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
|
||||||
"resource://gre/modules/SafeBrowsing.jsm");
|
"resource://gre/modules/SafeBrowsing.jsm");
|
||||||
|
@ -334,26 +334,6 @@
|
|||||||
orient="horizontal"
|
orient="horizontal"
|
||||||
hidden="true"/>
|
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"
|
<menupopup id="toolbar-context-menu"
|
||||||
onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('viewToolbarsMenuSeparator'));">
|
onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('viewToolbarsMenuSeparator'));">
|
||||||
<menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode)"
|
<menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode)"
|
||||||
|
@ -1492,10 +1492,6 @@
|
|||||||
if (wasActive)
|
if (wasActive)
|
||||||
aBrowser.focus();
|
aBrowser.focus();
|
||||||
|
|
||||||
let evt = document.createEvent("Events");
|
|
||||||
evt.initEvent("TabRemotenessChange", true, false);
|
|
||||||
tab.dispatchEvent(evt);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
]]>
|
]]>
|
||||||
</body>
|
</body>
|
||||||
|
@ -59,9 +59,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "CustomizationTabPreloader",
|
|||||||
XPCOMUtils.defineLazyModuleGetter(this, "PdfJs",
|
XPCOMUtils.defineLazyModuleGetter(this, "PdfJs",
|
||||||
"resource://pdf.js/PdfJs.jsm");
|
"resource://pdf.js/PdfJs.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "ProcessHangMonitor",
|
|
||||||
"resource:///modules/ProcessHangMonitor.jsm");
|
|
||||||
|
|
||||||
#ifdef NIGHTLY_BUILD
|
#ifdef NIGHTLY_BUILD
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "ShumwayUtils",
|
XPCOMUtils.defineLazyModuleGetter(this, "ShumwayUtils",
|
||||||
"resource://shumway/ShumwayUtils.jsm");
|
"resource://shumway/ShumwayUtils.jsm");
|
||||||
@ -763,8 +760,6 @@ BrowserGlue.prototype = {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ProcessHangMonitor.init();
|
|
||||||
|
|
||||||
// A channel for "remote troubleshooting" code...
|
// A channel for "remote troubleshooting" code...
|
||||||
let channel = new WebChannel("remote-troubleshooting", "remote-troubleshooting");
|
let channel = new WebChannel("remote-troubleshooting", "remote-troubleshooting");
|
||||||
channel.listen((id, data, target) => {
|
channel.listen((id, data, target) => {
|
||||||
|
@ -854,9 +854,17 @@ let gDevToolsBrowser = {
|
|||||||
.getService(Ci.nsISlowScriptDebug);
|
.getService(Ci.nsISlowScriptDebug);
|
||||||
let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
|
let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
|
||||||
|
|
||||||
function slowScriptDebugHandler(aTab, aCallback) {
|
debugService.activationHandler = function(aWindow) {
|
||||||
let target = devtools.TargetFactory.forTab(aTab);
|
let chromeWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIWebNavigation)
|
||||||
|
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||||
|
.rootTreeItem
|
||||||
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindow)
|
||||||
|
.QueryInterface(Ci.nsIDOMChromeWindow);
|
||||||
|
let target = devtools.TargetFactory.forTab(chromeWindow.gBrowser.selectedTab);
|
||||||
|
|
||||||
|
let setupFinished = false;
|
||||||
gDevTools.showToolbox(target, "jsdebugger").then(toolbox => {
|
gDevTools.showToolbox(target, "jsdebugger").then(toolbox => {
|
||||||
let threadClient = toolbox.getCurrentPanel().panelWin.gThreadClient;
|
let threadClient = toolbox.getCurrentPanel().panelWin.gThreadClient;
|
||||||
|
|
||||||
@ -866,13 +874,13 @@ let gDevToolsBrowser = {
|
|||||||
case "paused":
|
case "paused":
|
||||||
// When the debugger is already paused.
|
// When the debugger is already paused.
|
||||||
threadClient.breakOnNext();
|
threadClient.breakOnNext();
|
||||||
aCallback();
|
setupFinished = true;
|
||||||
break;
|
break;
|
||||||
case "attached":
|
case "attached":
|
||||||
// When the debugger is already open.
|
// When the debugger is already open.
|
||||||
threadClient.interrupt(() => {
|
threadClient.interrupt(() => {
|
||||||
threadClient.breakOnNext();
|
threadClient.breakOnNext();
|
||||||
aCallback();
|
setupFinished = true;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "resuming":
|
case "resuming":
|
||||||
@ -880,7 +888,7 @@ let gDevToolsBrowser = {
|
|||||||
threadClient.addOneTimeListener("resumed", () => {
|
threadClient.addOneTimeListener("resumed", () => {
|
||||||
threadClient.interrupt(() => {
|
threadClient.interrupt(() => {
|
||||||
threadClient.breakOnNext();
|
threadClient.breakOnNext();
|
||||||
aCallback();
|
setupFinished = true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@ -889,20 +897,6 @@ let gDevToolsBrowser = {
|
|||||||
threadClient.state);
|
threadClient.state);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
debugService.activationHandler = function(aWindow) {
|
|
||||||
let chromeWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIWebNavigation)
|
|
||||||
.QueryInterface(Ci.nsIDocShellTreeItem)
|
|
||||||
.rootTreeItem
|
|
||||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIDOMWindow)
|
|
||||||
.QueryInterface(Ci.nsIDOMChromeWindow);
|
|
||||||
|
|
||||||
let setupFinished = false;
|
|
||||||
slowScriptDebugHandler(chromeWindow.gBrowser.selectedTab,
|
|
||||||
() => { setupFinished = true; });
|
|
||||||
|
|
||||||
// Don't return from the interrupt handler until the debugger is brought
|
// Don't return from the interrupt handler until the debugger is brought
|
||||||
// up; no reason to continue executing the slow script.
|
// up; no reason to continue executing the slow script.
|
||||||
@ -914,18 +908,6 @@ let gDevToolsBrowser = {
|
|||||||
}
|
}
|
||||||
utils.leaveModalState();
|
utils.leaveModalState();
|
||||||
};
|
};
|
||||||
|
|
||||||
debugService.remoteActivationHandler = function(aBrowser, aCallback) {
|
|
||||||
let chromeWindow = aBrowser.ownerDocument.defaultView;
|
|
||||||
let tab = chromeWindow.gBrowser.getTabForBrowser(aBrowser);
|
|
||||||
chromeWindow.gBrowser.selected = tab;
|
|
||||||
|
|
||||||
function callback() {
|
|
||||||
aCallback.finishDebuggerStartup();
|
|
||||||
}
|
|
||||||
|
|
||||||
slowScriptDebugHandler(tab, callback);
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -831,11 +831,3 @@ just addresses the organization to follow, e.g. "This site is run by " -->
|
|||||||
<!ENTITY panicButton.thankyou.msg2 "Safe browsing!">
|
<!ENTITY panicButton.thankyou.msg2 "Safe browsing!">
|
||||||
<!ENTITY panicButton.thankyou.buttonlabel "Thanks!">
|
<!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">
|
|
||||||
|
@ -435,11 +435,6 @@ dataReportingNotification.message = %1$S automatically sends some data to
|
|||||||
dataReportingNotification.button.label = Choose What I Share
|
dataReportingNotification.button.label = Choose What I Share
|
||||||
dataReportingNotification.button.accessKey = C
|
dataReportingNotification.button.accessKey = C
|
||||||
|
|
||||||
# Process hang reporter
|
|
||||||
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 notification popup
|
||||||
webapps.install = Install
|
webapps.install = Install
|
||||||
webapps.install.accesskey = I
|
webapps.install.accesskey = I
|
||||||
|
@ -1,309 +0,0 @@
|
|||||||
/* -*- mode: js; indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
let Cc = Components.classes;
|
|
||||||
let Ci = Components.interfaces;
|
|
||||||
let Cu = Components.utils;
|
|
||||||
|
|
||||||
this.EXPORTED_SYMBOLS = ["ProcessHangMonitor"];
|
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This JSM is responsible for observing content process hang reports
|
|
||||||
* and asking the user what to do about them. See nsIHangReport for
|
|
||||||
* the platform interface.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If a hang hasn't been reported for more than 5 seconds, assume the
|
|
||||||
* content process has gotten unstuck (and hide the hang notification).
|
|
||||||
*/
|
|
||||||
const HANG_EXPIRATION_TIME = 5000;
|
|
||||||
|
|
||||||
let ProcessHangMonitor = {
|
|
||||||
/**
|
|
||||||
* Collection of hang reports that haven't expired or been dismissed
|
|
||||||
* by the user. The keys are nsIHangReports and values keys are
|
|
||||||
* timers. Each time the hang is reported, the timer is refreshed so
|
|
||||||
* it expires after HANG_EXPIRATION_TIME.
|
|
||||||
*/
|
|
||||||
_activeReports: new Map(),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize hang reporting. Called once in the parent process.
|
|
||||||
*/
|
|
||||||
init: function() {
|
|
||||||
Services.obs.addObserver(this, "process-hang-report", false);
|
|
||||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
|
||||||
Services.ww.registerNotification(this);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Terminate JavaScript associated with the hang being reported for
|
|
||||||
* the selected browser in |win|.
|
|
||||||
*/
|
|
||||||
terminateScript: function(win) {
|
|
||||||
this.handleUserInput(win, report => report.terminateScript());
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start devtools debugger for JavaScript associated with the hang
|
|
||||||
* being reported for the selected browser in |win|.
|
|
||||||
*/
|
|
||||||
debugScript: function(win) {
|
|
||||||
this.handleUserInput(win, report => {
|
|
||||||
function callback() {
|
|
||||||
report.endStartingDebugger();
|
|
||||||
}
|
|
||||||
|
|
||||||
report.beginStartingDebugger();
|
|
||||||
|
|
||||||
let svc = Cc["@mozilla.org/dom/slow-script-debug;1"].getService(Ci.nsISlowScriptDebug);
|
|
||||||
let handler = svc.remoteActivationHandler;
|
|
||||||
handler.handleSlowScriptDebug(report.scriptBrowser, callback);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Kill the plugin process causing the hang being reported for the
|
|
||||||
* selected browser in |win|.
|
|
||||||
*/
|
|
||||||
terminatePlugin: function(win) {
|
|
||||||
this.handleUserInput(win, report => report.terminatePlugin());
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Kill the content process causing the hang being reported for the selected
|
|
||||||
* browser in |win|.
|
|
||||||
*/
|
|
||||||
terminateProcess: function(win) {
|
|
||||||
this.handleUserInput(win, report => report.terminateProcess());
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
refreshMenu: function(win) {
|
|
||||||
let report = this.findReport(win.gBrowser.selectedBrowser);
|
|
||||||
if (!report) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setVisible(id, visible) {
|
|
||||||
let item = win.document.getElementById(id);
|
|
||||||
item.hidden = !visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If there is a hang report associated with the selected browser in
|
|
||||||
* |win|, invoke |func| on that report and stop notifying the user
|
|
||||||
* about it.
|
|
||||||
*/
|
|
||||||
handleUserInput: function(win, func) {
|
|
||||||
let report = this.findReport(win.gBrowser.selectedBrowser);
|
|
||||||
if (!report) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.removeReport(report);
|
|
||||||
|
|
||||||
return func(report);
|
|
||||||
},
|
|
||||||
|
|
||||||
observe: function(subject, topic, data) {
|
|
||||||
switch (topic) {
|
|
||||||
case "xpcom-shutdown":
|
|
||||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
|
||||||
Services.obs.removeObserver(this, "process-hang-report");
|
|
||||||
Services.ww.unregisterNotification(this);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "process-hang-report":
|
|
||||||
this.reportHang(subject.QueryInterface(Ci.nsIHangReport));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "domwindowopened":
|
|
||||||
// Install event listeners on the new window in case one of
|
|
||||||
// its tabs is already hung.
|
|
||||||
let win = subject.QueryInterface(Ci.nsIDOMWindow);
|
|
||||||
let listener = (ev) => {
|
|
||||||
win.removeEventListener("load", listener, true);
|
|
||||||
this.updateWindows();
|
|
||||||
};
|
|
||||||
win.addEventListener("load", listener, true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find any active hang reports for the given <browser> element.
|
|
||||||
*/
|
|
||||||
findReport: function(browser) {
|
|
||||||
let frameLoader = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
|
|
||||||
for (let [report, timer] of this._activeReports) {
|
|
||||||
if (report.isReportForBrowser(frameLoader)) {
|
|
||||||
return report;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterate over all XUL windows and ensure that the proper hang
|
|
||||||
* reports are shown for each one. Also install event handlers in
|
|
||||||
* each window to watch for events that would cause a different hang
|
|
||||||
* report to be displayed.
|
|
||||||
*/
|
|
||||||
updateWindows: function() {
|
|
||||||
let e = Services.wm.getEnumerator("navigator:browser");
|
|
||||||
while (e.hasMoreElements()) {
|
|
||||||
let win = e.getNext();
|
|
||||||
|
|
||||||
this.updateWindow(win);
|
|
||||||
|
|
||||||
// Only listen for these events if there are active hang reports.
|
|
||||||
if (this._activeReports.size) {
|
|
||||||
this.trackWindow(win);
|
|
||||||
} else {
|
|
||||||
this.untrackWindow(win);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If there is a hang report for the current tab in |win|, display it.
|
|
||||||
*/
|
|
||||||
updateWindow: function(win) {
|
|
||||||
let report = this.findReport(win.gBrowser.selectedBrowser);
|
|
||||||
|
|
||||||
if (report) {
|
|
||||||
this.showNotification(win, report);
|
|
||||||
} else {
|
|
||||||
this.hideNotification(win);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the notification for a hang.
|
|
||||||
*/
|
|
||||||
showNotification: function(win, report) {
|
|
||||||
let nb = win.document.getElementById("high-priority-global-notificationbox");
|
|
||||||
let notification = nb.getNotificationWithValue("process-hang");
|
|
||||||
if (notification) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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.label"),
|
|
||||||
accessKey: bundle.getString("processHang.button.accessKey"),
|
|
||||||
popup: "processHangOptions",
|
|
||||||
callback: null,
|
|
||||||
}];
|
|
||||||
|
|
||||||
nb.appendNotification(message, "process-hang",
|
|
||||||
"chrome://browser/content/aboutRobots-icon.png",
|
|
||||||
nb.PRIORITY_WARNING_HIGH, buttons);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure that no hang notifications are visible in |win|.
|
|
||||||
*/
|
|
||||||
hideNotification: function(win) {
|
|
||||||
let nb = win.document.getElementById("high-priority-global-notificationbox");
|
|
||||||
let notification = nb.getNotificationWithValue("process-hang");
|
|
||||||
if (notification) {
|
|
||||||
nb.removeNotification(notification);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Install event handlers on |win| to watch for events that would
|
|
||||||
* cause a different hang report to be displayed.
|
|
||||||
*/
|
|
||||||
trackWindow: function(win) {
|
|
||||||
win.gBrowser.tabContainer.addEventListener("TabSelect", this, true);
|
|
||||||
win.gBrowser.tabContainer.addEventListener("TabRemotenessChange", this, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
untrackWindow: function(win) {
|
|
||||||
win.gBrowser.tabContainer.removeEventListener("TabSelect", this, true);
|
|
||||||
win.gBrowser.tabContainer.removeEventListener("TabRemotenessChange", this, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleEvent: function(event) {
|
|
||||||
let win = event.target.ownerDocument.defaultView;
|
|
||||||
|
|
||||||
// If a new tab is selected or if a tab changes remoteness, then
|
|
||||||
// we may need to show or hide a hang notification.
|
|
||||||
|
|
||||||
if (event.type == "TabSelect" || event.type == "TabRemotenessChange") {
|
|
||||||
this.updateWindow(win);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle a potentially new hang report. If it hasn't been seen
|
|
||||||
* before, show a notification for it in all open XUL windows.
|
|
||||||
*/
|
|
||||||
reportHang: function(report) {
|
|
||||||
// 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, HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise create a new timer and display the report.
|
|
||||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
|
||||||
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.removeReport(otherReport);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
@ -27,7 +27,6 @@ EXTRA_JS_MODULES += [
|
|||||||
'NetworkPrioritizer.jsm',
|
'NetworkPrioritizer.jsm',
|
||||||
'offlineAppCache.jsm',
|
'offlineAppCache.jsm',
|
||||||
'PanelFrame.jsm',
|
'PanelFrame.jsm',
|
||||||
'ProcessHangMonitor.jsm',
|
|
||||||
'RemotePrompt.jsm',
|
'RemotePrompt.jsm',
|
||||||
'SitePermissions.jsm',
|
'SitePermissions.jsm',
|
||||||
'Social.jsm',
|
'Social.jsm',
|
||||||
|
@ -16,9 +16,6 @@ SlowScriptDebug.prototype = {
|
|||||||
|
|
||||||
get activationHandler() { return this._activationHandler; },
|
get activationHandler() { return this._activationHandler; },
|
||||||
set activationHandler(cb) { return this._activationHandler = cb; },
|
set activationHandler(cb) { return this._activationHandler = cb; },
|
||||||
|
|
||||||
get remoteActivationHandler() { return this._remoteActivationHandler; },
|
|
||||||
set remoteActivationHandler(cb) { return this._remoteActivationHandler = cb; },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SlowScriptDebug]);
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SlowScriptDebug]);
|
||||||
|
@ -67,7 +67,6 @@
|
|||||||
#include "mozilla/EventListenerManager.h"
|
#include "mozilla/EventListenerManager.h"
|
||||||
#include "mozilla/EventStates.h"
|
#include "mozilla/EventStates.h"
|
||||||
#include "mozilla/MouseEvents.h"
|
#include "mozilla/MouseEvents.h"
|
||||||
#include "mozilla/ProcessHangMonitor.h"
|
|
||||||
#include "AudioChannelService.h"
|
#include "AudioChannelService.h"
|
||||||
#include "MessageEvent.h"
|
#include "MessageEvent.h"
|
||||||
#include "nsAboutProtocolUtils.h"
|
#include "nsAboutProtocolUtils.h"
|
||||||
@ -10970,45 +10969,17 @@ nsGlobalWindow::ShowSlowScriptDialog()
|
|||||||
return KillSlowScript;
|
return KillSlowScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we should offer the option to debug
|
|
||||||
JS::AutoFilename filename;
|
|
||||||
unsigned lineno;
|
|
||||||
bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno);
|
|
||||||
|
|
||||||
if (XRE_GetProcessType() == GeckoProcessType_Content &&
|
|
||||||
ProcessHangMonitor::Get()) {
|
|
||||||
ProcessHangMonitor::SlowScriptAction action;
|
|
||||||
nsRefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
|
|
||||||
nsCOMPtr<nsITabChild> child = do_GetInterface(GetDocShell());
|
|
||||||
action = monitor->NotifySlowScript(child,
|
|
||||||
filename.get(),
|
|
||||||
lineno);
|
|
||||||
if (action == ProcessHangMonitor::Terminate) {
|
|
||||||
return KillSlowScript;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action == ProcessHangMonitor::StartDebugger) {
|
|
||||||
// Spin a nested event loop so that the debugger in the parent can fetch
|
|
||||||
// any information it needs. Once the debugger has started, return to the
|
|
||||||
// script.
|
|
||||||
nsRefPtr<nsGlobalWindow> outer = GetOuterWindowInternal();
|
|
||||||
outer->EnterModalState();
|
|
||||||
while (!monitor->IsDebuggerStartupComplete()) {
|
|
||||||
NS_ProcessNextEvent(nullptr, true);
|
|
||||||
}
|
|
||||||
outer->LeaveModalState();
|
|
||||||
return ContinueSlowScript;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ContinueSlowScriptAndKeepNotifying;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the nsIPrompt interface from the docshell
|
// Get the nsIPrompt interface from the docshell
|
||||||
nsCOMPtr<nsIDocShell> ds = GetDocShell();
|
nsCOMPtr<nsIDocShell> ds = GetDocShell();
|
||||||
NS_ENSURE_TRUE(ds, KillSlowScript);
|
NS_ENSURE_TRUE(ds, KillSlowScript);
|
||||||
nsCOMPtr<nsIPrompt> prompt = do_GetInterface(ds);
|
nsCOMPtr<nsIPrompt> prompt = do_GetInterface(ds);
|
||||||
NS_ENSURE_TRUE(prompt, KillSlowScript);
|
NS_ENSURE_TRUE(prompt, KillSlowScript);
|
||||||
|
|
||||||
|
// Check if we should offer the option to debug
|
||||||
|
JS::AutoFilename filename;
|
||||||
|
unsigned lineno;
|
||||||
|
bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno);
|
||||||
|
|
||||||
// Prioritize the SlowScriptDebug interface over JSD1.
|
// Prioritize the SlowScriptDebug interface over JSD1.
|
||||||
nsCOMPtr<nsISlowScriptDebugCallback> debugCallback;
|
nsCOMPtr<nsISlowScriptDebugCallback> debugCallback;
|
||||||
|
|
||||||
|
@ -726,7 +726,6 @@ public:
|
|||||||
|
|
||||||
enum SlowScriptResponse {
|
enum SlowScriptResponse {
|
||||||
ContinueSlowScript = 0,
|
ContinueSlowScript = 0,
|
||||||
ContinueSlowScriptAndKeepNotifying,
|
|
||||||
AlwaysContinueSlowScript,
|
AlwaysContinueSlowScript,
|
||||||
KillSlowScript
|
KillSlowScript
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
interface nsIDOMWindow;
|
interface nsIDOMWindow;
|
||||||
interface nsIDOMEventTarget;
|
|
||||||
|
|
||||||
[scriptable, function, uuid(f7dbb80c-5d1e-4fd9-b55c-a9ffda4a75b1)]
|
[scriptable, function, uuid(f7dbb80c-5d1e-4fd9-b55c-a9ffda4a75b1)]
|
||||||
interface nsISlowScriptDebugCallback : nsISupports
|
interface nsISlowScriptDebugCallback : nsISupports
|
||||||
@ -13,22 +12,8 @@ interface nsISlowScriptDebugCallback : nsISupports
|
|||||||
void handleSlowScriptDebug(in nsIDOMWindow aWindow);
|
void handleSlowScriptDebug(in nsIDOMWindow aWindow);
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, function, uuid(b1c6ecd0-8fa4-11e4-b4a9-0800200c9a66)]
|
|
||||||
interface nsISlowScriptDebugerStartupCallback : nsISupports
|
|
||||||
{
|
|
||||||
void finishDebuggerStartup();
|
|
||||||
};
|
|
||||||
|
|
||||||
[scriptable, function, uuid(dbee14b0-8fa0-11e4-b4a9-0800200c9a66)]
|
|
||||||
interface nsISlowScriptDebugRemoteCallback : nsISupports
|
|
||||||
{
|
|
||||||
void handleSlowScriptDebug(in nsIDOMEventTarget aBrowser,
|
|
||||||
in nsISlowScriptDebugerStartupCallback aCallback);
|
|
||||||
};
|
|
||||||
|
|
||||||
[scriptable, uuid(f75d4164-3aa7-4395-ba44-a5f95b2e8427)]
|
[scriptable, uuid(f75d4164-3aa7-4395-ba44-a5f95b2e8427)]
|
||||||
interface nsISlowScriptDebug : nsISupports
|
interface nsISlowScriptDebug : nsISupports
|
||||||
{
|
{
|
||||||
attribute nsISlowScriptDebugCallback activationHandler;
|
attribute nsISlowScriptDebugCallback activationHandler;
|
||||||
attribute nsISlowScriptDebugRemoteCallback remoteActivationHandler;
|
|
||||||
};
|
};
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include "mozilla/a11y/DocAccessibleChild.h"
|
#include "mozilla/a11y/DocAccessibleChild.h"
|
||||||
#endif
|
#endif
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "mozilla/ProcessHangMonitorIPC.h"
|
|
||||||
#include "mozilla/docshell/OfflineCacheUpdateChild.h"
|
#include "mozilla/docshell/OfflineCacheUpdateChild.h"
|
||||||
#include "mozilla/dom/ContentBridgeChild.h"
|
#include "mozilla/dom/ContentBridgeChild.h"
|
||||||
#include "mozilla/dom/ContentBridgeParent.h"
|
#include "mozilla/dom/ContentBridgeParent.h"
|
||||||
@ -1000,13 +999,6 @@ ContentChild::AllocPBackgroundChild(Transport* aTransport,
|
|||||||
return BackgroundChild::Alloc(aTransport, aOtherProcess);
|
return BackgroundChild::Alloc(aTransport, aOtherProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
PProcessHangMonitorChild*
|
|
||||||
ContentChild::AllocPProcessHangMonitorChild(Transport* aTransport,
|
|
||||||
ProcessId aOtherProcess)
|
|
||||||
{
|
|
||||||
return CreateHangMonitorChild(aTransport, aOtherProcess);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||||
static void
|
static void
|
||||||
SetUpSandboxEnvironment()
|
SetUpSandboxEnvironment()
|
||||||
|
@ -126,10 +126,6 @@ public:
|
|||||||
AllocPImageBridgeChild(mozilla::ipc::Transport* aTransport,
|
AllocPImageBridgeChild(mozilla::ipc::Transport* aTransport,
|
||||||
base::ProcessId aOtherProcess) MOZ_OVERRIDE;
|
base::ProcessId aOtherProcess) MOZ_OVERRIDE;
|
||||||
|
|
||||||
PProcessHangMonitorChild*
|
|
||||||
AllocPProcessHangMonitorChild(Transport* aTransport,
|
|
||||||
ProcessId aOtherProcess) MOZ_OVERRIDE;
|
|
||||||
|
|
||||||
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||||
// Cleans up any resources used by the process when sandboxed.
|
// Cleans up any resources used by the process when sandboxed.
|
||||||
void CleanUpSandboxEnvironment();
|
void CleanUpSandboxEnvironment();
|
||||||
|
@ -73,8 +73,6 @@
|
|||||||
#include "mozilla/net/NeckoParent.h"
|
#include "mozilla/net/NeckoParent.h"
|
||||||
#include "mozilla/plugins/PluginBridge.h"
|
#include "mozilla/plugins/PluginBridge.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "mozilla/ProcessHangMonitor.h"
|
|
||||||
#include "mozilla/ProcessHangMonitorIPC.h"
|
|
||||||
#include "mozilla/Services.h"
|
#include "mozilla/Services.h"
|
||||||
#include "mozilla/StaticPtr.h"
|
#include "mozilla/StaticPtr.h"
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
@ -1804,11 +1802,6 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
|||||||
// finish waiting in the xpcom-shutdown/profile-before-change observer.
|
// finish waiting in the xpcom-shutdown/profile-before-change observer.
|
||||||
mIPCOpen = false;
|
mIPCOpen = false;
|
||||||
|
|
||||||
if (mHangMonitorActor) {
|
|
||||||
ProcessHangMonitor::RemoveProcess(mHangMonitorActor);
|
|
||||||
mHangMonitorActor = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (why == NormalShutdown && !mCalledClose) {
|
if (why == NormalShutdown && !mCalledClose) {
|
||||||
// If we shut down normally but haven't called Close, assume somebody
|
// If we shut down normally but haven't called Close, assume somebody
|
||||||
// else called Close on us. In that case, we still need to call
|
// else called Close on us. In that case, we still need to call
|
||||||
@ -2041,7 +2034,6 @@ ContentParent::InitializeMembers()
|
|||||||
mCreatedPairedMinidumps = false;
|
mCreatedPairedMinidumps = false;
|
||||||
mShutdownPending = false;
|
mShutdownPending = false;
|
||||||
mIPCOpen = true;
|
mIPCOpen = true;
|
||||||
mHangMonitorActor = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentParent::ContentParent(mozIApplication* aApp,
|
ContentParent::ContentParent(mozIApplication* aApp,
|
||||||
@ -2121,8 +2113,6 @@ ContentParent::ContentParent(mozIApplication* aApp,
|
|||||||
|
|
||||||
ContentProcessManager::GetSingleton()->AddContentProcess(this);
|
ContentProcessManager::GetSingleton()->AddContentProcess(this);
|
||||||
|
|
||||||
ProcessHangMonitor::AddProcess(this);
|
|
||||||
|
|
||||||
// Set a reply timeout for CPOWs.
|
// Set a reply timeout for CPOWs.
|
||||||
SetReplyTimeoutMs(Preferences::GetInt("dom.ipc.cpow.timeout", 0));
|
SetReplyTimeoutMs(Preferences::GetInt("dom.ipc.cpow.timeout", 0));
|
||||||
}
|
}
|
||||||
@ -3060,14 +3050,6 @@ ContentParent::AllocPBackgroundParent(Transport* aTransport,
|
|||||||
return BackgroundParent::Alloc(this, aTransport, aOtherProcess);
|
return BackgroundParent::Alloc(this, aTransport, aOtherProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
PProcessHangMonitorParent*
|
|
||||||
ContentParent::AllocPProcessHangMonitorParent(Transport* aTransport,
|
|
||||||
ProcessId aOtherProcess)
|
|
||||||
{
|
|
||||||
mHangMonitorActor = CreateHangMonitorParent(this, aTransport, aOtherProcess);
|
|
||||||
return mHangMonitorActor;
|
|
||||||
}
|
|
||||||
|
|
||||||
PSharedBufferManagerParent*
|
PSharedBufferManagerParent*
|
||||||
ContentParent::AllocPSharedBufferManagerParent(mozilla::ipc::Transport* aTransport,
|
ContentParent::AllocPSharedBufferManagerParent(mozilla::ipc::Transport* aTransport,
|
||||||
base::ProcessId aOtherProcess)
|
base::ProcessId aOtherProcess)
|
||||||
@ -4317,8 +4299,7 @@ ContentParent::RecvNotifyKeywordSearchLoading(const nsString &aProvider,
|
|||||||
bool
|
bool
|
||||||
ContentParent::ShouldContinueFromReplyTimeout()
|
ContentParent::ShouldContinueFromReplyTimeout()
|
||||||
{
|
{
|
||||||
nsRefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
|
return false;
|
||||||
return !monitor || !monitor->ShouldTimeOutCPOWs();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -485,10 +485,6 @@ private:
|
|||||||
AllocPBackgroundParent(Transport* aTransport, ProcessId aOtherProcess)
|
AllocPBackgroundParent(Transport* aTransport, ProcessId aOtherProcess)
|
||||||
MOZ_OVERRIDE;
|
MOZ_OVERRIDE;
|
||||||
|
|
||||||
PProcessHangMonitorParent*
|
|
||||||
AllocPProcessHangMonitorParent(Transport* aTransport,
|
|
||||||
ProcessId aOtherProcess) MOZ_OVERRIDE;
|
|
||||||
|
|
||||||
virtual bool RecvGetProcessAttributes(ContentParentId* aCpId,
|
virtual bool RecvGetProcessAttributes(ContentParentId* aCpId,
|
||||||
bool* aIsForApp,
|
bool* aIsForApp,
|
||||||
bool* aIsForBrowser) MOZ_OVERRIDE;
|
bool* aIsForBrowser) MOZ_OVERRIDE;
|
||||||
@ -843,8 +839,6 @@ private:
|
|||||||
static int32_t sNuwaPid;
|
static int32_t sNuwaPid;
|
||||||
static bool sNuwaReady;
|
static bool sNuwaReady;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PProcessHangMonitorParent* mHangMonitorActor;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
@ -21,7 +21,6 @@ include protocol PFileDescriptorSet;
|
|||||||
include protocol PFMRadio;
|
include protocol PFMRadio;
|
||||||
include protocol PFileSystemRequest;
|
include protocol PFileSystemRequest;
|
||||||
include protocol PHal;
|
include protocol PHal;
|
||||||
include protocol PProcessHangMonitor;
|
|
||||||
include protocol PImageBridge;
|
include protocol PImageBridge;
|
||||||
include protocol PMemoryReportRequest;
|
include protocol PMemoryReportRequest;
|
||||||
include protocol PMobileConnection;
|
include protocol PMobileConnection;
|
||||||
@ -346,7 +345,6 @@ prio(normal upto urgent) intr protocol PContent
|
|||||||
parent spawns PPluginModule;
|
parent spawns PPluginModule;
|
||||||
|
|
||||||
parent opens PCompositor;
|
parent opens PCompositor;
|
||||||
parent opens PProcessHangMonitor;
|
|
||||||
parent opens PSharedBufferManager;
|
parent opens PSharedBufferManager;
|
||||||
parent opens PImageBridge;
|
parent opens PImageBridge;
|
||||||
child opens PBackground;
|
child opens PBackground;
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
||||||
* vim: sw=2 ts=8 et :
|
|
||||||
*/
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
|
|
||||||
struct SlowScriptData
|
|
||||||
{
|
|
||||||
TabId tabId;
|
|
||||||
nsCString filename;
|
|
||||||
uint32_t lineno;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PluginHangData
|
|
||||||
{
|
|
||||||
uint32_t pluginId;
|
|
||||||
};
|
|
||||||
|
|
||||||
union HangData
|
|
||||||
{
|
|
||||||
SlowScriptData;
|
|
||||||
PluginHangData;
|
|
||||||
};
|
|
||||||
|
|
||||||
protocol PProcessHangMonitor
|
|
||||||
{
|
|
||||||
parent:
|
|
||||||
async HangEvidence(HangData data);
|
|
||||||
|
|
||||||
child:
|
|
||||||
async TerminateScript();
|
|
||||||
|
|
||||||
async BeginStartingDebugger();
|
|
||||||
async EndStartingDebugger();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace mozilla
|
|
@ -1,954 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "mozilla/ProcessHangMonitor.h"
|
|
||||||
#include "mozilla/ProcessHangMonitorIPC.h"
|
|
||||||
|
|
||||||
#include "mozilla/Atomics.h"
|
|
||||||
#include "mozilla/dom/ContentParent.h"
|
|
||||||
#include "mozilla/dom/Element.h"
|
|
||||||
#include "mozilla/dom/TabChild.h"
|
|
||||||
#include "mozilla/dom/TabParent.h"
|
|
||||||
#include "mozilla/Monitor.h"
|
|
||||||
#include "mozilla/plugins/PluginBridge.h"
|
|
||||||
#include "mozilla/Preferences.h"
|
|
||||||
#include "mozilla/unused.h"
|
|
||||||
|
|
||||||
#include "nsIFrameLoader.h"
|
|
||||||
#include "nsIHangReport.h"
|
|
||||||
#include "nsITabParent.h"
|
|
||||||
#include "nsPluginHost.h"
|
|
||||||
#include "nsThreadUtils.h"
|
|
||||||
|
|
||||||
#include "base/task.h"
|
|
||||||
#include "base/thread.h"
|
|
||||||
|
|
||||||
using namespace mozilla;
|
|
||||||
using namespace mozilla::dom;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Basic architecture:
|
|
||||||
*
|
|
||||||
* Each process has its own ProcessHangMonitor singleton. This singleton exists
|
|
||||||
* as long as there is at least one content process in the system. Each content
|
|
||||||
* process has a HangMonitorChild and the chrome process has one
|
|
||||||
* HangMonitorParent per process. Each process (including the chrome process)
|
|
||||||
* runs a hang monitoring thread. The PHangMonitor actors are bound to this
|
|
||||||
* thread so that they never block on the main thread.
|
|
||||||
*
|
|
||||||
* When the content process detects a hang, it posts a task to its hang thread,
|
|
||||||
* which sends an IPC message to the hang thread in the parent. The parent
|
|
||||||
* cancels any ongoing CPOW requests and then posts a runnable to the main
|
|
||||||
* thread that notifies Firefox frontend code of the hang. The frontend code is
|
|
||||||
* passed an nsIHangReport, which can be used to terminate the hang.
|
|
||||||
*
|
|
||||||
* If the user chooses to terminate a script, a task is posted to the chrome
|
|
||||||
* process's hang monitoring thread, which sends an IPC message to the hang
|
|
||||||
* thread in the content process. That thread sets a flag to indicate that JS
|
|
||||||
* execution should be terminated the next time it hits the interrupt
|
|
||||||
* callback. A similar scheme is used for debugging slow scripts. If a content
|
|
||||||
* process or plug-in needs to be terminated, the chrome process does so
|
|
||||||
* directly, without messaging the content process.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
/* Child process objects */
|
|
||||||
|
|
||||||
class HangMonitorChild
|
|
||||||
: public PProcessHangMonitorChild
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit HangMonitorChild(ProcessHangMonitor* aMonitor);
|
|
||||||
virtual ~HangMonitorChild();
|
|
||||||
|
|
||||||
void Open(Transport* aTransport, ProcessHandle aHandle,
|
|
||||||
MessageLoop* aIOLoop);
|
|
||||||
|
|
||||||
typedef ProcessHangMonitor::SlowScriptAction SlowScriptAction;
|
|
||||||
SlowScriptAction NotifySlowScript(nsITabChild* aTabChild,
|
|
||||||
const char* aFileName,
|
|
||||||
unsigned aLineNo);
|
|
||||||
void NotifySlowScriptAsync(TabId aTabId,
|
|
||||||
const nsCString& aFileName,
|
|
||||||
unsigned aLineNo);
|
|
||||||
|
|
||||||
bool IsDebuggerStartupComplete();
|
|
||||||
|
|
||||||
void NotifyPluginHang(uint32_t aPluginId);
|
|
||||||
void NotifyPluginHangAsync(uint32_t aPluginId);
|
|
||||||
|
|
||||||
void ClearHang();
|
|
||||||
|
|
||||||
virtual bool RecvTerminateScript() MOZ_OVERRIDE;
|
|
||||||
virtual bool RecvBeginStartingDebugger() MOZ_OVERRIDE;
|
|
||||||
virtual bool RecvEndStartingDebugger() MOZ_OVERRIDE;
|
|
||||||
|
|
||||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
|
||||||
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
static HangMonitorChild* Get() { return sInstance; }
|
|
||||||
|
|
||||||
MessageLoop* MonitorLoop() { return mHangMonitor->MonitorLoop(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void ShutdownOnThread();
|
|
||||||
|
|
||||||
static HangMonitorChild* sInstance;
|
|
||||||
|
|
||||||
const nsRefPtr<ProcessHangMonitor> mHangMonitor;
|
|
||||||
Monitor mMonitor;
|
|
||||||
|
|
||||||
// Main thread-only.
|
|
||||||
bool mSentReport;
|
|
||||||
|
|
||||||
// These fields must be accessed with mMonitor held.
|
|
||||||
bool mTerminateScript;
|
|
||||||
bool mStartDebugger;
|
|
||||||
bool mFinishedStartingDebugger;
|
|
||||||
bool mShutdownDone;
|
|
||||||
|
|
||||||
// This field is only accessed on the hang thread.
|
|
||||||
bool mIPCOpen;
|
|
||||||
};
|
|
||||||
|
|
||||||
HangMonitorChild* HangMonitorChild::sInstance;
|
|
||||||
|
|
||||||
/* Parent process objects */
|
|
||||||
|
|
||||||
class HangMonitorParent;
|
|
||||||
|
|
||||||
class HangMonitoredProcess MOZ_FINAL
|
|
||||||
: public nsIHangReport
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NS_DECL_THREADSAFE_ISUPPORTS
|
|
||||||
|
|
||||||
HangMonitoredProcess(HangMonitorParent* aActor,
|
|
||||||
ContentParent* aContentParent)
|
|
||||||
: mActor(aActor), mContentParent(aContentParent) {}
|
|
||||||
|
|
||||||
NS_IMETHOD GetHangType(uint32_t* aHangType) MOZ_OVERRIDE;
|
|
||||||
NS_IMETHOD GetScriptBrowser(nsIDOMElement** aBrowser) MOZ_OVERRIDE;
|
|
||||||
NS_IMETHOD GetScriptFileName(nsACString& aFileName) MOZ_OVERRIDE;
|
|
||||||
NS_IMETHOD GetScriptLineNo(uint32_t* aLineNo) MOZ_OVERRIDE;
|
|
||||||
|
|
||||||
NS_IMETHOD GetPluginName(nsACString& aPluginName) MOZ_OVERRIDE;
|
|
||||||
|
|
||||||
NS_IMETHOD TerminateScript() MOZ_OVERRIDE;
|
|
||||||
NS_IMETHOD BeginStartingDebugger() MOZ_OVERRIDE;
|
|
||||||
NS_IMETHOD EndStartingDebugger() MOZ_OVERRIDE;
|
|
||||||
NS_IMETHOD TerminatePlugin() MOZ_OVERRIDE;
|
|
||||||
NS_IMETHOD TerminateProcess() MOZ_OVERRIDE;
|
|
||||||
|
|
||||||
NS_IMETHOD IsReportForBrowser(nsIFrameLoader* aFrameLoader, bool* aResult);
|
|
||||||
|
|
||||||
void Clear() { mContentParent = nullptr; mActor = nullptr; }
|
|
||||||
|
|
||||||
void SetHangData(const HangData& aHangData) { mHangData = aHangData; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
~HangMonitoredProcess() {}
|
|
||||||
|
|
||||||
// Everything here is main thread-only.
|
|
||||||
HangMonitorParent* mActor;
|
|
||||||
ContentParent* mContentParent;
|
|
||||||
HangData mHangData;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HangMonitorParent
|
|
||||||
: public PProcessHangMonitorParent
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit HangMonitorParent(ProcessHangMonitor* aMonitor);
|
|
||||||
virtual ~HangMonitorParent();
|
|
||||||
|
|
||||||
void Open(Transport* aTransport, ProcessHandle aHandle,
|
|
||||||
MessageLoop* aIOLoop);
|
|
||||||
|
|
||||||
virtual bool RecvHangEvidence(const HangData& aHangData) MOZ_OVERRIDE;
|
|
||||||
|
|
||||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
|
||||||
|
|
||||||
void SetProcess(HangMonitoredProcess* aProcess) { mProcess = aProcess; }
|
|
||||||
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
void TerminateScript();
|
|
||||||
void BeginStartingDebugger();
|
|
||||||
void EndStartingDebugger();
|
|
||||||
|
|
||||||
MessageLoop* MonitorLoop() { return mHangMonitor->MonitorLoop(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void ShutdownOnThread();
|
|
||||||
|
|
||||||
const nsRefPtr<ProcessHangMonitor> mHangMonitor;
|
|
||||||
|
|
||||||
// This field is read-only after construction.
|
|
||||||
bool mReportHangs;
|
|
||||||
|
|
||||||
// This field is only accessed on the hang thread.
|
|
||||||
bool mIPCOpen;
|
|
||||||
|
|
||||||
Monitor mMonitor;
|
|
||||||
|
|
||||||
// Must be accessed with mMonitor held.
|
|
||||||
nsRefPtr<HangMonitoredProcess> mProcess;
|
|
||||||
bool mShutdownDone;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct RunnableMethodTraits<HangMonitorChild>
|
|
||||||
{
|
|
||||||
typedef HangMonitorChild Class;
|
|
||||||
static void RetainCallee(Class* obj) { }
|
|
||||||
static void ReleaseCallee(Class* obj) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct RunnableMethodTraits<HangMonitorParent>
|
|
||||||
{
|
|
||||||
typedef HangMonitorParent Class;
|
|
||||||
static void RetainCallee(Class* obj) { }
|
|
||||||
static void ReleaseCallee(Class* obj) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
/* HangMonitorChild implementation */
|
|
||||||
|
|
||||||
HangMonitorChild::HangMonitorChild(ProcessHangMonitor* aMonitor)
|
|
||||||
: mHangMonitor(aMonitor),
|
|
||||||
mMonitor("HangMonitorChild lock"),
|
|
||||||
mSentReport(false),
|
|
||||||
mTerminateScript(false),
|
|
||||||
mStartDebugger(false),
|
|
||||||
mFinishedStartingDebugger(false),
|
|
||||||
mShutdownDone(false),
|
|
||||||
mIPCOpen(true)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
}
|
|
||||||
|
|
||||||
HangMonitorChild::~HangMonitorChild()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
MOZ_ASSERT(sInstance == this);
|
|
||||||
sInstance = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorChild::Shutdown()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
MonitorAutoLock lock(mMonitor);
|
|
||||||
while (!mShutdownDone) {
|
|
||||||
mMonitor.Wait();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorChild::ShutdownOnThread()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
|
|
||||||
MonitorAutoLock lock(mMonitor);
|
|
||||||
mShutdownDone = true;
|
|
||||||
mMonitor.Notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorChild::ActorDestroy(ActorDestroyReason aWhy)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
|
|
||||||
mIPCOpen = false;
|
|
||||||
|
|
||||||
// We use a task here to ensure that IPDL is finished with this
|
|
||||||
// HangMonitorChild before it gets deleted on the main thread.
|
|
||||||
MonitorLoop()->PostTask(
|
|
||||||
FROM_HERE,
|
|
||||||
NewRunnableMethod(this, &HangMonitorChild::ShutdownOnThread));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
HangMonitorChild::RecvTerminateScript()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
|
|
||||||
MonitorAutoLock lock(mMonitor);
|
|
||||||
mTerminateScript = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
HangMonitorChild::RecvBeginStartingDebugger()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
|
|
||||||
MonitorAutoLock lock(mMonitor);
|
|
||||||
mStartDebugger = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
HangMonitorChild::RecvEndStartingDebugger()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
|
|
||||||
MonitorAutoLock lock(mMonitor);
|
|
||||||
mFinishedStartingDebugger = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorChild::Open(Transport* aTransport, ProcessHandle aHandle,
|
|
||||||
MessageLoop* aIOLoop)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
|
|
||||||
MOZ_ASSERT(!sInstance);
|
|
||||||
sInstance = this;
|
|
||||||
|
|
||||||
DebugOnly<bool> ok = PProcessHangMonitorChild::Open(aTransport, aHandle, aIOLoop);
|
|
||||||
MOZ_ASSERT(ok);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorChild::NotifySlowScriptAsync(TabId aTabId,
|
|
||||||
const nsCString& aFileName,
|
|
||||||
unsigned aLineNo)
|
|
||||||
{
|
|
||||||
if (mIPCOpen) {
|
|
||||||
unused << SendHangEvidence(SlowScriptData(aTabId, aFileName, aLineNo));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HangMonitorChild::SlowScriptAction
|
|
||||||
HangMonitorChild::NotifySlowScript(nsITabChild* aTabChild,
|
|
||||||
const char* aFileName,
|
|
||||||
unsigned aLineNo)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
mSentReport = true;
|
|
||||||
|
|
||||||
{
|
|
||||||
MonitorAutoLock lock(mMonitor);
|
|
||||||
|
|
||||||
if (mTerminateScript) {
|
|
||||||
mTerminateScript = false;
|
|
||||||
return SlowScriptAction::Terminate;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mStartDebugger) {
|
|
||||||
mStartDebugger = false;
|
|
||||||
return SlowScriptAction::StartDebugger;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TabId id;
|
|
||||||
if (aTabChild) {
|
|
||||||
nsRefPtr<TabChild> tabChild = static_cast<TabChild*>(aTabChild);
|
|
||||||
id = tabChild->GetTabId();
|
|
||||||
}
|
|
||||||
nsAutoCString filename(aFileName);
|
|
||||||
|
|
||||||
MonitorLoop()->PostTask(
|
|
||||||
FROM_HERE,
|
|
||||||
NewRunnableMethod(this, &HangMonitorChild::NotifySlowScriptAsync,
|
|
||||||
id, filename, aLineNo));
|
|
||||||
return SlowScriptAction::Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
HangMonitorChild::IsDebuggerStartupComplete()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
MonitorAutoLock lock(mMonitor);
|
|
||||||
|
|
||||||
if (mFinishedStartingDebugger) {
|
|
||||||
mFinishedStartingDebugger = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorChild::NotifyPluginHang(uint32_t aPluginId)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
mSentReport = true;
|
|
||||||
|
|
||||||
MonitorLoop()->PostTask(
|
|
||||||
FROM_HERE,
|
|
||||||
NewRunnableMethod(this,
|
|
||||||
&HangMonitorChild::NotifyPluginHangAsync,
|
|
||||||
aPluginId));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorChild::NotifyPluginHangAsync(uint32_t aPluginId)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
|
|
||||||
if (mIPCOpen) {
|
|
||||||
unused << SendHangEvidence(PluginHangData(aPluginId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorChild::ClearHang()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
if (mSentReport) {
|
|
||||||
MonitorAutoLock lock(mMonitor);
|
|
||||||
mSentReport = false;
|
|
||||||
mTerminateScript = false;
|
|
||||||
mStartDebugger = false;
|
|
||||||
mFinishedStartingDebugger = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HangMonitorParent implementation */
|
|
||||||
|
|
||||||
HangMonitorParent::HangMonitorParent(ProcessHangMonitor* aMonitor)
|
|
||||||
: mHangMonitor(aMonitor),
|
|
||||||
mIPCOpen(true),
|
|
||||||
mMonitor("HangMonitorParent lock"),
|
|
||||||
mShutdownDone(false)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
mReportHangs = mozilla::Preferences::GetBool("dom.ipc.reportProcessHangs", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
HangMonitorParent::~HangMonitorParent()
|
|
||||||
{
|
|
||||||
// For some reason IPDL doesn't autmatically delete the channel for a
|
|
||||||
// bridged protocol (bug 1090570). So we have to do it ourselves.
|
|
||||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask<Transport>(GetTransport()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorParent::Shutdown()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
MonitorAutoLock lock(mMonitor);
|
|
||||||
|
|
||||||
if (mProcess) {
|
|
||||||
mProcess->Clear();
|
|
||||||
mProcess = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
MonitorLoop()->PostTask(
|
|
||||||
FROM_HERE,
|
|
||||||
NewRunnableMethod(this, &HangMonitorParent::ShutdownOnThread));
|
|
||||||
|
|
||||||
while (!mShutdownDone) {
|
|
||||||
mMonitor.Wait();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorParent::ShutdownOnThread()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
|
|
||||||
// mIPCOpen is only written from this thread, so need need to take the lock
|
|
||||||
// here. We'd be shooting ourselves in the foot, because ActorDestroy takes
|
|
||||||
// it.
|
|
||||||
if (mIPCOpen) {
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
MonitorAutoLock lock(mMonitor);
|
|
||||||
mShutdownDone = true;
|
|
||||||
mMonitor.Notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorParent::ActorDestroy(ActorDestroyReason aWhy)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
mIPCOpen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorParent::Open(Transport* aTransport, ProcessHandle aHandle,
|
|
||||||
MessageLoop* aIOLoop)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
|
|
||||||
DebugOnly<bool> ok = PProcessHangMonitorParent::Open(aTransport, aHandle, aIOLoop);
|
|
||||||
MOZ_ASSERT(ok);
|
|
||||||
}
|
|
||||||
|
|
||||||
class HangObserverNotifier MOZ_FINAL : public nsRunnable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HangObserverNotifier(HangMonitoredProcess* aProcess, const HangData& aHangData)
|
|
||||||
: mProcess(aProcess),
|
|
||||||
mHangData(aHangData)
|
|
||||||
{}
|
|
||||||
|
|
||||||
NS_IMETHOD
|
|
||||||
Run()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
mProcess->SetHangData(mHangData);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> observerService =
|
|
||||||
mozilla::services::GetObserverService();
|
|
||||||
observerService->NotifyObservers(mProcess, "process-hang-report", nullptr);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
nsRefPtr<HangMonitoredProcess> mProcess;
|
|
||||||
HangData mHangData;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool
|
|
||||||
HangMonitorParent::RecvHangEvidence(const HangData& aHangData)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
|
|
||||||
if (!mReportHangs) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mHangMonitor->InitiateCPOWTimeout();
|
|
||||||
|
|
||||||
MonitorAutoLock lock(mMonitor);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIRunnable> notifier = new HangObserverNotifier(mProcess, aHangData);
|
|
||||||
NS_DispatchToMainThread(notifier);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorParent::TerminateScript()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
|
|
||||||
if (mIPCOpen) {
|
|
||||||
unused << SendTerminateScript();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorParent::BeginStartingDebugger()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
|
|
||||||
if (mIPCOpen) {
|
|
||||||
unused << SendBeginStartingDebugger();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
HangMonitorParent::EndStartingDebugger()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
|
|
||||||
if (mIPCOpen) {
|
|
||||||
unused << SendEndStartingDebugger();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HangMonitoredProcess implementation */
|
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(HangMonitoredProcess, nsIHangReport)
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HangMonitoredProcess::GetHangType(uint32_t* aHangType)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
switch (mHangData.type()) {
|
|
||||||
case HangData::TSlowScriptData:
|
|
||||||
*aHangType = SLOW_SCRIPT;
|
|
||||||
break;
|
|
||||||
case HangData::TPluginHangData:
|
|
||||||
*aHangType = PLUGIN_HANG;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
MOZ_ASSERT(false);
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HangMonitoredProcess::GetScriptBrowser(nsIDOMElement** aBrowser)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
if (mHangData.type() != HangData::TSlowScriptData) {
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
TabId tabId = mHangData.get_SlowScriptData().tabId();
|
|
||||||
if (!mContentParent) {
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsTArray<PBrowserParent*> tabs;
|
|
||||||
mContentParent->ManagedPBrowserParent(tabs);
|
|
||||||
for (size_t i = 0; i < tabs.Length(); i++) {
|
|
||||||
TabParent* tp = static_cast<TabParent*>(tabs[i]);
|
|
||||||
if (tp->GetTabId() == tabId) {
|
|
||||||
nsCOMPtr<nsIDOMElement> node = do_QueryInterface(tp->GetOwnerElement());
|
|
||||||
node.forget(aBrowser);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*aBrowser = nullptr;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HangMonitoredProcess::GetScriptFileName(nsACString& aFileName)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
if (mHangData.type() != HangData::TSlowScriptData) {
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
aFileName = mHangData.get_SlowScriptData().filename();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HangMonitoredProcess::GetScriptLineNo(uint32_t* aLineNo)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
if (mHangData.type() != HangData::TSlowScriptData) {
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
*aLineNo = mHangData.get_SlowScriptData().lineno();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HangMonitoredProcess::GetPluginName(nsACString& aPluginName)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
if (mHangData.type() != HangData::TPluginHangData) {
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t id = mHangData.get_PluginHangData().pluginId();
|
|
||||||
|
|
||||||
nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
|
|
||||||
nsPluginTag* tag = host->PluginWithId(id);
|
|
||||||
if (!tag) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
aPluginName = tag->mName;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HangMonitoredProcess::TerminateScript()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
if (mHangData.type() != HangData::TSlowScriptData) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mActor) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessHangMonitor::Get()->MonitorLoop()->PostTask(
|
|
||||||
FROM_HERE,
|
|
||||||
NewRunnableMethod(mActor, &HangMonitorParent::TerminateScript));
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HangMonitoredProcess::BeginStartingDebugger()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
if (mHangData.type() != HangData::TSlowScriptData) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mActor) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessHangMonitor::Get()->MonitorLoop()->PostTask(
|
|
||||||
FROM_HERE,
|
|
||||||
NewRunnableMethod(mActor, &HangMonitorParent::BeginStartingDebugger));
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HangMonitoredProcess::EndStartingDebugger()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
if (mHangData.type() != HangData::TSlowScriptData) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mActor) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessHangMonitor::Get()->MonitorLoop()->PostTask(
|
|
||||||
FROM_HERE,
|
|
||||||
NewRunnableMethod(mActor, &HangMonitorParent::EndStartingDebugger));
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HangMonitoredProcess::TerminatePlugin()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
if (mHangData.type() != HangData::TPluginHangData) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t id = mHangData.get_PluginHangData().pluginId();
|
|
||||||
plugins::TerminatePlugin(id);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HangMonitoredProcess::TerminateProcess()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
if (!mContentParent) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
mContentParent->KillHard();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HangMonitoredProcess::IsReportForBrowser(nsIFrameLoader* aFrameLoader, bool* aResult)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
if (!mActor) {
|
|
||||||
*aResult = false;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsITabParent> itp;
|
|
||||||
aFrameLoader->GetTabParent(getter_AddRefs(itp));
|
|
||||||
if (!itp) {
|
|
||||||
*aResult = false;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
*aResult = mContentParent == static_cast<TabParent*>(itp.get())->Manager();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessHangMonitor* ProcessHangMonitor::sInstance;
|
|
||||||
|
|
||||||
ProcessHangMonitor::ProcessHangMonitor()
|
|
||||||
: mCPOWTimeout(false)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
MOZ_COUNT_CTOR(ProcessHangMonitor);
|
|
||||||
|
|
||||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
|
||||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
||||||
obs->AddObserver(this, "xpcom-shutdown", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
mThread = new base::Thread("ProcessHangMonitor");
|
|
||||||
if (!mThread->Start()) {
|
|
||||||
delete mThread;
|
|
||||||
mThread = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessHangMonitor::~ProcessHangMonitor()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
MOZ_COUNT_DTOR(ProcessHangMonitor);
|
|
||||||
|
|
||||||
MOZ_ASSERT(sInstance == this);
|
|
||||||
sInstance = nullptr;
|
|
||||||
|
|
||||||
delete mThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessHangMonitor*
|
|
||||||
ProcessHangMonitor::GetOrCreate()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
if (!sInstance) {
|
|
||||||
sInstance = new ProcessHangMonitor();
|
|
||||||
}
|
|
||||||
return sInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(ProcessHangMonitor, nsIObserver)
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
ProcessHangMonitor::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
if (!strcmp(aTopic, "xpcom-shutdown")) {
|
|
||||||
if (HangMonitorChild* child = HangMonitorChild::Get()) {
|
|
||||||
child->Shutdown();
|
|
||||||
delete child;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
||||||
if (obs) {
|
|
||||||
obs->RemoveObserver(this, "xpcom-shutdown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessHangMonitor::SlowScriptAction
|
|
||||||
ProcessHangMonitor::NotifySlowScript(nsITabChild* aTabChild,
|
|
||||||
const char* aFileName,
|
|
||||||
unsigned aLineNo)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
return HangMonitorChild::Get()->NotifySlowScript(aTabChild, aFileName, aLineNo);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ProcessHangMonitor::IsDebuggerStartupComplete()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
return HangMonitorChild::Get()->IsDebuggerStartupComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ProcessHangMonitor::ShouldTimeOutCPOWs()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
if (mCPOWTimeout) {
|
|
||||||
mCPOWTimeout = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ProcessHangMonitor::InitiateCPOWTimeout()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
|
|
||||||
mCPOWTimeout = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ProcessHangMonitor::NotifyPluginHang(uint32_t aPluginId)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
return HangMonitorChild::Get()->NotifyPluginHang(aPluginId);
|
|
||||||
}
|
|
||||||
|
|
||||||
PProcessHangMonitorParent*
|
|
||||||
mozilla::CreateHangMonitorParent(ContentParent* aContentParent,
|
|
||||||
mozilla::ipc::Transport* aTransport,
|
|
||||||
base::ProcessId aOtherProcess)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
ProcessHangMonitor* monitor = ProcessHangMonitor::GetOrCreate();
|
|
||||||
HangMonitorParent* parent = new HangMonitorParent(monitor);
|
|
||||||
|
|
||||||
HangMonitoredProcess* process = new HangMonitoredProcess(parent, aContentParent);
|
|
||||||
parent->SetProcess(process);
|
|
||||||
|
|
||||||
base::ProcessHandle handle;
|
|
||||||
if (!base::OpenProcessHandle(aOtherProcess, &handle)) {
|
|
||||||
// XXX need to kill |aOtherProcess|, it's boned
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
monitor->MonitorLoop()->PostTask(
|
|
||||||
FROM_HERE,
|
|
||||||
NewRunnableMethod(parent, &HangMonitorParent::Open,
|
|
||||||
aTransport, handle, XRE_GetIOMessageLoop()));
|
|
||||||
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
PProcessHangMonitorChild*
|
|
||||||
mozilla::CreateHangMonitorChild(mozilla::ipc::Transport* aTransport,
|
|
||||||
base::ProcessId aOtherProcess)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
ProcessHangMonitor* monitor = ProcessHangMonitor::GetOrCreate();
|
|
||||||
HangMonitorChild* child = new HangMonitorChild(monitor);
|
|
||||||
|
|
||||||
base::ProcessHandle handle;
|
|
||||||
if (!base::OpenProcessHandle(aOtherProcess, &handle)) {
|
|
||||||
// XXX need to kill |aOtherProcess|, it's boned
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
monitor->MonitorLoop()->PostTask(
|
|
||||||
FROM_HERE,
|
|
||||||
NewRunnableMethod(child, &HangMonitorChild::Open,
|
|
||||||
aTransport, handle, XRE_GetIOMessageLoop()));
|
|
||||||
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageLoop*
|
|
||||||
ProcessHangMonitor::MonitorLoop()
|
|
||||||
{
|
|
||||||
return mThread->message_loop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ void
|
|
||||||
ProcessHangMonitor::AddProcess(ContentParent* aContentParent)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
if (mozilla::Preferences::GetBool("dom.ipc.processHangMonitor", false)) {
|
|
||||||
DebugOnly<bool> opened = PProcessHangMonitor::Open(aContentParent);
|
|
||||||
MOZ_ASSERT(opened);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ void
|
|
||||||
ProcessHangMonitor::RemoveProcess(PProcessHangMonitorParent* aParent)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
auto parent = static_cast<HangMonitorParent*>(aParent);
|
|
||||||
parent->Shutdown();
|
|
||||||
delete parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ void
|
|
||||||
ProcessHangMonitor::ClearHang()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
if (HangMonitorChild* child = HangMonitorChild::Get()) {
|
|
||||||
child->ClearHang();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef mozilla_ProcessHangMonitor_h
|
|
||||||
#define mozilla_ProcessHangMonitor_h
|
|
||||||
|
|
||||||
#include "mozilla/Atomics.h"
|
|
||||||
#include "nsIObserver.h"
|
|
||||||
|
|
||||||
class nsGlobalWindow;
|
|
||||||
class nsITabChild;
|
|
||||||
|
|
||||||
class MessageLoop;
|
|
||||||
|
|
||||||
namespace base {
|
|
||||||
class Thread;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
|
|
||||||
namespace dom {
|
|
||||||
class ContentParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
class PProcessHangMonitorParent;
|
|
||||||
class PProcessHangMonitorChild;
|
|
||||||
|
|
||||||
class ProcessHangMonitor MOZ_FINAL
|
|
||||||
: public nsIObserver
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
ProcessHangMonitor();
|
|
||||||
virtual ~ProcessHangMonitor();
|
|
||||||
|
|
||||||
public:
|
|
||||||
static ProcessHangMonitor* Get() { return sInstance; }
|
|
||||||
static ProcessHangMonitor* GetOrCreate();
|
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
|
||||||
NS_DECL_NSIOBSERVER
|
|
||||||
|
|
||||||
static void AddProcess(dom::ContentParent* aContentParent);
|
|
||||||
static void RemoveProcess(PProcessHangMonitorParent* aParent);
|
|
||||||
|
|
||||||
static void ClearHang();
|
|
||||||
|
|
||||||
enum SlowScriptAction {
|
|
||||||
Continue,
|
|
||||||
Terminate,
|
|
||||||
StartDebugger
|
|
||||||
};
|
|
||||||
SlowScriptAction NotifySlowScript(nsITabChild* aTabChild,
|
|
||||||
const char* aFileName,
|
|
||||||
unsigned aLineNo);
|
|
||||||
|
|
||||||
void NotifyPluginHang(uint32_t aPluginId);
|
|
||||||
|
|
||||||
bool IsDebuggerStartupComplete();
|
|
||||||
|
|
||||||
void InitiateCPOWTimeout();
|
|
||||||
bool ShouldTimeOutCPOWs();
|
|
||||||
|
|
||||||
MessageLoop* MonitorLoop();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ProcessHangMonitor* sInstance;
|
|
||||||
|
|
||||||
Atomic<bool> mCPOWTimeout;
|
|
||||||
|
|
||||||
base::Thread* mThread;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // mozilla_ProcessHangMonitor_h
|
|
@ -1,34 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef mozilla_ProcessHangMonitorIPC_h
|
|
||||||
#define mozilla_ProcessHangMonitorIPC_h
|
|
||||||
|
|
||||||
#include "base/task.h"
|
|
||||||
#include "base/thread.h"
|
|
||||||
|
|
||||||
#include "mozilla/PProcessHangMonitor.h"
|
|
||||||
#include "mozilla/PProcessHangMonitorParent.h"
|
|
||||||
#include "mozilla/PProcessHangMonitorChild.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
|
|
||||||
namespace dom {
|
|
||||||
class ContentParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
PProcessHangMonitorParent*
|
|
||||||
CreateHangMonitorParent(mozilla::dom::ContentParent* aContentParent,
|
|
||||||
mozilla::ipc::Transport* aTransport,
|
|
||||||
base::ProcessId aOtherProcess);
|
|
||||||
|
|
||||||
PProcessHangMonitorChild*
|
|
||||||
CreateHangMonitorChild(mozilla::ipc::Transport* aTransport,
|
|
||||||
base::ProcessId aOtherProcess);
|
|
||||||
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // mozilla_ProcessHangMonitorIPC_h
|
|
@ -4,12 +4,6 @@
|
|||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
XPIDL_SOURCES += [
|
|
||||||
'nsIHangReport.idl',
|
|
||||||
]
|
|
||||||
|
|
||||||
XPIDL_MODULE = 'dom'
|
|
||||||
|
|
||||||
EXPORTS += [
|
EXPORTS += [
|
||||||
'nsICachedFileDescriptorListener.h',
|
'nsICachedFileDescriptorListener.h',
|
||||||
]
|
]
|
||||||
@ -45,8 +39,6 @@ EXPORTS.mozilla.dom += [
|
|||||||
EXPORTS.mozilla += [
|
EXPORTS.mozilla += [
|
||||||
'AppProcessChecker.h',
|
'AppProcessChecker.h',
|
||||||
'PreallocatedProcessManager.h',
|
'PreallocatedProcessManager.h',
|
||||||
'ProcessHangMonitor.h',
|
|
||||||
'ProcessHangMonitorIPC.h',
|
|
||||||
'ProcessPriorityManager.h',
|
'ProcessPriorityManager.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -81,7 +73,6 @@ SOURCES += [
|
|||||||
'Blob.cpp',
|
'Blob.cpp',
|
||||||
'ContentChild.cpp',
|
'ContentChild.cpp',
|
||||||
'CrashReporterChild.cpp',
|
'CrashReporterChild.cpp',
|
||||||
'ProcessHangMonitor.cpp',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
IPDL_SOURCES += [
|
IPDL_SOURCES += [
|
||||||
@ -101,7 +92,6 @@ IPDL_SOURCES += [
|
|||||||
'PFilePicker.ipdl',
|
'PFilePicker.ipdl',
|
||||||
'PMemoryReportRequest.ipdl',
|
'PMemoryReportRequest.ipdl',
|
||||||
'PPluginWidget.ipdl',
|
'PPluginWidget.ipdl',
|
||||||
'PProcessHangMonitor.ipdl',
|
|
||||||
'PScreenManager.ipdl',
|
'PScreenManager.ipdl',
|
||||||
'PTabContext.ipdlh',
|
'PTabContext.ipdlh',
|
||||||
]
|
]
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "nsISupports.idl"
|
|
||||||
|
|
||||||
interface nsIDOMElement;
|
|
||||||
interface nsIFrameLoader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When a content process hangs, Gecko notifies "process-hang-report" observers
|
|
||||||
* and passes an nsIHangReport for the subject parameter. There is at most one
|
|
||||||
* nsIHangReport associated with a given content process. As long as the content
|
|
||||||
* process stays stuck, the "process-hang-report" observer will continue to be
|
|
||||||
* notified at regular intervals (approximately once per second). The content
|
|
||||||
* process will continue to run uninhibitedly during this time.
|
|
||||||
*/
|
|
||||||
|
|
||||||
[scriptable, uuid(3b88d100-8d5b-11e4-b4a9-0800200c9a66)]
|
|
||||||
interface nsIHangReport : nsISupports
|
|
||||||
{
|
|
||||||
const unsigned long SLOW_SCRIPT = 1;
|
|
||||||
const unsigned long PLUGIN_HANG = 2;
|
|
||||||
|
|
||||||
// The type of hang being reported: SLOW_SCRIPT or PLUGIN_HANG.
|
|
||||||
readonly attribute unsigned long hangType;
|
|
||||||
|
|
||||||
// For SLOW_SCRIPT reports, these fields contain information about the
|
|
||||||
// slow script.
|
|
||||||
// Only valid for SLOW_SCRIPT reports.
|
|
||||||
readonly attribute nsIDOMElement scriptBrowser;
|
|
||||||
readonly attribute ACString scriptFileName;
|
|
||||||
readonly attribute unsigned long scriptLineNo;
|
|
||||||
|
|
||||||
// For PLUGIN_HANGs, this field contains information about the plugin.
|
|
||||||
// Only valid for PLUGIN_HANG reports.
|
|
||||||
readonly attribute ACString pluginName;
|
|
||||||
|
|
||||||
// Terminate the slow script if it is still running.
|
|
||||||
// Only valid for SLOW_SCRIPT reports.
|
|
||||||
void terminateScript();
|
|
||||||
|
|
||||||
// Terminate the plugin if it is still hung.
|
|
||||||
// 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();
|
|
||||||
|
|
||||||
// Inform the content process that the slow script debugger has finished
|
|
||||||
// spinning up. The content process will run a nested event loop until this
|
|
||||||
// method is called.
|
|
||||||
// Only valid for SLOW_SCRIPT reports.
|
|
||||||
void endStartingDebugger();
|
|
||||||
|
|
||||||
// Inquire whether the report is for a content process loaded by the given
|
|
||||||
// frameloader.
|
|
||||||
bool isReportForBrowser(in nsIFrameLoader aFrameLoader);
|
|
||||||
};
|
|
@ -201,8 +201,6 @@ public:
|
|||||||
// Does not accept nullptr and should never fail.
|
// Does not accept nullptr and should never fail.
|
||||||
nsPluginTag* TagForPlugin(nsNPAPIPlugin* aPlugin);
|
nsPluginTag* TagForPlugin(nsNPAPIPlugin* aPlugin);
|
||||||
|
|
||||||
nsPluginTag* PluginWithId(uint32_t aId);
|
|
||||||
|
|
||||||
nsresult GetPlugin(const char *aMimeType, nsNPAPIPlugin** aPlugin);
|
nsresult GetPlugin(const char *aMimeType, nsNPAPIPlugin** aPlugin);
|
||||||
nsresult GetPluginForContentProcess(uint32_t aPluginId, nsNPAPIPlugin** aPlugin);
|
nsresult GetPluginForContentProcess(uint32_t aPluginId, nsNPAPIPlugin** aPlugin);
|
||||||
void NotifyContentModuleDestroyed(uint32_t aPluginId);
|
void NotifyContentModuleDestroyed(uint32_t aPluginId);
|
||||||
@ -278,6 +276,7 @@ private:
|
|||||||
|
|
||||||
// Returns the first plugin at |path|
|
// Returns the first plugin at |path|
|
||||||
nsPluginTag* FirstPluginWithPath(const nsCString& path);
|
nsPluginTag* FirstPluginWithPath(const nsCString& path);
|
||||||
|
nsPluginTag* PluginWithId(uint32_t aId);
|
||||||
|
|
||||||
nsresult EnsurePrivateDirServiceProvider();
|
nsresult EnsurePrivateDirServiceProvider();
|
||||||
|
|
||||||
|
@ -24,9 +24,6 @@ FindPluginsForContent(uint32_t aPluginEpoch,
|
|||||||
nsTArray<PluginTag>* aPlugins,
|
nsTArray<PluginTag>* aPlugins,
|
||||||
uint32_t* aNewPluginEpoch);
|
uint32_t* aNewPluginEpoch);
|
||||||
|
|
||||||
void
|
|
||||||
TerminatePlugin(uint32_t aPluginId);
|
|
||||||
|
|
||||||
} // namespace plugins
|
} // namespace plugins
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "mozilla/plugins/PluginBridge.h"
|
#include "mozilla/plugins/PluginBridge.h"
|
||||||
#include "mozilla/plugins/PluginInstanceParent.h"
|
#include "mozilla/plugins/PluginInstanceParent.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "mozilla/ProcessHangMonitor.h"
|
|
||||||
#include "mozilla/Services.h"
|
#include "mozilla/Services.h"
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
#include "mozilla/unused.h"
|
#include "mozilla/unused.h"
|
||||||
@ -70,7 +69,6 @@ using namespace mozilla::plugins::parent;
|
|||||||
using namespace CrashReporter;
|
using namespace CrashReporter;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char kContentTimeoutPref[] = "dom.ipc.plugins.contentTimeoutSecs";
|
|
||||||
static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
|
static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
|
||||||
static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs";
|
static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs";
|
||||||
static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs";
|
static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs";
|
||||||
@ -261,22 +259,6 @@ PRCList PluginModuleMapping::sModuleListHead =
|
|||||||
|
|
||||||
bool PluginModuleMapping::sIsLoadModuleOnStack = false;
|
bool PluginModuleMapping::sIsLoadModuleOnStack = false;
|
||||||
|
|
||||||
void
|
|
||||||
mozilla::plugins::TerminatePlugin(uint32_t aPluginId)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
||||||
|
|
||||||
nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
|
|
||||||
nsPluginTag* pluginTag = host->PluginWithId(aPluginId);
|
|
||||||
if (!pluginTag || !pluginTag->mPlugin) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<nsNPAPIPlugin> plugin = pluginTag->mPlugin;
|
|
||||||
PluginModuleChromeParent* chromeParent = static_cast<PluginModuleChromeParent*>(plugin->GetLibrary());
|
|
||||||
chromeParent->TerminateChildProcess(MessageLoop::current());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ PluginLibrary*
|
/* static */ PluginLibrary*
|
||||||
PluginModuleContentParent::LoadModule(uint32_t aPluginId)
|
PluginModuleContentParent::LoadModule(uint32_t aPluginId)
|
||||||
{
|
{
|
||||||
@ -307,8 +289,6 @@ PluginModuleContentParent::LoadModule(uint32_t aPluginId)
|
|||||||
mapping.forget();
|
mapping.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
parent->mPluginId = aPluginId;
|
|
||||||
|
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,8 +328,6 @@ PluginModuleContentParent::Initialize(mozilla::ipc::Transport* aTransport,
|
|||||||
// all share the same channel.
|
// all share the same channel.
|
||||||
parent->GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
|
parent->GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
|
||||||
|
|
||||||
TimeoutChanged(kContentTimeoutPref, parent);
|
|
||||||
|
|
||||||
// moduleMapping is linked into PluginModuleMapping::sModuleListHead and is
|
// moduleMapping is linked into PluginModuleMapping::sModuleListHead and is
|
||||||
// needed later, so since this function is returning successfully we
|
// needed later, so since this function is returning successfully we
|
||||||
// forget it here.
|
// forget it here.
|
||||||
@ -539,12 +517,6 @@ PluginModuleParent::~PluginModuleParent()
|
|||||||
PluginModuleContentParent::PluginModuleContentParent()
|
PluginModuleContentParent::PluginModuleContentParent()
|
||||||
: PluginModuleParent(false)
|
: PluginModuleParent(false)
|
||||||
{
|
{
|
||||||
Preferences::RegisterCallback(TimeoutChanged, kContentTimeoutPref, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginModuleContentParent::~PluginModuleContentParent()
|
|
||||||
{
|
|
||||||
Preferences::UnregisterCallback(TimeoutChanged, kContentTimeoutPref, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId)
|
PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId)
|
||||||
@ -678,7 +650,7 @@ PluginModuleChromeParent::WriteExtraDataForMinidump(AnnotationTable& notes)
|
|||||||
#endif // MOZ_CRASHREPORTER
|
#endif // MOZ_CRASHREPORTER
|
||||||
|
|
||||||
void
|
void
|
||||||
PluginModuleParent::SetChildTimeout(const int32_t aChildTimeout)
|
PluginModuleChromeParent::SetChildTimeout(const int32_t aChildTimeout)
|
||||||
{
|
{
|
||||||
int32_t timeoutMs = (aChildTimeout > 0) ? (1000 * aChildTimeout) :
|
int32_t timeoutMs = (aChildTimeout > 0) ? (1000 * aChildTimeout) :
|
||||||
MessageChannel::kNoTimeout;
|
MessageChannel::kNoTimeout;
|
||||||
@ -686,33 +658,24 @@ PluginModuleParent::SetChildTimeout(const int32_t aChildTimeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PluginModuleParent::TimeoutChanged(const char* aPref, void* aModule)
|
PluginModuleChromeParent::TimeoutChanged(const char* aPref, void* aModule)
|
||||||
{
|
{
|
||||||
PluginModuleParent* module = static_cast<PluginModuleParent*>(aModule);
|
|
||||||
|
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||||
#ifndef XP_WIN
|
#ifndef XP_WIN
|
||||||
if (!strcmp(aPref, kChildTimeoutPref)) {
|
if (!strcmp(aPref, kChildTimeoutPref)) {
|
||||||
MOZ_ASSERT(module->IsChrome());
|
|
||||||
// The timeout value used by the parent for children
|
// The timeout value used by the parent for children
|
||||||
int32_t timeoutSecs = Preferences::GetInt(kChildTimeoutPref, 0);
|
int32_t timeoutSecs = Preferences::GetInt(kChildTimeoutPref, 0);
|
||||||
module->SetChildTimeout(timeoutSecs);
|
static_cast<PluginModuleChromeParent*>(aModule)->SetChildTimeout(timeoutSecs);
|
||||||
#else
|
#else
|
||||||
if (!strcmp(aPref, kChildTimeoutPref) ||
|
if (!strcmp(aPref, kChildTimeoutPref) ||
|
||||||
!strcmp(aPref, kHangUIMinDisplayPref) ||
|
!strcmp(aPref, kHangUIMinDisplayPref) ||
|
||||||
!strcmp(aPref, kHangUITimeoutPref)) {
|
!strcmp(aPref, kHangUITimeoutPref)) {
|
||||||
MOZ_ASSERT(module->IsChrome());
|
static_cast<PluginModuleChromeParent*>(aModule)->EvaluateHangUIState(true);
|
||||||
static_cast<PluginModuleChromeParent*>(module)->EvaluateHangUIState(true);
|
|
||||||
#endif // XP_WIN
|
#endif // XP_WIN
|
||||||
} else if (!strcmp(aPref, kParentTimeoutPref)) {
|
} else if (!strcmp(aPref, kParentTimeoutPref)) {
|
||||||
// The timeout value used by the child for its parent
|
// The timeout value used by the child for its parent
|
||||||
MOZ_ASSERT(module->IsChrome());
|
|
||||||
int32_t timeoutSecs = Preferences::GetInt(kParentTimeoutPref, 0);
|
int32_t timeoutSecs = Preferences::GetInt(kParentTimeoutPref, 0);
|
||||||
unused << static_cast<PluginModuleChromeParent*>(module)->SendSetParentHangTimeout(timeoutSecs);
|
unused << static_cast<PluginModuleChromeParent*>(aModule)->SendSetParentHangTimeout(timeoutSecs);
|
||||||
} else if (!strcmp(aPref, kContentTimeoutPref)) {
|
|
||||||
MOZ_ASSERT(!module->IsChrome());
|
|
||||||
int32_t timeoutSecs = Preferences::GetInt(kContentTimeoutPref, 0);
|
|
||||||
module->SetChildTimeout(timeoutSecs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -896,23 +859,6 @@ PluginModuleChromeParent::ShouldContinueFromReplyTimeout()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
PluginModuleContentParent::ShouldContinueFromReplyTimeout()
|
|
||||||
{
|
|
||||||
nsRefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
|
|
||||||
if (!monitor) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
monitor->NotifyPluginHang(mPluginId);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
PluginModuleContentParent::OnExitedSyncSend()
|
|
||||||
{
|
|
||||||
ProcessHangMonitor::ClearHang();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop)
|
PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop)
|
||||||
{
|
{
|
||||||
|
@ -176,9 +176,6 @@ protected:
|
|||||||
PluginAsyncSurrogate** aSurrogate = nullptr);
|
PluginAsyncSurrogate** aSurrogate = nullptr);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void SetChildTimeout(const int32_t aChildTimeout);
|
|
||||||
static void TimeoutChanged(const char* aPref, void* aModule);
|
|
||||||
|
|
||||||
virtual void UpdatePluginTimeout() {}
|
virtual void UpdatePluginTimeout() {}
|
||||||
|
|
||||||
virtual bool RecvNotifyContentModuleDestroyed() MOZ_OVERRIDE { return true; }
|
virtual bool RecvNotifyContentModuleDestroyed() MOZ_OVERRIDE { return true; }
|
||||||
@ -312,19 +309,13 @@ class PluginModuleContentParent : public PluginModuleParent
|
|||||||
static void OnLoadPluginResult(const uint32_t& aPluginId, const bool& aResult);
|
static void OnLoadPluginResult(const uint32_t& aPluginId, const bool& aResult);
|
||||||
static void AssociatePluginId(uint32_t aPluginId, base::ProcessId aProcessId);
|
static void AssociatePluginId(uint32_t aPluginId, base::ProcessId aProcessId);
|
||||||
|
|
||||||
virtual ~PluginModuleContentParent();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE;
|
|
||||||
virtual void OnExitedSyncSend() MOZ_OVERRIDE;
|
|
||||||
|
|
||||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||||
void OnCrash(DWORD processID) MOZ_OVERRIDE {}
|
void OnCrash(DWORD processID) MOZ_OVERRIDE {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static PluginModuleContentParent* sSavedModuleParent;
|
static PluginModuleContentParent* sSavedModuleParent;
|
||||||
|
|
||||||
uint32_t mPluginId;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PluginModuleChromeParent
|
class PluginModuleChromeParent
|
||||||
@ -352,9 +343,6 @@ class PluginModuleChromeParent
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
OnHangUIContinue();
|
OnHangUIContinue();
|
||||||
|
|
||||||
void
|
|
||||||
EvaluateHangUIState(const bool aReset);
|
|
||||||
#endif // XP_WIN
|
#endif // XP_WIN
|
||||||
|
|
||||||
virtual bool WaitForIPCConnection() MOZ_OVERRIDE;
|
virtual bool WaitForIPCConnection() MOZ_OVERRIDE;
|
||||||
@ -414,6 +402,8 @@ private:
|
|||||||
CrashReporterParent* CrashReporter();
|
CrashReporterParent* CrashReporter();
|
||||||
|
|
||||||
void CleanupFromTimeout(const bool aByHangUI);
|
void CleanupFromTimeout(const bool aByHangUI);
|
||||||
|
void SetChildTimeout(const int32_t aChildTimeout);
|
||||||
|
static void TimeoutChanged(const char* aPref, void* aModule);
|
||||||
|
|
||||||
virtual void UpdatePluginTimeout() MOZ_OVERRIDE;
|
virtual void UpdatePluginTimeout() MOZ_OVERRIDE;
|
||||||
|
|
||||||
@ -459,6 +449,9 @@ private:
|
|||||||
#endif // MOZ_CRASHREPORTER
|
#endif // MOZ_CRASHREPORTER
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
EvaluateHangUIState(const bool aReset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launches the Plugin Hang UI.
|
* Launches the Plugin Hang UI.
|
||||||
*
|
*
|
||||||
|
@ -177,11 +177,6 @@ public:
|
|||||||
return INTR_SEMS == mMesageSemantics && OUT_MESSAGE == mDirection;
|
return INTR_SEMS == mMesageSemantics && OUT_MESSAGE == mDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsOutgoingSync() const {
|
|
||||||
return (mMesageSemantics == INTR_SEMS || mMesageSemantics == SYNC_SEMS) &&
|
|
||||||
mDirection == OUT_MESSAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Describe(int32_t* id, const char** dir, const char** sems,
|
void Describe(int32_t* id, const char** dir, const char** sems,
|
||||||
const char** name) const
|
const char** name) const
|
||||||
{
|
{
|
||||||
@ -223,9 +218,6 @@ public:
|
|||||||
if (frame.IsInterruptIncall())
|
if (frame.IsInterruptIncall())
|
||||||
mThat.EnteredCall();
|
mThat.EnteredCall();
|
||||||
|
|
||||||
if (frame.IsOutgoingSync())
|
|
||||||
mThat.EnteredSyncSend();
|
|
||||||
|
|
||||||
mThat.mSawInterruptOutMsg |= frame.IsInterruptOutcall();
|
mThat.mSawInterruptOutMsg |= frame.IsInterruptOutcall();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,9 +226,7 @@ public:
|
|||||||
|
|
||||||
MOZ_ASSERT(!mThat.mCxxStackFrames.empty());
|
MOZ_ASSERT(!mThat.mCxxStackFrames.empty());
|
||||||
|
|
||||||
const InterruptFrame& frame = mThat.mCxxStackFrames.back();
|
bool exitingCall = mThat.mCxxStackFrames.back().IsInterruptIncall();
|
||||||
bool exitingSync = frame.IsOutgoingSync();
|
|
||||||
bool exitingCall = frame.IsInterruptIncall();
|
|
||||||
mThat.mCxxStackFrames.shrinkBy(1);
|
mThat.mCxxStackFrames.shrinkBy(1);
|
||||||
|
|
||||||
bool exitingStack = mThat.mCxxStackFrames.empty();
|
bool exitingStack = mThat.mCxxStackFrames.empty();
|
||||||
@ -249,9 +239,6 @@ public:
|
|||||||
if (exitingCall)
|
if (exitingCall)
|
||||||
mThat.ExitedCall();
|
mThat.ExitedCall();
|
||||||
|
|
||||||
if (exitingSync)
|
|
||||||
mThat.ExitedSyncSend();
|
|
||||||
|
|
||||||
if (exitingStack)
|
if (exitingStack)
|
||||||
mThat.ExitedCxxStack();
|
mThat.ExitedCxxStack();
|
||||||
}
|
}
|
||||||
|
@ -291,14 +291,6 @@ class MessageChannel : HasResultCodes
|
|||||||
mListener->OnExitedCall();
|
mListener->OnExitedCall();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnteredSyncSend() {
|
|
||||||
mListener->OnEnteredSyncSend();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExitedSyncSend() {
|
|
||||||
mListener->OnExitedSyncSend();
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageListener *Listener() const {
|
MessageListener *Listener() const {
|
||||||
return mListener.get();
|
return mListener.get();
|
||||||
}
|
}
|
||||||
|
@ -98,11 +98,6 @@ class MessageListener
|
|||||||
return RIPChildWins;
|
return RIPChildWins;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnEnteredSyncSend() {
|
|
||||||
}
|
|
||||||
virtual void OnExitedSyncSend() {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void ProcessRemoteNativeEventsInInterruptCall() {
|
virtual void ProcessRemoteNativeEventsInInterruptCall() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,6 @@
|
|||||||
#include "mozilla/dom/WindowBinding.h"
|
#include "mozilla/dom/WindowBinding.h"
|
||||||
#include "mozilla/Atomics.h"
|
#include "mozilla/Atomics.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/ProcessHangMonitor.h"
|
|
||||||
#include "AccessCheck.h"
|
#include "AccessCheck.h"
|
||||||
#include "nsGlobalWindow.h"
|
#include "nsGlobalWindow.h"
|
||||||
#include "nsAboutProtocolUtils.h"
|
#include "nsAboutProtocolUtils.h"
|
||||||
@ -1113,7 +1112,6 @@ class Watchdog
|
|||||||
#include "ipc/Nuwa.h"
|
#include "ipc/Nuwa.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PREF_MAX_SCRIPT_RUN_TIME_CHILD "dom.max_child_script_run_time"
|
|
||||||
#define PREF_MAX_SCRIPT_RUN_TIME_CONTENT "dom.max_script_run_time"
|
#define PREF_MAX_SCRIPT_RUN_TIME_CONTENT "dom.max_script_run_time"
|
||||||
#define PREF_MAX_SCRIPT_RUN_TIME_CHROME "dom.max_chrome_script_run_time"
|
#define PREF_MAX_SCRIPT_RUN_TIME_CHROME "dom.max_chrome_script_run_time"
|
||||||
|
|
||||||
@ -1136,7 +1134,6 @@ class WatchdogManager : public nsIObserver
|
|||||||
mozilla::Preferences::AddStrongObserver(this, "dom.use_watchdog");
|
mozilla::Preferences::AddStrongObserver(this, "dom.use_watchdog");
|
||||||
mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CONTENT);
|
mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CONTENT);
|
||||||
mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHROME);
|
mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHROME);
|
||||||
mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHILD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -1150,7 +1147,6 @@ class WatchdogManager : public nsIObserver
|
|||||||
mozilla::Preferences::RemoveObserver(this, "dom.use_watchdog");
|
mozilla::Preferences::RemoveObserver(this, "dom.use_watchdog");
|
||||||
mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CONTENT);
|
mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CONTENT);
|
||||||
mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHROME);
|
mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHROME);
|
||||||
mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHILD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -1228,10 +1224,7 @@ class WatchdogManager : public nsIObserver
|
|||||||
int32_t chromeTime = Preferences::GetInt(PREF_MAX_SCRIPT_RUN_TIME_CHROME, 20);
|
int32_t chromeTime = Preferences::GetInt(PREF_MAX_SCRIPT_RUN_TIME_CHROME, 20);
|
||||||
if (chromeTime <= 0)
|
if (chromeTime <= 0)
|
||||||
chromeTime = INT32_MAX;
|
chromeTime = INT32_MAX;
|
||||||
int32_t childTime = Preferences::GetInt(PREF_MAX_SCRIPT_RUN_TIME_CHILD, 3);
|
mWatchdog->SetMinScriptRunTimeSeconds(std::min(contentTime, chromeTime));
|
||||||
if (childTime <= 0)
|
|
||||||
childTime = INT32_MAX;
|
|
||||||
mWatchdog->SetMinScriptRunTimeSeconds(std::min(std::min(contentTime, chromeTime), childTime));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1348,10 +1341,6 @@ XPCJSRuntime::DefaultJSContextCallback(JSRuntime *rt)
|
|||||||
void
|
void
|
||||||
XPCJSRuntime::ActivityCallback(void *arg, bool active)
|
XPCJSRuntime::ActivityCallback(void *arg, bool active)
|
||||||
{
|
{
|
||||||
if (!active) {
|
|
||||||
ProcessHangMonitor::ClearHang();
|
|
||||||
}
|
|
||||||
|
|
||||||
XPCJSRuntime* self = static_cast<XPCJSRuntime*>(arg);
|
XPCJSRuntime* self = static_cast<XPCJSRuntime*>(arg);
|
||||||
self->mWatchdogManager->RecordRuntimeActivity(active);
|
self->mWatchdogManager->RecordRuntimeActivity(active);
|
||||||
}
|
}
|
||||||
@ -1390,16 +1379,13 @@ XPCJSRuntime::InterruptCallback(JSContext *cx)
|
|||||||
if (!nsContentUtils::IsInitialized())
|
if (!nsContentUtils::IsInitialized())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
bool contentProcess = XRE_GetProcessType() == GeckoProcessType_Content;
|
|
||||||
|
|
||||||
// This is at least the second interrupt callback we've received since
|
// This is at least the second interrupt callback we've received since
|
||||||
// returning to the event loop. See how long it's been, and what the limit
|
// returning to the event loop. See how long it's been, and what the limit
|
||||||
// is.
|
// is.
|
||||||
TimeDuration duration = TimeStamp::NowLoRes() - self->mSlowScriptCheckpoint;
|
TimeDuration duration = TimeStamp::NowLoRes() - self->mSlowScriptCheckpoint;
|
||||||
bool chrome = nsContentUtils::IsCallerChrome();
|
bool chrome = nsContentUtils::IsCallerChrome();
|
||||||
const char *prefName = contentProcess ? PREF_MAX_SCRIPT_RUN_TIME_CHILD
|
const char *prefName = chrome ? PREF_MAX_SCRIPT_RUN_TIME_CHROME
|
||||||
: chrome ? PREF_MAX_SCRIPT_RUN_TIME_CHROME
|
: PREF_MAX_SCRIPT_RUN_TIME_CONTENT;
|
||||||
: PREF_MAX_SCRIPT_RUN_TIME_CONTENT;
|
|
||||||
int32_t limit = Preferences::GetInt(prefName, chrome ? 20 : 10);
|
int32_t limit = Preferences::GetInt(prefName, chrome ? 20 : 10);
|
||||||
|
|
||||||
// If there's no limit, or we're within the limit, let it go.
|
// If there's no limit, or we're within the limit, let it go.
|
||||||
@ -1437,9 +1423,7 @@ XPCJSRuntime::InterruptCallback(JSContext *cx)
|
|||||||
|
|
||||||
// The user chose to continue the script. Reset the timer, and disable this
|
// The user chose to continue the script. Reset the timer, and disable this
|
||||||
// machinery with a pref of the user opted out of future slow-script dialogs.
|
// machinery with a pref of the user opted out of future slow-script dialogs.
|
||||||
if (response != nsGlobalWindow::ContinueSlowScriptAndKeepNotifying)
|
self->mSlowScriptCheckpoint = TimeStamp::NowLoRes();
|
||||||
self->mSlowScriptCheckpoint = TimeStamp::NowLoRes();
|
|
||||||
|
|
||||||
if (response == nsGlobalWindow::AlwaysContinueSlowScript)
|
if (response == nsGlobalWindow::AlwaysContinueSlowScript)
|
||||||
Preferences::SetInt(prefName, 0);
|
Preferences::SetInt(prefName, 0);
|
||||||
|
|
||||||
|
@ -2278,7 +2278,6 @@ pref("editor.positioning.offset", 0);
|
|||||||
|
|
||||||
pref("dom.use_watchdog", true);
|
pref("dom.use_watchdog", true);
|
||||||
pref("dom.max_chrome_script_run_time", 20);
|
pref("dom.max_chrome_script_run_time", 20);
|
||||||
pref("dom.max_child_script_run_time", 2);
|
|
||||||
pref("dom.max_script_run_time", 10);
|
pref("dom.max_script_run_time", 10);
|
||||||
|
|
||||||
// If true, ArchiveReader will be enabled
|
// If true, ArchiveReader will be enabled
|
||||||
@ -2325,9 +2324,6 @@ pref("dom.ipc.plugins.timeoutSecs", 45);
|
|||||||
// to a synchronous request before terminating itself. After this
|
// to a synchronous request before terminating itself. After this
|
||||||
// point the child assumes the parent is hung. Currently disabled.
|
// point the child assumes the parent is hung. Currently disabled.
|
||||||
pref("dom.ipc.plugins.parentTimeoutSecs", 0);
|
pref("dom.ipc.plugins.parentTimeoutSecs", 0);
|
||||||
// How long a plugin in e10s is allowed to process a synchronous IPC
|
|
||||||
// message before we notify the chrome process of a hang.
|
|
||||||
pref("dom.ipc.plugins.contentTimeoutSecs", 2);
|
|
||||||
// How long a plugin launch is allowed to take before
|
// How long a plugin launch is allowed to take before
|
||||||
// we consider it failed.
|
// we consider it failed.
|
||||||
pref("dom.ipc.plugins.processLaunchTimeoutSecs", 45);
|
pref("dom.ipc.plugins.processLaunchTimeoutSecs", 45);
|
||||||
@ -2345,7 +2341,6 @@ pref("dom.ipc.tabs.shutdownTimeoutSecs", 5);
|
|||||||
#else
|
#else
|
||||||
// No timeout in DEBUG builds
|
// No timeout in DEBUG builds
|
||||||
pref("dom.ipc.plugins.timeoutSecs", 0);
|
pref("dom.ipc.plugins.timeoutSecs", 0);
|
||||||
pref("dom.ipc.plugins.contentTimeoutSecs", 0);
|
|
||||||
pref("dom.ipc.plugins.processLaunchTimeoutSecs", 0);
|
pref("dom.ipc.plugins.processLaunchTimeoutSecs", 0);
|
||||||
pref("dom.ipc.plugins.parentTimeoutSecs", 0);
|
pref("dom.ipc.plugins.parentTimeoutSecs", 0);
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
|
@ -28,8 +28,7 @@ class GeckoInstance(object):
|
|||||||
"browser.displayedE10SPrompt.3": 5,
|
"browser.displayedE10SPrompt.3": 5,
|
||||||
"browser.displayedE10SPrompt.4": 5,
|
"browser.displayedE10SPrompt.4": 5,
|
||||||
"browser.tabs.remote.autostart.1": False,
|
"browser.tabs.remote.autostart.1": False,
|
||||||
"browser.tabs.remote.autostart.2": False,
|
"browser.tabs.remote.autostart.2": False}
|
||||||
"dom.ipc.reportProcessHangs": False}
|
|
||||||
|
|
||||||
def __init__(self, host, port, bin, profile=None, app_args=None, symbols_path=None,
|
def __init__(self, host, port, bin, profile=None, app_args=None, symbols_path=None,
|
||||||
gecko_log=None, prefs=None):
|
gecko_log=None, prefs=None):
|
||||||
|
@ -14,8 +14,6 @@ user_pref("dom.forms.color", true); // on for testing
|
|||||||
user_pref("dom.max_script_run_time", 0); // no slow script dialogs
|
user_pref("dom.max_script_run_time", 0); // no slow script dialogs
|
||||||
user_pref("hangmonitor.timeout", 0); // no hang monitor
|
user_pref("hangmonitor.timeout", 0); // no hang monitor
|
||||||
user_pref("dom.max_chrome_script_run_time", 0);
|
user_pref("dom.max_chrome_script_run_time", 0);
|
||||||
user_pref("dom.max_child_script_run_time", 0);
|
|
||||||
user_pref("dom.ipc.reportProcessHangs", false); // process hang monitor
|
|
||||||
user_pref("dom.popup_maximum", -1);
|
user_pref("dom.popup_maximum", -1);
|
||||||
user_pref("dom.send_after_paint_to_content", true);
|
user_pref("dom.send_after_paint_to_content", true);
|
||||||
user_pref("dom.successive_dialog_time_limit", 0);
|
user_pref("dom.successive_dialog_time_limit", 0);
|
||||||
|
Loading…
Reference in New Issue
Block a user