Bug 248970 - Private Browsing mode (global toggle for saving/caching everything) [Private Browsing service]; r=mconnor
authorEhsan Akhgari <ehsan.akhgari@gmail.com>
Tue, 04 Nov 2008 02:52:22 +0330
changeset 21245 12487541851bbd07ae813cb1d6629a627a24a500
parent 21244 c588d41a49e53d81ec1a00e7e80f0fb1848b8923
child 21246 a48936e198bf54121ac9f0c6980ecd2c795775d0
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconnor
bugs248970
milestone1.9.1b2pre
Bug 248970 - Private Browsing mode (global toggle for saving/caching everything) [Private Browsing service]; r=mconnor
browser/base/content/browser.js
browser/components/Makefile.in
browser/components/privatebrowsing/Makefile.in
browser/components/privatebrowsing/src/Makefile.in
browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
browser/components/privatebrowsing/test/Makefile.in
browser/components/privatebrowsing/test/browser/Makefile.in
browser/components/privatebrowsing/test/browser/browser_privatebrowsing_ui.js
browser/components/privatebrowsing/test/unit/head_privatebrowsing.js
browser/components/privatebrowsing/test/unit/test_0-privatebrowsing.js
browser/components/privatebrowsing/test/unit/test_httpauth.js
browser/components/privatebrowsing/test/unit/test_privatebrowsing_exit.js
browser/installer/unix/packages-static
browser/installer/windows/packages-static
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1295,16 +1295,18 @@ function delayedStartup(isLoadingBlank, 
 
 #ifndef XP_MACOSX
   updateEditUIVisibility();
   let placesContext = document.getElementById("placesContext");
   placesContext.addEventListener("popupshowing", updateEditUIVisibility, false);
   placesContext.addEventListener("popuphiding", updateEditUIVisibility, false);
 #endif
 
+  // initialize the private browsing UI
+  gPrivateBrowsingUI.init();
 }
 
 function BrowserShutdown()
 {
   tabPreviews.uninit();
   ctrlTab.uninit();
 
   gGestureSupport.init(false);
@@ -6731,8 +6733,52 @@ function getNotificationBox(aWindow) {
   if (foundBrowser)
     return gBrowser.getNotificationBox(foundBrowser)
   return null;
 };
 
 /* DEPRECATED */
 function getBrowser() gBrowser;
 function getNavToolbox() gNavToolbox;
+
+let gPrivateBrowsingUI = {
+  _observerService: null,
+  _privateBrowsingService: null,
+
+  init: function PBUI_init() {
+    this._observerService = Cc["@mozilla.org/observer-service;1"].
+                            getService(Ci.nsIObserverService);
+    this._observerService.addObserver(this, "private-browsing", false);
+    this._observerService.addObserver(this, "quit-application", false);
+
+    this._privateBrowsingService = Cc["@mozilla.org/privatebrowsing;1"].
+                                   getService(Ci.nsIPrivateBrowsingService);
+
+    if (this._privateBrowsingService.privateBrowsingEnabled)
+      this.onEnterPrivateBrowsing();
+    else
+      this.onExitPrivateBrowsing();
+  },
+
+  observe: function PBUI_observe(aSubject, aTopic, aData) {
+    if (aTopic == "private-browsing") {
+      if (aData == "enter")
+        this.onEnterPrivateBrowsing();
+      else if (aData == "exit")
+        this.onExitPrivateBrowsing();
+    }
+    else if (aTopic == "quit-application") {
+      this._observerService.removeObserver(this, "quit-application");
+      this._observerService.removeObserver(this, "private-browsing");
+    }
+  },
+
+  onEnterPrivateBrowsing: function PBUI_onEnterPrivateBrowsing() {
+  },
+
+  onExitPrivateBrowsing: function PBUI_onExitPrivateBrowsing() {
+  },
+
+  toggleMode: function PBUI_toggleMode() {
+    this._privateBrowsingService.privateBrowsingEnabled =
+      !this._privateBrowsingService.privateBrowsingEnabled;
+  }
+};
--- a/browser/components/Makefile.in
+++ b/browser/components/Makefile.in
@@ -66,16 +66,17 @@ DIRS = \
 	migration \
 	preferences \
 	search \
 	sessionstore \
 	shell \
 	sidebar \
 	feeds \
 	places \
+	privatebrowsing \
 	$(NULL)
 
 ifdef MOZ_SAFE_BROWSING
 DIRS += safebrowsing
 endif
 
 DIRS += build
 
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/Makefile.in
@@ -0,0 +1,53 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Private Browsing.
+#
+# The Initial Developer of the Original Code is
+# Ehsan Akhgari.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Ehsan Akhgari <ehsan.akhgari@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = privatebrowsing
+
+DIRS = src
+
+ifdef ENABLE_TESTS
+DIRS += test
+endif
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/src/Makefile.in
@@ -0,0 +1,47 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Private Browsing.
+#
+# The Initial Developer of the Original Code is
+# Ehsan Akhgari.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Ehsan Akhgari <ehsan.akhgari@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH   = ../../../..
+topsrcdir = @top_srcdir@
+srcdir    = @srcdir@
+VPATH   = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+EXTRA_PP_COMPONENTS = nsPrivateBrowsingService.js
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
@@ -0,0 +1,245 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Private Browsing.
+#
+# The Initial Developer of the Original Code is
+# Ehsan Akhgari.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Ehsan Akhgari <ehsan.akhgari@gmail.com> (Original Author)
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const Cr = Components.results;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+function PrivateBrowsingService() {
+  this._obs.addObserver(this, "quit-application-granted", false);
+}
+
+PrivateBrowsingService.prototype = {
+  // Observer Service
+  __obs: null,
+  get _obs() {
+    if (!this.__obs)
+      this.__obs = Cc["@mozilla.org/observer-service;1"].
+                   getService(Ci.nsIObserverService);
+    return this.__obs;
+  },
+
+  // Whether the private browsing mode is currently active or not.
+  _inPrivateBrowsing: false,
+
+  // Saved browser state before entering the private mode.
+  _savedBrowserState: null,
+
+  // Whether we're in the process of shutting down
+  _quitting: false,
+
+  // How to treat the non-private session
+  _saveSession: true,
+
+  // Make sure we don't allow re-enterant changing of the private mode
+  _alreadyChangingMode: false,
+
+  // XPCOM registration
+  classDescription: "PrivateBrowsing Service",
+  contractID: "@mozilla.org/privatebrowsing;1",
+  classID: Components.ID("{c31f4883-839b-45f6-82ad-a6a9bc5ad599}"),
+  _xpcom_categories: [
+    { category: "app-startup", service: true }
+  ],
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrivateBrowsingService, 
+                                         Ci.nsIObserver]),
+
+  _unload: function PBS__destroy() {
+    // Force an exit from the private browsing mode on shutdown
+    this._quitting = true;
+    if (this._inPrivateBrowsing)
+      this.privateBrowsingEnabled = false;
+
+    this._obs.removeObserver(this, "quit-application-granted");
+  },
+
+  _onPrivateBrowsingModeChanged: function PBS__onPrivateBrowsingModeChanged() {
+    // clear all auth tokens
+    let sdr = Cc["@mozilla.org/security/sdr;1"].
+              getService(Ci.nsISecretDecoderRing);
+    sdr.logoutAndTeardown();
+
+    // clear plain HTTP auth sessions
+    let authMgr = Cc['@mozilla.org/network/http-auth-manager;1'].
+                  getService(Ci.nsIHttpAuthManager);
+    authMgr.clearAll();
+
+    let ss = Cc["@mozilla.org/browser/sessionstore;1"].
+             getService(Ci.nsISessionStore);
+    if (this.privateBrowsingEnabled) {
+      // whether we should save and close the current session
+      this._saveSession = true;
+      var prefBranch = Cc["@mozilla.org/preferences-service;1"].
+                       getService(Ci.nsIPrefBranch);
+      try {
+        if (prefBranch.getBoolPref("browser.privatebrowsing.keep_current_session"))
+          this._saveSession = false;
+      } catch (ex) {}
+
+      // save the whole browser state in order to restore all windows/tabs later
+      if (this._saveSession && !this._savedBrowserState) {
+        this._savedBrowserState = ss.getBrowserState();
+
+        // Close all windows
+        this._closeAllWindows();
+
+        // Open a single window
+        this._openSingleWindow();
+      }
+    }
+    else {
+      // restore the windows/tabs which were open before entering the private mode
+      if (this._saveSession && this._savedBrowserState) {
+        if (!this._quitting) // don't restore when shutting down!
+          ss.setBrowserState(this._savedBrowserState);
+        this._savedBrowserState = null;
+      }
+    }
+  },
+
+#ifndef XP_WIN
+#define BROKEN_WM_Z_ORDER
+#endif
+
+  _closeAllWindows: function PBS__closeAllWindows() {
+    let windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].
+                         getService(Ci.nsIWindowMediator);
+#ifdef BROKEN_WM_Z_ORDER
+    let windowsEnum = windowMediator.getEnumerator("navigator:browser");
+#else
+    let windowsEnum = windowMediator.getZOrderDOMWindowEnumerator("navigator:browser", false);
+#endif
+
+    while (windowsEnum.hasMoreElements()) {
+      let win = windowsEnum.getNext();
+      win.close();
+    }
+  },
+
+  _openSingleWindow: function PBS__openSingleWindow() {
+    let windowWatcher = Cc["@mozilla.org/embedcomp/window-watcher;1"].
+                        getService(Ci.nsIWindowWatcher);
+    windowWatcher.openWindow(null, "chrome://browser/content/browser.xul",
+                             null, "chrome,all,resizable=yes,dialog=no", null);
+  },
+
+  _canEnterPrivateBrowsingMode: function PBS__canEnterPrivateBrowsingMode() {
+    let cancelEnter = Cc["@mozilla.org/supports-PRBool;1"].
+                      createInstance(Ci.nsISupportsPRBool);
+    cancelEnter.data = false;
+    this._obs.notifyObservers(cancelEnter, "private-browsing-cancel-vote", "enter");
+    return !cancelEnter.data;
+  },
+
+  _canLeavePrivateBrowsingMode: function PBS__canLeavePrivateBrowsingMode() {
+    let cancelLeave = Cc["@mozilla.org/supports-PRBool;1"].
+                      createInstance(Ci.nsISupportsPRBool);
+    cancelLeave.data = false;
+    this._obs.notifyObservers(cancelLeave, "private-browsing-cancel-vote", "exit");
+    return !cancelLeave.data;
+  },
+
+  // nsIObserver
+
+  observe: function PBS_observe(aSubject, aTopic, aData) {
+    switch (aTopic) {
+      case "quit-application-granted":
+        this._unload();
+        break;
+    }
+  },
+
+  // nsIPrivateBrowsingService
+
+  /**
+   * Return the current status of private browsing.
+   */
+  get privateBrowsingEnabled PBS_get_privateBrowsingEnabled() {
+    return this._inPrivateBrowsing;
+  },
+
+  /**
+   * Enter or leave private browsing mode.
+   */
+  set privateBrowsingEnabled PBS_set_privateBrowsingEnabled(val) {
+    // Allowing observers to set the private browsing status from their
+    // notification handlers is not desired, because it will change the
+    // status of the service while it's in the process of another transition.
+    // So, we detect a reentrant call here and throw an error.
+    // This is documented in nsIPrivateBrowsingService.idl.
+    if (this._alreadyChangingMode)
+      throw Cr.NS_ERROR_FAILURE;
+
+    try {
+      this._alreadyChangingMode = true;
+
+      if (val != this._inPrivateBrowsing) {
+        if (val) {
+          if (!this._canEnterPrivateBrowsingMode())
+            return;
+        }
+        else {
+          if (!this._canLeavePrivateBrowsingMode())
+            return;
+        }
+
+        this._inPrivateBrowsing = val != false;
+
+        let data = val ? "enter" : "exit";
+
+        let quitting = Cc["@mozilla.org/supports-PRBool;1"].
+                       createInstance(Ci.nsISupportsPRBool);
+        quitting.data = this._quitting;
+        this._obs.notifyObservers(quitting, "private-browsing", data);
+
+        this._onPrivateBrowsingModeChanged();
+      }
+    } catch (ex) {
+      Cu.reportError("Exception thrown while processing the " +
+        "private browsing mode change request: " + ex.toString());
+    } finally {
+      this._alreadyChangingMode = false;
+    }
+  }
+};
+
+function NSGetModule(compMgr, fileSpec)
+  XPCOMUtils.generateModule([PrivateBrowsingService]);
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/Makefile.in
@@ -0,0 +1,53 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Private Browsing.
+#
+# The Initial Developer of the Original Code is
+# Ehsan Akhgari.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Ehsan Akhgari <ehsan.akhgari@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+relativesrcdir  = browser/components/privatebrowsing/test
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= test_privatebrowsing
+
+XPCSHELL_TESTS	= unit
+
+DIRS +=	browser \
+		$(NULL)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/Makefile.in
@@ -0,0 +1,52 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Private Browsing.
+#
+# The Initial Developer of the Original Code is
+# Ehsan Akhgari.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Ehsan Akhgari <ehsan.akhgari@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+relativesrcdir  = browser/components/privatebrowsing/test/browser
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_BROWSER_TEST_FILES =  \
+		browser_privatebrowsing_ui.js \
+		$(NULL)
+
+libs:: $(_BROWSER_TEST_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_ui.js
@@ -0,0 +1,66 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Private Browsing Tests.
+ *
+ * The Initial Developer of the Original Code is
+ * Ehsan Akhgari.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ehsan Akhgari <ehsan.akhgari@gmail.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// This test makes sure that the gPrivateBrowsingUI object works correctly.
+
+function test() {
+  // initialization
+  let prefBranch = Cc["@mozilla.org/preferences-service;1"].
+                   getService(Ci.nsIPrefBranch);
+  prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
+  let pb = Cc["@mozilla.org/privatebrowsing;1"].
+           getService(Ci.nsIPrivateBrowsingService);
+  let observer = {
+    observe: function (aSubject, aTopic, aData) {
+      if (aTopic == "private-browsing")
+        this.data = aData;
+    },
+    data: null
+  };
+  let os = Cc["@mozilla.org/observer-service;1"].
+           getService(Ci.nsIObserverService);
+  os.addObserver(observer, "private-browsing", false);
+
+  // test the gPrivateBrowsingUI object
+  ok(gPrivateBrowsingUI, "The gPrivateBrowsingUI object exists");
+  gPrivateBrowsingUI.toggleMode();
+  // check to see if the Private Browsing mode was activated successfully
+  is(observer.data, "enter", "Private Browsing mode was activated using the gPrivateBrowsingUI object");
+  gPrivateBrowsingUI.toggleMode()
+  // check to see if the Private Browsing mode was deactivated successfully
+  is(observer.data, "exit", "Private Browsing mode was deactivated using the gPrivateBrowsingUI object");
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/unit/head_privatebrowsing.js
@@ -0,0 +1,53 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Private Browsing Tests.
+ *
+ * The Initial Developer of the Original Code is
+ * Ehsan Akhgari.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ehsan Akhgari <ehsan.akhgari@gmail.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cr = Components.results;
+const Cu = Components.utils;
+
+const kPrivateBrowsingNotification = "private-browsing";
+const kPrivateBrowsingCancelVoteNotification = "private-browsing-cancel-vote";
+const kEnter = "enter";
+const kExit = "exit";
+
+function LOG(aMsg) {
+  aMsg = ("*** PRIVATEBROWSING TESTS: " + aMsg);
+  Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).
+                                      logStringMessage(aMsg);
+  print(aMsg);
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/unit/test_0-privatebrowsing.js
@@ -0,0 +1,220 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Private Browsing Tests.
+ *
+ * The Initial Developer of the Original Code is
+ * Ehsan Akhgari.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ehsan Akhgari <ehsan.akhgari@gmail.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// This tests the private browsing service to make sure it implements its
+// documented interface correctly.
+
+// This test should run before the rest of private browsing service unit tests,
+// hence the naming used for this file.
+
+function run_test() {
+  // initialization
+  var os = Cc["@mozilla.org/observer-service;1"].
+           getService(Ci.nsIObserverService);
+  var prefBranch = Cc["@mozilla.org/preferences-service;1"].
+                   getService(Ci.nsIPrefBranch);
+  prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
+
+  // the contract ID should be available
+  do_check_true("@mozilla.org/privatebrowsing;1" in Cc);
+
+  // the interface should be available
+  do_check_true("nsIPrivateBrowsingService" in Ci);
+
+  // it should be possible to initialize the component
+  try {
+    var pb = Cc["@mozilla.org/privatebrowsing;1"].
+             getService(Ci.nsIPrivateBrowsingService);
+  } catch (ex) {
+    LOG("exception thrown when trying to get the service: " + ex);
+    do_throw("private browsing service could not be initialized");
+  }
+
+  // private browsing should be turned off initially
+  do_check_false(pb.privateBrowsingEnabled);
+
+  // it should be possible to toggle its status
+  pb.privateBrowsingEnabled = true;
+  do_check_true(pb.privateBrowsingEnabled);
+  pb.privateBrowsingEnabled = false;
+  do_check_false(pb.privateBrowsingEnabled);
+
+  // test the private-browsing notification
+  var observer = {
+    observe: function(aSubject, aTopic, aData) {
+      if (aTopic == kPrivateBrowsingNotification)
+        this.data = aData;
+    },
+    data: null
+  };
+  os.addObserver(observer, kPrivateBrowsingNotification, false);
+  pb.privateBrowsingEnabled = true;
+  do_check_eq(observer.data, kEnter);
+  pb.privateBrowsingEnabled = false;
+  do_check_eq(observer.data, kExit);
+  os.removeObserver(observer, kPrivateBrowsingNotification);
+
+  // make sure that setting the private browsing mode from within an observer throws
+  observer = {
+    observe: function(aSubject, aTopic, aData) {
+      if (aTopic == kPrivateBrowsingNotification) {
+        try {
+          pb.privateBrowsingEnabled = (aData == kEnter);
+          do_throw("Setting privateBrowsingEnabled inside the " + aData +
+            " notification should throw");
+        } catch (ex) {
+          if (!("result" in ex && ex.result == Cr.NS_ERROR_FAILURE))
+            do_throw("Unexpected exception caught: " + ex);
+        }
+      }
+    }
+  };
+  os.addObserver(observer, kPrivateBrowsingNotification, false);
+  pb.privateBrowsingEnabled = true;
+  do_check_true(pb.privateBrowsingEnabled); // the exception should not interfere with the mode change
+  pb.privateBrowsingEnabled = false;
+  do_check_false(pb.privateBrowsingEnabled); // the exception should not interfere with the mode change
+  os.removeObserver(observer, kPrivateBrowsingNotification);
+
+  // make sure that getting the private browsing mode from within an observer doesn't throw
+  observer = {
+    observe: function(aSubject, aTopic, aData) {
+      if (aTopic == kPrivateBrowsingNotification) {
+        try {
+          var dummy = pb.privateBrowsingEnabled;
+          if (aData == kEnter)
+            do_check_true(dummy);
+          else if (aData == kExit)
+            do_check_false(dummy);
+        } catch (ex) {
+          do_throw("Unexpected exception caught: " + ex);
+        }
+      }
+    }
+  };
+  os.addObserver(observer, kPrivateBrowsingNotification, false);
+  pb.privateBrowsingEnabled = true;
+  do_check_true(pb.privateBrowsingEnabled); // just a sanity check
+  pb.privateBrowsingEnabled = false;
+  do_check_false(pb.privateBrowsingEnabled); // just a sanity check
+  os.removeObserver(observer, kPrivateBrowsingNotification);
+
+  // check that the private-browsing-cancel-vote notification is sent before the
+  // private-browsing notification
+  observer = {
+    observe: function(aSubject, aTopic, aData) {
+      switch (aTopic) {
+      case kPrivateBrowsingCancelVoteNotification:
+      case kPrivateBrowsingNotification:
+        this.notifications.push(aTopic + " " + aData);
+      }
+    },
+    notifications: []
+  };
+  os.addObserver(observer, kPrivateBrowsingCancelVoteNotification, false);
+  os.addObserver(observer, kPrivateBrowsingNotification, false);
+  pb.privateBrowsingEnabled = true;
+  do_check_true(pb.privateBrowsingEnabled); // just a sanity check
+  pb.privateBrowsingEnabled = false;
+  do_check_false(pb.privateBrowsingEnabled); // just a sanity check
+  os.removeObserver(observer, kPrivateBrowsingNotification);
+  os.removeObserver(observer, kPrivateBrowsingCancelVoteNotification);
+  var reference_order = [
+      kPrivateBrowsingCancelVoteNotification + " " + kEnter,
+      kPrivateBrowsingNotification + " " + kEnter,
+      kPrivateBrowsingCancelVoteNotification + " " + kExit,
+      kPrivateBrowsingNotification + " " + kExit
+    ];
+  do_check_eq(observer.notifications.join(","), reference_order.join(","));
+
+  // make sure that the private-browsing-cancel-vote notification can be used
+  // to cancel the mode switch
+  observer = {
+    observe: function(aSubject, aTopic, aData) {
+      switch (aTopic) {
+      case kPrivateBrowsingCancelVoteNotification:
+        do_check_neq(aSubject, null);
+        try {
+          aSubject.QueryInterface(Ci.nsISupportsPRBool);
+        } catch (ex) {
+          do_throw("aSubject in " + kPrivateBrowsingCancelVoteNotification +
+            " should implement nsISupportsPRBool");
+        }
+        do_check_false(aSubject.data);
+        aSubject.data = true; // cancel the mode switch
+
+        // fall through
+      case kPrivateBrowsingNotification:
+        this.notifications.push(aTopic + " " + aData);
+      }
+    },
+    nextPhase: function() {
+      this.notifications.push("enter phase " + (++this._phase));
+    },
+    notifications: [],
+    _phase: 0
+  };
+  os.addObserver(observer, kPrivateBrowsingCancelVoteNotification, false);
+  os.addObserver(observer, kPrivateBrowsingNotification, false);
+  pb.privateBrowsingEnabled = true;
+  do_check_false(pb.privateBrowsingEnabled); // should have been canceled
+  // temporarily disable the observer
+  os.removeObserver(observer, kPrivateBrowsingCancelVoteNotification);
+  observer.nextPhase();
+  pb.privateBrowsingEnabled = true; // this time, should enter successfully
+  do_check_true(pb.privateBrowsingEnabled); // should have been canceled
+  // re-enable the observer
+  os.addObserver(observer, kPrivateBrowsingCancelVoteNotification, false);
+  pb.privateBrowsingEnabled = false;
+  do_check_true(pb.privateBrowsingEnabled); // should have been canceled
+  os.removeObserver(observer, kPrivateBrowsingCancelVoteNotification);
+  observer.nextPhase();
+  pb.privateBrowsingEnabled = false; // this time, should exit successfully
+  do_check_false(pb.privateBrowsingEnabled);
+  os.removeObserver(observer, kPrivateBrowsingNotification);
+  reference_order = [
+      kPrivateBrowsingCancelVoteNotification + " " + kEnter,
+      "enter phase 1",
+      kPrivateBrowsingNotification + " " + kEnter,
+      kPrivateBrowsingCancelVoteNotification + " " + kExit,
+      "enter phase 2",
+      kPrivateBrowsingNotification + " " + kExit,
+    ];
+  do_check_eq(observer.notifications.join(","), reference_order.join(","));
+
+  prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/unit/test_httpauth.js
@@ -0,0 +1,114 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Private Browsing Tests.
+ *
+ * The Initial Developer of the Original Code is
+ * Ehsan Akhgari.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ehsan Akhgari <ehsan.akhgari@gmail.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// This test makes sure the HTTP authenticated sessions are correctly cleared
+// when entering and leaving the private browsing mode.
+
+function run_test() {
+  var prefBranch = Cc["@mozilla.org/preferences-service;1"].
+                   getService(Ci.nsIPrefBranch);
+  prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
+
+  var pb = Cc["@mozilla.org/privatebrowsing;1"].
+           getService(Ci.nsIPrivateBrowsingService);
+
+  var am = Cc["@mozilla.org/network/http-auth-manager;1"].
+           getService(Ci.nsIHttpAuthManager);
+
+  const kHost1 = "pbtest3.example.com";
+  const kHost2 = "pbtest4.example.com";
+  const kPort = 80;
+  const kHTTP = "http";
+  const kBasic = "basic";
+  const kRealm = "realm";
+  const kDomain = "example.com";
+  const kUser = "user";
+  const kUser2 = "user2";
+  const kPassword = "pass";
+  const kPassword2 = "pass2";
+  const kEmpty = "";
+
+  try {
+    var domain = {value: kEmpty}, user = {value: kEmpty}, pass = {value: kEmpty};
+    // simulate a login via HTTP auth outside of the private mode
+    am.setAuthIdentity(kHTTP, kHost1, kPort, kBasic, kRealm, kEmpty, kDomain, kUser, kPassword);
+    // make sure the recently added auth entry is available outside the private browsing mode
+    am.getAuthIdentity(kHTTP, kHost1, kPort, kBasic, kRealm, kEmpty, domain, user, pass);
+    do_check_eq(domain.value, kDomain);
+    do_check_eq(user.value, kUser);
+    do_check_eq(pass.value, kPassword);
+    // enter private browsing mode
+    pb.privateBrowsingEnabled = true;
+    // make sure the added auth entry is no longer accessible
+    domain = {value: kEmpty}, user = {value: kEmpty}, pass = {value: kEmpty};
+    try {
+      // should throw
+      am.getAuthIdentity(kHTTP, kHost1, kPort, kBasic, kRealm, kEmpty, domain, user, pass);
+      do_throw("Auth entry should not be retrievable after entering the private browsing mode");
+    } catch (e) {
+      do_check_eq(domain.value, kEmpty);
+      do_check_eq(user.value, kEmpty);
+      do_check_eq(pass.value, kEmpty);
+    }
+
+    // simulate a login via HTTP auth inside of the private mode
+    am.setAuthIdentity(kHTTP, kHost2, kPort, kBasic, kRealm, kEmpty, kDomain, kUser2, kPassword2);
+    // make sure the recently added auth entry is available outside the private browsing mode
+    domain = {value: kEmpty}, user = {value: kEmpty}, pass = {value: kEmpty};
+    am.getAuthIdentity(kHTTP, kHost2, kPort, kBasic, kRealm, kEmpty, domain, user, pass);
+    do_check_eq(domain.value, kDomain);
+    do_check_eq(user.value, kUser2);
+    do_check_eq(pass.value, kPassword2);
+    // exit private browsing mode
+    pb.privateBrowsingEnabled = false;
+    // make sure the added auth entry is no longer accessible
+    domain = {value: kEmpty}, user = {value: kEmpty}, pass = {value: kEmpty};
+    try {
+      // should throw
+      am.getAuthIdentity(kHTTP, kHost2, kPort, kBasic, kRealm, kEmpty, domain, user, pass);
+      do_throw("Auth entry should not be retrievable after exiting the private browsing mode");
+    } catch (e) {
+      do_check_eq(domain.value, kEmpty);
+      do_check_eq(user.value, kEmpty);
+      do_check_eq(pass.value, kEmpty);
+    }
+  } catch (e) {
+    do_throw("Unexpected exception while testing HTTP auth manager: " + e);
+  } finally {
+    prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/unit/test_privatebrowsing_exit.js
@@ -0,0 +1,99 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Private Browsing Tests.
+ *
+ * The Initial Developer of the Original Code is
+ * Ehsan Akhgari.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ehsan Akhgari <ehsan.akhgari@gmail.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// This test makes sure that the private browsing mode is left at application
+// shutdown.
+
+function run_test() {
+  // initialization
+  var os = Cc["@mozilla.org/observer-service;1"].
+           getService(Ci.nsIObserverService);
+  var pb = Cc["@mozilla.org/privatebrowsing;1"].
+           getService(Ci.nsIPrivateBrowsingService);
+  var appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].
+                   getService(Ci.nsIAppStartup);
+  var prefBranch = Cc["@mozilla.org/preferences-service;1"].
+                   getService(Ci.nsIPrefBranch);
+  prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
+
+  var expectedQuitting;
+  var called = 0;
+  var observer = {
+    observe: function(aSubject, aTopic, aData) {
+      if (aTopic == kPrivateBrowsingNotification &&
+          aData == kExit) {
+        // increment the call counter
+        ++ called;
+
+        do_check_neq(aSubject, null);
+        try {
+          aSubject.QueryInterface(Ci.nsISupportsPRBool);
+        } catch (ex) {
+          do_throw("aSubject was not null, but wasn't an nsISupportsPRBool");
+        }
+        // check the "quitting" argument
+        do_check_eq(aSubject.data, expectedQuitting);
+
+        // finish up the test
+        if (expectedQuitting) {
+          os.removeObserver(this, kPrivateBrowsingNotification);
+          prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
+          do_test_finished();
+        }
+      }
+    }
+  };
+
+  // set the observer
+  os.addObserver(observer, kPrivateBrowsingNotification, false);
+
+  // enter the private browsing mode
+  pb.privateBrowsingEnabled = true;
+
+  // exit the private browsing mode
+  expectedQuitting = false;
+  pb.privateBrowsingEnabled = false;
+  do_check_eq(called, 1);
+
+  // enter the private browsing mode
+  pb.privateBrowsingEnabled = true;
+
+  // exit and leave the test pending
+  expectedQuitting = true;
+  do_test_pending();
+  appStartup.quit(Ci.nsIAppStartup.eForceQuit);
+}
--- a/browser/installer/unix/packages-static
+++ b/browser/installer/unix/packages-static
@@ -152,16 +152,17 @@ bin/components/necko.xpt
 #ifdef MOZ_OJI
 bin/components/oji.xpt
 #endif
 bin/components/loginmgr.xpt
 bin/components/places.xpt
 bin/components/plugin.xpt
 bin/components/prefetch.xpt
 bin/components/pref.xpt
+bin/components/privatebrowsing.xpt
 bin/components/proxyObjInst.xpt
 bin/components/toolkitremote.xpt
 bin/components/rdf.xpt
 bin/components/satchel.xpt
 bin/components/saxparser.xpt
 bin/components/shistory.xpt
 bin/components/spellchecker.xpt
 bin/components/storage.xpt
@@ -200,16 +201,17 @@ bin/components/FeedWriter.js
 bin/components/fuelApplication.js
 bin/components/WebContentConverter.js
 bin/components/nsAddonRepository.js
 bin/components/nsBrowserContentHandler.js
 bin/components/nsBrowserGlue.js
 bin/components/nsSetDefaultBrowser.js
 bin/components/nsMicrosummaryService.js
 bin/components/nsPlacesTransactionsService.js
+bin/components/nsPrivateBrowsingService.js
 bin/components/nsSearchService.js
 bin/components/nsSearchSuggestions.js
 bin/components/nsLoginInfo.js
 bin/components/nsLoginManager.js
 bin/components/nsLoginManagerPrompter.js
 bin/components/storage-Legacy.js
 bin/components/storage-mozStorage.js
 bin/components/jsconsole-clhandler.js
--- a/browser/installer/windows/packages-static
+++ b/browser/installer/windows/packages-static
@@ -158,16 +158,17 @@ bin\components\necko_viewsource.xpt
 #ifdef MOZ_OJI
 bin\components\oji.xpt
 #endif
 bin\components\loginmgr.xpt
 bin\components\places.xpt
 bin\components\plugin.xpt
 bin\components\pref.xpt
 bin\components\prefetch.xpt
+bin\components\privatebrowsing.xpt
 bin\components\profile.xpt
 bin\components\proxyObject.xpt
 bin\components\rdf.xpt
 bin\components\satchel.xpt
 bin\components\saxparser.xpt
 bin\components\shistory.xpt
 bin\components\storage.xpt
 bin\components\toolkitprofile.xpt
@@ -219,16 +220,17 @@ bin\components\nsSearchService.js
 bin\components\nsSearchSuggestions.js
 bin\components\nsSidebar.js
 bin\components\nsExtensionManager.js
 bin\components\nsBlocklistService.js
 bin\components\nsUpdateService.js
 bin\components\nsMicrosummaryService.js
 bin\components\nsPlacesTransactionsService.js
 bin\components\nsPostUpdateWin.js
+bin\components\nsPrivateBrowsingService.js
 bin\components\nsLoginInfo.js
 bin\components\nsLoginManager.js
 bin\components\nsLoginManagerPrompter.js
 bin\components\storage-Legacy.js
 bin\components\storage-mozStorage.js
 bin\components\pluginGlue.js
 bin\components\extensions.xpt
 bin\components\update.xpt