forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			211 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* -*- 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/. */
 | |
| 
 | |
| import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
 | |
| 
 | |
| const lazy = {};
 | |
| 
 | |
| ChromeUtils.defineESModuleGetters(lazy, {
 | |
|   CrashSubmit: "resource://gre/modules/CrashSubmit.sys.mjs",
 | |
| });
 | |
| 
 | |
| ChromeUtils.defineLazyGetter(lazy, "gNavigatorBundle", function () {
 | |
|   const url = "chrome://browser/locale/browser.properties";
 | |
|   return Services.strings.createBundle(url);
 | |
| });
 | |
| 
 | |
| export const PluginManager = {
 | |
|   gmpCrashes: new Map(),
 | |
| 
 | |
|   observe(subject, topic, data) {
 | |
|     switch (topic) {
 | |
|       case "gmp-plugin-crash":
 | |
|         this._registerGMPCrash(subject);
 | |
|         break;
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   _registerGMPCrash(subject) {
 | |
|     let propertyBag = subject;
 | |
|     if (
 | |
|       !(propertyBag instanceof Ci.nsIWritablePropertyBag2) ||
 | |
|       !propertyBag.hasKey("pluginID") ||
 | |
|       !propertyBag.hasKey("pluginDumpID") ||
 | |
|       !propertyBag.hasKey("pluginName")
 | |
|     ) {
 | |
|       console.error("PluginManager can not read plugin information.");
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     let pluginID = propertyBag.getPropertyAsUint32("pluginID");
 | |
|     let pluginDumpID = propertyBag.getPropertyAsAString("pluginDumpID");
 | |
|     let pluginName = propertyBag.getPropertyAsACString("pluginName");
 | |
|     if (pluginDumpID) {
 | |
|       this.gmpCrashes.set(pluginID, { pluginDumpID, pluginID, pluginName });
 | |
|     }
 | |
| 
 | |
|     // Only the parent process gets the gmp-plugin-crash observer
 | |
|     // notification, so we need to inform any content processes that
 | |
|     // the GMP has crashed. This then fires PluginCrashed events in
 | |
|     // all the relevant windows, which will trigger child actors being
 | |
|     // created, which will contact us again, when we'll use the
 | |
|     // gmpCrashes collection to respond.
 | |
|     if (Services.ppmm) {
 | |
|       Services.ppmm.broadcastAsyncMessage("gmp-plugin-crash", {
 | |
|         pluginName,
 | |
|         pluginID,
 | |
|       });
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Submit a crash report for a crashed plugin.
 | |
|    *
 | |
|    * @param pluginCrashID
 | |
|    *        An object with a pluginID.
 | |
|    * @param keyVals
 | |
|    *        An object whose key-value pairs will be merged
 | |
|    *        with the ".extra" file submitted with the report.
 | |
|    *        The properties of htis object will override properties
 | |
|    *        of the same name in the .extra file.
 | |
|    */
 | |
|   submitCrashReport(pluginCrashID, keyVals = {}) {
 | |
|     let report = this.getCrashReport(pluginCrashID);
 | |
|     if (!report) {
 | |
|       console.error(
 | |
|         `Could not find plugin dump IDs for ${JSON.stringify(pluginCrashID)}.` +
 | |
|           `It is possible that a report was already submitted.`
 | |
|       );
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     let { pluginDumpID } = report;
 | |
|     lazy.CrashSubmit.submit(
 | |
|       pluginDumpID,
 | |
|       lazy.CrashSubmit.SUBMITTED_FROM_CRASH_TAB,
 | |
|       {
 | |
|         recordSubmission: true,
 | |
|         extraExtraKeyVals: keyVals,
 | |
|       }
 | |
|     );
 | |
| 
 | |
|     this.gmpCrashes.delete(pluginCrashID.pluginID);
 | |
|   },
 | |
| 
 | |
|   getCrashReport(pluginCrashID) {
 | |
|     return this.gmpCrashes.get(pluginCrashID.pluginID);
 | |
|   },
 | |
| };
 | |
| 
 | |
| export class PluginParent extends JSWindowActorParent {
 | |
|   receiveMessage(msg) {
 | |
|     let browser = this.manager.rootFrameLoader.ownerElement;
 | |
|     switch (msg.name) {
 | |
|       case "PluginContent:ShowPluginCrashedNotification":
 | |
|         this.showPluginCrashedNotification(browser, msg.data.pluginCrashID);
 | |
|         break;
 | |
| 
 | |
|       default:
 | |
|         console.error(
 | |
|           "PluginParent did not expect to handle message ",
 | |
|           msg.name
 | |
|         );
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Shows a plugin-crashed notification bar for a browser that has had a
 | |
|    * GMP plugin crash.
 | |
|    *
 | |
|    * @param browser
 | |
|    *        The browser to show the notification for.
 | |
|    * @param pluginCrashID
 | |
|    *        The unique-per-process identifier for GMP.
 | |
|    */
 | |
|   showPluginCrashedNotification(browser, pluginCrashID) {
 | |
|     // If there's already an existing notification bar, don't do anything.
 | |
|     let notificationBox = browser.getTabBrowser().getNotificationBox(browser);
 | |
|     let notification =
 | |
|       notificationBox.getNotificationWithValue("plugin-crashed");
 | |
| 
 | |
|     let report = PluginManager.getCrashReport(pluginCrashID);
 | |
|     if (notification || !report) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // Configure the notification bar
 | |
|     let priority = notificationBox.PRIORITY_WARNING_MEDIUM;
 | |
|     let iconURL = "chrome://global/skin/icons/plugin.svg";
 | |
|     let reloadLabel = lazy.gNavigatorBundle.GetStringFromName(
 | |
|       "crashedpluginsMessage.reloadButton.label"
 | |
|     );
 | |
|     let reloadKey = lazy.gNavigatorBundle.GetStringFromName(
 | |
|       "crashedpluginsMessage.reloadButton.accesskey"
 | |
|     );
 | |
| 
 | |
|     let buttons = [
 | |
|       {
 | |
|         label: reloadLabel,
 | |
|         accessKey: reloadKey,
 | |
|         popup: null,
 | |
|         callback() {
 | |
|           browser.reload();
 | |
|         },
 | |
|       },
 | |
|     ];
 | |
| 
 | |
|     if (AppConstants.MOZ_CRASHREPORTER) {
 | |
|       let submitLabel = lazy.gNavigatorBundle.GetStringFromName(
 | |
|         "crashedpluginsMessage.submitButton.label"
 | |
|       );
 | |
|       let submitKey = lazy.gNavigatorBundle.GetStringFromName(
 | |
|         "crashedpluginsMessage.submitButton.accesskey"
 | |
|       );
 | |
|       let submitButton = {
 | |
|         label: submitLabel,
 | |
|         accessKey: submitKey,
 | |
|         popup: null,
 | |
|         callback: () => {
 | |
|           PluginManager.submitCrashReport(pluginCrashID);
 | |
|         },
 | |
|       };
 | |
| 
 | |
|       buttons.push(submitButton);
 | |
|     }
 | |
| 
 | |
|     let messageString = lazy.gNavigatorBundle.formatStringFromName(
 | |
|       "crashedpluginsMessage.title",
 | |
|       [report.pluginName]
 | |
|     );
 | |
|     notification = notificationBox.appendNotification(
 | |
|       "plugin-crashed",
 | |
|       {
 | |
|         label: messageString,
 | |
|         image: iconURL,
 | |
|         priority,
 | |
|       },
 | |
|       buttons
 | |
|     );
 | |
| 
 | |
|     // Add the "learn more" link.
 | |
|     let link = notification.ownerDocument.createXULElement("label", {
 | |
|       is: "text-link",
 | |
|     });
 | |
|     link.setAttribute(
 | |
|       "value",
 | |
|       lazy.gNavigatorBundle.GetStringFromName("crashedpluginsMessage.learnMore")
 | |
|     );
 | |
|     let crashurl = Services.urlFormatter.formatURLPref("app.support.baseURL");
 | |
|     crashurl += "plugin-crashed-notificationbar";
 | |
|     link.href = crashurl;
 | |
|     // Append a blank text node to make sure we don't put
 | |
|     // the link right next to the end of the message text.
 | |
|     notification.messageText.appendChild(new Text(" "));
 | |
|     notification.messageText.appendChild(link);
 | |
|   }
 | |
| }
 | 
