tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

PluginParent.sys.mjs (6019B)


      1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
      2 * This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
      7 
      8 const lazy = {};
      9 
     10 ChromeUtils.defineESModuleGetters(lazy, {
     11  CrashSubmit: "resource://gre/modules/CrashSubmit.sys.mjs",
     12 });
     13 
     14 ChromeUtils.defineLazyGetter(lazy, "gNavigatorBundle", function () {
     15  const url = "chrome://browser/locale/browser.properties";
     16  return Services.strings.createBundle(url);
     17 });
     18 
     19 export const PluginManager = {
     20  gmpCrashes: new Map(),
     21 
     22  observe(subject, topic) {
     23    switch (topic) {
     24      case "gmp-plugin-crash":
     25        this._registerGMPCrash(subject);
     26        break;
     27    }
     28  },
     29 
     30  _registerGMPCrash(subject) {
     31    let propertyBag = subject;
     32    if (
     33      !(propertyBag instanceof Ci.nsIWritablePropertyBag2) ||
     34      !propertyBag.hasKey("pluginID") ||
     35      !propertyBag.hasKey("pluginDumpID") ||
     36      !propertyBag.hasKey("pluginName")
     37    ) {
     38      console.error("PluginManager can not read plugin information.");
     39      return;
     40    }
     41 
     42    let pluginID = propertyBag.getPropertyAsUint32("pluginID");
     43    let pluginDumpID = propertyBag.getPropertyAsAString("pluginDumpID");
     44    let pluginName = propertyBag.getPropertyAsACString("pluginName");
     45    if (pluginDumpID) {
     46      this.gmpCrashes.set(pluginID, { pluginDumpID, pluginID, pluginName });
     47    }
     48 
     49    // Only the parent process gets the gmp-plugin-crash observer
     50    // notification, so we need to inform any content processes that
     51    // the GMP has crashed. This then fires PluginCrashed events in
     52    // all the relevant windows, which will trigger child actors being
     53    // created, which will contact us again, when we'll use the
     54    // gmpCrashes collection to respond.
     55    if (Services.ppmm) {
     56      Services.ppmm.broadcastAsyncMessage("gmp-plugin-crash", {
     57        pluginName,
     58        pluginID,
     59      });
     60    }
     61  },
     62 
     63  /**
     64   * Submit a crash report for a crashed plugin.
     65   *
     66   * @param pluginCrashID
     67   *        An object with a pluginID.
     68   * @param keyVals
     69   *        An object whose key-value pairs will be merged
     70   *        with the ".extra" file submitted with the report.
     71   *        The properties of htis object will override properties
     72   *        of the same name in the .extra file.
     73   */
     74  submitCrashReport(pluginCrashID, keyVals = {}) {
     75    let report = this.getCrashReport(pluginCrashID);
     76    if (!report) {
     77      console.error(
     78        `Could not find plugin dump IDs for ${JSON.stringify(pluginCrashID)}.` +
     79          `It is possible that a report was already submitted.`
     80      );
     81      return;
     82    }
     83 
     84    let { pluginDumpID } = report;
     85    lazy.CrashSubmit.submit(
     86      pluginDumpID,
     87      lazy.CrashSubmit.SUBMITTED_FROM_CRASH_TAB,
     88      {
     89        recordSubmission: true,
     90        extraExtraKeyVals: keyVals,
     91      }
     92    );
     93 
     94    this.gmpCrashes.delete(pluginCrashID.pluginID);
     95  },
     96 
     97  getCrashReport(pluginCrashID) {
     98    return this.gmpCrashes.get(pluginCrashID.pluginID);
     99  },
    100 };
    101 
    102 export class PluginParent extends JSWindowActorParent {
    103  receiveMessage(msg) {
    104    let browser = this.manager.rootFrameLoader.ownerElement;
    105    switch (msg.name) {
    106      case "PluginContent:ShowPluginCrashedNotification":
    107        this.showPluginCrashedNotification(browser, msg.data.pluginCrashID);
    108        break;
    109 
    110      default:
    111        console.error(
    112          "PluginParent did not expect to handle message ",
    113          msg.name
    114        );
    115        break;
    116    }
    117 
    118    return null;
    119  }
    120 
    121  /**
    122   * Shows a plugin-crashed notification bar for a browser that has had a
    123   * GMP plugin crash.
    124   *
    125   * @param browser
    126   *        The browser to show the notification for.
    127   * @param pluginCrashID
    128   *        The unique-per-process identifier for GMP.
    129   */
    130  showPluginCrashedNotification(browser, pluginCrashID) {
    131    // If there's already an existing notification bar, don't do anything.
    132    let notificationBox = browser.getTabBrowser().getNotificationBox(browser);
    133    let notification =
    134      notificationBox.getNotificationWithValue("plugin-crashed");
    135 
    136    let report = PluginManager.getCrashReport(pluginCrashID);
    137    if (notification || !report) {
    138      return;
    139    }
    140 
    141    // Configure the notification bar
    142    let priority = notificationBox.PRIORITY_WARNING_MEDIUM;
    143    let iconURL = "chrome://global/skin/icons/plugin.svg";
    144    let reloadLabel = lazy.gNavigatorBundle.GetStringFromName(
    145      "crashedpluginsMessage.reloadButton.label"
    146    );
    147    let reloadKey = lazy.gNavigatorBundle.GetStringFromName(
    148      "crashedpluginsMessage.reloadButton.accesskey"
    149    );
    150 
    151    let buttons = [
    152      {
    153        label: reloadLabel,
    154        accessKey: reloadKey,
    155        popup: null,
    156        callback() {
    157          browser.reload();
    158        },
    159      },
    160    ];
    161 
    162    if (AppConstants.MOZ_CRASHREPORTER) {
    163      let submitLabel = lazy.gNavigatorBundle.GetStringFromName(
    164        "crashedpluginsMessage.submitButton.label"
    165      );
    166      let submitKey = lazy.gNavigatorBundle.GetStringFromName(
    167        "crashedpluginsMessage.submitButton.accesskey"
    168      );
    169      let submitButton = {
    170        label: submitLabel,
    171        accessKey: submitKey,
    172        popup: null,
    173        callback: () => {
    174          PluginManager.submitCrashReport(pluginCrashID);
    175        },
    176      };
    177 
    178      buttons.push(submitButton);
    179    }
    180 
    181    // Add the "learn more" link.
    182    let learnMoreLink = {
    183      supportPage: "plugin-crashed-notificationbar",
    184      label: lazy.gNavigatorBundle.GetStringFromName(
    185        "crashedpluginsMessage.learnMore"
    186      ),
    187    };
    188    buttons.push(learnMoreLink);
    189 
    190    let messageString = lazy.gNavigatorBundle.formatStringFromName(
    191      "crashedpluginsMessage.title",
    192      [report.pluginName]
    193    );
    194    notificationBox.appendNotification(
    195      "plugin-crashed",
    196      {
    197        label: messageString,
    198        image: iconURL,
    199        priority,
    200      },
    201      buttons
    202    );
    203  }
    204 }