Bug 1369761 - ContextualIdentityService should not be initialized before first paint, r=florian
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 13 Jun 2017 13:04:49 +0200
changeset 412439 28ae65a052aa9f10014e82f9d4219185573bd5eb
parent 412438 68d154644c0fda6841351fbe149810668c8a1e76
child 412440 221a20df9bc59dd9ac47e895f2c622f9e2e0163d
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersflorian
bugs1369761
milestone56.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 1369761 - ContextualIdentityService should not be initialized before first paint, r=florian
browser/base/content/browser.js
browser/base/content/nsContextMenu.js
browser/base/content/test/performance/browser_startup.js
browser/base/content/utilityOverlay.js
browser/components/nsBrowserGlue.js
toolkit/components/contextualidentity/ContextualIdentityService.jsm
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -7,21 +7,22 @@
 
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 var Cc = Components.classes;
 var Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/ContextualIdentityService.jsm");
 Cu.import("resource://gre/modules/NotificationDB.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
                                   "resource://gre/modules/Preferences.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
+                                  "resource://gre/modules/ContextualIdentityService.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "extensionNameFromURI", () => {
   return Cu.import("resource://gre/modules/ExtensionParent.jsm", {}).extensionNameFromURI;
 });
 
 // lazy module getters
 
 /* global AboutHome:false,
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -1,27 +1,28 @@
 /* -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ts=2 sw=2 sts=2 et tw=80: */
 /* 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/. */
 
-Components.utils.import("resource://gre/modules/ContextualIdentityService.jsm");
 Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
 Components.utils.import("resource://gre/modules/LoginManagerContextMenu.jsm");
 Components.utils.import("resource://gre/modules/BrowserUtils.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 
 XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
   "resource://gre/modules/LoginHelper.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "WebNavigationFrames",
   "resource://gre/modules/WebNavigationFrames.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
+  "resource://gre/modules/ContextualIdentityService.jsm");
 
 var gContextMenuContentData = null;
 
 function openContextMenu(aMessage) {
   let data = aMessage.data;
   let browser = aMessage.target;
 
   let spellInfo = data.spellInfo;
--- a/browser/base/content/test/performance/browser_startup.js
+++ b/browser/base/content/test/performance/browser_startup.js
@@ -52,16 +52,19 @@ const startupPhases = {
   // We reach this phase right after showing the first browser window.
   // This means that anything already loaded at this point has been loaded
   // before first paint and delayed it.
   "before first paint": {blacklist: {
     components: new Set([
       "nsSearchService.js",
       "UnifiedComplete.js",
     ]),
+    modules: new Set([
+     "resource://gre/modules/ContextualIdentityService.jsm"
+    ]),
     services: new Set([
       "@mozilla.org/browser/search-service;1",
     ])
   }},
 
   // 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.
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -1,24 +1,26 @@
 /* -*- 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/. */
 
 // Services = object with smart getters for common XPCOM services
 Components.utils.import("resource://gre/modules/AppConstants.jsm");
-Components.utils.import("resource://gre/modules/ContextualIdentityService.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 Components.utils.import("resource:///modules/RecentWindow.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ShellService",
                                   "resource:///modules/ShellService.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
+                                  "resource://gre/modules/ContextualIdentityService.jsm");
+
 XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
                                    "@mozilla.org/browser/aboutnewtab-service;1",
                                    "nsIAboutNewTabService");
 
 Object.defineProperty(this, "BROWSER_NEW_TAB_URL", {
   configurable: true,
   enumerable: true,
   get() {
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -14,16 +14,18 @@ Cu.import("resource://gre/modules/Servic
 Cu.import("resource://gre/modules/AppConstants.jsm");
 Cu.import("resource://gre/modules/AsyncPrefs.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils", "@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils");
 XPCOMUtils.defineLazyServiceGetter(this, "AlertsService", "@mozilla.org/alerts-service;1", "nsIAlertsService");
 XPCOMUtils.defineLazyGetter(this, "WeaveService", () =>
   Cc["@mozilla.org/weave/service;1"].getService().wrappedJSObject
 );
+XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
+                                  "resource://gre/modules/ContextualIdentityService.jsm");
 
 // lazy module getters
 
 /* global AboutHome:false, AboutNewTab:false, AddonManager:false, AppMenuNotifications:false,
           AsyncShutdown:false, AutoCompletePopup:false, BookmarkHTMLUtils:false,
           BookmarkJSONUtils:false, BrowserUITelemetry:false, BrowserUsageTelemetry:false,
           ContentClick:false, ContentPrefServiceParent:false, ContentSearch:false,
           DateTimePickerHelper:false, DirectoryLinksProvider:false,
@@ -1174,16 +1176,21 @@ BrowserGlue.prototype = {
 
       if (willPrompt) {
         Services.tm.dispatchToMainThread(function() {
           DefaultBrowserCheck.prompt(RecentWindow.getMostRecentBrowserWindow());
         });
       }
     }
 
+    // Let's load the contextual identities.
+    Services.tm.mainThread.idleDispatch(() => {
+      ContextualIdentityService.load();
+    });
+
     this._sanitizer.onStartup();
     E10SAccessibilityCheck.onWindowsRestored();
   },
 
   _createExtraDefaultProfile() {
     if (!AppConstants.MOZ_DEV_EDITION) {
       return;
     }
--- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm
+++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm
@@ -85,21 +85,16 @@ function _ContextualIdentityService(path
 
   _path: null,
   _dataReady: false,
 
   _saver: null,
 
   init(path) {
     this._path = path;
-    this._saver = new DeferredTask(() => this.save(), SAVE_DELAY_MS);
-    AsyncShutdown.profileBeforeChange.addBlocker("ContextualIdentityService: writing data",
-                                                 () => this._saver.finalize());
-
-    this.load();
   },
 
   load() {
     OS.File.read(this._path).then(bytes => {
       // If synchronous loading happened in the meantime, exit now.
       if (this._dataReady) {
         return;
       }
@@ -149,47 +144,66 @@ function _ContextualIdentityService(path
     if (this._dataReady) {
       return;
     }
 
     this.resetDefault();
   },
 
   saveSoon() {
+    if (!this._saver) {
+      this._saverCallback = () => this._saver.finalize();
+
+      this._saver = new DeferredTask(() => this.save(), SAVE_DELAY_MS);
+      AsyncShutdown.profileBeforeChange.addBlocker(
+        "ContextualIdentityService: writing data", this._saverCallback);
+    } else {
+      this._saver.disarm();
+    }
+
     this._saver.arm();
   },
 
   save() {
-   let object = {
-     version: 2,
-     lastUserContextId: this._lastUserContextId,
-     identities: this._identities
-   };
+    AsyncShutdown.profileBeforeChange.removeBlocker(this._saverCallback);
+
+    this._saver = null;
+    this._saverCallback = null;
 
-   let bytes = gTextEncoder.encode(JSON.stringify(object));
-   return OS.File.writeAtomic(this._path, bytes,
-                              { tmpPath: this._path + ".tmp" });
+    let object = {
+      version: 2,
+      lastUserContextId: this._lastUserContextId,
+      identities: this._identities
+    };
+
+    let bytes = gTextEncoder.encode(JSON.stringify(object));
+    return OS.File.writeAtomic(this._path, bytes,
+                               { tmpPath: this._path + ".tmp" });
   },
 
   create(name, icon, color) {
+    this.ensureDataReady();
+
     let identity = {
       userContextId: ++this._lastUserContextId,
       public: true,
       icon,
       color,
       name
     };
 
     this._identities.push(identity);
     this.saveSoon();
 
     return Cu.cloneInto(identity, {});
   },
 
   update(userContextId, name, icon, color) {
+    this.ensureDataReady();
+
     let identity = this._identities.find(identity => identity.userContextId == userContextId &&
                                          identity.public);
     if (identity && name) {
       identity.name = name;
       identity.color = color;
       identity.icon = icon;
       delete identity.l10nID;
       delete identity.accessKey;
@@ -197,16 +211,18 @@ function _ContextualIdentityService(path
       Services.obs.notifyObservers(null, "contextual-identity-updated", userContextId);
       this.saveSoon();
     }
 
     return !!identity;
   },
 
   remove(userContextId) {
+    this.ensureDataReady();
+
     let index = this._identities.findIndex(i => i.userContextId == userContextId && i.public);
     if (index == -1) {
       return false;
     }
 
     Services.obs.notifyObservers(null, "clear-origin-attributes-data",
                                  JSON.stringify({ userContextId }));