Bug 1404584 wip use update and uninstall events to clear old chrome_settings_overrides draft
authorAndrew Swan <aswan@mozilla.com>
Wed, 25 Oct 2017 13:21:31 -0700
changeset 686981 d78015c18f74939491365c3dcb40f103f1f2b4a1
parent 686980 4697c678cda68114a27d2eb51f171cf2d1f74ac3
child 737539 a099fb73d2681beb9eea7b3bef2da831dedae499
push id86369
push useraswan@mozilla.com
push dateThu, 26 Oct 2017 18:05:35 +0000
bugs1404584, 1409245
milestone58.0a1
Bug 1404584 wip use update and uninstall events to clear old chrome_settings_overrides This is a work in progress, it depends on the patches from bug 1409245. MozReview-Commit-ID: ArdO2LMaR9G
browser/components/extensions/ext-browser.json
browser/components/extensions/ext-chrome-settings-overrides.js
toolkit/components/extensions/ExtensionParent.jsm
toolkit/components/extensions/ExtensionPreferencesManager.jsm
--- a/browser/components/extensions/ext-browser.json
+++ b/browser/components/extensions/ext-browser.json
@@ -22,16 +22,17 @@
     "scopes": ["addon_parent"],
     "paths": [
       ["browsingData"]
     ]
   },
   "chrome_settings_overrides": {
     "url": "chrome://browser/content/ext-chrome-settings-overrides.js",
     "scopes": [],
+    "events": ["update", "uninstall"],
     "schema": "chrome://browser/content/schemas/chrome_settings_overrides.json",
     "manifest": ["chrome_settings_overrides"]
   },
   "commands": {
     "url": "chrome://browser/content/ext-commands.js",
     "schema": "chrome://browser/content/schemas/commands.json",
     "scopes": ["addon_parent"],
     "manifest": ["commands"],
--- a/browser/components/extensions/ext-chrome-settings-overrides.js
+++ b/browser/components/extensions/ext-chrome-settings-overrides.js
@@ -29,76 +29,93 @@ const searchInitialized = () => {
 
       Services.obs.removeObserver(observer, SEARCH_SERVICE_TOPIC);
       resolve();
     }, SEARCH_SERVICE_TOPIC);
   });
 };
 
 this.chrome_settings_overrides = class extends ExtensionAPI {
-  processDefaultSearchSetting(action) {
-    let {extension} = this;
+  static processDefaultSearchSetting(action, id) {
     let item = ExtensionSettingsStore.getSetting(DEFAULT_SEARCH_STORE_TYPE, DEFAULT_SEARCH_SETTING_NAME);
     if (!item) {
       return;
     }
     if (Services.search.currentEngine.name != item.value &&
         Services.search.currentEngine.name != item.initialValue) {
       // The current engine is not the same as the value that the ExtensionSettingsStore has.
       // This means that the user changed the engine, so we shouldn't control it anymore.
       // Do nothing and remove our entry from the ExtensionSettingsStore.
-      ExtensionSettingsStore.removeSetting(extension.id, DEFAULT_SEARCH_STORE_TYPE, DEFAULT_SEARCH_SETTING_NAME);
+      ExtensionSettingsStore.removeSetting(id, DEFAULT_SEARCH_STORE_TYPE, DEFAULT_SEARCH_SETTING_NAME);
       return;
     }
-    item = ExtensionSettingsStore[action](extension.id, DEFAULT_SEARCH_STORE_TYPE, DEFAULT_SEARCH_SETTING_NAME);
+    item = ExtensionSettingsStore[action](id, DEFAULT_SEARCH_STORE_TYPE, DEFAULT_SEARCH_SETTING_NAME);
     if (item) {
       try {
         let engine = Services.search.getEngineByName(item.value || item.initialValue);
         if (engine) {
           Services.search.currentEngine = engine;
         }
       } catch (e) {
         Components.utils.reportError(e);
       }
     }
   }
 
+  static onUninstall(id) {
+    this.processDefaultSearchSetting("removeSetting", id);
+
+    // XXX move this somewhere shared
+    // We shouldn't need to wait for search initialized here
+    // because the search service should be ready to go.
+    let engines = Services.search.getEnginesByExtensionID(extension.id);
+    for (let engine of engines) {
+      try {
+        Services.search.removeEngine(engine);
+      } catch (e) {
+        Components.utils.reportError(e);
+      }
+    }
+  }
+
+  static onUpdate(id, manifest) {
+    let haveHomepage = manifest && manifest.chrome_settings_overrides &&
+                       manifest.chrome_settings_overrides.homepage;
+    if (!haveHomepage) {
+      ExtensionPreferencesManager.removeSetting(id, "homepage_override");
+    }
+
+    // XXX something with search settings too
+  }
+
   async onManifestEntry(entryName) {
     let {extension} = this;
     let {manifest} = extension;
 
     await ExtensionSettingsStore.initialize();
     if (manifest.chrome_settings_overrides.homepage) {
       ExtensionPreferencesManager.setSetting(extension.id, "homepage_override",
                                              manifest.chrome_settings_overrides.homepage);
     }
     if (manifest.chrome_settings_overrides.search_provider) {
       await searchInitialized();
       extension.callOnClose({
         close: () => {
-          if (extension.shutdownReason == "ADDON_DISABLE" ||
-              extension.shutdownReason == "ADDON_UNINSTALL") {
-            switch (extension.shutdownReason) {
-              case "ADDON_DISABLE":
-                this.processDefaultSearchSetting("disable");
-                break;
+          if (extension.shutdownReason == "ADDON_DISABLE") {
+            chrome_settings_overrides.processDefaultSearchSetting("disable", extension.id);
+          }
 
-              case "ADDON_UNINSTALL":
-                this.processDefaultSearchSetting("removeSetting");
-                break;
-            }
-            // We shouldn't need to wait for search initialized here
-            // because the search service should be ready to go.
-            let engines = Services.search.getEnginesByExtensionID(extension.id);
-            for (let engine of engines) {
-              try {
-                Services.search.removeEngine(engine);
-              } catch (e) {
-                Components.utils.reportError(e);
-              }
+          // We shouldn't need to wait for search initialized here
+          // because the search service should be ready to go.
+          let engines = Services.search.getEnginesByExtensionID(extension.id);
+          for (let engine of engines) {
+            try {
+              Services.search.removeEngine(engine);
+            } catch (e) {
+              Components.utils.reportError(e);
             }
           }
         },
       });
 
       let searchProvider = manifest.chrome_settings_overrides.search_provider;
       let engineName = searchProvider.name.trim();
       if (searchProvider.is_default) {
@@ -140,31 +157,31 @@ this.chrome_settings_overrides = class e
         }
         // Needs to be called every time to handle reenabling, but
         // only sets default for install or enable.
         await this.setDefault(engineName);
       } else if (ExtensionSettingsStore.hasSetting(
                 extension.id, DEFAULT_SEARCH_STORE_TYPE, DEFAULT_SEARCH_SETTING_NAME)) {
         // is_default has been removed, but we still have a setting. Remove it.
         // This won't cover the case where the entire search_provider is removed.
-        this.processDefaultSearchSetting("removeSetting");
+        chrome_settings_overrides.processDefaultSearchSetting("removeSetting");
       }
     }
   }
 
   async setDefault(engineName) {
     let {extension} = this;
     if (extension.startupReason === "ADDON_INSTALL") {
       let item = await ExtensionSettingsStore.addSetting(
         extension.id, DEFAULT_SEARCH_STORE_TYPE, DEFAULT_SEARCH_SETTING_NAME, engineName, () => {
           return Services.search.currentEngine.name;
         });
       Services.search.currentEngine = Services.search.getEngineByName(item.value);
     } else if (extension.startupReason === "ADDON_ENABLE") {
-      this.processDefaultSearchSetting("enable");
+      chrome_settings_overrides.processDefaultSearchSetting("enable");
     }
   }
 
   addSearchEngine(searchProvider) {
     let {extension} = this;
     let isCurrent = false;
     let index = -1;
     if (extension.startupReason === "ADDON_UPGRADE") {
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -72,28 +72,53 @@ let StartupCache;
 const global = this;
 
 // This object loads the ext-*.js scripts that define the extension API.
 let apiManager = new class extends SchemaAPIManager {
   constructor() {
     super("main");
     this.initialized = null;
 
-    this.on("startup", (event, extension) => { // eslint-disable-line mozilla/balanced-listeners
+    // eslint-disable mozilla/balanced-listeners
+    this.on("startup", (e, extension) => { // eslint-disable-line mozilla/balanced-listeners
       let promises = [];
       for (let apiName of this.eventModules.get("startup")) {
         promises.push(this.asyncGetAPI(apiName, extension).then(api => {
           if (api) {
-            api.onStartup(extension.startupReason);
+            api.onStartup();
           }
         }));
       }
 
       return Promise.all(promises);
     });
+
+    this.on("update", (e, {id}) => {
+      let modules = this.eventModules.get("update");
+      if (modules.size == 0) {
+        return;
+      }
+
+      // XXX load manifest
+      let manifest = null;
+
+      return Promise.all(Array.from(modules).map(async apiName => {
+        let module = await this.asyncLoadModule(apiName);
+        module.onUpdate(id, manifest);
+      }));
+    });
+
+    this.on("uninstall", (e, {id}) => {
+      let modules = this.eventModules.get("uninstall");
+      return Promise.all(Array.from(modules).map(async apiName => {
+        let module = await this.asyncLoadModule(apiName);
+        module.onUninstall(id);
+      }));
+    });
+    // eslint-enable mozilla/balanced-listeners
   }
 
   getModuleJSONURLs() {
     return Array.from(XPCOMUtils.enumerateCategoryEntries(CATEGORY_EXTENSION_MODULES),
                       ([name, url]) => url);
   }
 
   // Loads all the ext-*.js scripts currently registered.
--- a/toolkit/components/extensions/ExtensionPreferencesManager.jsm
+++ b/toolkit/components/extensions/ExtensionPreferencesManager.jsm
@@ -31,46 +31,30 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/ExtensionSettingsStore.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
                                   "resource://gre/modules/Preferences.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "defaultPreferences", function() {
   return new Preferences({defaultBranch: true});
 });
 
-const ADDON_REPLACE_REASONS = new Set([
-  "ADDON_DOWNGRADE",
-  "ADDON_UPGRADE",
-]);
+/* eslint-disable mozilla/balanced-listeners */
+Management.on("uninstall", (type, {id}) => {
+  ExtensionPreferencesManager.removeAll(id);
+});
 
-/* eslint-disable mozilla/balanced-listeners */
 Management.on("shutdown", (type, extension) => {
-  switch (extension.shutdownReason) {
-    case "ADDON_DISABLE":
-    case "ADDON_DOWNGRADE":
-    case "ADDON_UPGRADE":
-      if (ADDON_REPLACE_REASONS.has(extension.shutdownReason)) {
-        Services.obs.notifyObservers(null, "web-extension-preferences-replacing");
-      }
-      this.ExtensionPreferencesManager.disableAll(extension.id);
-      break;
-
-    case "ADDON_UNINSTALL":
-      this.ExtensionPreferencesManager.removeAll(extension.id);
-      break;
+  if (extension.shutdownReason == "ADDON_DISABLE") {
+    this.ExtensionPreferencesManager.disableAll(extension.id);
   }
 });
 
 Management.on("startup", async (type, extension) => {
-  if (["ADDON_ENABLE", "ADDON_UPGRADE", "ADDON_DOWNGRADE"].includes(extension.startupReason)) {
-    const enablePromise = this.ExtensionPreferencesManager.enableAll(extension.id);
-    if (ADDON_REPLACE_REASONS.has(extension.startupReason)) {
-      await enablePromise;
-      Services.obs.notifyObservers(null, "web-extension-preferences-replaced");
-    }
+  if (extension.startupReason == "ADDON_ENABLE") {
+    this.ExtensionPreferencesManager.enableAll(extension.id);
   }
 });
 /* eslint-enable mozilla/balanced-listeners */
 
 const STORE_TYPE = "prefs";
 
 // Definitions of settings, each of which correspond to a different API.
 let settingsMap = new Map();