[Pkg-mozext-commits] [requestpolicy] 172/280: integrate EnvMan into Environment, et cetera

David Prévot taffit at moszumanska.debian.org
Sat May 2 20:30:19 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 355cf5d61126262c9b22ccf3b018ee78bca6ef9d
Author: Martin Kimmerle <dev at 256k.de>
Date:   Fri Jan 23 14:37:43 2015 +0100

    integrate EnvMan into Environment, et cetera
    
    This commit removes the EnvironmentManager introduced by
    commit `75aca76`. The managing-functionality has been merged
    into the `Environment` class itself, which means that each
    environment manages its inner environments. The EnvMan's
    special startup- and shutdown-tasks can now be found in
    `ProcessEnvironment` which is an instance of one of the
    following classes:
    - ParentProcessEnvironment
    - ChildProcessEnvironment
    Those two classes aren't exported, as each process needs only
    one instance of one of the two classes.
    Further information will be documented in the wiki.
    
    Another change, which is even more significant, is a bugfix
    introduced as well by commit `75aca76`. That commit made the
    assumption that if a framescript is in a child process, that
    framescript will be the only framescript in that process.
    THIS IS WRONG. Usually there are several framescripts in the
    same process. The opposite should be seldomly the case. The
    solution was to
---
 src/bootstrap.js                                  |  21 +-
 src/content/lib/content-policy.jsm                |   2 +-
 src/content/lib/environment.jsm                   | 434 ++++++++++++++++------
 src/content/lib/environment.process.js            | 221 +++++++++++
 src/content/lib/logger.jsm                        |   2 +-
 src/content/lib/manager-for-event-listeners.jsm   |   1 -
 src/content/lib/manager-for-message-listeners.jsm |   9 +-
 src/content/lib/observer-manager.jsm              |   2 +-
 src/content/lib/prefs.jsm                         |   2 +-
 src/content/lib/process-environment.jsm           |  53 ---
 src/content/lib/request-processor.compat.js       |   2 +-
 src/content/lib/request-processor.jsm             |   2 +-
 src/content/lib/request-processor.redirects.js    |   4 +-
 src/content/lib/request.jsm                       |   8 +-
 src/content/lib/script-loader.jsm                 |   2 +-
 src/content/lib/utils.jsm                         |   2 +-
 src/content/main/about-uri.jsm                    |   2 +-
 src/content/main/environment-manager-child.js     | 116 ------
 src/content/main/environment-manager-parent.js    | 117 ------
 src/content/main/environment-manager.jsm          | 135 -------
 src/content/main/pref-manager.jsm                 |   2 +-
 src/content/main/requestpolicy-service.jsm        |   2 +-
 src/content/main/window-manager.jsm               |  13 +-
 src/content/settings/common.js                    |   2 +-
 src/content/ui/frame.dom-content-loaded.js        |   8 +-
 src/content/ui/frame.js                           | 178 +++------
 src/content/ui/overlay.js                         |   4 +-
 src/content/ui/request-log.js                     |   5 +-
 28 files changed, 646 insertions(+), 705 deletions(-)

diff --git a/src/bootstrap.js b/src/bootstrap.js
index 23ea63b..738ce6e 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 envManURI = "chrome://requestpolicy/content/main/" +
-    "environment-manager.jsm";
+var mod = {};
+const envURI = "chrome://requestpolicy/content/lib/environment.jsm";
 
 /**
  * If any Exception gets into bootstrap.js, it will be a severe error.
@@ -38,22 +38,23 @@ function logSevereError(msg, e) {
   Cu.reportError(e);
 }
 
-function startup(...startupArgs) {
+function startup(data, reason) {
   try {
-    // Import the EnvironmentManager and call its startup() function.
-    Cu.import(envManURI);
-    EnvironmentManager.startup(startupArgs);
+    // Import the ProcessEnvironment and call its startup() function.
+    Cu.import(envURI, mod);
+    mod.ProcessEnvironment.startup(arguments);
   } catch(e) {
     logSevereError("startup() failed!", e);
   }
 }
 
-function shutdown(...shutdownArgs) {
+function shutdown(data, reason) {
+
   try {
     // shutdown, unset and unload.
-    EnvironmentManager.shutdown(shutdownArgs);
-    EnvironmentManager = null;
-    Cu.unload(envManURI);
+    mod.ProcessEnvironment.shutdown(arguments);
+    mod = {};
+    Cu.unload(envURI);
   } catch(e) {
     logSevereError("shutdown() failed!", e);
   }
diff --git a/src/content/lib/content-policy.jsm b/src/content/lib/content-policy.jsm
index c1108a2..c781a3d 100644
--- a/src/content/lib/content-policy.jsm
+++ b/src/content/lib/content-policy.jsm
@@ -39,7 +39,7 @@ ScriptLoader.importModules([
   "lib/request",
   "lib/utils",
   "lib/request-processor",
-  "lib/process-environment"
+  "lib/environment"
 ], globalScope);
 
 
diff --git a/src/content/lib/environment.jsm b/src/content/lib/environment.jsm
index b6a28f1..200e3b7 100644
--- a/src/content/lib/environment.jsm
+++ b/src/content/lib/environment.jsm
@@ -21,27 +21,34 @@
  * ***** END LICENSE BLOCK *****
  */
 
+let EXPORTED_SYMBOLS = [
+  "Environment",
+  "FrameScriptEnvironment",
+  "ProcessEnvironment"
+];
+
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 
-let EXPORTED_SYMBOLS = ["Environment"];
-
 let globalScope = this;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-//Cu.import("resource://gre/modules/devtools/Console.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/devtools/Console.jsm");
 
 Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
 
 ScriptLoader.defineLazyModuleGetters({
   "lib/manager-for-event-listeners": ["ManagerForEventListeners"],
-  "main/environment-manager": ["EnvironmentManager"],
+  "lib/manager-for-message-listeners": ["ManagerForMessageListeners"],
+  "lib/utils/constants": ["C"],
   "lib/observer-manager": ["ObserverManager"]
 }, globalScope);
 
 
 
+
 let ENV_STATES = {
   "NOT_STARTED": 0,
   "STARTING_UP": 1,
@@ -72,29 +79,94 @@ let LEVEL_STATES = {
 };
 
 
+let BOOTSTRAP = {
+  "startup": {
+    levelSequence: [
+      LEVELS.ESSENTIAL,
+      LEVELS.BACKEND,
+      LEVELS.INTERFACE,
+      LEVELS.UI
+    ],
+    lastLevel: LEVELS.UI,
+    envStates: {
+      "beforeProcessing": ENV_STATES.NOT_STARTED,
+      "duringProcessing": ENV_STATES.STARTING_UP,
+      "afterProcessing": ENV_STATES.STARTUP_DONE
+    },
+    functions: {
+      "beforeProcessing": function() {
+        // "this" will be an environment
+        let self = this;
+        //console.log("[RPC] starting up Environment " + getEnvInfo(self) + "." +
+        //            (self.outerEnv ?
+        //             " OuterEnv is " + getEnvInfo(self.outerEnv) + "." :
+        //             " No OuterEnv."));
+        self.register();
+      },
+      "afterProcessing": function() {}
+    }
+  },
+  "shutdown": {
+    levelSequence: [
+      LEVELS.UI,
+      LEVELS.INTERFACE,
+      LEVELS.BACKEND,
+      LEVELS.ESSENTIAL
+    ],
+    lastLevel: LEVELS.ESSENTIAL,
+    envStates: {
+      "beforeProcessing": ENV_STATES.STARTUP_DONE,
+      "duringProcessing": ENV_STATES.SHUTTING_DOWN,
+      "afterProcessing": ENV_STATES.SHUT_DOWN
+    },
+    functions: {
+      "beforeProcessing": function() {},
+      "afterProcessing": function() {
+        // "this" will be an environment
+        let self = this;
+        self.innerEnvs.length = 0;
+        self.unregister();
+      }
+    }
+  }
+};
+function getBootstrapMetadata(startupOrShutdown) {
+  return BOOTSTRAP[startupOrShutdown];
+}
+
+
 /**
- * The `Environment` class can take care of the "startup" (=initialization) and
- * "shutdown" of any environment.
+ * The `Environment` class can take care of the "startup" (=initialization)
+ * and "shutdown" of any environment.
  *
  * To each `Environment` instance, `startup` and `shutdown` functions can be
- * added. As soon as the Environment's startup() function is called, all of
- * those functions will be called; same for shutdown().
+ * added. As soon as the Environment starts up, e.g. via its startup()
+ * function, all those functions will be called. Equally the shutdown
+ * functions are called on the environment's shutdown.
  *
  * Both startup and shutdown functions will have Levels assigned. The levels
- * of the functions determine in which sequence they are called
+ * of the functions determine in which sequence they are called.
+ *
+ * @constructor
+ * @param {Environment=} aOuterEnv - the Environment to which this environment
+ *     will register itself. Inner environments shut down when its outer
+ *     environment shuts down.
+ * @param {string=} aName - the Environment's name; only needed for debugging.
  */
-function Environment(aName) {
+function Environment(aOuterEnv, aName="anonymous") {
   let self = this;
 
-  // the Environment's name is only needed for debugging
-  self.name = aName || "anonymous";
-
   self.envState = ENV_STATES.NOT_STARTED;
 
-  self.startupLevels = generateLevelObjects();
-  self.shutdownLevels = generateLevelObjects();
+  self.name = aName;
+
+  self.outerEnv = aOuterEnv instanceof Environment ? aOuterEnv : null;
+  self.innerEnvs = new Set();
 
-  EnvironmentManager.registerEnvironment(self);
+  self.levels = {
+    "startup": generateLevelObjects(),
+    "shutdown": generateLevelObjects()
+  };
 
   // Define a Lazy Getter to get an ObserverManager for this Environment.
   // Using that Getter is more convenient than doing it manually, as the
@@ -117,7 +189,6 @@ function Environment(aName) {
   //console.debug('[RPC] created new Environment "'+self.name+'"');
 }
 
-Environment.ENV_STATES = ENV_STATES;
 Environment.LEVELS = LEVELS;
 
 
@@ -136,53 +207,62 @@ function generateLevelObjects() {
   return obj;
 }
 
-(function addLevelIterators(Environment) {
-  let startupSequence = [
-    LEVELS.ESSENTIAL,
-    LEVELS.BACKEND,
-    LEVELS.INTERFACE,
-    LEVELS.UI
-  ];
-  let shutdownSequence = [
-    LEVELS.UI,
-    LEVELS.INTERFACE,
-    LEVELS.BACKEND,
-    LEVELS.ESSENTIAL
-  ];
-
-  function lastValue(aArray) {
-    return aArray[aArray.length - 1];
-  }
-
-  Environment.lastStartupLevel = lastValue(startupSequence);
-  Environment.lastShutdownLevel = lastValue(shutdownSequence);
-
-  function iterateLevels(aSequence, aFn, aUntilLevel=lastValue(aSequence)) {
-    for (let i = 0, len = aSequence.length; i < len; ++i) {
-      // Note: It's necessary to use for(;;) instead of  for(..of..)
-      //       because the order/sequence must be exactly the same as in the
-      //       array.  for(..of..) doesn't guarantee that the elements are
-      //       called in order.
 
-      let level = aSequence[i];
-      aFn(level);
-
-      if (level === aUntilLevel) {
-        // Stop after aUntilLevel
-        break;
-      }
-    }
-  };
+/**
+ * Registers the environment to its outer environment.
+ */
+Environment.prototype.register = function() {
+  let self = this;
+  if (self.outerEnv) {
+    self.outerEnv.registerInnerEnvironment(self);
+  }
+}
+/**
+ * Unregisters the environment from its outer environment.
+ */
+Environment.prototype.unregister = function() {
+  let self = this;
+  if (self.outerEnv) {
+    self.outerEnv.unregisterInnerEnvironment(self);
+  }
+}
+/**
+ * Function called by an inner environment when it starts up.
+ *
+ * @param {Environment} aEnv - the environment that wants to register itself.
+ */
+Environment.prototype.registerInnerEnvironment = function(aEnv) {
+  let self = this;
+  if (self.envState === ENV_STATES.NOT_STARTED) {
+    console.warn("[RPC] registerInnerEnvironment() has been called, " +
+                 "but the outer environment hasn't started up yet. " +
+                 "Starting up now.");
+    self.startup();
+  }
+  //console.debug("[RPC] registering inner environment.");
+  self.innerEnvs.add(aEnv);
+};
+/**
+ * Function that is called each time an inner environment shuts down.
+ *
+ * @param {Environment} aEnv - the environment that is unregistering
+ */
+Environment.prototype.unregisterInnerEnvironment = function(aEnv) {
+  let self = this;
 
-  Environment.iterateStartupLevels = iterateLevels.bind(null, startupSequence);
-  Environment.iterateShutdownLevels = iterateLevels.bind(null, shutdownSequence);
-})(Environment);
+  if (self.innerEnvs.has(aEnv) === false) {
+    console.error("[RPC] it seems like an inner Environment " +
+                  "did not register.");
+  } else {
+    self.innerEnvs.delete(aEnv);
+  }
+};
 
 
 
 
 /**
- * This set of functions can be used for adding startup/shutdown functions.
+ * Add a startup function to the environment.
  */
 Environment.prototype.addStartupFunction = function(aLevel, f) {
   let self = this;
@@ -190,7 +270,7 @@ Environment.prototype.addStartupFunction = function(aLevel, f) {
     // the environment is shutting down or already shut down.
     return;
   }
-  if (self.startupLevels[aLevel].levelState >= LEVEL_STATES.PROCESSING) {
+  if (self.levels["startup"][aLevel].levelState >= LEVEL_STATES.PROCESSING) {
     // Either the startup functions of the same level as `aLevel` have
     //        already been processed
     //    OR  they are currently being processed.
@@ -201,13 +281,16 @@ Environment.prototype.addStartupFunction = function(aLevel, f) {
     // the startup process did not reach the function's level yet.
     //
     // ==> remember the function.
-    self.startupLevels[aLevel].functions.push(f);
+    self.levels["startup"][aLevel].functions.push(f);
   }
 };
 
+/**
+ * Add a shutdown function to the environment.
+ */
 Environment.prototype.addShutdownFunction = function(aLevel, f) {
   let self = this;
-  if (self.shutdownLevels[aLevel].levelState >= LEVEL_STATES.PROCESSING) {
+  if (self.levels["shutdown"][aLevel].levelState >= LEVEL_STATES.PROCESSING) {
     // Either the shutdown functions of the same level as `aLevel` have
     //        already been processed
     //    OR  they are currently being processed.
@@ -221,96 +304,189 @@ Environment.prototype.addShutdownFunction = function(aLevel, f) {
     // level yet.
     //
     // ==> remember the function.
-    self.shutdownLevels[aLevel].functions.push(f);
+    self.levels["shutdown"][aLevel].functions.push(f);
   }
 };
 
 
+// have a scope/closure for private functions specific to
+// startup() and shutdown().
+(function createMethods_StartupAndShutdown(Environment) {
+  /**
+   * Iterates all levels of either the startup or the shutdown
+   * sequence and calls a function for each level.
+   *
+   * @param {string} aStartupOrShutdown
+   * @param {function()} aFn - the function to call
+   * @param {integer=} aUntilLevel - if specified, iteration stops
+   *     after that level.
+   */
+  function iterateLevels(aStartupOrShutdown, aFn, aUntilLevel=null) {
+    let sequence = BOOTSTRAP[aStartupOrShutdown].levelSequence;
+
+    for (let i = 0, len = sequence.length; i < len; ++i) {
+      // Note: It's necessary to use for(;;) instead of  for(..of..)
+      //       because the order/sequence must be exactly the same as in the
+      //       array.  for(..of..) doesn't guarantee that the elements are
+      //       called in order.
+
+      let level = sequence[i];
+      aFn(level);
+
+      if (level === aUntilLevel) {
+        // Stop after aUntilLevel
+        break;
+      }
+    }
+  }
+
 
-(function addStartupAndShutdown(Environment) {
   /**
-   * This function calls all functions of a function queue.
+   * This function calls all functions in an array.
+   *
+   * @param {Array.<function()>} aFunctions
+   * @param {Array} aBootstrapArgs - the arguments to apply
    */
-  function callFunctions(fnArray, fnArgsToApply) {
+  function callFunctions(aFunctions, aBootstrapArgs) {
     // process the Array as long as it contains elements
-    while (fnArray.length > 0) {
+    while (aFunctions.length > 0) {
       // The following is either `fnArray.pop()` or `fnArray.shift()`
       // depending on `sequence`.
-      let f = fnArray.pop();
+      let f = aFunctions.pop();
 
       // call the function
-      f.apply(null, fnArgsToApply);
+      f.apply(null, aBootstrapArgs);
+      //console.debug("[RPC] function called! (" + fnArray.length +
+      //              " functions left)");
     }
   };
 
-  function processLevel(aLevelObj, fnArgsToApply) {
-    if (aLevelObj.levelState === LEVEL_STATES.NOT_ENTERED) {
-      aLevelObj.levelState = LEVEL_STATES.PROCESSING;
-      callFunctions(aLevelObj.functions, fnArgsToApply);
-      aLevelObj.levelState = LEVEL_STATES.FINISHED_PROCESSING;
+
+  /**
+   * Process a level independently of the environment's states and
+   * independently of the other levels' states.
+   *
+   * @this {Environment}
+   * @param {string} aStartupOrShutdown - either "startup" or "shutdown"
+   * @param {integer} aLevel
+   */
+  function processLevel(aStartupOrShutdown, aLevel, aBootstrapArgs) {
+    let self = this;
+
+    let levelObj = self.levels[aStartupOrShutdown][aLevel];
+
+    if (levelObj.levelState === LEVEL_STATES.NOT_ENTERED) {
+      levelObj.levelState = LEVEL_STATES.PROCESSING;
+
+      if (aStartupOrShutdown === "shutdown") {
+        // shut down all inner environments
+        self.innerEnvs.forEach(function(innerEnv) {
+          innerEnv.shutdown(aBootstrapArgs, aLevel);
+        });
+      }
+
+      callFunctions(levelObj.functions, aBootstrapArgs);
+
+      levelObj.levelState = LEVEL_STATES.FINISHED_PROCESSING;
     }
   }
 
 
-  let {lastStartupLevel, lastShutdownLevel} = Environment;
-
   /**
-   * @param {Array} fnArgsToApply
-   * @param {integer=} untilLevel - The level after which the startup
-   *     processing is stopped.
+   * Iterate levels and call processLevel() for each level.
+   *
+   * @this {Environment}
+   * @param {string} aStartupOrShutdown
+   * @param {Array} aBootstrapArgs
+   * @param {integer=} aUntilLevel
    */
-  Environment.prototype.startup = function(fnArgsToApply,
-                                           untilLevel=lastStartupLevel) {
+  function processLevels(aStartupOrShutdown, aBootstrapArgs, aUntilLevel) {
     let self = this;
+    iterateLevels(aStartupOrShutdown, function (level) {
+      processLevel.call(self, aStartupOrShutdown, level, aBootstrapArgs);
+    }, aUntilLevel);
+  }
 
-    if (self.envState == ENV_STATES.NOT_STARTED) {
-      //console.log('[RPC] starting up Environment "'+self.name+'"...');
-      self.envState = ENV_STATES.STARTING_UP;
-    }
 
-    if (self.envState === ENV_STATES.STARTING_UP) {
-      Environment.iterateStartupLevels(function (level) {
-        let levelObj = self.startupLevels[level];
-        processLevel(levelObj, fnArgsToApply);
-      }, untilLevel);
+  /**
+   * Return some information about an environment.
+   *
+   * @param {Environment} env
+   * @return {string}
+   */
+  function getEnvInfo(env) {
+    return "'" + env.name + "' (" + env.uid + ")";
+  }
 
-      if (untilLevel === lastStartupLevel) {
-        self.envState = ENV_STATES.STARTUP_DONE;
-      }
-    }
-  };
+  /**
+   * Log some debug information on startup or shutdown.
+   *
+   * @this {Environment}
+   * @param {string} aStartupOrShutdown
+   */
+  function logStartupOrShutdown(aStartupOrShutdown) {
+    let self = this;
+    console.log("[RPC] " + aStartupOrShutdown + ": " + getEnvInfo(self) + "." +
+                (self.outerEnv ?
+                 " OuterEnv is " + getEnvInfo(self.outerEnv) + "." :
+                 " No OuterEnv."));
+  }
 
   /**
-   * @param {Array} fnArgsToApply
-   * @param {integer=} untilLevel - The level after which the shutdown
-   *     processing is stopped.
+   * Actual body of the functions startup() and shutdown().
+   *
+   * @this {Environment}
+   * @param {string} aStartupOrShutdown - either "startup" or "shutdown"
+   * @param {Array} aBootstrapArgs
+   * @param {integer=} aUntilLevel - The level after which the startup
+   *     (or shutdown) processing is stopped.
    */
-  Environment.prototype.shutdown = function(fnArgsToApply,
-                                            untilLevel=lastShutdownLevel) {
+  function bootstrap(aStartupOrShutdown,
+                     aBootstrapArgs,
+                     aUntilLevel=BOOTSTRAP[aStartupOrShutdown].lastLevel) {
     let self = this;
 
-    if (self.envState === ENV_STATES.STARTUP_DONE) {
-      //console.log('[RPC] shutting down Environment "'+self.name+'"...');
-      self.envState = ENV_STATES.SHUTTING_DOWN;
+    let {
+      lastLevel,
+      envStates,
+      functions
+    } = getBootstrapMetadata(aStartupOrShutdown);
+
+    if (self.envState === envStates["beforeProcessing"]) {
+      //logStartupOrShutdown.call(self, aStartupOrShutdown);
+      functions["beforeProcessing"].call(self);
+
+      self.envState = envStates["duringProcessing"];
     }
 
-    if (self.envState === ENV_STATES.SHUTTING_DOWN) {
-      Environment.iterateShutdownLevels(function (level) {
-        let levelObj = self.shutdownLevels[level];
-        processLevel(levelObj, fnArgsToApply);
-      }, untilLevel);
+    if (self.envState === envStates["duringProcessing"]) {
+      processLevels.call(self, aStartupOrShutdown, aBootstrapArgs, aUntilLevel);
 
-      if (untilLevel === lastShutdownLevel) {
-        EnvironmentManager.unregisterEnvironment(self);
-        self.envState = ENV_STATES.SHUT_DOWN;
+      if (aUntilLevel === lastLevel) {
+        self.envState = envStates["afterProcessing"];
+        functions["afterProcessing"].call(self);
       }
     }
   };
+
+  Environment.prototype.startup = function(aBootstrapArgs, aUntilLevel) {
+    let self = this;
+    bootstrap.call(self, "startup", aBootstrapArgs, aUntilLevel);
+  };
+
+  Environment.prototype.shutdown = function(aBootstrapArgs, aUntilLevel) {
+    let self = this;
+    bootstrap.call(self, "shutdown", aBootstrapArgs, aUntilLevel);
+  };
+
 })(Environment);
 
 /**
- * Helper function: shuts down the environment when an EventTarget's "unload"
- * event occurres.
+ * Tell the Environment to shut down when an EventTarget's
+ * "unload" event occurres.
+ *
+ * @param {EventTarget} aEventTarget - an object having the functions
+ *     addEventListener() and removeEventListener().
  */
 Environment.prototype.shutdownOnUnload = function(aEventTarget) {
   let self = this;
@@ -320,3 +496,39 @@ Environment.prototype.shutdownOnUnload = function(aEventTarget) {
     self.shutdown();
   });
 };
+
+
+/**
+ * @constructor
+ * @extends {Environment}
+ * @param {ContentFrameMessageManager} aMM
+ * @param {string=} aName - the environment's name, passed to the superclass.
+ */
+function FrameScriptEnvironment(aMM, aName="frame script environment") {
+  let self = this;
+
+  // The outer Environment will be either ChildProcessEnvironment
+  // or ParentProcessEnvironment.
+  let _outerEnv = ProcessEnvironment;
+
+  Environment.call(self, _outerEnv, aName);
+
+  self.addStartupFunction(LEVELS.INTERFACE, function() {
+    // shut down the framescript on the message manager's
+    // `unload`. That event will occur when the browsing context
+    // (e.g. the tab) has been closed.
+    self.shutdownOnUnload(aMM);
+  });
+
+  // a "MessageListener"-Manager for this environment
+  XPCOMUtils.defineLazyGetter(self, "mlManager", function() {
+    return new ManagerForMessageListeners(self, aMM);
+  });
+}
+FrameScriptEnvironment.prototype = Object.create(Environment.prototype);
+FrameScriptEnvironment.prototype.constructor = Environment;
+
+
+// Load the "ProcessEnvironment"
+Services.scriptloader.loadSubScript("chrome://requestpolicy/content/" +
+                                    "lib/environment.process.js");
diff --git a/src/content/lib/environment.process.js b/src/content/lib/environment.process.js
new file mode 100644
index 0000000..53fe5ab
--- /dev/null
+++ b/src/content/lib/environment.process.js
@@ -0,0 +1,221 @@
+/*
+ * ***** 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 *****
+ */
+
+
+// ProcessEnvironment is either a ParentProcessEnvironment or
+// a ChildProcessEnvironment.
+let ProcessEnvironment = (function() {
+
+
+  // determine if this is the main process
+  let isMainProcess = (function isMainProcess() {
+    let xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
+        .getService(Ci.nsIXULRuntime);
+    // The "default" type means that it's the main process,
+    // the chrome process. This is relevant for multiprocess
+    // firefox aka Electrolysis (e10s).
+    return xulRuntime.processType === xulRuntime.PROCESS_TYPE_DEFAULT;
+  }());
+
+
+  const shutdownMessage = C.MM_PREFIX + "shutdown";
+
+  /**
+   * @constructor
+   * @extends {Environment}
+   * @param {string=} aName - the environment's name, passed to the superclass.
+   */
+  function ProcessEnvironmentBase(aName="Process Environment") {
+    let self = this;
+
+    // Process environments are the outermost environment in each process.
+    let outerEnv = null;
+
+    Environment.call(self, outerEnv, aName);
+
+    self.isMainProcess = isMainProcess;
+  }
+  ProcessEnvironmentBase.prototype = Object.create(Environment.prototype);
+  ProcessEnvironmentBase.prototype.constructor = Environment;
+
+
+
+
+  /**
+   * @constructor
+   * @extends {ProcessEnvironmentBase}
+   * @param {string=} aName - the environment's name, passed to the superclass.
+   */
+  function ParentProcessEnvironment(aName="Parent Process Environment") {
+    let self = this;
+    ProcessEnvironmentBase.call(self, aName);
+
+
+    function sendShutdownMessageToChildren() {
+      let parentMM = Cc["@mozilla.org/parentprocessmessagemanager;1"]
+          .getService(Ci.nsIMessageBroadcaster);
+      parentMM.broadcastAsyncMessage(shutdownMessage);
+    };
+
+    // Very important: The shutdown message must be sent *after*
+    //     calling `removeDelayedFrameScript`, which is done in
+    //     the LEVELS.INTERFACE level.
+    self.addShutdownFunction(Environment.LEVELS.BACKEND,
+                             sendShutdownMessageToChildren);
+  }
+  ParentProcessEnvironment.prototype = Object.create(ProcessEnvironmentBase.prototype);
+  ParentProcessEnvironment.prototype.constructor = ProcessEnvironmentBase;
+
+
+
+  /**
+   * @override
+   */
+  ParentProcessEnvironment.prototype.startup = function() {
+    let self = this;
+
+    // Create a dummy scope for modules that have to be imported
+    // but not remembered. As the scope is a local variable,
+    // it will be removed after the function has finished.
+    // However, the main modules register their startup and
+    // shutdown functions anyway.
+    let dummyScope = {};
+
+
+    /**
+     * The following section is not optimal – read on…
+     */
+    {
+      // Load and init PrefManager before anything else is loaded!
+      // The reason is that the Logger, which is imported by many modules,
+      // expects the prefs to be initialized and available already.
+      let {PrefManager} = ScriptLoader.importModule("main/pref-manager");
+      PrefManager.init();
+
+      // TODO: use the Browser Console for logging, see #563.
+      //       *Then* it's no longer necessary to load and init PrefManager
+      //       first. PrefManager will then be loaded and initialized when all
+      //       other back end modules are loaded / initialized.
+    }
+
+    // import main modules:
+    ScriptLoader.importModules([
+      "main/requestpolicy-service",
+      "lib/content-policy",
+      "main/window-manager",
+      "main/about-uri"
+    ], dummyScope);
+
+    ProcessEnvironmentBase.prototype.startup.apply(self, arguments);
+  };
+
+
+  /**
+   * @override
+   */
+  ParentProcessEnvironment.prototype.shutdown = function() {
+    let self = this;
+
+    ProcessEnvironmentBase.prototype.shutdown.apply(self, arguments);
+
+    // 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);
+
+    ScriptLoader.doShutdownTasks();
+    Cu.unload("chrome://requestpolicy/content/lib/script-loader.jsm");
+  };
+
+
+
+
+  /**
+   * @constructor
+   * @extends {ProcessEnvironmentBase}
+   * @param {string=} aName - the environment's name, passed to the superclass.
+   */
+  function ChildProcessEnvironment(aName="Child Process Environment") {
+    let self = this;
+    ProcessEnvironmentBase.call(self, aName);
+
+    let childMM = Cc["@mozilla.org/childprocessmessagemanager;1"]
+        .getService(Ci.nsISyncMessageSender);
+
+    /**
+     * This function will be called when the paren process
+     * sends the shutdown message. After this function has
+     * finished, RequestPolicy has cleaned up itself from
+     * that child process.
+     */
+    function receiveShutdownMessage() {
+      childMM.removeMessageListener(shutdownMessage, receiveShutdownMessage);
+      self.shutdown();
+
+      // Unloading `environment.jsm` has to be the last task.
+      // After that task, any global object, such as
+      // `Environment` or `Cu` is not available anymore.
+      console.debug("unloading environment.jsm");
+      Cu.unload("chrome://requestpolicy/content/lib/environment.jsm");
+    };
+
+    childMM.addMessageListener(shutdownMessage, receiveShutdownMessage);
+  }
+  ChildProcessEnvironment.prototype = Object.create(ProcessEnvironmentBase.prototype);
+  ChildProcessEnvironment.prototype.constructor = ProcessEnvironmentBase;
+
+
+  /**
+   * @override
+   */
+  ChildProcessEnvironment.prototype.shutdown = function() {
+    let self = this;
+
+    ProcessEnvironmentBasevironmentBase.prototype.shutdown.apply(self, arguments);
+
+    ScriptLoader.doShutdownTasks();
+    Cu.unload("chrome://requestpolicy/content/lib/script-loader.jsm");
+  };
+
+  ChildProcessEnvironment.prototype.registerInnerEnvironment = function(aEnv) {
+    let self = this;
+    if (self.envState === ENV_STATES.NOT_STARTED) {
+      // The child Process Environment needs to start up when
+      // the first framescript in that child is loading.
+      console.debug("[RPC] Going to start up Child Process Environment.");
+      self.startup();
+    }
+    ProcessEnvironmentBase.prototype.registerInnerEnvironment.apply(self,
+                                                                    arguments);
+  };
+
+
+
+
+  if (isMainProcess === true) {
+    return new ParentProcessEnvironment();
+  } else {
+    return new ChildProcessEnvironment();
+  }
+
+})();
diff --git a/src/content/lib/logger.jsm b/src/content/lib/logger.jsm
index 28d47c5..b315d25 100644
--- a/src/content/lib/logger.jsm
+++ b/src/content/lib/logger.jsm
@@ -32,7 +32,7 @@ Cu.import("resource://gre/modules/devtools/Console.jsm");
 
 Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
 ScriptLoader.importModules([
-  "lib/process-environment",
+  "lib/environment",
   "lib/prefs"
 ], this);
 
diff --git a/src/content/lib/manager-for-event-listeners.jsm b/src/content/lib/manager-for-event-listeners.jsm
index a0bb897..eca395d 100644
--- a/src/content/lib/manager-for-event-listeners.jsm
+++ b/src/content/lib/manager-for-event-listeners.jsm
@@ -31,7 +31,6 @@ let globalScope = this;
 
 Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
 ScriptLoader.importModules([
-  "main/environment-manager",
   "lib/environment",
   "lib/logger"
 ], globalScope);
diff --git a/src/content/lib/manager-for-message-listeners.jsm b/src/content/lib/manager-for-message-listeners.jsm
index 46ae22b..4e46b3a 100644
--- a/src/content/lib/manager-for-message-listeners.jsm
+++ b/src/content/lib/manager-for-message-listeners.jsm
@@ -31,7 +31,6 @@ let globalScope = this;
 
 Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
 ScriptLoader.importModules([
-  "main/environment-manager",
   "lib/environment",
   "lib/logger",
   "lib/utils/constants"
@@ -104,6 +103,14 @@ ManagerForMessageListeners.prototype.addListener = function(aMessageName,
                    '"');
     return;
   }
+  if (aMessageName.indexOf(C.MM_PREFIX) === 0) {
+    Logger.warning(Logger.TYPE_INTERNAL,
+                   "The message name that has been passed to " +
+                   "`addListener()` contains the MM Prefix. " +
+                   "Extracting the message name.");
+    aMessageName = aMessageName.substr(C.MM_PREFIX.length)
+  }
+
   let listener = {
     messageName: aMessageName,
     messageID: C.MM_PREFIX + aMessageName,
diff --git a/src/content/lib/observer-manager.jsm b/src/content/lib/observer-manager.jsm
index 3075d10..ba98868 100644
--- a/src/content/lib/observer-manager.jsm
+++ b/src/content/lib/observer-manager.jsm
@@ -32,7 +32,7 @@ let globalScope = this;
 Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
 ScriptLoader.importModules([
   "lib/utils/observers",
-  "lib/process-environment"
+  "lib/environment"
 ], globalScope);
 
 ScriptLoader.defineLazyModuleGetters({
diff --git a/src/content/lib/prefs.jsm b/src/content/lib/prefs.jsm
index 766f5a5..8d9d754 100644
--- a/src/content/lib/prefs.jsm
+++ b/src/content/lib/prefs.jsm
@@ -30,7 +30,7 @@ let EXPORTED_SYMBOLS = ['rpPrefBranch', 'rootPrefBranch', 'Prefs'];
 Cu.import("resource://gre/modules/Services.jsm");
 
 Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
-ScriptLoader.importModules(["lib/process-environment"], this);
+ScriptLoader.importModules(["lib/environment"], this);
 
 
 
diff --git a/src/content/lib/process-environment.jsm b/src/content/lib/process-environment.jsm
deleted file mode 100644
index f6ce784..0000000
--- a/src/content/lib/process-environment.jsm
+++ /dev/null
@@ -1,53 +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 = [
-  "ProcessEnvironment",
-  // Not only ProcessEnvironment is exported, but also `Environment`. This
-  // might be helpful somewhere.
-  "Environment"
-];
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-let globalScope = this;
-
-Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
-ScriptLoader.importModules([
-  "main/environment-manager",
-  "lib/environment"
-], globalScope);
-
-let envName = EnvironmentManager.isMainProcess ?
-    "Parent ProcEnv" : "Child ProcEnv";
-
-// create a new Environment
-let ProcessEnvironment = new Environment(envName);
-
-
-// set whether this is the main process
-ProcessEnvironment.isMainProcess = EnvironmentManager.isMainProcess;
diff --git a/src/content/lib/request-processor.compat.js b/src/content/lib/request-processor.compat.js
index d111f37..4d63b30 100644
--- a/src/content/lib/request-processor.compat.js
+++ b/src/content/lib/request-processor.compat.js
@@ -27,7 +27,7 @@ Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
 ScriptLoader.importModules([
   "lib/logger",
   "lib/utils",
-  "lib/process-environment"
+  "lib/environment"
 ], this);
 
 
diff --git a/src/content/lib/request-processor.jsm b/src/content/lib/request-processor.jsm
index 4676e53..5b32554 100644
--- a/src/content/lib/request-processor.jsm
+++ b/src/content/lib/request-processor.jsm
@@ -48,7 +48,7 @@ ScriptLoader.importModules([
   "lib/request",
   "lib/request-result",
   "lib/request-set",
-  "lib/process-environment"
+  "lib/environment"
 ], this);
 ScriptLoader.defineLazyModuleGetters({
   "lib/content-policy": ["PolicyImplementation"]
diff --git a/src/content/lib/request-processor.redirects.js b/src/content/lib/request-processor.redirects.js
index afe42c6..52e7933 100644
--- a/src/content/lib/request-processor.redirects.js
+++ b/src/content/lib/request-processor.redirects.js
@@ -36,7 +36,7 @@ ScriptLoader.importModules([
   "lib/request",
   "lib/request-result",
   "lib/http-response",
-  "lib/process-environment"
+  "lib/environment"
 ], this);
 
 
@@ -305,7 +305,7 @@ let RequestProcessor = (function(self) {
       Logger.severe(
           Logger.TYPE_HEADER_REDIRECT, "Failed removing " +
           "'" + headerType + "' header to <" + destURI + ">" +
-          "  in response from <" + originURI + ">." + e);
+          "  in response from <" + originURI + ">. " + e, e);
     }
   }
 
diff --git a/src/content/lib/request.jsm b/src/content/lib/request.jsm
index 0052225..a6b6185 100644
--- a/src/content/lib/request.jsm
+++ b/src/content/lib/request.jsm
@@ -365,11 +365,9 @@ function RedirectRequest(httpResponse) {
                httpResponse.destURI.specIgnoringRef, REQUEST_TYPE_REDIRECT);
   this.httpResponse = httpResponse;
 
-  XPCOMUtils.defineLazyGetter(this, "browser", getBrowser);
+  XPCOMUtils.defineLazyGetter(this, "browser", function() {
+    return httpResponse.browser;
+  });
 }
 RedirectRequest.prototype = Object.create(Request.prototype);
 RedirectRequest.prototype.constructor = Request;
-
-function getBrowser() {
-  return this.httpResponse.browser;
-}
diff --git a/src/content/lib/script-loader.jsm b/src/content/lib/script-loader.jsm
index 4bc66f4..6476ba2 100644
--- a/src/content/lib/script-loader.jsm
+++ b/src/content/lib/script-loader.jsm
@@ -62,7 +62,7 @@ let ScriptLoader = (function() {
   // a module shouldn't unload itself
   moduleUnloadExceptions[getModuleURI("lib/script-loader")] = true;
   // EnvironmentManager has to be unloaded even later than ScriptLoader
-  moduleUnloadExceptions[getModuleURI("main/environment-manager")] = true;
+  moduleUnloadExceptions[getModuleURI("lib/environment")] = true;
 
 
   // contains the module IDs that are currently being imported initially and
diff --git a/src/content/lib/utils.jsm b/src/content/lib/utils.jsm
index 2039e55..289b07b 100644
--- a/src/content/lib/utils.jsm
+++ b/src/content/lib/utils.jsm
@@ -35,7 +35,7 @@ Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
 ScriptLoader.importModules([
   "lib/prefs",
   "lib/utils/constants",
-  "lib/process-environment"
+  "lib/environment"
 ], this);
 
 if (ProcessEnvironment.isMainProcess) {
diff --git a/src/content/main/about-uri.jsm b/src/content/main/about-uri.jsm
index 461dd90..9f37331 100644
--- a/src/content/main/about-uri.jsm
+++ b/src/content/main/about-uri.jsm
@@ -34,7 +34,7 @@ let globalScope = this;
 
 
 Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
-ScriptLoader.importModule("lib/process-environment", globalScope);
+ScriptLoader.importModule("lib/environment", globalScope);
 
 
 var filenames = {
diff --git a/src/content/main/environment-manager-child.js b/src/content/main/environment-manager-child.js
deleted file mode 100644
index 7fbb689..0000000
--- a/src/content/main/environment-manager-child.js
+++ /dev/null
@@ -1,116 +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 *****
- */
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-//Cu.import("resource://gre/modules/devtools/Console.jsm");
-
-
-let EnvironmentManager = (function(self) {
-  // Manually import the scriptloader without waiting for the startup.
-  let mod = {};
-  let scriptLoaderURI = "chrome://requestpolicy/content/lib/script-loader.jsm";
-  Cu.import(scriptLoaderURI, mod);
-  mod.ScriptLoader.defineLazyModuleGetters({
-    "lib/utils/constants": ["C"]
-  }, mod);
-
-
-  // ================================
-  // variables set by `registerFramescript`:
-  // ---------------------------------------
-  // the content frame's message manager
-  let mm = null;
-
-  // The framescript's URI will be checked against the URI in the
-  // message to ensure there is no conflics between old and new framescripts
-  // in case the addon is disabled and enabled in quick succession.
-  // For details see:
-  // https://palant.de/2014/11/19/unloading-frame-scripts-in-restartless-extensions
-  let framescriptURI = null;
-  // ================================
-
-
-  let shutdownMessageName = mod.C.MM_PREFIX + "shutdown";
-
-  function shutDownEnvMan(message) {
-    if (message.data.uri == framescriptURI) {
-      //console.log("[RPC] Child EnvironmentManager received `shutdown` " +
-      //            'message. Going to shut down all environments.');
-
-      /**
-       * cleanup
-       */
-      {
-        mm.removeMessageListener(shutdownMessageName, shutDownEnvMan);
-        framescriptURI = null;
-        // remove the reference to the message manager
-        mm = null;
-      }
-
-      /**
-       * shut down all environments
-       */
-      {
-        self.shutdown();
-        // if shutdown() arguments would be needed, the following could be used:
-        //self.shutdown.apply(self, message.data.arguments);
-      }
-    }
-  };
-
-
-  /**
-   * Each framescript instance registers itself to EnvironmentManager. The
-   * purpose is that Environment Managers in child process listen to the
-   * "shutdown" message. When that message is received, the child's
-   * EnvironmentManager shuts down.
-   *
-   * Note: framescripts might also be in the *main* process, but then it's not
-   *       necessary to listen for "shutdown" as each environment in the
-   *       framescript's has direct access to the *main* EnvironmentManager.
-   */
-  self.registerFramescript = function(aContentFrameMessageManager) {
-    // ensure that `registerFramescript` is called only once
-    if (mm === null) {
-      //console.log("a framescript has registered");
-      // remember the MM
-      mm = aContentFrameMessageManager;
-      // set the framescriptURI
-      framescriptURI = Components.stack.caller.filename;
-      // manually add a Message Listener (without a ManagerForMessageListeners)
-      mm.addMessageListener(shutdownMessageName, shutDownEnvMan);
-    }
-  };
-
-
-
-  self.doShutdownTasks = function() {
-    // "shutdown" and unload the mod.ScriptLoader *manually*
-    mod.ScriptLoader.doShutdownTasks();
-    mod = {};
-    Cu.unload(scriptLoaderURI);
-  }
-
-
-  return self;
-}(EnvironmentManager || {}));
diff --git a/src/content/main/environment-manager-parent.js b/src/content/main/environment-manager-parent.js
deleted file mode 100644
index 60826f7..0000000
--- a/src/content/main/environment-manager-parent.js
+++ /dev/null
@@ -1,117 +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 *****
- */
-
-
-let globalScope = globalScope || this;
-
-
-let EnvironmentManager = (function(self) {
-
-  // Object for holding imported modules, especilly the mod.ScriptLoader.
-  let mod = {};
-
-  let scriptLoaderURI = "chrome://requestpolicy/content/lib/script-loader.jsm";
-
-  let ScriptLoader = null;
-
-
-  /**
-   * Ignore any calls to `registerFramescript` completely; the
-   * `ContentFrameMessageManager` handed over is needed only in child proceses.
-   */
-  self.registerFramescript = function(aContentFrameMessageManager) {
-    // do nothing.
-  };
-
-
-
-  /**
-   * This is the first function to be called by the EnvironmentManager's
-   * startup() function.
-   *
-   * This function imports essential modules which depend recursively on
-   * other modules, so that finally, after this function has finished,
-   * all modules will be available to be imported by any other module.
-   */
-  self.doStartupTasks = function() {
-    // =======================================
-    // Manually load the ScriptLoader.
-    // ---------------------------------------
-    // ( It has to be unloaded manually as well! The shutdown function is
-    //   defined below. )
-    Cu.import(scriptLoaderURI, mod);
-    // =======================================
-
-
-    // Create a dummy scope for modules that have to be imported but not
-    // remembered by EnvironmentManager. As the scope is a local variable,
-    // it will be removed after the function has finished.
-    // However, the main modules register their startup and shutdown functions
-    // anyway.
-    let dummyScope = {};
-
-
-    /**
-     * The following section is not optimal – read on…
-     */
-    {
-      // Load and init PrefManager before anything else is loaded!
-      // The reason is that the Logger, which is imported by many modules,
-      // expects the prefs to be initialized and available already.
-      let {PrefManager} = mod.ScriptLoader.importModule("main/pref-manager");
-      PrefManager.init();
-
-      // TODO: use the Browser Console for logging, see #563.
-      //       *Then* it's no longer necessary to load and init PrefManager
-      //       first. PrefManager will then be loaded and initialized when all
-      //       other back end modules are loaded / initialized.
-    }
-
-    // import main modules:
-    mod.ScriptLoader.importModules([
-      "main/requestpolicy-service",
-      "lib/content-policy",
-      "main/window-manager",
-      "main/about-uri"
-    ], dummyScope);
-  }
-
-
-
-  /**
-   * On shutdown, this function is the last one to be called.
-   */
-  self.doShutdownTasks = 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);
-
-    // "shutdown" and unload the mod.ScriptLoader *manually*
-    mod.ScriptLoader.doShutdownTasks();
-    mod = {};
-    Cu.unload(scriptLoaderURI);
-  }
-
-  return self;
-}(EnvironmentManager || {}));
diff --git a/src/content/main/environment-manager.jsm b/src/content/main/environment-manager.jsm
deleted file mode 100644
index 8512bf0..0000000
--- a/src/content/main/environment-manager.jsm
+++ /dev/null
@@ -1,135 +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 = ["EnvironmentManager"];
-
-let globalScope = this;
-
-Cu.import("resource://gre/modules/Services.jsm");
-//Cu.import("resource://gre/modules/devtools/Console.jsm");
-
-
-/**
- * EnvironmentManager is one of the central modules relevant for the
- * extension's bootstrapping process. However, this is documented elsewhere,
- * possibly in the developer wiki.
- */
-let EnvironmentManager = (function(self) {
-
-  // determine if this is the main process
-  self.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;
-  }());
-
-  let procString = (self.isMainProcess ? "parent" : "child") + " process";
-
-  //console.debug("[RPC] creating new EnvironmentManager (" + procString + ")");
-
-
-  // this function is set by a framescript
-  self.asyncUnloadEnvMan = function() {};
-
-
-  self.environments = new Set();
-
-  self.registerEnvironment = function(aEnv) {
-    self.environments.add(aEnv);
-  };
-  self.unregisterEnvironment = function(aEnv) {
-    self.environments.delete(aEnv);
-    self.asyncUnloadEnvMan();
-  };
-
-
-  // Ensure that `doStartupTasks` and `doShutdownTasks` exist. They can be
-  // overwritten.
-  self.doStartupTasks = self.doStartupTasks || function() {};
-  self.doShutdownTasks = self.doShutdownTasks || function() {};
-
-
-  /**
-   */
-  self.startup = function() {
-    //console.debug("[RPC] EnvironmentManager ("+procString+") is going to " +
-    //              "start up the Process Environment...");
-    self.doStartupTasks();
-
-    // on startup, only the Process Environment is started.
-    Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
-    ScriptLoader.importModule("lib/process-environment")
-        .ProcessEnvironment.startup();
-  };
-
-  self.shutdown = function(fnArgsToApply) {
-    // remove the comments in this function for debugging.
-    //console.debug("[RPC] EnvironmentManager ("+procString+") is going to " +
-    //              "shut down all registered Environments...");
-    //if (self.isMainProcess) {
-    //  // only group in the main process -- some loggings of the child process
-    //  // might not reach the parent. In case the `groupEnd()` does not reach
-    //  // the parent, the Group will live for the whole browser session!
-    //  console.group();
-    //}
-
-    Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
-    let {Environment} = ScriptLoader.importModule("lib/environment");
-
-    // shut down
-    Environment.iterateShutdownLevels(function (level) {
-      //console.debug("[RPC] reaching level "+level+" ...");
-      self.environments.forEach(function(env) {
-        env.shutdown(fnArgsToApply, level);
-      });
-    });
-
-    // final tasks
-    //console.debug("[RPC] reaching level 0 ...");
-    self.doShutdownTasks();
-
-    // remove the references to all environments
-    self.environments = new Set();
-
-    //console.debug("[RPC] EnvironmentManager ("+procString+") finished " +
-    //              "shutting down all registered Environments.");
-    //if (self.isMainProcess) {
-    //  console.groupEnd();
-    //}
-  };
-
-  return self;
-}(EnvironmentManager || {}));
-
-
-// load parent- or child-specific parts
-let subScriptURI = EnvironmentManager.isMainProcess === true ?
-    "chrome://requestpolicy/content/main/environment-manager-parent.js" :
-    "chrome://requestpolicy/content/main/environment-manager-child.js";
-Services.scriptloader.loadSubScriptWithOptions(subScriptURI,
-                                               {/*ignoreCache: true*/});
diff --git a/src/content/main/pref-manager.jsm b/src/content/main/pref-manager.jsm
index 84aabf6..49a548e 100644
--- a/src/content/main/pref-manager.jsm
+++ b/src/content/main/pref-manager.jsm
@@ -36,7 +36,7 @@ Cu.import("resource://gre/modules/devtools/Console.jsm");
 Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm");
 ScriptLoader.importModules([
   "lib/utils/constants",
-  "lib/process-environment"
+  "lib/environment"
 ], globalScope);
 
 XPCOMUtils.defineLazyGetter(globalScope, "rpPrefBranch", function() {
diff --git a/src/content/main/requestpolicy-service.jsm b/src/content/main/requestpolicy-service.jsm
index fa33322..212b962 100644
--- a/src/content/main/requestpolicy-service.jsm
+++ b/src/content/main/requestpolicy-service.jsm
@@ -39,7 +39,7 @@ ScriptLoader.importModules([
   "lib/subscription",
   "lib/utils",
   "lib/utils/constants",
-  "lib/process-environment"
+  "lib/environment"
 ], this);
 
 
diff --git a/src/content/main/window-manager.jsm b/src/content/main/window-manager.jsm
index 59d25e2..2ea349e 100644
--- a/src/content/main/window-manager.jsm
+++ b/src/content/main/window-manager.jsm
@@ -40,7 +40,7 @@ let rpWindowManager = (function(self) {
     "lib/utils",
     "lib/utils/xul",
     "lib/utils/constants",
-    "lib/process-environment"
+    "lib/environment"
   ], globalScope);
 
   // import the WindowListener
@@ -129,12 +129,17 @@ let rpWindowManager = (function(self) {
   }
 
   function unloadFromWindow(window) {
-    // # 6 : unload frame scripts
+    // # 6 : stop loading framescripts into new tabs
     // --------------------------
+    // Note that it's not necessary to tell the framescripts'
+    // environments to shut down. Instead:
+    // - In case the window is closed, the will shut down on
+    //   the ContentFrameMessageManager's "unload" event.
+    // - In case the addon is being disabled or firefox gets quit,
+    //   the ParentProcessEnvironment will send a message to all
+    //   children.
     let mm = window.messageManager;
     mm.removeDelayedFrameScript(frameScriptURI);
-    Logger.dump("broadcasting `shutdown` message to framescripts!");
-    mm.broadcastAsyncMessage(C.MM_PREFIX + "shutdown", {uri: frameScriptURI});
 
 
     // # 5 : "shutdown" the overlay
diff --git a/src/content/settings/common.js b/src/content/settings/common.js
index c14cda0..7054eee 100644
--- a/src/content/settings/common.js
+++ b/src/content/settings/common.js
@@ -19,7 +19,7 @@ ScriptLoader.importModules([
 ], this);
 
 // create a new Environment for this window
-var WinEnv = new Environment("WinEnv");
+var WinEnv = new Environment(ProcessEnvironment, "WinEnv");
 // The Environment has to be shut down when the content window gets unloaded.
 WinEnv.shutdownOnUnload(content);
 // start up right now, as there won't be any startup functions
diff --git a/src/content/ui/frame.dom-content-loaded.js b/src/content/ui/frame.dom-content-loaded.js
index 7a230a1..f2f1278 100644
--- a/src/content/ui/frame.dom-content-loaded.js
+++ b/src/content/ui/frame.dom-content-loaded.js
@@ -130,7 +130,7 @@ let ManagerForDOMContentLoaded = (function() {
   function onDocumentLoaded(doc) {
     // Create a new Environment for this Document and shut it down when
     // the document is unloaded.
-    let DocEnv = new Environment("DocEnv");
+    let DocEnv = new Environment(framescriptEnv, "DocEnv");
     DocEnv.shutdownOnUnload(doc.defaultView);
     // start up the Environment immediately, as it won't have any startup
     // functions.
@@ -289,12 +289,12 @@ let ManagerForDOMContentLoaded = (function() {
   }
 
 
-  FrameScriptEnv.elManager.addListener(mm, "DOMContentLoaded",
+  framescriptEnv.elManager.addListener(mm, "DOMContentLoaded",
                                        onDOMContentLoaded, true);
 
   // DOMFrameContentLoaded is same DOMContentLoaded but also fires for
   // enclosed frames.
-  FrameScriptEnv.elManager.addListener(mm, "DOMFrameContentLoaded",
+  framescriptEnv.elManager.addListener(mm, "DOMFrameContentLoaded",
                                        onDOMFrameContentLoaded, true);
 
   //mm.addEventListener("DOMContentLoaded", onDOMContentLoaded, true);
@@ -304,7 +304,7 @@ let ManagerForDOMContentLoaded = (function() {
   //mm.addEventListener("DOMFrameContentLoaded", onDOMFrameContentLoaded, true);
   //
   //// clean up on shutdown
-  //FrameScriptEnv.addShutdownFunction(Environment.LEVELS.INTERFACE, function() {
+  //framescriptEnv.addShutdownFunction(Environment.LEVELS.INTERFACE, function() {
   //  Logger.dump('removing listeners for "DOMContentLoaded" and ' +
   //              '"DOMFrameContentLoaded"');
   //  mm.removeEventListener("DOMContentLoaded", onDOMContentLoaded, true);
diff --git a/src/content/ui/frame.js b/src/content/ui/frame.js
index a60c30f..2dae42f 100644
--- a/src/content/ui/frame.js
+++ b/src/content/ui/frame.js
@@ -21,7 +21,7 @@
  */
 
 Components.utils.import("resource://gre/modules/Services.jsm");
-//Components.utils.import("resource://gre/modules/devtools/Console.jsm");
+Components.utils.import("resource://gre/modules/devtools/Console.jsm");
 
 /**
  * This anonymous function is needed because of Mozilla Bug 673569, fixed in
@@ -36,135 +36,61 @@ Components.utils.import("resource://gre/modules/Services.jsm");
   // the ContentFrameMessageManager of this framescript
   let mm = this;
 
-  // Create a new scope that can be removed easily when the framescript has to
-  // be unloaded.
-  var FrameScriptScope = {
-    mm: mm,
-    content: mm.content,
-    Components: mm.Components,
-
-    Ci: mm.Components.interfaces,
-    Cc: mm.Components.classes,
-    Cu: mm.Components.utils
-  };
-
   const Cu = Components.utils;
-  Cu.import("chrome://requestpolicy/content/lib/script-loader.jsm",
-            FrameScriptScope);
-  let ScriptLoader = FrameScriptScope.ScriptLoader;
 
+  // import some modules
+  let {ScriptLoader} = Cu.import(
+      "chrome://requestpolicy/content/lib/script-loader.jsm", {});
+  let mod = {};
   ScriptLoader.importModules([
     "lib/utils/constants",
     "lib/logger",
-    "lib/environment",
-    "main/environment-manager"
-  ], FrameScriptScope);
-  let C = FrameScriptScope.C;
-  let Environment = FrameScriptScope.Environment;
-  let EnvironmentManager = FrameScriptScope.EnvironmentManager;
-
-
-  /**
-   * This function gets a Environment variable that has the same lifespan as
-   * the framescript. , i.e. the Environment's shutdown() function will be called
-   * when the Tab is  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.
-   */
-  FrameScriptScope.FrameScriptEnv = (function getFrameScriptEnv() {
-    // Check if this is the main process.
-    if (EnvironmentManager.isMainProcess === true) {
-      //console.debug('[RPC] the framescript is in the main process. ' +
-      //              'Creating a new environment...');
-      // 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(["lib/environment"]);
-      return new Environment("FrameScriptEnv (main process)");
-    } else {
-      //console.debug('[RPC] the framescript is in a child process. ' +
-      //              "Going to use the child's ProcEnv...");
-      // This is a child process. The `ProcessEnvironment` can be used for this
-      // window's Environment.
-      return ScriptLoader.importModule("lib/process-environment")
-                         .ProcessEnvironment;
-    }
-  }());
+    "lib/environment"
+  ], mod);
+  let {C, Logger, Environment, FrameScriptEnvironment} = mod;
 
-  let FrameScriptEnv = FrameScriptScope.FrameScriptEnv;
 
-  FrameScriptEnv.addShutdownFunction(Environment.LEVELS.ESSENTIAL, function() {
-    //console.debug("removing FrameScriptScope");
-    FrameScriptScope = null;
-  });
+  let framescriptEnv = new FrameScriptEnvironment(mm);
+  let mlManager = framescriptEnv.mlManager;
 
 
-  let {ManagerForMessageListeners} = ScriptLoader.importModule(
-      "lib/manager-for-message-listeners");
-  FrameScriptScope.mlManager = new ManagerForMessageListeners(
-      FrameScriptEnv, mm);
-  let mlManager = FrameScriptScope.mlManager;
+  // Create a scope for the sub-scripts, which also can
+  // be removed easily when the framescript gets unloaded.
+  var framescriptScope = {
+    "mm": mm,
+    "content": mm.content,
+    "Components": mm.Components,
 
+    "Ci": mm.Components.interfaces,
+    "Cc": mm.Components.classes,
+    "Cu": mm.Components.utils,
 
+    "ScriptLoader": ScriptLoader,
+    "C": C,
+    "Logger": Logger,
+    "Environment": Environment,
 
-  /**
-   * Ensure that the framescript is „shut down“ when the addon gets disabled.
-   *
-   * TODO: use the Child Message Manager instead!
-   *       https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/The_message_manager#Process_Message_Managers
-   */
-  {
-    // Hand over the ContentFrameMessageManager of this framescript to the
-    // EnvironmentManager. The EnvironmentManager then shuts down all environments
-    // in the child process when the "shutdown" message is received. If this
-    // framescript is in the *chrome* process (aka. main process / parent process)
-    // then EnvironmentManager will simply ignore this function call.
-    EnvironmentManager.registerFramescript(mm);
-  }
+    "framescriptEnv": framescriptEnv,
+    "mlManager": mlManager
+  };
 
-  /**
-   * Ensure that the framescript is „shut down“ when the correspondung Tab gets
-   * closed.
-   */
-  {
-    FrameScriptEnv.shutdownOnUnload(mm);
+  function loadSubScripts() {
+    Services.scriptloader.loadSubScriptWithOptions(
+        'chrome://requestpolicy/content/ui/frame.blocked-content.js',
+        {target: framescriptScope/*, ignoreCache: true*/});
+    Services.scriptloader.loadSubScriptWithOptions(
+        'chrome://requestpolicy/content/ui/frame.dom-content-loaded.js',
+        {target: framescriptScope/*, ignoreCache: true*/});
   }
+  framescriptEnv.addStartupFunction(Environment.LEVELS.ESSENTIAL,
+                                    loadSubScripts);
+
+  framescriptEnv.addShutdownFunction(Environment.LEVELS.ESSENTIAL, function() {
+    //console.debug("removing framescriptScope '" + framescriptEnv.uid + "'");
+    framescriptScope = null;
+  });
+
 
-  /**
-   * Ensure that EnvironmentManager is unloaded in a child process. If it
-   * wouldn't be unloaded, the EnvironmentManager might be the same one the
-   * next time the addon gets enabled.
-   *
-   * The unload can't be done from EnvironmentManager itself, as due to Mozilla
-   * Bug 769253 a module cannot unload itself. This is also the reason why
-   * the unload is done async -- the shutdown functions are called by
-   * EnvironmentManager.
-   */
-  function unloadEnvMan() {
-    // The runnable (nsIRunnable) that will be executed asynchronously.
-    let runnableForUnloadingEnvMan = {
-      run: function() {
-        Components.utils.unload("chrome://requestpolicy/content/" +
-                                "main/environment-manager.jsm");
-      }
-    };
-
-    // tell the current thread to run the `unloadEnvMan` runnable async.
-    Components.classes["@mozilla.org/thread-manager;1"]
-        .getService(Components.interfaces.nsIThreadManager)
-        .currentThread
-        .dispatch(runnableForUnloadingEnvMan,
-                  Components.interfaces.nsIEventTarget.DISPATCH_NORMAL);
-  }
-  if (EnvironmentManager.isMainProcess === false) {
-    Environment.asyncUnloadEnvMan = unloadEnvMan;
-  }
 
 
   function reloadDocument() {
@@ -179,19 +105,6 @@ Components.utils.import("resource://gre/modules/Services.jsm");
     setLocation(message.data.uri);
   });
 
-  function loadSubScripts() {
-    Services.scriptloader.loadSubScriptWithOptions(
-        'chrome://requestpolicy/content/ui/frame.blocked-content.js',
-        {target: FrameScriptScope/*, ignoreCache: true*/});
-    Services.scriptloader.loadSubScriptWithOptions(
-        'chrome://requestpolicy/content/ui/frame.dom-content-loaded.js',
-        {target: FrameScriptScope/*, ignoreCache: true*/});
-  }
-  FrameScriptEnv.addStartupFunction(Environment.LEVELS.BACKEND,
-                                    loadSubScripts);
-
-  FrameScriptEnv.startup();
-
 
 
   // Listen for click events so that we can allow requests that result from
@@ -231,7 +144,12 @@ Components.utils.import("resource://gre/modules/Services.jsm");
       return;
     }
   };
-  FrameScriptEnv.addStartupFunction(Environment.LEVELS.INTERFACE, function() {
-    FrameScriptEnv.elManager.addListener(mm, "click", mouseClicked, true);
+
+  framescriptEnv.addStartupFunction(Environment.LEVELS.INTERFACE, function() {
+    framescriptEnv.elManager.addListener(mm, "click", mouseClicked, true);
   });
+
+
+  // start up the framescript's environment
+  framescriptEnv.startup();
 }());
diff --git a/src/content/ui/overlay.js b/src/content/ui/overlay.js
index a068102..80a7305 100644
--- a/src/content/ui/overlay.js
+++ b/src/content/ui/overlay.js
@@ -41,7 +41,7 @@ requestpolicy.overlay = (function() {
 
   // iMod: Alias for ScriptLoader.importModule
   let iMod = ScriptLoader.importModule;
-  let {Environment} = iMod("lib/environment");
+  let {Environment, ProcessEnvironment} = iMod("lib/environment");
   let {ManagerForMessageListeners} = iMod("lib/manager-for-message-listeners");
   let {Logger} = iMod("lib/logger");
   let {rpPrefBranch, Prefs} = iMod("lib/prefs");
@@ -61,7 +61,7 @@ requestpolicy.overlay = (function() {
 
 
   // create an environment for this overlay.
-  let OverlayEnvironment = new Environment("OverlayEnv");
+  let OverlayEnvironment = new Environment(ProcessEnvironment, "OverlayEnv");
   // manage this overlay's message listeners:
   let mlManager = new ManagerForMessageListeners(OverlayEnvironment,
                                                  window.messageManager);
diff --git a/src/content/ui/request-log.js b/src/content/ui/request-log.js
index d95ba35..a60714e 100644
--- a/src/content/ui/request-log.js
+++ b/src/content/ui/request-log.js
@@ -36,10 +36,11 @@ window.requestpolicy.requestLog = (function (self) {
   }());
   let {StringUtils} = ScriptLoader.importModule("lib/utils/strings");
   let {WindowUtils} = ScriptLoader.importModule("lib/utils/windows");
-  let {Environment} = ScriptLoader.importModule("lib/environment");
+  let {Environment,
+       ProcessEnvironment} = ScriptLoader.importModule("lib/environment");
 
   // create a new Environment for this window
-  var WinEnv = new Environment("WinEnv");
+  var WinEnv = new Environment(ProcessEnvironment, "WinEnv");
   // The Environment has to be shut down when the content window gets unloaded.
   WinEnv.shutdownOnUnload(window);
   // start up right now, as there won't be any startup functions

-- 
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