Bug 1497264 - Split addon/webextension.js into webextension.js and webextension-proxy.js;r=ochameau,yulia
authorJulian Descottes <jdescottes@mozilla.com>
Tue, 08 Jan 2019 18:18:14 +0000
changeset 510061 e62e0dfddefe6a582c72c52071742bbc9f3865b0
parent 510060 033f84c32bce3df3cd0ffd487673463c09bda3cf
child 510062 1898dd0aeab9facb23b0ec8fd4f7a4aa5b994fa3
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersochameau, yulia
bugs1497264
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1497264 - Split addon/webextension.js into webextension.js and webextension-proxy.js;r=ochameau,yulia Depends on D15384 Differential Revision: https://phabricator.services.mozilla.com/D15385
devtools/server/actors/addon/webextension.js
devtools/server/actors/targets/moz.build
devtools/server/actors/targets/webextension-proxy.js
--- a/devtools/server/actors/addon/webextension.js
+++ b/devtools/server/actors/addon/webextension.js
@@ -7,19 +7,19 @@
 /*
  * Represents a WebExtension add-on in the parent process. This gives some metadata about
  * the add-on and watches for uninstall events. This uses a proxy to access the
  * WebExtension in the WebExtension process via the message manager.
  *
  * See devtools/docs/backend/actor-hierarchy.md for more details.
  */
 
-const {DebuggerServer} = require("devtools/server/main");
 const protocol = require("devtools/shared/protocol");
-const {webExtensionSpec} = require("devtools/shared/specs/addon/webextension");
+const { webExtensionSpec } = require("devtools/shared/specs/addon/webextension");
+const { WebExtensionTargetActorProxy } = require("devtools/server/actors/targets/webextension-proxy");
 
 loader.lazyImporter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
 loader.lazyImporter(this, "ExtensionParent", "resource://gre/modules/ExtensionParent.jsm");
 
 /**
  * Creates the actor that represents the addon in the parent process, which connects
  * itself to a WebExtensionTargetActor counterpart which is created in the extension
  * process (or in the main process if the WebExtensions OOP mode is disabled).
@@ -173,89 +173,8 @@ const WebExtensionActor = protocol.Actor
       return;
     }
 
     this.destroy();
   },
 });
 
 exports.WebExtensionActor = WebExtensionActor;
-
-function WebExtensionTargetActorProxy(connection, parentActor) {
-  this._conn = connection;
-  this._parentActor = parentActor;
-  this.addonId = parentActor.addonId;
-
-  this._onChildExit = this._onChildExit.bind(this);
-
-  this._form = null;
-  this._browser = null;
-  this._childActorID = null;
-}
-
-WebExtensionTargetActorProxy.prototype = {
-  /**
-   * Connect the webextension child actor.
-   */
-  async connect() {
-    if (this._browser) {
-      throw new Error("This actor is already connected to the extension process");
-    }
-
-    // Called when the debug browser element has been destroyed
-    // (no actor is using it anymore to connect the child extension process).
-    const onDestroy = this.destroy.bind(this);
-
-    this._browser = await ExtensionParent.DebugUtils.getExtensionProcessBrowser(this);
-
-    this._form = await DebuggerServer.connectToFrame(this._conn, this._browser, onDestroy,
-                                                     {addonId: this.addonId});
-
-    this._childActorID = this._form.actor;
-
-    // Exit the proxy child actor if the child actor has been destroyed.
-    this._mm.addMessageListener("debug:webext_child_exit", this._onChildExit);
-
-    return this._form;
-  },
-
-  get isOOP() {
-    return this._browser ? this._browser.isRemoteBrowser : undefined;
-  },
-
-  get _mm() {
-    return this._browser && (
-      this._browser.messageManager ||
-      this._browser.frameLoader.messageManager);
-  },
-
-  destroy() {
-    if (this._mm) {
-      this._mm.removeMessageListener("debug:webext_child_exit", this._onChildExit);
-
-      this._mm.sendAsyncMessage("debug:webext_parent_exit", {
-        actor: this._childActorID,
-      });
-
-      ExtensionParent.DebugUtils.releaseExtensionProcessBrowser(this);
-    }
-
-    if (this._parentActor) {
-      this._parentActor.onProxyDestroy();
-    }
-
-    this._parentActor = null;
-    this._browser = null;
-    this._childActorID = null;
-    this._form = null;
-  },
-
-  /**
-   * Handle the child actor exit.
-   */
-  _onChildExit(msg) {
-    if (msg.json.actor !== this._childActorID) {
-      return;
-    }
-
-    this.destroy();
-  },
-};
--- a/devtools/server/actors/targets/moz.build
+++ b/devtools/server/actors/targets/moz.build
@@ -6,11 +6,12 @@
 
 DevToolsModules(
     'browsing-context.js',
     'chrome-window.js',
     'content-process.js',
     'frame-proxy.js',
     'frame.js',
     'parent-process.js',
+    'webextension-proxy.js',
     'webextension.js',
     'worker.js',
 )
copy from devtools/server/actors/addon/webextension.js
copy to devtools/server/actors/targets/webextension-proxy.js
--- a/devtools/server/actors/addon/webextension.js
+++ b/devtools/server/actors/targets/webextension-proxy.js
@@ -1,188 +1,17 @@
 /* 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";
 
-/*
- * Represents a WebExtension add-on in the parent process. This gives some metadata about
- * the add-on and watches for uninstall events. This uses a proxy to access the
- * WebExtension in the WebExtension process via the message manager.
- *
- * See devtools/docs/backend/actor-hierarchy.md for more details.
- */
-
 const {DebuggerServer} = require("devtools/server/main");
-const protocol = require("devtools/shared/protocol");
-const {webExtensionSpec} = require("devtools/shared/specs/addon/webextension");
-
-loader.lazyImporter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
-loader.lazyImporter(this, "ExtensionParent", "resource://gre/modules/ExtensionParent.jsm");
-
-/**
- * Creates the actor that represents the addon in the parent process, which connects
- * itself to a WebExtensionTargetActor counterpart which is created in the extension
- * process (or in the main process if the WebExtensions OOP mode is disabled).
- *
- * The WebExtensionActor subscribes itself as an AddonListener on the AddonManager
- * and forwards this events to child actor (e.g. on addon reload or when the addon is
- * uninstalled completely) and connects to the child extension process using a `browser`
- * element provided by the extension internals (it is not related to any single extension,
- * but it will be created automatically to the currently selected "WebExtensions OOP mode"
- * and it persist across the extension reloads (it is destroyed once the actor exits).
- * WebExtensionActor is a child of RootActor, it can be retrieved via
- * RootActor.listAddons request.
- *
- * @param {DebuggerServerConnection} conn
- *        The connection to the client.
- * @param {AddonWrapper} addon
- *        The target addon.
- */
-const WebExtensionActor = protocol.ActorClassWithSpec(webExtensionSpec, {
-  initialize(conn, addon) {
-    this.conn = conn;
-    this.addon = addon;
-    this.addonId = addon.id;
-    this._childFormPromise = null;
-
-    AddonManager.addAddonListener(this);
-  },
-
-  destroy() {
-    AddonManager.removeAddonListener(this);
-
-    this.addon = null;
-    this._childFormPromise = null;
-
-    if (this._destroyProxy) {
-      this._destroyProxy();
-      delete this._destroyProxy;
-    }
-  },
-
-  reload() {
-    return this.addon.reload().then(() => {
-      return {};
-    });
-  },
-
-  form() {
-    const policy = ExtensionParent.WebExtensionPolicy.getByID(this.addonId);
-    return {
-      actor: this.actorID,
-      id: this.addonId,
-      name: this.addon.name,
-      url: this.addon.sourceURI ? this.addon.sourceURI.spec : undefined,
-      // iconDataURL is available after calling loadIconDataURL
-      iconDataURL: this._iconDataURL,
-      iconURL: this.addon.iconURL,
-      isSystem: this.addon.isSystem,
-      debuggable: this.addon.isDebuggable,
-      temporarilyInstalled: this.addon.temporarilyInstalled,
-      type: this.addon.type,
-      isWebExtension: this.addon.isWebExtension,
-      isAPIExtension: this.addon.isAPIExtension,
-      manifestURL: policy && policy.getURL("manifest.json"),
-      warnings: ExtensionParent.DebugUtils.getExtensionManifestWarnings(this.addonId),
-    };
-  },
 
-  connect() {
-    if (this._childFormPormise) {
-      return this._childFormPromise;
-    }
-
-    const proxy = new WebExtensionTargetActorProxy(this.conn, this);
-    this._childFormPromise = proxy.connect().then(form => {
-      // Merge into the child actor form, some addon metadata
-      // (e.g. the addon name shown in the addon debugger window title).
-      return Object.assign(form, {
-        id: this.addon.id,
-        name: this.addon.name,
-        iconURL: this.addon.iconURL,
-        // Set the isOOP attribute on the connected child actor form.
-        isOOP: proxy.isOOP,
-      });
-    });
-    this._destroyProxy = () => proxy.destroy();
-
-    return this._childFormPromise;
-  },
-
-  // This function will be called from RootActor in case that the debugger client
-  // retrieves list of addons with `iconDataURL` option.
-  async loadIconDataURL() {
-    this._iconDataURL = await this.getIconDataURL();
-  },
-
-  async getIconDataURL() {
-    if (!this.addon.iconURL) {
-      return null;
-    }
-
-    const xhr = new XMLHttpRequest();
-    xhr.responseType = "blob";
-    xhr.open("GET", this.addon.iconURL, true);
-
-    if (this.addon.iconURL.toLowerCase().endsWith(".svg")) {
-      // Maybe SVG, thus force to change mime type.
-      xhr.overrideMimeType("image/svg+xml");
-    }
-
-    try {
-      const blob = await new Promise((resolve, reject) => {
-        xhr.onload = () => resolve(xhr.response);
-        xhr.onerror = reject;
-        xhr.send();
-      });
-
-      const reader = new FileReader();
-      return await new Promise((resolve, reject) => {
-        reader.onloadend = () => resolve(reader.result);
-        reader.onerror = reject;
-        reader.readAsDataURL(blob);
-      });
-    } catch (_) {
-      console.warn(`Failed to create data url from [${ this.addon.iconURL }]`);
-      return null;
-    }
-  },
-
-  // WebExtensionTargetActorProxy callbacks.
-
-  onProxyDestroy() {
-    // Invalidate the cached child actor and form Promise
-    // if the child actor exits.
-    this._childFormPromise = null;
-    delete this._destroyProxy;
-  },
-
-  // AddonManagerListener callbacks.
-
-  onInstalled(addon) {
-    if (addon.id != this.addonId) {
-      return;
-    }
-
-    // Update the AddonManager's addon object on reload/update.
-    this.addon = addon;
-  },
-
-  onUninstalled(addon) {
-    if (addon != this.addon) {
-      return;
-    }
-
-    this.destroy();
-  },
-});
-
-exports.WebExtensionActor = WebExtensionActor;
+loader.lazyImporter(this, "ExtensionParent", "resource://gre/modules/ExtensionParent.jsm");
 
 function WebExtensionTargetActorProxy(connection, parentActor) {
   this._conn = connection;
   this._parentActor = parentActor;
   this.addonId = parentActor.addonId;
 
   this._onChildExit = this._onChildExit.bind(this);
 
@@ -254,8 +83,11 @@ WebExtensionTargetActorProxy.prototype =
   _onChildExit(msg) {
     if (msg.json.actor !== this._childActorID) {
       return;
     }
 
     this.destroy();
   },
 };
+
+exports.WebExtensionTargetActorProxy = WebExtensionTargetActorProxy;
+