[Pkg-mozext-commits] [requestpolicy] 102/280: Add `Environment` class, replaces BootstrapManager

David Prévot taffit at moszumanska.debian.org
Sat May 2 20:30:06 UTC 2015


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch master
in repository requestpolicy.

commit 3f9b0d8c62474aa40cb64bf5b5776a29436e62cc
Author: Martin Kimmerle <dev at 256k.de>
Date:   Fri Jan 2 19:43:46 2015 +0100

    Add `Environment` class, replaces BootstrapManager
    
    This commit introduces the Environment class. There is also the
    `ProcessEnvironment` module, which simply creates one Environment instance
    per process that is available for all modules.
    
    Environment implements the main functionality of BootstrapManager, but as it's
    a class, more instances can be created, such as "window" environments. The
    Environment class simplifies greatly the startup and shutdown processes for
    both the main process and frame scripts, as well as for content windows running
    in the main process such as the preferences web pages.
    
    By the way, ObserverManager profits a lot from this change, as it dosn't
    need to detect the process type itself anymore.
---
 src/bootstrap.js                                |  25 ++--
 src/content/lib/about-uri.jsm                   |   6 +-
 src/content/lib/bootstrap-manager.jsm           | 131 ---------------------
 src/content/lib/content-policy.jsm              |   4 +-
 src/content/lib/environment.jsm                 | 149 ++++++++++++++++++++++++
 src/content/lib/logger.jsm                      |   4 +-
 src/content/lib/observer-manager.js             |  70 ++++-------
 src/content/lib/process-environment.jsm         | 149 ++++++++++++++++++++++++
 src/content/lib/request-processor.jsm           |   3 +-
 src/content/lib/requestpolicy-service.jsm       |  12 +-
 src/content/lib/script-loader.jsm               |  21 +---
 src/content/lib/utils.jsm                       |   8 +-
 src/content/lib/window-manager-toolbarbutton.js |   4 +-
 src/content/lib/window-manager.jsm              |   6 +-
 src/content/ui/frame.js                         |  62 +++++++++-
 15 files changed, 423 insertions(+), 231 deletions(-)

diff --git a/src/bootstrap.js b/src/bootstrap.js
index 4d62f6f..d7f4978 100644
--- a/src/bootstrap.js
+++ b/src/bootstrap.js
@@ -25,8 +25,8 @@ const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 
-const bootstrapManagerURI = "chrome://requestpolicy/content/lib/" +
-    "bootstrap-manager.jsm";
+const procEnvURI = "chrome://requestpolicy/content/lib/" +
+    "process-environment.jsm";
 
 /**
  * If any Exception gets into bootstrap.js, it will be a severe error.
@@ -44,14 +44,13 @@ function startup(data, reason) {
   //debugger;
 
   try {
-    // Import the BootstrapManager and call its startup() function, that's all
-    // what has to be done here.
-    // It is IMPORTANT that BootstrapManager is the FIRST module that is
-    // imported! The reason is that many modules call
-    // `BootstrapManager.registerStartupFunction()` at **load-time**, so
-    // BootstrapManager has to be available.
-    Cu.import(bootstrapManagerURI);
-    BootstrapManager.startup(data, reason);
+    // Import the ProcessEnvironment and call its startup() function.
+    // Note: It is IMPORTANT that ProcessEnvironment is the FIRST module to be
+    //       imported! The reason is that many modules call
+    //       `ProcessEnvironment.enqueueStartupFunction()` at *load-time*, so
+    //       ProcessEnvironment has to be available.
+    Cu.import(procEnvURI);
+    ProcessEnvironment.startup(data, reason);
   } catch(e) {
     logSevereError("startup() failed! " + e, e.stack);
   }
@@ -63,8 +62,10 @@ function shutdown(data, reason) {
   }
 
   try {
-    BootstrapManager.shutdown(data, reason);
-    Cu.unload(bootstrapManagerURI);
+    // shutdown, unset and unload.
+    ProcessEnvironment.shutdown(data, reason);
+    ProcessEnvironment = null;
+    Cu.unload(procEnvURI);
   } catch(e) {
     logSevereError("shutdown() failed! " + e, e.stack);
   }
diff --git a/src/content/lib/about-uri.jsm b/src/content/lib/about-uri.jsm
index d8cca79..2fae90b 100644
--- a/src/content/lib/about-uri.jsm
+++ b/src/content/lib/about-uri.jsm
@@ -32,7 +32,7 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 let EXPORTED_SYMBOLS = ["AboutRequestPolicy"];
 
 Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
-ScriptLoader.importModule("bootstrap-manager", this);
+ScriptLoader.importModule("process-environment", this);
 
 var filenames = {
   "basicprefs": "basicprefs.html",
@@ -91,13 +91,13 @@ let AboutRequestPolicy = (function() {
 
 
 
-  BootstrapManager.registerStartupFunction(function() {
+  ProcessEnvironment.enqueueStartupFunction(function() {
     Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
         .registerFactory(self.classID, self.classDescription, self.contractID,
             self);
   });
 
-  BootstrapManager.registerShutdownFunction(function() {
+  ProcessEnvironment.pushShutdownFunction(function() {
     let registrar = Components.manager
         .QueryInterface(Ci.nsIComponentRegistrar);
     // This needs to run asynchronously, see bug 753687
diff --git a/src/content/lib/bootstrap-manager.jsm b/src/content/lib/bootstrap-manager.jsm
deleted file mode 100644
index 36b4491..0000000
--- a/src/content/lib/bootstrap-manager.jsm
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * ***** BEGIN LICENSE BLOCK *****
- *
- * RequestPolicy - A Firefox extension for control over cross-site requests.
- * Copyright (c) 2008-2012 Justin Samuel
- * Copyright (c) 2014-2015 Martin Kimmerle
- *
- * This program is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * ***** END LICENSE BLOCK *****
- */
-
-const Ci = Components.interfaces;
-const Cc = Components.classes;
-const Cu = Components.utils;
-
-let EXPORTED_SYMBOLS = ["BootstrapManager"];
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-let globalScope = this;
-let scriptLoaderURI = "chrome://requestpolicy/content/lib/script-loader.jsm";
-// TODO: implement. see https://github.com/RequestPolicyContinued/requestpolicy/issues/486
-//let SevereErrorHandler = {};
-
-
-
-let BootstrapManager = (function() {
-  let self = {};
-
-
-  let startupFunctionStack = [];
-  let shutdownFunctionStack = [];
-  //let installFunctionStack = [];
-  //let uninstallFunctionStack = [];
-
-  /**
-   * The functions in one of the arrays above will be called. Not that the list
-   * itself might get even more entries while it is being called; therefore
-   * pop() is used.
-   */
-  let callBootstrapFunctions = function(functions, data, reason) {
-    // pop the topmost function as long as there is one.
-    //
-    // The combination of push() and pop() leads to FILO (first in, last out)
-    // for the shutdown process. In other words, it's a stack
-    for (let f = functions.pop(); !!f; f = functions.pop()) {
-      f(data, reason);
-    }
-  };
-  let callStartupFunctions = callBootstrapFunctions.bind(this, startupFunctionStack);
-  let callShutdownFunctions = callBootstrapFunctions.bind(this, shutdownFunctionStack);
-  //let callInstallFunctions = callBootstrapFunctions.bind(this, installFunctionStack);
-  //let callUninstallFunctions = callBootstrapFunctions.bind(this, uninstallFunctionStack);
-
-  /**
-   * This set of functions can be used for adding startup/shutdown functions.
-   * Note: the first startup function to be executed will import all modules so
-   * that all subsequent startup-functions get called *after* all modules have
-   * been loaded.
-   */
-  let registerFunction = function(target, f) {
-    target.push(f);
-  };
-  self.registerStartupFunction = registerFunction.bind(this, startupFunctionStack);
-  self.registerShutdownFunction = registerFunction.bind(this, shutdownFunctionStack);
-  //self.registerInstallFunction = registerFunction.bind(this, installFunctionStack);
-  //self.registerUninstallFunction = registerFunction.bind(this, uninstallFunctionStack);
-
-
-
-  /**
-   * Import main modules on startup. This will be the first function that will
-   * be called, and as the modules depend on all other modules recursively, all
-   * modules will be loaded already when the second startup function gets
-   * called.
-   */
-  self.registerStartupFunction(function() {
-    // Manually load the ScriptLoader. It has to be unloded manually as well!
-    Cu.import(scriptLoaderURI, globalScope);
-
-    // Next, import essential modules. Dependencies will be imported as well.
-    //
-    // It's IMPORTANT that those modules are imported in a startup-function
-    // and NOT when BootstrapManager itself gets loaded. The reason is that many
-    // modules call `BootstrapManager.registerStartupFunction()` at load-time,
-    // which wouldn't be available if BootstrapManager is *itself* still being
-    // loaded. This would be an "import()-loop".
-    {
-      // At first initialize the preferences. Its scope doesn't need to be
-      // remembered.
-      Services.scriptloader.loadSubScript(
-          "chrome://requestpolicy/content/lib/default-prefs-initializer.js",
-          {});
-      // import the Logger as the first module so that its startup-function
-      // will be called after this one
-      ScriptLoader.importModule("logger");
-      ScriptLoader.importModules(["requestpolicy-service", "window-manager",
-                                  "about-uri"], globalScope);
-    }
-  });
-
-  self.registerShutdownFunction(function() {
-    // HACK WARNING: The Addon Manager does not properly clear all addon
-    //               related caches on update; in order to fully update
-    //               images and locales, their caches need clearing here.
-    Services.obs.notifyObservers(null, "chrome-flush-caches", null);
-
-    // manually unload the ScriptLoader
-    Cu.unload(scriptLoaderURI);
-  });
-
-
-
-  // when startup() and shutdown() are called, simply call all
-  self.startup = callStartupFunctions.bind(this);
-  self.shutdown = callShutdownFunctions.bind(this);
-
-  return self;
-}());
diff --git a/src/content/lib/content-policy.jsm b/src/content/lib/content-policy.jsm
index 6c0ab05..dfb7746 100644
--- a/src/content/lib/content-policy.jsm
+++ b/src/content/lib/content-policy.jsm
@@ -39,7 +39,7 @@ ScriptLoader.importModules([
   "request",
   "utils",
   "request-processor",
-  "bootstrap-manager"
+  "process-environment"
 ], globalScope);
 
 
@@ -77,7 +77,7 @@ let PolicyImplementation = (function() {
   };
 
 
-  BootstrapManager.registerShutdownFunction(function() {
+  ProcessEnvironment.pushShutdownFunction(function() {
     let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
     let catMan = Utils.categoryManager;
 
diff --git a/src/content/lib/environment.jsm b/src/content/lib/environment.jsm
new file mode 100644
index 0000000..c22d66b
--- /dev/null
+++ b/src/content/lib/environment.jsm
@@ -0,0 +1,149 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ *
+ * RequestPolicy - A Firefox extension for control over cross-site requests.
+ * Copyright (c) 2008-2012 Justin Samuel
+ * Copyright (c) 2014-2015 Martin Kimmerle
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ***** END LICENSE BLOCK *****
+ */
+
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+const Cu = Components.utils;
+
+let EXPORTED_SYMBOLS = ["Environment"];
+
+
+/**
+ * The `Environment` class can take care of the "startup" (=initialization) and
+ * "shutdown" of any environment.
+ *
+ * Example implementations for this class are:
+ *   - "process" environments -- created e.g. by bootstrap.js
+ *   - "window" environments -- used in frame scripts and on pref web pages
+ *
+ * The Environment contains
+ *   - one *queue* for startup functions
+ *   - one *stack* for shutdown functions
+ * Those functions will be called when startup() and shutdown(), respectively,
+ * are called.
+ *
+ * ### Implementation of the Queue and the Stack:
+ * The Queue is implemented in a FIFO [3] sense, the Stack in a LIFO [4] sense.
+ *   => for the queue, Array.push() and Array.shift() are used.
+ *   => for the stack, Array.push() and Array.pop() are used.
+ *
+ * ### Reason for queue <--> stack distinction:
+ * The most important files will add their startup & shutdown functions
+ * before the less important functions will do.
+ *   => Startup: the important functions should be called first
+ *   => Shutdown: the important functions should be called last
+ *
+ * ### more information on FIFO/LIFO and Queues/Stacks:
+ *   [1] https://en.wikipedia.org/wiki/Queue_%28abstract_data_type%29
+ *   [2] https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29
+ *   [3] https://en.wikipedia.org/wiki/FIFO
+ *   [4] https://en.wikipedia.org/wiki/LIFO_%28computing%29
+ */
+function Environment() {
+  let self = this;
+
+  self.state = Environment.STATE_SHUT_DOWN;
+
+  // The function queues
+  self.startupFnQueue = [];
+  self.shutdownFnStack = [];
+}
+
+Environment.STATE_SHUT_DOWN = 0;
+Environment.STATE_STARTING_UP = 1;
+Environment.STATE_STARTUP_DONE = 2;
+Environment.STATE_SHUTTING_DOWN = 3;
+
+
+/**
+ * This set of functions can be used for adding startup/shutdown functions.
+ */
+Environment.prototype.enqueueStartupFunction = function(f) {
+  let self = this;
+  switch (self.state) {
+    case Environment.STATE_SHUTTING_DOWN:
+      // When the shutdown is currently in progress we simply ignore the
+      // startup() function, as it makes no sense.
+      break;
+
+    case Environment.STATE_STARTUP_DONE:
+      // If the environment already finished starting up, the function is added
+      // to the stack and the stack is processed immediately.
+      // Note: Calling `callFunctions` is on purpose, as the function `f` might
+      //       add more startup functions as well!
+      self.startupFnQueue.push(f);
+      callFunctions(self.startupFnQueue, arguments);
+      break;
+
+    default:
+      // In any other case, add the function to the stack.
+      self.startupFnQueue.push(f);
+      break;
+  }
+};
+Environment.prototype.pushShutdownFunction = function(f) {
+  let self = this;
+  self.shutdownFnStack.push(f);
+};
+
+
+/**
+ * This function calls all functions of a function queue.
+ */
+function callFunctions(fnArray, sequence, fnArgsToApply) {
+  // `sequence` decides whether LIFO or FIFO is used
+  let popOrShift = sequence === "lifo" ? "pop" : "shift";
+
+  // process the Array as long as it contains elements
+  while (fnArray.length > 0) {
+    // The following is either `fnArray.pop()` or `fnArray.shift()`
+    // depending on `sequence`.
+    let f = fnArray[popOrShift]();
+
+    // call the function
+    f.apply(this, fnArgsToApply);
+  }
+};
+
+
+Environment.prototype.startup = function() {
+  let self = this;
+  self.state = Environment.STATE_STARTING_UP;
+  callFunctions(self.startupFnQueue, arguments);
+  self.state = Environment.STATE_STARTUP_DONE;
+};
+
+Environment.prototype.shutdown = function() {
+  let self = this;
+  self.state = Environment.STATE_SHUTTING_DOWN;
+  callFunctions(self.shutdownFnStack, arguments);
+  self.state = Environment.STATE_SHUT_DOWN;
+};
+
+
+Environment.prototype.shutdownOnWindowUnload = function(aWindow) {
+  let self = this;
+  aWindow.addEventListener("unload", function() {
+    self.shutdown();
+  });
+};
diff --git a/src/content/lib/logger.jsm b/src/content/lib/logger.jsm
index 87d2533..d339430 100644
--- a/src/content/lib/logger.jsm
+++ b/src/content/lib/logger.jsm
@@ -31,7 +31,7 @@ Cu.import("resource://gre/modules/Services.jsm");
 
 Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
 ScriptLoader.importModules([
-  "bootstrap-manager",
+  "process-environment",
   "prefs"
 ], this);
 
@@ -122,7 +122,7 @@ let Logger = (function() {
     initialized = true;
   }
 
-  BootstrapManager.registerStartupFunction(init);
+  ProcessEnvironment.enqueueStartupFunction(init);
 
 
 
diff --git a/src/content/lib/observer-manager.js b/src/content/lib/observer-manager.js
index c685888..cb45888 100644
--- a/src/content/lib/observer-manager.js
+++ b/src/content/lib/observer-manager.js
@@ -21,6 +21,8 @@
  * ***** END LICENSE BLOCK *****
  */
 
+// TODO: convert this file into a module, as we now have `ProcessEnvironment`
+//       which handles startup and shutdown and can be imported from anywhere.
 
 /**
  * The ObserverManager provides an interface to `nsIObserverService` which takes
@@ -48,9 +50,8 @@ var ObserverManager = ObserverManager || (function() {
     Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm", mod);
     ScriptLoader = mod.ScriptLoader;
   }
-  let {isMainProcess} = ScriptLoader.importModule("utils/process-info");
-  let {Logger} = ScriptLoader.importModule("logger");
-
+  let Logger;
+  let {ProcessEnvironment} = ScriptLoader.importModule("process-environment");
 
 
   /**
@@ -83,6 +84,9 @@ var ObserverManager = ObserverManager || (function() {
   };
 
 
+
+
+
   // an object holding all observers for unregistering when unloading the page
   let observers = [];
 
@@ -103,50 +107,24 @@ var ObserverManager = ObserverManager || (function() {
       "requestpolicy-prefs-changed");
 
 
-  //
-  // The following section is about unregistering the observers.
-  //
-  {
-    /**
-     * This function unregisters all registered observers. It will be called
-     * before the obserers and their enironment is destroyed, see below.
-     */
-    let unregisterObservers = function(event) {
-      while (observers.length > 0) {
-        let observer = observers.pop();
-        Logger.dump("Unregistering observer for topic " + observer.topic);
-        observer.unregister();
-      }
-    };
-
-    // Now it's necessary to detect the environment. Two possibilities:
-    // (a) Either the script has been loaded directly into a window's scope
-    // (b) or it has been loaded by a *.jsm file.
-    //
-    // In case (a) the Observers will be unregistered at the window's `unload`, in
-    // the other case this will happen on RP shutdown.
-    if (typeof content !== 'undefined') {
-      // case (a), a `content` object exists
-      // (see https://developer.mozilla.org/en-US/docs/Web/API/window.content)
-      content.addEventListener("unload", unregisterObservers);
-    } else {
-      // case (b)
-
-      // if: Is this a child process or the main process?
-      if (!isMainProcess) {
-        Logger.warning(Logger.TYPE_INTERNAL, "It won't be possible to " +
-                       "unregister the observers; this is a child process, " +
-                       "so there has to be a `content` object in " +
-                       "ObserverManager's environment, but there is no " +
-                       "`content` object!",
-                       new Error());
-      } else {
-        // it's the main process
-        let {BootstrapManager} = ScriptLoader.importModule("bootstrap-manager");
-        BootstrapManager.registerShutdownFunction(unregisterObservers);
-      }
+
+
+
+  ProcessEnvironment.enqueueStartupFunction(function() {
+    // Load the Logger now, not earlier. Otherwise it could be null.
+    Logger = ScriptLoader.importModule("logger").Logger;
+  });
+
+  /**
+   * The function will unregister all registered observers.
+   */
+  ProcessEnvironment.pushShutdownFunction(function() {
+    while (observers.length > 0) {
+      let observer = observers.pop();
+      Logger.dump("Unregistering observer for topic " + observer.topic);
+      observer.unregister();
     }
-  }
+  });
 
   return self;
 }());
diff --git a/src/content/lib/process-environment.jsm b/src/content/lib/process-environment.jsm
new file mode 100644
index 0000000..f4488eb
--- /dev/null
+++ b/src/content/lib/process-environment.jsm
@@ -0,0 +1,149 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ *
+ * RequestPolicy - A Firefox extension for control over cross-site requests.
+ * Copyright (c) 2008-2012 Justin Samuel
+ * Copyright (c) 2014-2015 Martin Kimmerle
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ***** END LICENSE BLOCK *****
+ */
+
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+const Cu = Components.utils;
+
+let EXPORTED_SYMBOLS = ["ProcessEnvironment"];
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+let globalScope = this;
+let scriptLoaderURI = "chrome://requestpolicy/content/lib/script-loader.jsm";
+
+
+// In the main process this module is the first one to be loaded and the last to
+// be unloded. So this file defines what is done on the extension's startup.
+// These are the steps for the main process:
+//  1. the script loader is loaded *manually* (!)
+//  2. the module containing the Environment class is loaded
+//  3. create a new ProcessEnvironment (the Main Process Environment)
+//  4. define the startup function
+//     --> It loads all essential modules.
+//         This implicitely and recursively loads all other modules.
+//  5. define the shutdown function
+//     5.1. As the ScriptLoader must not load any of RP's modules, its
+//          Main Process shutdown function will be called from here.
+//     5.2. As this the ScriptLoader has been loaded manually, it has to be
+//          unloded manually as well!
+
+
+// =======================================
+// Step 1: Manually load the ScriptLoader.
+// ---------------------------------------
+// ( If this is the main process, it has to be unaloded manually as well! The
+//   shutdown function is defined below. )
+Cu.import(scriptLoaderURI, globalScope);
+// =======================================
+
+
+// =======================================
+// Step 2: load the Environment class
+// ----------------------------------
+ScriptLoader.importModule("environment", globalScope);
+// =======================================
+
+
+// =======================================
+// Step 3: create a new Environment
+// --------------------------------
+let ProcessEnvironment = new Environment();
+// =======================================
+
+
+// determine if this is the main process
+ProcessEnvironment.isMainProcess = (function isMainProcess() {
+  let xulRuntime = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
+  // The "default" type means that we're on the main process, the chrome process.
+  // This is relevant for multiprocessor firefox aka Electrolysis (e10s).
+  return xulRuntime.processType === xulRuntime.PROCESS_TYPE_DEFAULT;
+}());
+
+
+
+if (ProcessEnvironment.isMainProcess) {
+  // The following startup functions should be defined only in the main process.
+
+  // =======================================
+  // Step 4: define the startup function
+  // -----------------------------------
+  /**
+   * Import main modules on startup. This will be the first function that will
+   * be called. It imports essential modules which depend recursively on other
+   * modules. This means that when the second startup function is being called,
+   * all modules will already be loaded.
+   */
+  ProcessEnvironment.enqueueStartupFunction(function() {
+    // Import essential modules. Dependencies will be imported as well.
+    //
+    // IMPORTANT note:
+    //     Those modules have to be imported in a startup-function and NOT at
+    //     the time the `ProcessEnvironment` module itself is being loaded.
+    // In detail:
+    //     `ProcessEnvironment.enqueueStartupFunction()` is called by many
+    //     modules at load-time. If those modules would be loaded when
+    //     `process-environment.jsm` wasn't already loaded completely, the
+    //     `ProcessEnvironment` wouldn't be available. This would be an
+    //     "import()-loop".
+    // Illustration:
+    //     bootstrap.js  calls  load(ProcessEnvironment)
+    //         ProcessEnvironment  calls  load(moduleXY)
+    //             moduleXY  calls  load(ProcessEnvironment)
+    //                 ProcessEnvironment says "You can't load me, I didn't
+    //                 finish yet!"
+    {
+      // At first initialize the preferences. Its scope doesn't need to be
+      // remembered.
+      Services.scriptloader.loadSubScript("chrome://requestpolicy/content/lib/"+
+                                          "default-prefs-initializer.js", {});
+
+      // import the Logger as the first module so that its startup-function
+      // will be called after this one
+      ScriptLoader.importModule("logger", globalScope);
+      ScriptLoader.importModules(["requestpolicy-service", "window-manager",
+                                  "about-uri"], globalScope);
+    }
+  });
+  // =======================================
+
+
+  // =======================================
+  // Step 5: define the shutdown function
+  // ------------------------------------
+  ProcessEnvironment.pushShutdownFunction(function() {
+    // HACK WARNING: The Addon Manager does not properly clear all addon
+    //               related caches on update; in order to fully update
+    //               images and locales, their caches need clearing here.
+    Services.obs.notifyObservers(null, "chrome-flush-caches", null);
+
+
+    // Step 5.1: call ScriptLoader's Main Process shutdown functions
+    ScriptLoader.unloadAllLibraries();
+    ScriptLoader.unloadAllModules();
+
+    // Step 5.2: manually unload the ScriptLoader
+    Cu.unload(scriptLoaderURI);
+  });
+  // =======================================
+}
diff --git a/src/content/lib/request-processor.jsm b/src/content/lib/request-processor.jsm
index e536cc0..fecd15b 100644
--- a/src/content/lib/request-processor.jsm
+++ b/src/content/lib/request-processor.jsm
@@ -47,8 +47,7 @@ ScriptLoader.importModules([
   "utils",
   "request",
   "request-result",
-  "request-set",
-  "bootstrap-manager"
+  "request-set"
 ], this);
 ScriptLoader.defineLazyModuleGetters({
   "content-policy": ["PolicyImplementation"],
diff --git a/src/content/lib/requestpolicy-service.jsm b/src/content/lib/requestpolicy-service.jsm
index badcee3..9bfa004 100644
--- a/src/content/lib/requestpolicy-service.jsm
+++ b/src/content/lib/requestpolicy-service.jsm
@@ -42,7 +42,7 @@ ScriptLoader.importModules([
   "utils",
   "content-policy",
   "constants",
-  "bootstrap-manager",
+  "process-environment",
   "observer-manager"
 ], this);
 
@@ -435,10 +435,10 @@ let rpService = (function() {
 
 
   // /////////////////////////////////////////////////////////////////////////
-  // Bootstrap functions
+  // startup and shutdown functions
   // /////////////////////////////////////////////////////////////////////////
 
-  BootstrapManager.registerStartupFunction(function() {
+  ProcessEnvironment.enqueueStartupFunction(function() {
     init();
 
     loadConfigAndRules();
@@ -448,7 +448,7 @@ let rpService = (function() {
     initializeApplicationCompatibility();
   });
 
-  BootstrapManager.registerShutdownFunction(function(data, reason) {
+  ProcessEnvironment.pushShutdownFunction(function(data, reason) {
     if (reason == ADDON_DISABLE || reason == ADDON_UNINSTALL) {
       handleUninstallOrDisable();
     }
@@ -457,7 +457,9 @@ let rpService = (function() {
     rpServiceInitialized = false;
   });
 
-  //BootstrapManager.registerUninstallFunction(function(data, reason) {
+  // TODO: Handle uninstallation in bootstrap.js, not here, RP might be disabled
+  //       when being uninstalled.
+  //ProcessEnvironment.registerUninstallFunction(function(data, reason) {
   //  handleUninstallOrDisable();
   //});
 
diff --git a/src/content/lib/script-loader.jsm b/src/content/lib/script-loader.jsm
index 38aba82..d820dca 100644
--- a/src/content/lib/script-loader.jsm
+++ b/src/content/lib/script-loader.jsm
@@ -55,24 +55,22 @@ let ScriptLoader = (function() {
 
   let importedModuleURIs = {};
 
-  let scopes = {};
-
   // contains the module IDs that are currently being imported initially and
   // have not finished importing yet.
   let modulesCurrentlyBeingImported = {};
 
 
   let self = {
-    unloadAllLibraries: function() {
-      scopes = {};
-    },
-
+    /**
+     * Unload all modules that have been imported.
+     * See https://developer.mozilla.org/en-US/docs/Components.utils.unload
+     * The Process Environment of the main process takes care of calling this
+     * function.
+     */
     unloadAllModules: function() {
       for (let uri in importedModuleURIs) {
         if (importedModuleURIs.hasOwnProperty(uri)) {
-          //dump("unloading " + uri + "  ...  ");
           Cu.unload(uri);
-          //dump("ok.\n");
           delete importedModuleURIs[uri];
         }
       }
@@ -179,10 +177,3 @@ let ScriptLoader = (function() {
 
   return self;
 }());
-
-let {BootstrapManager} = ScriptLoader.importModule("bootstrap-manager");
-
-BootstrapManager.registerShutdownFunction(function() {
-  ScriptLoader.unloadAllLibraries();
-  ScriptLoader.unloadAllModules();
-});
diff --git a/src/content/lib/utils.jsm b/src/content/lib/utils.jsm
index 70f2d75..02897c6 100644
--- a/src/content/lib/utils.jsm
+++ b/src/content/lib/utils.jsm
@@ -32,7 +32,11 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/AddonManager.jsm");
 
 Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
-ScriptLoader.importModules(["prefs", "constants", "bootstrap-manager"], this);
+ScriptLoader.importModules([
+  "prefs",
+  "constants",
+  "process-environment"
+], this);
 
 
 
@@ -173,7 +177,7 @@ let Utils = (function() {
     let sealInternal = function() {
       delete aModuleScope.internal;
     };
-    BootstrapManager.registerStartupFunction(sealInternal);
+    ProcessEnvironment.enqueueStartupFunction(sealInternal);
     return aModuleScope.internal;
   };
 
diff --git a/src/content/lib/window-manager-toolbarbutton.js b/src/content/lib/window-manager-toolbarbutton.js
index 3e7309b..98f27ac 100644
--- a/src/content/lib/window-manager-toolbarbutton.js
+++ b/src/content/lib/window-manager-toolbarbutton.js
@@ -46,11 +46,11 @@ let rpWindowManager = (function(self) {
   //
 
   if (isAustralis) {
-    BootstrapManager.registerStartupFunction(function() {
+    ProcessEnvironment.enqueueStartupFunction(function() {
       addToolbarButtonToAustralis();
     });
 
-    BootstrapManager.registerShutdownFunction(function() {
+    ProcessEnvironment.pushShutdownFunction(function() {
       let tbb = XULUtils.xulTrees.toolbarbutton[0];
       CustomizableUI.destroyWidget(tbb.id);
     });
diff --git a/src/content/lib/window-manager.jsm b/src/content/lib/window-manager.jsm
index 12a4209..ff11526 100644
--- a/src/content/lib/window-manager.jsm
+++ b/src/content/lib/window-manager.jsm
@@ -39,7 +39,7 @@ let rpWindowManager = (function(self) {
     "utils",
     "utils/xul",
     "constants",
-    "bootstrap-manager"
+    "process-environment"
   ], globalScope);
 
   let styleSheets = [
@@ -149,14 +149,14 @@ let rpWindowManager = (function(self) {
 
 
 
-  BootstrapManager.registerStartupFunction(function(data, reason) {
+  ProcessEnvironment.enqueueStartupFunction(function(data, reason) {
     forEachOpenWindow(loadIntoWindow);
     Services.wm.addListener(WindowListener);
 
     loadStyleSheets();
   });
 
-  BootstrapManager.registerShutdownFunction(function() {
+  ProcessEnvironment.pushShutdownFunction(function() {
     forEachOpenWindow(unloadFromWindow);
     Services.wm.removeListener(WindowListener);
 
diff --git a/src/content/ui/frame.js b/src/content/ui/frame.js
index bdcf179..054bf90 100644
--- a/src/content/ui/frame.js
+++ b/src/content/ui/frame.js
@@ -23,6 +23,49 @@
 var MMID = "requestpolicy at requestpolicy.com";
 
 Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("chrome://requestpolicy/content/lib/script-loader.jsm");
+
+
+
+/**
+ * This function gets a Environment variable that has the same lifespan like
+ * the content window, i.e. the Environment's shutdown() function will be called
+ * when the content window is unloaded.
+ *
+ * There are two cases:
+ *
+ * If this is the main process:
+ *     A new Environment is created.
+ *
+ * If this is *not* the main process:
+ *     `ProcessEnvironment` will be used. This ensures that this script will
+ *     have the same Environment as the modules that will be loaded.
+ */
+var WinEnv = (function getWindowEnvironment() {
+  var {ProcessEnvironment} = ScriptLoader.importModule("process-environment");
+
+  let env;
+
+  // Check if this is the main process.
+  if (ProcessEnvironment.isMainProcess === true) {
+    // This is the main process. The `ProcessEnvironment` can't be used as the
+    // content window's Environment, so a new Environment has to be created.
+    let {Environment} = ScriptLoader.importModules(["environment"]);
+    env = new Environment();
+  } else {
+    // This is a child process. The `ProcessEnvironment` can be used for this
+    // window's Environment.
+    env = ProcessEnvironment;
+  }
+
+  // Tell the Environment to shut down when the content window is unloaded.
+  // Note that this is necessary in any of the above cases.
+  env.shutdownOnWindowUnload(content);
+
+  return env;
+}());
+
+
 
 // fixme: It's unclear whether it's necessary to listen for *any* click in
 //        the window. Originally the following code has been part of
@@ -66,6 +109,7 @@ Components.utils.import("resource://gre/modules/Services.jsm");
     }
   }, true);*/
 
+WinEnv.enqueueStartupFunction(function() {
   addMessageListener(MMID + ":reload", function() {
     content.document.location.reload(false);
   });
@@ -73,10 +117,16 @@ Components.utils.import("resource://gre/modules/Services.jsm");
   addMessageListener(MMID + ":setLocation", function(message) {
     content.document.location.href = message.data.uri;
   });
+});
+
+
+WinEnv.enqueueStartupFunction(function() {
+  Services.scriptloader.loadSubScript(
+      'chrome://requestpolicy/content/ui/frame.blocked-content.js');
+  Services.scriptloader.loadSubScript(
+      'chrome://requestpolicy/content/ui/frame.dom-content-loaded.js');
+  Services.scriptloader.loadSubScript(
+      'chrome://requestpolicy/content/ui/frame.doc-manager.js');
+});
 
-Services.scriptloader.loadSubScript(
-    'chrome://requestpolicy/content/ui/frame.blocked-content.js');
-Services.scriptloader.loadSubScript(
-    'chrome://requestpolicy/content/ui/frame.dom-content-loaded.js');
-Services.scriptloader.loadSubScript(
-    'chrome://requestpolicy/content/ui/frame.doc-manager.js');
+WinEnv.startup();

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/requestpolicy.git



More information about the Pkg-mozext-commits mailing list