Commit f0ec628a authored by Greg Tatum's avatar Greg Tatum
Browse files

Bug 1582779 - Offer to restart the browser when JS Tracer is enabled; r=julienw

To test this feature, check the "JSTracer" feature, and the user should be
prompted with a message bar to restart the browser. This will then set the
proper environment variable. Unfortunately, currently the user can still do
this even if a feature is not available in the build. See Bug 1585659.

Differential Revision: https://phabricator.services.mozilla.com/D50085

--HG--
extra : moz-landing-system : lando
parent 8b60bbd4
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -77,6 +77,11 @@ declare namespace MockedExports {
      activeWindow: ChromeWindow;
    };
    scriptSecurityManager: any;
    startup: {
      quit: (optionsBitmask: number) => void,
      eForceQuit: number,
      eRestart: number
    };
  };

  const ServicesJSM: {
@@ -123,6 +128,8 @@ declare namespace MockedExports {
  };

  const Services: Services;

  const chrome: any;
}

declare module "devtools/shared/event-emitter2" {
@@ -137,6 +144,10 @@ declare module "Services" {
  export = MockedExports.Services;
}

declare module "chrome" {
  export = MockedExports.chrome;
}

declare module "resource://gre/modules/osfile.jsm" {
  export = MockedExports.osfileJSM;
}
+15 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ export interface State {
  threads: string[];
  objdirs: string[];
  initializedValues: InitializedValues | null;
  promptEnvRestart: null | string
}

export type Selector<T> = (state: State) => T;
@@ -137,6 +138,19 @@ export type ReceiveProfile = (

export type SetRecordingPreferences = (settings: object) => void;

/**
 * This is the type signature for a function to restart the browser with a given
 * environment variable. Currently only implemented for the popup.
 */
export type RestartBrowserWithEnvironmentVariable =
    (envName: string, value: string) => void;

/**
 * This is the type signature for a function to query the browser for an
 * environment variable. Currently only implemented for the popup.
 */
export type GetEnvironmentVariable = (envName: string) => string;

/**
 * This interface is injected into profiler.firefox.com
 */
@@ -202,6 +216,7 @@ export type Action =
  | {
      type: "CHANGE_FEATURES";
      features: string[];
      promptEnvRestart: string | null
    }
  | {
      type: "CHANGE_THREADS";
+37 −0
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
 * @typedef {import("./@types/perf").PreferenceFront} PreferenceFront
 * @typedef {import("./@types/perf").PerformancePref} PerformancePref
 * @typedef {import("./@types/perf").RecordingStateFromPreferences} RecordingStateFromPreferences
 * @typedef {import("./@types/perf").RestartBrowserWithEnvironmentVariable} RestartBrowserWithEnvironmentVariable
 * @typedef {import("./@types/perf").GetEnvironmentVariable} GetEnvironmentVariable
 */

/**
@@ -40,6 +42,8 @@ const lazyServices = requireLazy(() =>
  require("resource://gre/modules/Services.jsm")
);

const lazyChrome = requireLazy(() => require("chrome"));

const lazyOS = requireLazy(() => require("resource://gre/modules/osfile.jsm"));

const lazyProfilerGetSymbols = requireLazy(() =>
@@ -488,9 +492,42 @@ function createMultiModalGetSymbolTableFn(profile, getObjdirs, perfFront) {
  };
}

/**
 * Restarts the browser with a given environment variable set to a value.
 *
 * @type {RestartBrowserWithEnvironmentVariable}
 */
function restartBrowserWithEnvironmentVariable(envName, value) {
  const { Services } = lazyServices();
  const { Cc, Ci } = lazyChrome();
  const env = Cc["@mozilla.org/process/environment;1"].getService(
    Ci.nsIEnvironment
  );
  env.set(envName, value);

  Services.startup.quit(
    Services.startup.eForceQuit | Services.startup.eRestart
  );
}

/**
 * Gets an environment variable from the browser.
 *
 * @type {GetEnvironmentVariable}
 */
function getEnvironmentVariable(envName) {
  const { Cc, Ci } = lazyChrome();
  const env = Cc["@mozilla.org/process/environment;1"].getService(
    Ci.nsIEnvironment
  );
  return env.get(envName);
}

module.exports = {
  receiveProfile,
  getRecordingPreferencesFromDebuggee,
  setRecordingPreferencesOnDebuggee,
  createMultiModalGetSymbolTableFn,
  restartBrowserWithEnvironmentVariable,
  getEnvironmentVariable,
};
+42 −2
Original line number Diff line number Diff line
@@ -8,7 +8,10 @@ const {
  createFactory,
} = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { div } = require("devtools/client/shared/vendor/react-dom-factories");
const {
  div,
  button,
} = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const RecordingButton = createFactory(
  require("devtools/client/performance-new/components/RecordingButton.js")
@@ -21,6 +24,9 @@ const Description = createFactory(
);
const actions = require("devtools/client/performance-new/store/actions");
const selectors = require("devtools/client/performance-new/store/selectors");
const {
  restartBrowserWithEnvironmentVariable,
} = require("devtools/client/performance-new/browser");

/**
 * This is the top level component for initializing the performance recording panel.
@@ -41,6 +47,7 @@ class Perf extends PureComponent {
      recordingState: PropTypes.string.isRequired,
      isSupportedPlatform: PropTypes.bool,
      isPopup: PropTypes.bool,
      promptEnvRestart: PropTypes.string,

      // DispatchProps:
      changeRecordingState: PropTypes.func.isRequired,
@@ -58,6 +65,7 @@ class Perf extends PureComponent {
    this.handlePrivateBrowsingEnding = this.handlePrivateBrowsingEnding.bind(
      this
    );
    this.handleRestart = this.handleRestart.bind(this);
  }

  componentDidMount() {
@@ -244,8 +252,18 @@ class Perf extends PureComponent {
    this.props.changeRecordingState("available-to-record");
  }

  handleRestart() {
    const { promptEnvRestart } = this.props;
    if (!promptEnvRestart) {
      throw new Error(
        "handleRestart() should only be called when promptEnvRestart exists."
      );
    }
    restartBrowserWithEnvironmentVariable(promptEnvRestart, "1");
  }

  render() {
    const { isSupportedPlatform, isPopup } = this.props;
    const { isSupportedPlatform, isPopup, promptEnvRestart } = this.props;

    if (isSupportedPlatform === null) {
      // We don't know yet if this is a supported platform, wait for a response.
@@ -256,6 +274,27 @@ class Perf extends PureComponent {

    return div(
      { className: `perf ${additionalClassName}` },
      promptEnvRestart
        ? div(
            { className: "perf-env-restart" },
            div(
              {
                className:
                  "perf-photon-message-bar perf-photon-message-bar-warning perf-env-restart-fixed",
              },
              div({ className: "perf-photon-message-bar-warning-icon" }),
              "The browser must be restarted to enable this feature.",
              button(
                {
                  className: "perf-photon-button perf-photon-button-micro",
                  type: "button",
                  onClick: this.handleRestart,
                },
                "Restart"
              )
            )
          )
        : null,
      RecordingButton(),
      Settings(),
      isPopup ? null : Description()
@@ -269,6 +308,7 @@ function mapStateToProps(state) {
    recordingState: selectors.getRecordingState(state),
    isSupportedPlatform: selectors.getIsSupportedPlatform(state),
    isPopup: selectors.getIsPopup(state),
    promptEnvRestart: selectors.getPromptEnvRestart(state),
  };
}

+1 −1
Original line number Diff line number Diff line
@@ -184,7 +184,7 @@ const featureCheckboxes = [
  {
    name: "JSTracer",
    value: "jstracer",
    title: "Trace JS engine (Experimental, requires custom build.)",
    title: "Trace JS engine (Experimental.)",
  },
  {
    name: "Preference Read",
Loading