mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1196947 - Performance tools should display a message in private browsing, r=jsantell
This commit is contained in:
parent
9bfc1cf93e
commit
94946f8488
@ -35,7 +35,12 @@
|
||||
<!ENTITY performanceUI.bufferStatusFull "The buffer is full. Older samples are now being overwritten.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.loadingNotice): This is the label shown
|
||||
- in the call list view while loading a profile. -->
|
||||
- in the details view while the profiler is unavailable, for example, while
|
||||
- in Private Browsing mode. -->
|
||||
<!ENTITY performanceUI.unavailableNoticePB "Recording a profile is currently unavailable. Please close all private browsing windows and try again.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.loadingNotice): This is the label shown
|
||||
- in the details view while loading a profile. -->
|
||||
<!ENTITY performanceUI.loadingNotice "Loading…">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.recordButton): This string is displayed
|
||||
|
@ -30,6 +30,9 @@ module.exports = {
|
||||
// When a new recording is being tracked in the panel.
|
||||
NEW_RECORDING: "Performance:NewRecording",
|
||||
|
||||
// When a new recording can't be successfully created when started.
|
||||
NEW_RECORDING_FAILED: "Performance:NewRecordingFailed",
|
||||
|
||||
// When a recording is started or stopped or stopping via the PerformanceController
|
||||
RECORDING_STATE_CHANGE: "Performance:RecordingStateChange",
|
||||
|
||||
|
@ -89,6 +89,7 @@ var gToolbox, gTarget, gFront;
|
||||
var startupPerformance = Task.async(function*() {
|
||||
yield PerformanceController.initialize();
|
||||
yield PerformanceView.initialize();
|
||||
PerformanceController.enableFrontEventListeners();
|
||||
});
|
||||
|
||||
/**
|
||||
@ -97,6 +98,7 @@ var startupPerformance = Task.async(function*() {
|
||||
var shutdownPerformance = Task.async(function*() {
|
||||
yield PerformanceController.destroy();
|
||||
yield PerformanceView.destroy();
|
||||
PerformanceController.disableFrontEventListeners();
|
||||
});
|
||||
|
||||
/**
|
||||
@ -131,7 +133,6 @@ var PerformanceController = {
|
||||
this._prefs = require("devtools/client/performance/modules/global").PREFS;
|
||||
this._prefs.on("pref-changed", this._onPrefChanged);
|
||||
|
||||
gFront.on("*", this._onFrontEvent);
|
||||
ToolbarView.on(EVENTS.PREF_CHANGED, this._onPrefChanged);
|
||||
PerformanceView.on(EVENTS.UI_START_RECORDING, this.startRecording);
|
||||
PerformanceView.on(EVENTS.UI_STOP_RECORDING, this.stopRecording);
|
||||
@ -151,7 +152,6 @@ var PerformanceController = {
|
||||
this._telemetry.destroy();
|
||||
this._prefs.off("pref-changed", this._onPrefChanged);
|
||||
|
||||
gFront.off("*", this._onFrontEvent);
|
||||
ToolbarView.off(EVENTS.PREF_CHANGED, this._onPrefChanged);
|
||||
PerformanceView.off(EVENTS.UI_START_RECORDING, this.startRecording);
|
||||
PerformanceView.off(EVENTS.UI_STOP_RECORDING, this.stopRecording);
|
||||
@ -164,6 +164,27 @@ var PerformanceController = {
|
||||
gDevTools.off("pref-changed", this._onThemeChanged);
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables front event listeners.
|
||||
*
|
||||
* The rationale behind this is given by the async intialization of all the
|
||||
* frontend components. Even though the panel is considered "open" only after
|
||||
* both the controller and the view are created, and even though their
|
||||
* initialization is sequential (controller, then view), the controller might
|
||||
* start handling backend events before the view finishes if the event
|
||||
* listeners are added too soon.
|
||||
*/
|
||||
enableFrontEventListeners: function() {
|
||||
gFront.on("*", this._onFrontEvent);
|
||||
},
|
||||
|
||||
/**
|
||||
* Disables front event listeners.
|
||||
*/
|
||||
disableFrontEventListeners: function() {
|
||||
gFront.off("*", this._onFrontEvent);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the current devtools theme.
|
||||
*/
|
||||
@ -205,6 +226,27 @@ var PerformanceController = {
|
||||
this._prefs[prefName] = prefValue;
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks whether or not a new recording is supported by the PerformanceFront.
|
||||
* @return Promise:boolean
|
||||
*/
|
||||
canCurrentlyRecord: Task.async(function*() {
|
||||
// If we're testing the legacy front, the performance actor will exist,
|
||||
// with `canCurrentlyRecord` method; this ensures we test the legacy path.
|
||||
if (gFront.LEGACY_FRONT) {
|
||||
return true;
|
||||
}
|
||||
let hasActor = yield gTarget.hasActor("performance");
|
||||
if (!hasActor) {
|
||||
return true;
|
||||
}
|
||||
let actorCanCheck = yield gTarget.actorHasMethod("performance", "canCurrentlyRecord");
|
||||
if (!actorCanCheck) {
|
||||
return true;
|
||||
}
|
||||
return (yield gFront.canCurrentlyRecord()).success;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Starts recording with the PerformanceFront.
|
||||
*/
|
||||
@ -221,7 +263,13 @@ var PerformanceController = {
|
||||
sampleFrequency: this.getPref("profiler-sample-frequency")
|
||||
};
|
||||
|
||||
yield gFront.startRecording(options);
|
||||
// In some cases, like when the target has a private browsing tab,
|
||||
// recording is not currently supported because of the profiler module.
|
||||
// Present a notification in this case alerting the user of this issue.
|
||||
if (!(yield gFront.startRecording(options))) {
|
||||
this.emit(EVENTS.NEW_RECORDING_FAILED);
|
||||
PerformanceView.setState("unavailable");
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
|
@ -14,27 +14,30 @@ var PerformanceView = {
|
||||
// that the server has support for determining buffer status.
|
||||
_bufferStatusSupported: false,
|
||||
|
||||
// Mapping of state to selectors for different panes
|
||||
// of the main profiler view. Used in `PerformanceView.setState()`
|
||||
// Mapping of state to selectors for different properties and their values,
|
||||
// from the main profiler view. Used in `PerformanceView.setState()`
|
||||
states: {
|
||||
empty: [
|
||||
{ deck: "#performance-view", pane: "#empty-notice" }
|
||||
"unavailable": [
|
||||
{ sel: "#performance-view", opt: "selectedPanel", val: () => $("#unavailable-notice") },
|
||||
],
|
||||
recording: [
|
||||
{ deck: "#performance-view", pane: "#performance-view-content" },
|
||||
{ deck: "#details-pane-container", pane: "#recording-notice" }
|
||||
"empty": [
|
||||
{ sel: "#performance-view", opt: "selectedPanel", val: () => $("#empty-notice") }
|
||||
],
|
||||
"recording": [
|
||||
{ sel: "#performance-view", opt: "selectedPanel", val: () => $("#performance-view-content") },
|
||||
{ sel: "#details-pane-container", opt: "selectedPanel", val: () => $("#recording-notice") }
|
||||
],
|
||||
"console-recording": [
|
||||
{ deck: "#performance-view", pane: "#performance-view-content" },
|
||||
{ deck: "#details-pane-container", pane: "#console-recording-notice" }
|
||||
{ sel: "#performance-view", opt: "selectedPanel", val: () => $("#performance-view-content") },
|
||||
{ sel: "#details-pane-container", opt: "selectedPanel", val: () => $("#console-recording-notice") }
|
||||
],
|
||||
recorded: [
|
||||
{ deck: "#performance-view", pane: "#performance-view-content" },
|
||||
{ deck: "#details-pane-container", pane: "#details-pane" }
|
||||
"recorded": [
|
||||
{ sel: "#performance-view", opt: "selectedPanel", val: () => $("#performance-view-content") },
|
||||
{ sel: "#details-pane-container", opt: "selectedPanel", val: () => $("#details-pane") }
|
||||
],
|
||||
loading: [
|
||||
{ deck: "#performance-view", pane: "#performance-view-content" },
|
||||
{ deck: "#details-pane-container", pane: "#loading-notice" }
|
||||
"loading": [
|
||||
{ sel: "#performance-view", opt: "selectedPanel", val: () => $("#performance-view-content") },
|
||||
{ sel: "#details-pane-container", opt: "selectedPanel", val: () => $("#loading-notice") }
|
||||
]
|
||||
},
|
||||
|
||||
@ -52,6 +55,7 @@ var PerformanceView = {
|
||||
this._onRecordingSelected = this._onRecordingSelected.bind(this);
|
||||
this._onProfilerStatusUpdated = this._onProfilerStatusUpdated.bind(this);
|
||||
this._onRecordingStateChange = this._onRecordingStateChange.bind(this);
|
||||
this._onNewRecordingFailed = this._onNewRecordingFailed.bind(this);
|
||||
|
||||
for (let button of $$(".record-button")) {
|
||||
button.addEventListener("click", this._onRecordButtonClick);
|
||||
@ -64,8 +68,13 @@ var PerformanceView = {
|
||||
PerformanceController.on(EVENTS.PROFILER_STATUS_UPDATED, this._onProfilerStatusUpdated);
|
||||
PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
|
||||
PerformanceController.on(EVENTS.NEW_RECORDING, this._onRecordingStateChange);
|
||||
PerformanceController.on(EVENTS.NEW_RECORDING_FAILED, this._onNewRecordingFailed);
|
||||
|
||||
this.setState("empty");
|
||||
if (yield PerformanceController.canCurrentlyRecord()) {
|
||||
this.setState("empty");
|
||||
} else {
|
||||
this.setState("unavailable");
|
||||
}
|
||||
|
||||
// Initialize the ToolbarView first, because other views may need access
|
||||
// to the OptionsView via the controller, to read prefs.
|
||||
@ -89,6 +98,7 @@ var PerformanceView = {
|
||||
PerformanceController.off(EVENTS.PROFILER_STATUS_UPDATED, this._onProfilerStatusUpdated);
|
||||
PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
|
||||
PerformanceController.off(EVENTS.NEW_RECORDING, this._onRecordingStateChange);
|
||||
PerformanceController.off(EVENTS.NEW_RECORDING_FAILED, this._onNewRecordingFailed);
|
||||
|
||||
yield ToolbarView.destroy();
|
||||
yield RecordingsView.destroy();
|
||||
@ -97,16 +107,18 @@ var PerformanceView = {
|
||||
}),
|
||||
|
||||
/**
|
||||
* Sets the state of the profiler view. Possible options are "empty",
|
||||
* "recording", "console-recording", "recorded".
|
||||
* Sets the state of the profiler view. Possible options are "unavailable",
|
||||
* "empty", "recording", "console-recording", "recorded".
|
||||
*/
|
||||
setState: function (state) {
|
||||
let viewConfig = this.states[state];
|
||||
if (!viewConfig) {
|
||||
throw new Error(`Invalid state for PerformanceView: ${state}`);
|
||||
}
|
||||
for (let { deck, pane } of viewConfig) {
|
||||
$(deck).selectedPanel = $(pane);
|
||||
for (let { sel, opt, val } of viewConfig) {
|
||||
for (let el of $$(sel)) {
|
||||
el[opt] = val();
|
||||
}
|
||||
}
|
||||
|
||||
this._state = state;
|
||||
@ -114,6 +126,7 @@ var PerformanceView = {
|
||||
if (state === "console-recording") {
|
||||
let recording = PerformanceController.getCurrentRecording();
|
||||
let label = recording.getLabel() || "";
|
||||
|
||||
// Wrap the label in quotes if it exists for the commands.
|
||||
label = label ? `"${label}"` : "";
|
||||
|
||||
@ -192,7 +205,7 @@ var PerformanceView = {
|
||||
*
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
_activateRecordButtons: function (activate) {
|
||||
_toggleRecordButtons: function (activate) {
|
||||
for (let button of $$(".record-button")) {
|
||||
if (activate) {
|
||||
button.setAttribute("checked", "true");
|
||||
@ -209,7 +222,7 @@ var PerformanceView = {
|
||||
let currentRecording = PerformanceController.getCurrentRecording();
|
||||
let recordings = PerformanceController.getRecordings();
|
||||
|
||||
this._activateRecordButtons(recordings.find(r => !r.isConsole() && r.isRecording()));
|
||||
this._toggleRecordButtons(recordings.find(r => !r.isConsole() && r.isRecording()));
|
||||
this._lockRecordButtons(recordings.find(r => !r.isConsole() && r.isFinalizing()));
|
||||
|
||||
if (currentRecording && currentRecording.isFinalizing()) {
|
||||
@ -223,6 +236,14 @@ var PerformanceView = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* When starting a recording has failed.
|
||||
*/
|
||||
_onNewRecordingFailed: function (e) {
|
||||
this._lockRecordButtons(false);
|
||||
this._toggleRecordButtons(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for clicking the clear button.
|
||||
*/
|
||||
@ -238,7 +259,7 @@ var PerformanceView = {
|
||||
this.emit(EVENTS.UI_STOP_RECORDING);
|
||||
} else {
|
||||
this._lockRecordButtons(true);
|
||||
this._activateRecordButtons(true);
|
||||
this._toggleRecordButtons(true);
|
||||
this.emit(EVENTS.UI_START_RECORDING);
|
||||
}
|
||||
},
|
||||
|
@ -157,6 +157,30 @@
|
||||
<!-- Recording contents and general notice messages -->
|
||||
<deck id="performance-view" flex="1">
|
||||
|
||||
<!-- A default notice, shown while initially opening the tool.
|
||||
Keep this element the first child of #performance-view. -->
|
||||
<hbox id="tool-loading-notice"
|
||||
class="notice-container"
|
||||
flex="1">
|
||||
</hbox>
|
||||
|
||||
<!-- "Unavailable" notice, shown when the entire tool is disabled,
|
||||
for example, when in private browsing mode. -->
|
||||
<vbox id="unavailable-notice"
|
||||
class="notice-container"
|
||||
align="center"
|
||||
pack="center"
|
||||
flex="1">
|
||||
<hbox class="devtools-toolbarbutton-group"
|
||||
pack="center">
|
||||
<toolbarbutton class="devtools-toolbarbutton record-button"
|
||||
label="&performanceUI.startRecording;"
|
||||
standalone="true"/>
|
||||
</hbox>
|
||||
<label class="tool-disabled-message"
|
||||
value="&performanceUI.unavailableNoticePB;"/>
|
||||
</vbox>
|
||||
|
||||
<!-- "Empty" notice, shown when there's no recordings available -->
|
||||
<hbox id="empty-notice"
|
||||
class="notice-container"
|
||||
|
@ -8,9 +8,6 @@ support-files =
|
||||
doc_simple-test.html
|
||||
head.js
|
||||
|
||||
# Commented out tests are profiler tests
|
||||
# that need to be moved over to performance tool
|
||||
|
||||
[browser_aaa-run-first-leaktest.js]
|
||||
[browser_perf-categories-js-calltree.js]
|
||||
[browser_perf-clear-01.js]
|
||||
@ -81,6 +78,7 @@ skip-if = os == 'linux' # bug 1186322
|
||||
[browser_perf-overview-selection-02.js]
|
||||
[browser_perf-overview-selection-03.js]
|
||||
[browser_perf-overview-time-interval.js]
|
||||
[browser_perf-private-browsing.js]
|
||||
[browser_perf-states.js]
|
||||
skip-if = debug # bug 1203888
|
||||
[browser_perf-refresh.js]
|
||||
|
@ -22,7 +22,7 @@ function* spawnTest() {
|
||||
yield profileEnd;
|
||||
|
||||
yield gDevTools.showToolbox(target, "performance");
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
let panel = yield toolbox.getCurrentPanel().open();
|
||||
let { panelWin: { PerformanceController, RecordingsView }} = panel;
|
||||
|
||||
let recordings = PerformanceController.getRecordings();
|
||||
|
@ -6,8 +6,6 @@
|
||||
* when it is opened.
|
||||
*/
|
||||
|
||||
var WAIT_TIME = 10;
|
||||
|
||||
function* spawnTest() {
|
||||
let { target, toolbox, console } = yield initConsole(SIMPLE_URL);
|
||||
let front = toolbox.performance;
|
||||
@ -15,12 +13,13 @@ function* spawnTest() {
|
||||
let profileStart = once(front, "recording-started");
|
||||
console.profile("rust");
|
||||
yield profileStart;
|
||||
|
||||
profileStart = once(front, "recording-started");
|
||||
console.profile("rust2");
|
||||
yield profileStart;
|
||||
|
||||
yield gDevTools.showToolbox(target, "performance");
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
let panel = yield toolbox.getCurrentPanel().open();
|
||||
let { panelWin: { PerformanceController, RecordingsView }} = panel;
|
||||
|
||||
yield waitUntil(() => PerformanceController.getRecordings().length === 2);
|
||||
@ -39,6 +38,7 @@ function* spawnTest() {
|
||||
let profileEnd = once(front, "recording-stopped");
|
||||
console.profileEnd("rust");
|
||||
yield profileEnd;
|
||||
|
||||
profileEnd = once(front, "recording-stopped");
|
||||
console.profileEnd("rust2");
|
||||
yield profileEnd;
|
||||
|
@ -6,8 +6,6 @@
|
||||
* also console recordings that have finished before it was opened.
|
||||
*/
|
||||
|
||||
var WAIT_TIME = 10;
|
||||
|
||||
function* spawnTest() {
|
||||
let { target, toolbox, console } = yield initConsole(SIMPLE_URL);
|
||||
let front = toolbox.performance;
|
||||
@ -25,7 +23,7 @@ function* spawnTest() {
|
||||
yield profileStart;
|
||||
|
||||
yield gDevTools.showToolbox(target, "performance");
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
let panel = yield toolbox.getCurrentPanel().open();
|
||||
let { panelWin: { PerformanceController, RecordingsView }} = panel;
|
||||
|
||||
yield waitUntil(() => PerformanceController.getRecordings().length === 2);
|
||||
|
@ -28,7 +28,7 @@ function* spawnTest() {
|
||||
"performance tab is no longer highlighted when console.profile recording finishes");
|
||||
|
||||
yield gDevTools.showToolbox(target, "performance");
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
let panel = yield toolbox.getCurrentPanel().open();
|
||||
let { panelWin: { PerformanceController, RecordingsView }} = panel;
|
||||
|
||||
yield startRecording(panel);
|
||||
|
@ -20,7 +20,7 @@ function* spawnTest() {
|
||||
yield profileStart;
|
||||
|
||||
yield gDevTools.showToolbox(target, "performance");
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
let panel = yield toolbox.getCurrentPanel().open();
|
||||
let { panelWin: { PerformanceController, RecordingsView }} = panel;
|
||||
|
||||
yield waitUntil(() => PerformanceController.getRecordings().length === 2);
|
||||
|
@ -0,0 +1,93 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that disables the frontend when in private browsing mode.
|
||||
*/
|
||||
|
||||
let gPanelWinTuples = [];
|
||||
|
||||
function* spawnTest() {
|
||||
yield testNormalWindow();
|
||||
yield testPrivateWindow();
|
||||
yield testRecordingFailingInWindow(0);
|
||||
yield testRecordingFailingInWindow(1);
|
||||
yield teardownPerfInWindow(1);
|
||||
yield testRecordingSucceedingInWindow(0);
|
||||
yield teardownPerfInWindow(0);
|
||||
|
||||
gPanelWinTuples = null;
|
||||
finish();
|
||||
}
|
||||
|
||||
function* createPanelInWindow(options) {
|
||||
let win = yield addWindow(options);
|
||||
let tab = yield addTab(SIMPLE_URL, win);
|
||||
let target = TargetFactory.forTab(tab);
|
||||
yield target.makeRemote();
|
||||
|
||||
let toolbox = yield gDevTools.showToolbox(target, "performance");
|
||||
yield toolbox.initPerformance();
|
||||
|
||||
let panel = yield toolbox.getCurrentPanel().open();
|
||||
gPanelWinTuples.push({ panel, win });
|
||||
|
||||
return { panel, win };
|
||||
}
|
||||
|
||||
function* testNormalWindow() {
|
||||
let { panel } = yield createPanelInWindow({ private: false });
|
||||
let { PerformanceView } = panel.panelWin;
|
||||
|
||||
is(PerformanceView.getState(), "empty",
|
||||
"The initial state of the performance panel view is correct (1).");
|
||||
}
|
||||
|
||||
function* testPrivateWindow() {
|
||||
let { panel } = yield createPanelInWindow({ private: true });
|
||||
let { PerformanceView } = panel.panelWin;
|
||||
|
||||
is(PerformanceView.getState(), "unavailable",
|
||||
"The initial state of the performance panel view is correct (2).");
|
||||
}
|
||||
|
||||
function* testRecordingFailingInWindow(index) {
|
||||
let { panel } = gPanelWinTuples[index];
|
||||
let { EVENTS, PerformanceController } = panel.panelWin;
|
||||
|
||||
let onRecordingStarted = () => {
|
||||
ok(false, "Recording should not start while a private window is present.");
|
||||
};
|
||||
|
||||
PerformanceController.on(EVENTS.RECORDING_STARTED, onRecordingStarted);
|
||||
|
||||
let whenFailed = once(PerformanceController, EVENTS.NEW_RECORDING_FAILED);
|
||||
PerformanceController.startRecording();
|
||||
yield whenFailed;
|
||||
ok(true, "Recording has failed.");
|
||||
|
||||
PerformanceController.off(EVENTS.RECORDING_STARTED, onRecordingStarted);
|
||||
}
|
||||
|
||||
function* testRecordingSucceedingInWindow(index) {
|
||||
let { panel } = gPanelWinTuples[index];
|
||||
let { EVENTS, PerformanceController } = panel.panelWin;
|
||||
|
||||
let onRecordingFailed = () => {
|
||||
ok(false, "Recording should start while now private windows are present.");
|
||||
};
|
||||
|
||||
PerformanceController.on(EVENTS.NEW_RECORDING_FAILED, onRecordingFailed);
|
||||
|
||||
yield startRecording(panel);
|
||||
yield stopRecording(panel);
|
||||
ok(true, "Recording has succeeded.");
|
||||
|
||||
PerformanceController.off(EVENTS.RECORDING_STARTED, onRecordingFailed);
|
||||
}
|
||||
|
||||
function* teardownPerfInWindow(index) {
|
||||
let { panel, win } = gPanelWinTuples[index];
|
||||
yield teardown(panel, win);
|
||||
win.close();
|
||||
}
|
@ -105,6 +105,29 @@ registerCleanupFunction(() => {
|
||||
Cu.forceGC();
|
||||
});
|
||||
|
||||
|
||||
function whenDelayedStartupFinished(aWindow, aCallback) {
|
||||
Services.obs.addObserver(function observer(aSubject, aTopic) {
|
||||
if (aWindow == aSubject) {
|
||||
Services.obs.removeObserver(observer, aTopic);
|
||||
executeSoon(aCallback);
|
||||
}
|
||||
}, "browser-delayed-startup-finished", false);
|
||||
}
|
||||
|
||||
function addWindow(windowOptions) {
|
||||
let deferred = Promise.defer();
|
||||
let win = OpenBrowserWindow(windowOptions);
|
||||
|
||||
whenDelayedStartupFinished(win, () => {
|
||||
executeSoon(() => {
|
||||
deferred.resolve(win);
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function addTab(aUrl, aWindow) {
|
||||
info("Adding tab: " + aUrl);
|
||||
|
||||
@ -233,6 +256,8 @@ function initPerformance(aUrl, tool="performance", targetOps={}) {
|
||||
// Wait for the performance tool to be spun up
|
||||
yield toolbox.initPerformance();
|
||||
|
||||
// Panel is already initialized after `showToolbox` and `initPerformance`,
|
||||
// no need to wait for `open` here.
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
return { target, panel, toolbox };
|
||||
});
|
||||
@ -276,12 +301,12 @@ function consoleExecute (console, method, val) {
|
||||
return promise;
|
||||
}
|
||||
|
||||
function* teardown(panel) {
|
||||
function* teardown(panel, win = window) {
|
||||
info("Destroying the performance tool.");
|
||||
|
||||
let tab = panel.target.tab;
|
||||
yield panel._toolbox.destroy();
|
||||
yield removeTab(tab);
|
||||
yield removeTab(tab, win);
|
||||
}
|
||||
|
||||
function idleWait(time) {
|
||||
|
@ -107,10 +107,19 @@ var PerformanceActor = exports.PerformanceActor = protocol.ActorClass({
|
||||
response: RetVal("json")
|
||||
}),
|
||||
|
||||
canCurrentlyRecord: method(function() {
|
||||
return this.bridge.canCurrentlyRecord();
|
||||
}, {
|
||||
response: { value: RetVal("json") }
|
||||
}),
|
||||
|
||||
startRecording: method(Task.async(function *(options={}) {
|
||||
if (!this.bridge.canCurrentlyRecord().success) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let normalizedOptions = normalizePerformanceFeatures(options, this.traits.features);
|
||||
let recording = yield this.bridge.startRecording(normalizedOptions);
|
||||
|
||||
this.manage(recording);
|
||||
|
||||
return recording;
|
||||
@ -118,14 +127,18 @@ var PerformanceActor = exports.PerformanceActor = protocol.ActorClass({
|
||||
request: {
|
||||
options: Arg(0, "nullable:json"),
|
||||
},
|
||||
response: RetVal("performance-recording"),
|
||||
response: {
|
||||
recording: RetVal("nullable:performance-recording")
|
||||
}
|
||||
}),
|
||||
|
||||
stopRecording: actorBridge("stopRecording", {
|
||||
request: {
|
||||
options: Arg(0, "performance-recording"),
|
||||
},
|
||||
response: RetVal("performance-recording"),
|
||||
response: {
|
||||
recording: RetVal("performance-recording")
|
||||
}
|
||||
}),
|
||||
|
||||
isRecording: actorBridge("isRecording", {
|
||||
|
@ -282,6 +282,25 @@ const PerformanceRecorder = exports.PerformanceRecorder = Class({
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks whether or not recording is currently supported. At the moment,
|
||||
* this is only influenced by private browsing mode and the profiler.
|
||||
*/
|
||||
canCurrentlyRecord: function() {
|
||||
let success = true;
|
||||
let reasons = [];
|
||||
|
||||
if (!Profiler.canProfile()) {
|
||||
success = false,
|
||||
reasons.push("profiler-unavailable");
|
||||
}
|
||||
|
||||
// Check other factors that will affect the possibility of successfully
|
||||
// starting a recording here.
|
||||
|
||||
return { success, reasons };
|
||||
},
|
||||
|
||||
/**
|
||||
* Begins a recording session
|
||||
*
|
||||
|
@ -55,7 +55,10 @@ const ProfilerManager = (function () {
|
||||
* The nsIProfiler is target agnostic and interacts with the whole platform.
|
||||
* Therefore, special care needs to be given to make sure different profiler
|
||||
* consumers (i.e. "toolboxes") don't interfere with each other. Register
|
||||
* the instance here.
|
||||
* the profiler actor instances here.
|
||||
*
|
||||
* @param Profiler instance
|
||||
* A profiler actor class.
|
||||
*/
|
||||
addInstance: function (instance) {
|
||||
consumers.add(instance);
|
||||
@ -64,6 +67,12 @@ const ProfilerManager = (function () {
|
||||
this.registerEventListeners();
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the profiler actor instances here.
|
||||
*
|
||||
* @param Profiler instance
|
||||
* A profiler actor class.
|
||||
*/
|
||||
removeInstance: function (instance) {
|
||||
consumers.delete(instance);
|
||||
|
||||
@ -101,25 +110,36 @@ const ProfilerManager = (function () {
|
||||
// interested in.
|
||||
let currentTime = nsIProfilerModule.getElapsedTime();
|
||||
|
||||
nsIProfilerModule.StartProfiler(
|
||||
config.entries,
|
||||
config.interval,
|
||||
config.features,
|
||||
config.features.length,
|
||||
config.threadFilters,
|
||||
config.threadFilters.length
|
||||
);
|
||||
let { position, totalSize, generation } = this.getBufferInfo();
|
||||
try {
|
||||
nsIProfilerModule.StartProfiler(
|
||||
config.entries,
|
||||
config.interval,
|
||||
config.features,
|
||||
config.features.length,
|
||||
config.threadFilters,
|
||||
config.threadFilters.length
|
||||
);
|
||||
} catch (e) {
|
||||
// For some reason, the profiler couldn't be started. This could happen,
|
||||
// for example, when in private browsing mode.
|
||||
Cu.reportError(`Could not start the profiler module: ${e.message}`);
|
||||
return { started: false, reason: e, currentTime };
|
||||
}
|
||||
|
||||
this._updateProfilerStatusPolling();
|
||||
|
||||
let { position, totalSize, generation } = this.getBufferInfo();
|
||||
return { started: true, position, totalSize, generation, currentTime };
|
||||
},
|
||||
|
||||
/**
|
||||
* Attempts to stop the nsIProfiler module.
|
||||
*/
|
||||
stop: function () {
|
||||
// Actually stop the profiler only if the last client has stopped profiling.
|
||||
// Since this is used as a root actor, and the profiler module interacts with the
|
||||
// whole platform, we need to avoid a case in which the profiler is stopped
|
||||
// when there might be other clients still profiling.
|
||||
// Since this is used as a root actor, and the profiler module interacts
|
||||
// with the whole platform, we need to avoid a case in which the profiler
|
||||
// is stopped when there might be other clients still profiling.
|
||||
if (this.length <= 1) {
|
||||
nsIProfilerModule.StopProfiler();
|
||||
}
|
||||
@ -306,7 +326,8 @@ const ProfilerManager = (function () {
|
||||
*/
|
||||
unregisterEventListeners: function () {
|
||||
if (this._eventsRegistered) {
|
||||
PROFILER_SYSTEM_EVENTS.forEach(eventName => Services.obs.removeObserver(this, eventName));
|
||||
PROFILER_SYSTEM_EVENTS.forEach(eventName =>
|
||||
Services.obs.removeObserver(this, eventName));
|
||||
this._eventsRegistered = false;
|
||||
}
|
||||
},
|
||||
@ -482,6 +503,14 @@ var Profiler = exports.Profiler = Class({
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks whether or not the profiler module can currently run.
|
||||
* @return boolean
|
||||
*/
|
||||
Profiler.canProfile = function() {
|
||||
return nsIProfilerModule.CanProfile();
|
||||
};
|
||||
|
||||
/**
|
||||
* JSON.stringify callback used in Profiler.prototype.observe.
|
||||
*/
|
||||
|
@ -2,7 +2,7 @@
|
||||
/* 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"
|
||||
|
||||
%{C++
|
||||
@ -12,9 +12,10 @@ class nsCString;
|
||||
|
||||
[ref] native StringArrayRef(const nsTArray<nsCString>);
|
||||
|
||||
[scriptable, uuid(921e1223-b1ea-4906-bb26-a846e6b6835b)]
|
||||
[scriptable, uuid(ff398a14-df1c-4966-9ab2-772ea6a6da6c)]
|
||||
interface nsIProfiler : nsISupports
|
||||
{
|
||||
boolean CanProfile();
|
||||
void StartProfiler(in uint32_t aEntries, in double aInterval,
|
||||
[array, size_is(aFeatureCount)] in string aFeatures,
|
||||
in uint32_t aFeatureCount,
|
||||
|
@ -70,6 +70,13 @@ nsProfiler::Observe(nsISupports *aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProfiler::CanProfile(bool *aCanProfile)
|
||||
{
|
||||
*aCanProfile = !mLockedForPrivateBrowsing;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProfiler::StartProfiler(uint32_t aEntries, double aInterval,
|
||||
const char** aFeatures, uint32_t aFeatureCount,
|
||||
|
Loading…
Reference in New Issue
Block a user