Bug 1369436, Load PushComponents.js after startup. r=lina
☠☠ backed out by e2f842a491c9 ☠ ☠
authorEmma Malysz <emalysz@mozilla.com>
Thu, 12 Sep 2019 16:53:55 +0000
changeset 492900 a956d11fef6eae7ba0f9fe2f5219ed9df3c9a713
parent 492899 615f56b6ae6eca410e1bf2473abccc9eb795f9c9
child 492901 ab9df6cf0f4fbd1073e776dfa89a79b8d9febf07
push id95223
push usermconley@mozilla.com
push dateThu, 12 Sep 2019 20:56:07 +0000
treeherderautoland@a956d11fef6e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslina
bugs1369436
milestone71.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 1369436, Load PushComponents.js after startup. r=lina Differential Revision: https://phabricator.services.mozilla.com/D45079
browser/base/content/test/performance/browser_startup.js
browser/components/BrowserGlue.jsm
dom/push/PushComponents.jsm
dom/push/PushCrypto.jsm
dom/push/PushService.jsm
dom/push/PushServiceAndroidGCM.jsm
dom/push/PushServiceHttp2.jsm
dom/push/PushServiceWebSocket.jsm
--- a/browser/base/content/test/performance/browser_startup.js
+++ b/browser/base/content/test/performance/browser_startup.js
@@ -31,18 +31,16 @@ const startupPhases = {
         "resource:///modules/BrowserGlue.jsm",
         "resource://gre/modules/AppConstants.jsm",
         "resource://gre/modules/ActorManagerParent.jsm",
         "resource://gre/modules/CustomElementsListener.jsm",
         "resource://gre/modules/ExtensionUtils.jsm",
         "resource://gre/modules/MainProcessSingleton.jsm",
         "resource://gre/modules/XPCOMUtils.jsm",
         "resource://gre/modules/Services.jsm",
-        // Bugs to fix: The following components shouldn't be initialized that early.
-        "resource://gre/modules/PushComponents.jsm", // bug 1369436
       ]),
     },
   },
 
   // For the following phases of startup we have only a black list for now
 
   // We are at this phase after creating the first browser window (ie. after final-ui-startup).
   "before opening first browser window": {
@@ -77,16 +75,17 @@ const startupPhases = {
   // We are at this phase once we are ready to handle user events.
   // Anything loaded at this phase or before gets in the way of the user
   // interacting with the first browser window.
   "before handling user events": {
     blacklist: {
       components: new Set([
         "PageIconProtocolHandler.js",
         "PlacesCategoriesStarter.js",
+        "PushComponents.jsm",
         "nsPlacesExpiration.js",
       ]),
       modules: new Set([
         // Bug 1391495 - BrowserWindowTracker.jsm is intermittently used.
         // "resource:///modules/BrowserWindowTracker.jsm",
         "resource://gre/modules/BookmarkHTMLUtils.jsm",
         "resource://gre/modules/Bookmarks.jsm",
         "resource://gre/modules/ContextualIdentityService.jsm",
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -15,16 +15,22 @@ const { AppConstants } = ChromeUtils.imp
 );
 
 ChromeUtils.defineModuleGetter(
   this,
   "ActorManagerParent",
   "resource://gre/modules/ActorManagerParent.jsm"
 );
 
+ChromeUtils.defineModuleGetter(
+  this,
+  "PushService",
+  "resource://gre/modules/PushService.jsm"
+);
+
 const PREF_PDFJS_ENABLED_CACHE_STATE = "pdfjs.enabledCache.state";
 
 let ACTORS = {
   BrowserTab: {
     parent: {
       moduleURI: "resource:///actors/BrowserTabParent.jsm",
     },
     child: {
@@ -1996,16 +2002,21 @@ BrowserGlue.prototype = {
    * to the other ones scheduled together.
    */
   _scheduleStartupIdleTasks() {
     Services.tm.idleDispatchToMainThread(async () => {
       await ContextualIdentityService.load();
       Discovery.update();
     });
 
+    // Begin listening for incoming push messages.
+    Services.tm.idleDispatchToMainThread(() => {
+      PushService.ensureReady();
+    });
+
     Services.tm.idleDispatchToMainThread(() => {
       let enableCertErrorUITelemetry = Services.prefs.getBoolPref(
         "security.certerrors.recordEventTelemetry",
         false
       );
       Services.telemetry.setEventRecordingEnabled(
         "security.ui.certerror",
         enableCertErrorUITelemetry
--- a/dom/push/PushComponents.jsm
+++ b/dom/push/PushComponents.jsm
@@ -64,41 +64,32 @@ PushServiceBase.prototype = {
     Ci.nsIPushQuotaManager,
     Ci.nsIPushErrorReporter,
   ]),
 
   pushTopic: OBSERVER_TOPIC_PUSH,
   subscriptionChangeTopic: OBSERVER_TOPIC_SUBSCRIPTION_CHANGE,
   subscriptionModifiedTopic: OBSERVER_TOPIC_SUBSCRIPTION_MODIFIED,
 
-  _handleReady() {},
+  ensureReady() {},
 
   _addListeners() {
     for (let message of this._messages) {
       this._mm.addMessageListener(message, this);
     }
   },
 
   _isValidMessage(message) {
     return this._messages.includes(message.name);
   },
 
   observe(subject, topic, data) {
-    if (topic === "app-startup") {
-      Services.obs.addObserver(this, "sessionstore-windows-restored", true);
-      return;
-    }
-    if (topic === "sessionstore-windows-restored") {
-      Services.obs.removeObserver(this, "sessionstore-windows-restored");
-      this._handleReady();
-      return;
-    }
     if (topic === "android-push-service") {
       // Load PushService immediately.
-      this._handleReady();
+      this.ensureReady();
     }
   },
 
   _deliverSubscription(request, props) {
     if (!props) {
       request.onPushSubscription(Cr.NS_OK, null);
       return;
     }
@@ -260,17 +251,17 @@ Object.assign(PushServiceParent.prototyp
             requestID: data.requestID,
             result: error.result,
           });
         }
       )
       .catch(Cu.reportError);
   },
 
-  _handleReady() {
+  ensureReady() {
     this.service.init();
   },
 
   _toPageRecord(principal, data) {
     if (!data.scope) {
       throw new Error("Invalid page record: missing scope");
     }
     if (!principal) {
--- a/dom/push/PushCrypto.jsm
+++ b/dom/push/PushCrypto.jsm
@@ -10,17 +10,17 @@ const { XPCOMUtils } = ChromeUtils.impor
 );
 
 XPCOMUtils.defineLazyGetter(this, "gDOMBundle", () =>
   Services.strings.createBundle("chrome://global/locale/dom/dom.properties")
 );
 
 XPCOMUtils.defineLazyGlobalGetters(this, ["crypto"]);
 
-const EXPORTED_SYMBOLS = ["PushCrypto", "concatArray"];
+const EXPORTED_SYMBOLS = ["PushCrypto"];
 
 const UTF8 = new TextEncoder("utf-8");
 
 const ECDH_KEY = { name: "ECDH", namedCurve: "P-256" };
 const ECDSA_KEY = { name: "ECDSA", namedCurve: "P-256" };
 const HMAC_SHA256 = { name: "HMAC", hash: "SHA-256" };
 const NONCE_INFO = UTF8.encode("Content-Encoding: nonce");
 
@@ -598,16 +598,18 @@ class aesgcm128Decoder extends OldScheme
   }
 
   get padSize() {
     return 1;
   }
 }
 
 var PushCrypto = {
+  concatArray,
+
   generateAuthenticationSecret() {
     return crypto.getRandomValues(new Uint8Array(16));
   },
 
   validateAppServerKey(key) {
     return crypto.subtle
       .importKey("raw", key, ECDSA_KEY, true, ["verify"])
       .then(_ => key);
--- a/dom/push/PushService.jsm
+++ b/dom/push/PushService.jsm
@@ -15,32 +15,16 @@ const { clearTimeout, setTimeout } = Chr
   "resource://gre/modules/Timer.jsm"
 );
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 
 var PushServiceWebSocket, PushServiceHttp2;
 
-const CONNECTION_PROTOCOLS = (function() {
-  if ("android" != AppConstants.MOZ_WIDGET_TOOLKIT) {
-    ({ PushServiceWebSocket } = ChromeUtils.import(
-      "resource://gre/modules/PushServiceWebSocket.jsm"
-    ));
-    ({ PushServiceHttp2 } = ChromeUtils.import(
-      "resource://gre/modules/PushServiceHttp2.jsm"
-    ));
-    return [PushServiceWebSocket, PushServiceHttp2];
-  }
-  const { PushServiceAndroidGCM } = ChromeUtils.import(
-    "resource://gre/modules/PushServiceAndroidGCM.jsm"
-  );
-  return [PushServiceAndroidGCM];
-})();
-
 XPCOMUtils.defineLazyServiceGetter(
   this,
   "gPushNotifier",
   "@mozilla.org/push/Notifier;1",
   "nsIPushNotifier"
 );
 XPCOMUtils.defineLazyServiceGetter(
   this,
@@ -53,16 +37,34 @@ ChromeUtils.defineModuleGetter(
   "pushBroadcastService",
   "resource://gre/modules/PushBroadcastService.jsm"
 );
 ChromeUtils.defineModuleGetter(
   this,
   "PushCrypto",
   "resource://gre/modules/PushCrypto.jsm"
 );
+ChromeUtils.defineModuleGetter(
+  this,
+  "PushServiceAndroidGCM",
+  "resource://gre/modules/PushServiceAndroidGCM.jsm"
+);
+
+const CONNECTION_PROTOCOLS = (function() {
+  if ("android" != AppConstants.MOZ_WIDGET_TOOLKIT) {
+    ({ PushServiceWebSocket } = ChromeUtils.import(
+      "resource://gre/modules/PushServiceWebSocket.jsm"
+    ));
+    ({ PushServiceHttp2 } = ChromeUtils.import(
+      "resource://gre/modules/PushServiceHttp2.jsm"
+    ));
+    return [PushServiceWebSocket, PushServiceHttp2];
+  }
+  return [PushServiceAndroidGCM];
+})();
 
 const EXPORTED_SYMBOLS = ["PushService"];
 
 XPCOMUtils.defineLazyGetter(this, "console", () => {
   let { ConsoleAPI } = ChromeUtils.import("resource://gre/modules/Console.jsm");
   return new ConsoleAPI({
     maxLogLevelPref: "dom.push.loglevel",
     prefix: "PushService",
@@ -95,16 +97,35 @@ const PUSH_SERVICE_RUNNING = 5;
  **/
 
 // This is for starting and stopping service.
 const STARTING_SERVICE_EVENT = 0;
 const CHANGING_SERVICE_EVENT = 1;
 const STOPPING_SERVICE_EVENT = 2;
 const UNINIT_EVENT = 3;
 
+// Returns the backend for the given server URI.
+function getServiceForServerURI(uri) {
+  // Insecure server URLs are allowed for development and testing.
+  let allowInsecure = prefs.get("testing.allowInsecureServerURL");
+  if (AppConstants.MOZ_WIDGET_TOOLKIT == "android") {
+    if (uri.scheme == "https" || (allowInsecure && uri.scheme == "http")) {
+      return CONNECTION_PROTOCOLS;
+    }
+    return null;
+  }
+  if (uri.scheme == "wss" || (allowInsecure && uri.scheme == "ws")) {
+    return PushServiceWebSocket;
+  }
+  if (uri.scheme == "https" || (allowInsecure && uri.scheme == "http")) {
+    return PushServiceHttp2;
+  }
+  return null;
+}
+
 /**
  * Annotates an error with an XPCOM result code. We use this helper
  * instead of `Components.Exception` because the latter can assert in
  * `nsXPCComponents_Exception::HasInstance` when inspected at shutdown.
  */
 function errorWithResult(message, result = Cr.NS_ERROR_FAILURE) {
   let error = new Error(message);
   error.result = result;
@@ -403,41 +424,34 @@ var PushService = {
       .catch(e => {
         console.error("backgroundUnregister: Error notifying server", e);
       });
   },
 
   _findService(serverURL) {
     console.debug("findService()");
 
-    let uri;
-    let service;
-
     if (!serverURL) {
       console.warn("findService: No dom.push.serverURL found");
       return [];
     }
 
+    let uri;
     try {
       uri = Services.io.newURI(serverURL);
     } catch (e) {
       console.warn(
         "findService: Error creating valid URI from",
         "dom.push.serverURL",
         serverURL
       );
       return [];
     }
 
-    for (let connProtocol of CONNECTION_PROTOCOLS) {
-      if (connProtocol.validServerURI(uri)) {
-        service = connProtocol;
-        break;
-      }
-    }
+    let service = getServiceForServerURI(uri);
     return [service, uri];
   },
 
   _changeServerURL(serverURI, event, options = {}) {
     console.debug("changeServerURL()");
 
     switch (event) {
       case UNINIT_EVENT:
--- a/dom/push/PushServiceAndroidGCM.jsm
+++ b/dom/push/PushServiceAndroidGCM.jsm
@@ -74,35 +74,16 @@ var PushServiceAndroidGCM = {
       kPUSHANDROIDGCMDB_DB_NAME,
       kPUSHANDROIDGCMDB_DB_VERSION,
       kPUSHANDROIDGCMDB_STORE_NAME,
       "channelID",
       PushRecordAndroidGCM
     );
   },
 
-  validServerURI(serverURI) {
-    if (!serverURI) {
-      return false;
-    }
-
-    if (serverURI.scheme == "https") {
-      return true;
-    }
-    if (serverURI.scheme == "http") {
-      // Allow insecure server URLs for development and testing.
-      return !!prefs.get("testing.allowInsecureServerURL");
-    }
-    console.info(
-      "Unsupported Android GCM dom.push.serverURL scheme",
-      serverURI.scheme
-    );
-    return false;
-  },
-
   observe(subject, topic, data) {
     switch (topic) {
       case "nsPref:changed":
         if (data == "dom.push.debug") {
           // Reconfigure.
           let debug = !!prefs.get("debug");
           console.info(
             "Debug parameter changed; updating configuration with new debug",
--- a/dom/push/PushServiceHttp2.jsm
+++ b/dom/push/PushServiceHttp2.jsm
@@ -420,23 +420,16 @@ var PushServiceHttp2 = {
       PushRecordHttp2
     );
   },
 
   hasmainPushService() {
     return this._mainPushService !== null;
   },
 
-  validServerURI(serverURI) {
-    if (serverURI.scheme == "http") {
-      return !!prefs.getBoolPref("testing.allowInsecureServerURL", false);
-    }
-    return serverURI.scheme == "https";
-  },
-
   async connect(broadcastListeners) {
     let subscriptions = await this._mainPushService.getAllUnexpired();
     this.startConnections(subscriptions);
   },
 
   async sendSubscribeBroadcast(serviceId, version) {
     // Not implemented yet
   },
--- a/dom/push/PushServiceWebSocket.jsm
+++ b/dom/push/PushServiceWebSocket.jsm
@@ -249,23 +249,16 @@ var PushServiceWebSocket = {
 
     // The most likely reason for a pong or registration request timing out is
     // that the socket has disconnected. Best to reconnect.
     if (requestTimedOut) {
       this._reconnect();
     }
   },
 
-  validServerURI(serverURI) {
-    if (serverURI.scheme == "ws") {
-      return !!prefs.get("testing.allowInsecureServerURL");
-    }
-    return serverURI.scheme == "wss";
-  },
-
   get _UAID() {
     return prefs.get("userAgentID");
   },
 
   set _UAID(newID) {
     if (typeof newID !== "string") {
       console.warn(
         "Got invalid, non-string UAID",