Bug 1445990 - fix initialization of blocklist service in non-browser apps, r?florian draft
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Thu, 15 Mar 2018 16:16:11 +0000
changeset 768802 25cd0c17cb0b17579d9d10edd394c87a2b1959e6
parent 768017 6dd067028dc1295f86938730f7b6300d2b488d9c
push id102985
push usergijskruitbosch@gmail.com
push dateFri, 16 Mar 2018 21:37:21 +0000
reviewersflorian
bugs1445990
milestone61.0a1
Bug 1445990 - fix initialization of blocklist service in non-browser apps, r?florian MozReview-Commit-ID: GK4SA8gJ8Pf
browser/components/nsBrowserGlue.js
toolkit/mozapps/extensions/extensions.manifest
toolkit/mozapps/extensions/moz.build
toolkit/mozapps/extensions/nsBlocklistService.js
toolkit/mozapps/extensions/test/xpcshell/test_asyncBlocklistLoad.js
xpcom/system/nsIBlocklistService.idl
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1210,16 +1210,20 @@ BrowserGlue.prototype = {
       Services.tm.idleDispatchToMainThread(() => {
         JawsScreenReaderVersionCheck.onWindowsRestored();
       });
     }
 
     Services.tm.idleDispatchToMainThread(() => {
       LanguagePrompt.init();
     });
+
+    Services.tm.idleDispatchToMainThread(() => {
+      Services.blocklist.loadBlocklistAsync();
+    });
   },
 
   /**
    * Use this function as an entry point to schedule tasks that need
    * to run once per session, at any arbitrary point in time.
    * This function will be called from an idle observer. Check the value of
    * LATE_TASKS_IDLE_TIME_SEC to see the current value for this idle
    * observer.
--- a/toolkit/mozapps/extensions/extensions.manifest
+++ b/toolkit/mozapps/extensions/extensions.manifest
@@ -1,11 +1,13 @@
 component {66354bc9-7ed1-4692-ae1d-8da97d6b205e} nsBlocklistService.js process=main
 contract @mozilla.org/extensions/blocklist;1 {66354bc9-7ed1-4692-ae1d-8da97d6b205e} process=main
-category profile-after-change nsBlocklistService @mozilla.org/extensions/blocklist;1  process=main
+#ifndef MOZ_BUILD_APP_IS_BROWSER
+category profile-after-change nsBlocklistService @mozilla.org/extensions/blocklist;1 process=main
+#endif
 
 category update-timer nsBlocklistService @mozilla.org/extensions/blocklist;1,getService,blocklist-background-update-timer,extensions.blocklist.interval,86400
 component {4399533d-08d1-458c-a87a-235f74451cfa} addonManager.js
 contract @mozilla.org/addons/integration;1 {4399533d-08d1-458c-a87a-235f74451cfa}
 #ifndef MOZ_WIDGET_ANDROID
 category update-timer addonManager @mozilla.org/addons/integration;1,getService,addon-background-update-timer,extensions.update.interval,86400
 #endif
 component {7beb3ba8-6ec3-41b4-b67c-da89b8518922} amContentHandler.js
--- a/toolkit/mozapps/extensions/moz.build
+++ b/toolkit/mozapps/extensions/moz.build
@@ -4,16 +4,19 @@
 # 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/.
 
 SPHINX_TREES['addon-manager'] = 'docs'
 
 with Files('docs/**'):
     SCHEDULES.exclusive = ['docs']
 
+if CONFIG['MOZ_BUILD_APP'] == 'browser':
+    DEFINES['MOZ_BUILD_APP_IS_BROWSER'] = True
+
 if CONFIG['MOZ_BUILD_APP'] == 'mobile/android':
     DEFINES['MOZ_FENNEC'] = True
 
 DIRS += ['internal']
 TEST_DIRS += ['test']
 
 XPIDL_SOURCES += [
     'amIAddonManager.idl',
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -216,26 +216,23 @@ function parseRegExp(aStr) {
  * Manages the Blocklist. The Blocklist is a representation of the contents of
  * blocklist.xml and allows us to remotely disable / re-enable blocklisted
  * items managed by the Extension Manager with an item's appDisabled property.
  * It also blocklists plugins with data from blocklist.xml.
  */
 
 function Blocklist() {
   Services.obs.addObserver(this, "xpcom-shutdown");
-  Services.obs.addObserver(this, "sessionstore-windows-restored");
   gLoggingEnabled = Services.prefs.getBoolPref(PREF_EM_LOGGING_ENABLED, false);
   gBlocklistEnabled = Services.prefs.getBoolPref(PREF_BLOCKLIST_ENABLED, true);
   gBlocklistLevel = Math.min(Services.prefs.getIntPref(PREF_BLOCKLIST_LEVEL, DEFAULT_LEVEL),
                              MAX_BLOCK_LEVEL);
   Services.prefs.addObserver("extensions.blocklist.", this);
   Services.prefs.addObserver(PREF_EM_LOGGING_ENABLED, this);
   this.wrappedJSObject = this;
-  // requests from child processes come in here, see receiveMessage.
-  Services.ppmm.addMessageListener("Blocklist:content-blocklist-updated", this);
 }
 
 Blocklist.prototype = {
   /**
    * Extension ID -> array of Version Ranges
    * Each value in the version range array is a JS Object that has the
    * following properties:
    *   "minVersion"  The minimum version in a version range (default = 0)
@@ -250,26 +247,31 @@ Blocklist.prototype = {
    *                                 (default = *)
    */
   _addonEntries: null,
   _gfxEntries: null,
   _pluginEntries: null,
 
   shutdown() {
     Services.obs.removeObserver(this, "xpcom-shutdown");
-    Services.ppmm.removeMessageListener("Blocklist:content-blocklist-updated", this);
     Services.prefs.removeObserver("extensions.blocklist.", this);
     Services.prefs.removeObserver(PREF_EM_LOGGING_ENABLED, this);
   },
 
   observe(aSubject, aTopic, aData) {
     switch (aTopic) {
     case "xpcom-shutdown":
       this.shutdown();
       break;
+    case "profile-after-change":
+      // We're only called here on non-Desktop-Firefox, and use this opportunity to try to
+      // load the blocklist asynchronously. On desktop Firefox, we load the list from
+      // nsBrowserGlue after sessionstore-windows-restored.
+      this.loadBlocklistAsync();
+      break;
     case "nsPref:changed":
       switch (aData) {
         case PREF_EM_LOGGING_ENABLED:
           gLoggingEnabled = Services.prefs.getBoolPref(PREF_EM_LOGGING_ENABLED, false);
           break;
         case PREF_BLOCKLIST_ENABLED:
           gBlocklistEnabled = Services.prefs.getBoolPref(PREF_BLOCKLIST_ENABLED, true);
           this._loadBlocklist();
@@ -277,35 +279,19 @@ Blocklist.prototype = {
           break;
         case PREF_BLOCKLIST_LEVEL:
           gBlocklistLevel = Math.min(Services.prefs.getIntPref(PREF_BLOCKLIST_LEVEL, DEFAULT_LEVEL),
                                      MAX_BLOCK_LEVEL);
           this._blocklistUpdated(null, null);
           break;
       }
       break;
-    case "sessionstore-windows-restored":
-      Services.obs.removeObserver(this, "sessionstore-windows-restored");
-      this._preloadBlocklist();
-      break;
     }
   },
 
-  // Message manager message handlers
-  receiveMessage(aMsg) {
-    switch (aMsg.name) {
-      case "Blocklist:content-blocklist-updated":
-        Services.obs.notifyObservers(null, "content-blocklist-updated");
-        break;
-      default:
-        throw new Error("Unknown blocklist message received from content: " + aMsg.name);
-    }
-    return undefined;
-  },
-
   /* See nsIBlocklistService */
   isAddonBlocklisted(addon, appVersion, toolkitVersion) {
     return this.getAddonBlocklistState(addon, appVersion, toolkitVersion) ==
                    Ci.nsIBlocklistService.STATE_BLOCKED;
   },
 
   /* See nsIBlocklistService */
   getAddonBlocklistState(addon, appVersion, toolkitVersion) {
@@ -792,34 +778,34 @@ Blocklist.prototype = {
 
   /* Used for testing */
   _clear() {
     this._addonEntries = null;
     this._gfxEntries = null;
     this._pluginEntries = null;
   },
 
-  async _preloadBlocklist() {
+  async loadBlocklistAsync() {
     let profPath = OS.Path.join(OS.Constants.Path.profileDir, FILE_BLOCKLIST);
     try {
       await this._preloadBlocklistFile(profPath);
       return;
     } catch (e) {
-      LOG("Blocklist::_preloadBlocklist: Failed to load XML file " + e);
+      LOG("Blocklist::loadBlocklistAsync: Failed to load XML file " + e);
     }
 
     var appFile = FileUtils.getFile(KEY_APPDIR, [FILE_BLOCKLIST]);
     try {
       await this._preloadBlocklistFile(appFile.path);
       return;
     } catch (e) {
-      LOG("Blocklist::_preloadBlocklist: Failed to load XML file " + e);
+      LOG("Blocklist::loadBlocklistAsync: Failed to load XML file " + e);
     }
 
-    LOG("Blocklist::_preloadBlocklist: no XML File found");
+    LOG("Blocklist::loadBlocklistAsync: no XML File found");
   },
 
   async _preloadBlocklistFile(path) {
     if (this._addonEntries) {
       // The file has been already loaded.
       return;
     }
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_asyncBlocklistLoad.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_asyncBlocklistLoad.js
@@ -9,25 +9,25 @@ add_task(async function() {
 
   // sync -> async. Check that async code doesn't try to read the file
   // once it's already been read synchronously.
   let read = scope.OS.File.read;
   let triedToRead = false;
   scope.OS.File.read = () => triedToRead = true;
   blocklist._loadBlocklist();
   Assert.ok(blocklist.isLoaded);
-  await blocklist._preloadBlocklist();
+  await blocklist.loadBlocklistAsync();
   Assert.ok(!triedToRead);
   scope.OS.File.read = read;
   blocklist._clear();
 
   info("sync -> async complete");
 
   // async first. Check that once we preload the content, that is sufficient.
-  await blocklist._preloadBlocklist();
+  await blocklist.loadBlocklistAsync();
   Assert.ok(blocklist.isLoaded);
   // Calling _loadBlocklist now would just re-load the list sync.
 
   info("async test complete");
   blocklist._clear();
 
   // async -> sync -> async
   scope.OS.File.read = function(...args) {
@@ -35,13 +35,13 @@ add_task(async function() {
       executeSoon(() => {
         blocklist._loadBlocklist();
         // Now do the async bit after all:
         resolve(read(...args));
       });
     });
   };
 
-  await blocklist._preloadBlocklist();
+  await blocklist.loadBlocklistAsync();
   // We're mostly just checking this doesn't error out.
   Assert.ok(blocklist.isLoaded);
   info("mixed async/sync test complete");
 });
--- a/xpcom/system/nsIBlocklistService.idl
+++ b/xpcom/system/nsIBlocklistService.idl
@@ -128,16 +128,21 @@ interface nsIBlocklistService : nsISuppo
    *          it is not available.
    */
   AString getPluginInfoURL(in nsIPluginTag plugin);
 
   /**
    * Whether or not we've finished loading the blocklist.
    */
   readonly attribute boolean isLoaded;
+
+  /**
+   * Trigger loading the blocklist content asynchronously.
+   */
+  void loadBlocklistAsync();
 };
 
 /**
  * nsIBlocklistPrompt is used, if available, by the default implementation of 
  * nsIBlocklistService to display a confirmation UI to the user before blocking
  * extensions/plugins.
  */
 [scriptable, uuid(ba915921-b9c0-400d-8e4f-ca1b80c5699a)]