Backed out changeset 31d5dca2a3b4 (bug 801232) because of leaks
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 06 Dec 2012 14:01:35 -0500
changeset 115167 cf0da0cd77237e1385a8667902115a09f418cd8d
parent 115166 31d5dca2a3b4fff391dd501ab897d4080007f623
child 115168 ea20935fa19d682387c60516a377409e85db7115
child 115224 9c06414c186477da3c3882be3f04c1d7e6cf9637
push id23978
push usereakhgari@mozilla.com
push dateThu, 06 Dec 2012 19:01:42 +0000
treeherdermozilla-central@cf0da0cd7723 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs801232
milestone20.0a1
backs out31d5dca2a3b4fff391dd501ab897d4080007f623
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 31d5dca2a3b4 (bug 801232) because of leaks
browser/components/downloads/content/downloads.js
browser/components/downloads/content/indicator.js
browser/components/downloads/src/DownloadsCommon.jsm
browser/components/downloads/src/DownloadsStartup.js
browser/components/downloads/src/Makefile.in
browser/components/downloads/test/browser/browser_basic_functionality.js
browser/components/downloads/test/browser/browser_first_download_panel.js
browser/components/downloads/test/browser/head.js
--- a/browser/components/downloads/content/downloads.js
+++ b/browser/components/downloads/content/downloads.js
@@ -39,18 +39,16 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Globals
 
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils",
                                   "resource://gre/modules/DownloadUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
                                   "resource:///modules/DownloadsCommon.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
-                                  "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsPanel
 
 /**
  * Main entry point for the downloads panel interface.
  */
 const DownloadsPanel = {
@@ -104,17 +102,17 @@ const DownloadsPanel = {
     // panel, starting the service will make us load their data asynchronously.
     Services.downloads;
 
     // Now that data loading has eventually started, load the required XUL
     // elements and initialize our views.
     DownloadsOverlayLoader.ensureOverlayLoaded(this.kDownloadsOverlay,
                                                function DP_I_callback() {
       DownloadsViewController.initialize();
-      DownloadsCommon.getData(window).addView(DownloadsView);
+      DownloadsCommon.data.addView(DownloadsView);
       DownloadsPanel._attachEventListeners();
       aCallback();
     });
   },
 
   /**
    * Closes the downloads panel and frees the internal resources related to the
    * downloads.  The downloads panel can be reopened later, even after this
@@ -127,17 +125,17 @@ const DownloadsPanel = {
     }
 
     window.removeEventListener("unload", this.onWindowUnload, false);
 
     // Ensure that the panel is closed before shutting down.
     this.hidePanel();
 
     DownloadsViewController.terminate();
-    DownloadsCommon.getData(window).removeView(DownloadsView);
+    DownloadsCommon.data.removeView(DownloadsView);
     this._unattachEventListeners();
 
     this._state = this.kStateUninitialized;
   },
 
   //////////////////////////////////////////////////////////////////////////////
   //// Panel interface
 
@@ -227,17 +225,17 @@ const DownloadsPanel = {
     // Ignore events raised by nested popups.
     if (aEvent.target != aEvent.currentTarget) {
       return;
     }
 
     this._state = this.kStateShown;
 
     // Since at most one popup is open at any given time, we can set globally.
-    DownloadsCommon.getIndicatorData(window).attentionSuppressed = true;
+    DownloadsCommon.indicatorData.attentionSuppressed = true;
 
     // Ensure that an item is selected when the panel is focused.
     if (DownloadsView.richListBox.itemCount > 0 &&
         !DownloadsView.richListBox.selectedItem) {
       DownloadsView.richListBox.selectedIndex = 0;
     }
 
     this._focusPanel();
@@ -246,17 +244,17 @@ const DownloadsPanel = {
   onPopupHidden: function DP_onPopupHidden(aEvent)
   {
     // Ignore events raised by nested popups.
     if (aEvent.target != aEvent.currentTarget) {
       return;
     }
 
     // Since at most one popup is open at any given time, we can set globally.
-    DownloadsCommon.getIndicatorData(window).attentionSuppressed = false;
+    DownloadsCommon.indicatorData.attentionSuppressed = false;
 
     // Allow the anchor to be hidden.
     DownloadsButton.releaseAnchor();
 
     // Allow the panel to be reopened.
     this._state = this.kStateHidden;
   },
 
@@ -1107,21 +1105,17 @@ const DownloadsViewController = {
     // ancestors of the focused element.
     return !!element;
   },
 
   isCommandEnabled: function DVC_isCommandEnabled(aCommand)
   {
     // Handle commands that are not selection-specific.
     if (aCommand == "downloadsCmd_clearList") {
-      if (PrivateBrowsingUtils.isWindowPrivate(window)) {
-        return Services.downloads.canCleanUpPrivate;
-      } else {
-        return Services.downloads.canCleanUp;
-      }
+      return Services.downloads.canCleanUp;
     }
 
     // Other commands are selection-specific.
     let element = DownloadsView.richListBox.selectedItem;
     return element &&
            new DownloadsViewItemController(element).isCommandEnabled(aCommand);
   },
 
@@ -1158,35 +1152,31 @@ const DownloadsViewController = {
 
   /**
    * This object contains one key for each command that operates regardless of
    * the currently selected item in the list.
    */
   commands: {
     downloadsCmd_clearList: function DVC_downloadsCmd_clearList()
     {
-      if (PrivateBrowsingUtils.isWindowPrivate(window)) {
-        Services.downloads.cleanUpPrivate();
-      } else {
-        Services.downloads.cleanUp();
-      }
+      Services.downloads.cleanUp();
     }
   }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsViewItemController
 
 /**
  * Handles all the user interaction events, in particular the "commands",
  * related to a single item in the downloads list widgets.
  */
 function DownloadsViewItemController(aElement) {
   let downloadGuid = aElement.getAttribute("downloadGuid");
-  this.dataItem = DownloadsCommon.getData(window).dataItems[downloadGuid];
+  this.dataItem = DownloadsCommon.data.dataItems[downloadGuid];
 }
 
 DownloadsViewItemController.prototype = {
   //////////////////////////////////////////////////////////////////////////////
   //// Constants
 
   get kPrefBdmAlertOnExeOpen() "browser.download.manager.alertOnEXEOpen",
   get kPrefBdmScanWhenDone() "browser.download.manager.scanWhenDone",
@@ -1462,20 +1452,20 @@ const DownloadsSummary = {
    *        Set to true to activate the summary.
    */
   set active(aActive)
   {
     if (aActive == this._active || !this._summaryNode) {
       return this._active;
     }
     if (aActive) {
-      DownloadsCommon.getSummary(window, DownloadsView.kItemCountLimit)
+      DownloadsCommon.getSummary(DownloadsView.kItemCountLimit)
                      .addView(this);
     } else {
-      DownloadsCommon.getSummary(window, DownloadsView.kItemCountLimit)
+      DownloadsCommon.getSummary(DownloadsView.kItemCountLimit)
                      .removeView(this);
       DownloadsFooter.showingSummary = false;
     }
 
     return this._active = aActive;
   },
 
   /**
--- a/browser/components/downloads/content/indicator.js
+++ b/browser/components/downloads/content/indicator.js
@@ -281,31 +281,31 @@ const DownloadsIndicatorView = {
   ensureInitialized: function DIV_ensureInitialized()
   {
     if (this._initialized) {
       return;
     }
     this._initialized = true;
 
     window.addEventListener("unload", this.onWindowUnload, false);
-    DownloadsCommon.getIndicatorData(window).addView(this);
+    DownloadsCommon.indicatorData.addView(this);
   },
 
   /**
    * Frees the internal resources related to the indicator.
    */
   ensureTerminated: function DIV_ensureTerminated()
   {
     if (!this._initialized) {
       return;
     }
     this._initialized = false;
 
     window.removeEventListener("unload", this.onWindowUnload, false);
-    DownloadsCommon.getIndicatorData(window).removeView(this);
+    DownloadsCommon.indicatorData.removeView(this);
 
     // Reset the view properties, so that a neutral indicator is displayed if we
     // are visible only temporarily as an anchor.
     this.counter = "";
     this.percentComplete = 0;
     this.paused = false;
     this.attention = false;
   },
@@ -322,17 +322,17 @@ const DownloadsIndicatorView = {
     }
 
     function DIV_EO_callback() {
       this._operational = true;
 
       // If the view is initialized, we need to update the elements now that
       // they are finally available in the document.
       if (this._initialized) {
-        DownloadsCommon.getIndicatorData(window).refreshView(this);
+        DownloadsCommon.indicatorData.refreshView(this);
       }
 
       aCallback();
     }
 
     DownloadsOverlayLoader.ensureOverlayLoaded(
                                  DownloadsButton.kIndicatorOverlay,
                                  DIV_EO_callback.bind(this));
@@ -503,17 +503,17 @@ const DownloadsIndicatorView = {
     // This function is registered as an event listener, we can't use "this".
     DownloadsIndicatorView.ensureTerminated();
   },
 
   onCommand: function DIV_onCommand(aEvent)
   {
     if (DownloadsCommon.useToolkitUI) {
       // The panel won't suppress attention for us, we need to clear now.
-      DownloadsCommon.getIndicatorData(window).attention = false;
+      DownloadsCommon.indicatorData.attention = false;
       BrowserDownloadsUI();
     } else {
       DownloadsPanel.showPanel();
     }
 
     aEvent.stopPropagation();
   },
 
--- a/browser/components/downloads/src/DownloadsCommon.jsm
+++ b/browser/components/downloads/src/DownloadsCommon.jsm
@@ -51,20 +51,16 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "@mozilla.org/browser/browserglue;1",
                                    "nsIBrowserGlue");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
                                   "resource://gre/modules/PluralForm.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils",
                                   "resource://gre/modules/DownloadUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
-                                  "resource://gre/modules/PrivateBrowsingUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
-                                  "resource:///modules/RecentWindow.jsm");
 
 const nsIDM = Ci.nsIDownloadManager;
 
 const kDownloadsStringBundleUrl =
   "chrome://browser/locale/downloads/downloads.properties";
 
 const kDownloadsStringsRequiringFormatting = {
   sizeWithUnits: true,
@@ -172,105 +168,47 @@ this.DownloadsCommon = {
   {
     try {
       return Services.prefs.getBoolPref("browser.download.useToolkitUI");
     } catch (ex) { }
     return false;
   },
 
   /**
-   * Get access to one of the DownloadsData or PrivateDownloadsData objects,
-   * depending on the privacy status of the window in question.
+   * Returns a reference to the DownloadsData singleton.
    *
-   * @param aWindow
-   *        The browser window which owns the download button.
+   * This does not need to be a lazy getter, since no initialization is required
+   * at present.
    */
-  getData: function DC_getData(aWindow) {
-    if (PrivateBrowsingUtils.isWindowPrivate(aWindow)) {
-      return PrivateDownloadsData;
-    } else {
-      return DownloadsData;
-    }
-  },
-
-  /**
-   * Initializes the data link for both the private and non-private downloads
-   * data objects.
-   *
-   * @param aDownloadManagerService
-   *        Reference to the service implementing nsIDownloadManager.  We need
-   *        this because getService isn't available for us when this method is
-   *        called, and we must ensure to register our listeners before the
-   *        getService call for the Download Manager returns.
-   */
-  initializeAllDataLinks: function DC_initializeAllDataLinks(aDownloadManagerService) {
-    DownloadsData.initializeDataLink(aDownloadManagerService);
-    PrivateDownloadsData.initializeDataLink(aDownloadManagerService);
-  },
+  get data() DownloadsData,
 
   /**
-   * Terminates the data link for both the private and non-private downloads
-   * data objects.
-   */
-  terminateAllDataLinks: function DC_terminateAllDataLinks() {
-    DownloadsData.terminateDataLink();
-    PrivateDownloadsData.terminateDataLink();
-  },
-
-  /**
-   * Reloads the specified kind of downloads from the non-private store.
-   * This method must only be called when Private Browsing Mode is disabled.
+   * Returns a reference to the DownloadsData singleton.
    *
-   * @param aActiveOnly
-   *        True to load only active downloads from the database.
+   * This does not need to be a lazy getter, since no initialization is required
+   * at present.
    */
-  ensureAllPersistentDataLoaded:
-  function DC_ensureAllPersistentDataLoaded(aActiveOnly) {
-    DownloadsData.ensurePersistentDataLoaded(aActiveOnly);
-  },
-
-  /**
-   * Get access to one of the DownloadsIndicatorData or
-   * PrivateDownloadsIndicatorData objects, depending on the privacy status of
-   * the window in question.
-   */
-  getIndicatorData: function DC_getIndicatorData(aWindow) {
-    if (PrivateBrowsingUtils.isWindowPrivate(aWindow)) {
-      return PrivateDownloadsIndicatorData;
-    } else {
-      return DownloadsIndicatorData;
-    }
-  },
+  get indicatorData() DownloadsIndicatorData,
 
   /**
    * Returns a reference to the DownloadsSummaryData singleton - creating one
    * in the process if one hasn't been instantiated yet.
    *
-   * @param aWindow
-   *        The browser window which owns the download button.
    * @param aNumToExclude
    *        The number of items on the top of the downloads list to exclude
    *        from the summary.
    */
-  getSummary: function DC_getSummary(aWindow, aNumToExclude)
+  _summary: null,
+  getSummary: function DC_getSummary(aNumToExclude)
   {
-    if (PrivateBrowsingUtils.isWindowPrivate(aWindow)) {
-      if (this._privateSummary) {
-        return this._privateSummary;
-      }
-      return this._privateSummary = new DownloadsSummaryData(true, aNumToExclude);
-    } else {
-      if (this._summary) {
-        return this._summary;
-      }
-      return this._summary = new DownloadsSummaryData(false, aNumToExclude);
+    if (this._summary) {
+      return this._summary;
     }
+    return this._summary = new DownloadsSummaryData(aNumToExclude);
   },
-  _summary: null,
-  _privateSummary: null,
 
   /**
    * Given an iterable collection of DownloadDataItems, generates and returns
    * statistics about that collection.
    *
    * @param aDataItems An iterable collection of DownloadDataItems.
    *
    * @return Object whose properties are the generated statistics. Currently,
@@ -411,82 +349,59 @@ XPCOMUtils.defineLazyGetter(DownloadsCom
  * data.  For example, the deletion of one or more downloads is notified through
  * the nsIObserver interface, while any state or progress change is notified
  * through the nsIDownloadProgressListener interface.
  *
  * Note that using this object does not automatically start the Download Manager
  * service.  Consumers will see an empty list of downloads until the service is
  * actually started.  This is useful to display a neutral progress indicator in
  * the main browser window until the autostart timeout elapses.
- *
- * Note that DownloadsData and PrivateDownloadsData are two equivalent singleton
- * objects, one accessing non-private downloads, and the other accessing private
- * ones.
  */
-function DownloadsDataCtor(aPrivate) {
-  this._isPrivate = aPrivate;
-
-  // This Object contains all the available DownloadsDataItem objects, indexed by
-  // their globally unique identifier.  The identifiers of downloads that have
-  // been removed from the Download Manager data are still present, however the
-  // associated objects are replaced with the value "null".  This is required to
-  // prevent race conditions when populating the list asynchronously.
-  this.dataItems = {};
-
-#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
-  // While operating in Private Browsing Mode, persistent data items are parked
-  // here until we return to the normal mode.
-  this._persistentDataItems = {};
-#endif
-
-  // Array of view objects that should be notified when the available download
-  // data changes.
-  this._views = [];
-}
-
-DownloadsDataCtor.prototype = {
+const DownloadsData = {
   /**
    * Starts receiving events for current downloads.
    *
    * @param aDownloadManagerService
    *        Reference to the service implementing nsIDownloadManager.  We need
    *        this because getService isn't available for us when this method is
    *        called, and we must ensure to register our listeners before the
    *        getService call for the Download Manager returns.
    */
   initializeDataLink: function DD_initializeDataLink(aDownloadManagerService)
   {
     // Start receiving real-time events.
-    aDownloadManagerService.addPrivacyAwareListener(this);
+    aDownloadManagerService.addListener(this);
     Services.obs.addObserver(this, "download-manager-remove-download-guid", false);
-#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
     Services.obs.addObserver(this, "download-manager-database-type-changed",
                              false);
-#endif
   },
 
   /**
    * Stops receiving events for current downloads and cancels any pending read.
    */
   terminateDataLink: function DD_terminateDataLink()
   {
     this._terminateDataAccess();
 
     // Stop receiving real-time events.
-#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
     Services.obs.removeObserver(this, "download-manager-database-type-changed");
-#endif
     Services.obs.removeObserver(this, "download-manager-remove-download-guid");
     Services.downloads.removeListener(this);
   },
 
   //////////////////////////////////////////////////////////////////////////////
   //// Registration of views
 
   /**
+   * Array of view objects that should be notified when the available download
+   * data changes.
+   */
+  _views: [],
+
+  /**
    * Adds an object to be notified when the available download data changes.
    * The specified object is initialized with the currently available downloads.
    *
    * @param aView
    *        DownloadsView object to be added.  This reference must be passed to
    *        removeView before termination.
    */
   addView: function DD_addView(aView)
@@ -535,16 +450,31 @@ DownloadsDataCtor.prototype = {
       aView.onDataLoadCompleted();
     }
   },
 
   //////////////////////////////////////////////////////////////////////////////
   //// In-memory downloads data store
 
   /**
+   * Object containing all the available DownloadsDataItem objects, indexed by
+   * their numeric download identifier.  The identifiers of downloads that have
+   * been removed from the Download Manager data are still present, however the
+   * associated objects are replaced with the value "null".  This is required to
+   * prevent race conditions when populating the list asynchronously.
+   */
+  dataItems: {},
+
+  /**
+   * While operating in Private Browsing Mode, persistent data items are parked
+   * here until we return to the normal mode.
+   */
+  _persistentDataItems: {},
+
+  /**
    * Clears the loaded data.
    */
   clear: function DD_clear()
   {
     this._terminateDataAccess();
     this.dataItems = {};
   },
 
@@ -656,19 +586,17 @@ DownloadsDataCtor.prototype = {
       if (this._loadState == this.kLoadNone) {
         // Indicate to the views that a batch loading operation is in progress.
         this._views.forEach(
           function (view) view.onDataLoadStarting()
         );
 
         // Reload the list using the Download Manager service.  The list is
         // returned in no particular order.
-        let downloads = this._isPrivate ?
-                          Services.downloads.activePrivateDownloads :
-                          Services.downloads.activeDownloads;
+        let downloads = Services.downloads.activeDownloads;
         while (downloads.hasMoreElements()) {
           let download = downloads.getNext().QueryInterface(Ci.nsIDownload);
           this._getOrAddDataItem(download, true);
         }
         this._loadState = this.kLoadActive;
 
         // Indicate to the views that the batch loading operation is complete.
         this._views.forEach(
@@ -676,20 +604,17 @@ DownloadsDataCtor.prototype = {
         );
       }
     } else {
       if (this._loadState != this.kLoadAll) {
         // Load only the relevant columns from the downloads database.  The
         // columns are read in the _initFromDataRow method of DownloadsDataItem.
         // Order by descending download identifier so that the most recent
         // downloads are notified first to the listening views.
-        let dbConnection = this._isPrivate ?
-                             Services.downloads.privateDBConnection :
-                             Services.downloads.DBConnection;
-        let statement = dbConnection.createAsyncStatement(
+        let statement = Services.downloads.DBConnection.createAsyncStatement(
           "SELECT guid, target, name, source, referrer, state, "
         +        "startTime, endTime, currBytes, maxBytes "
         + "FROM moz_downloads "
         + "ORDER BY startTime DESC"
         );
         try {
           this._pendingStatement = statement.executeAsync(this);
         } finally {
@@ -784,17 +709,16 @@ DownloadsDataCtor.prototype = {
               if (aStatus == Components.results.NS_ERROR_NOT_AVAILABLE) {
                 this._removeDataItem(dataItemBinding.downloadGuid);
               }
             }.bind(this));
           }
         }
         break;
 
-#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
       case "download-manager-database-type-changed":
         let pbs = Cc["@mozilla.org/privatebrowsing;1"]
                   .getService(Ci.nsIPrivateBrowsingService);
         if (pbs.privateBrowsingEnabled) {
           // Save a reference to the persistent store before terminating access.
           this._persistentDataItems = this.dataItems;
           this.clear();
         } else {
@@ -802,31 +726,24 @@ DownloadsDataCtor.prototype = {
           this.clear();
           this.dataItems = this._persistentDataItems;
           this._persistentDataItems = null;
         }
         // Reinitialize the views with the current items.  View data has been
         // already invalidated by the previous calls.
         this._views.forEach(this._updateView, this);
         break;
-#endif
     }
   },
 
   //////////////////////////////////////////////////////////////////////////////
   //// nsIDownloadProgressListener
 
   onDownloadStateChange: function DD_onDownloadStateChange(aState, aDownload)
   {
-    if (aDownload.isPrivate != this._isPrivate) {
-      // Ignore the downloads with a privacy status other than what we are
-      // tracking.
-      return;
-    }
-
     // When a new download is added, it may have the same identifier of a
     // download that we previously deleted during this session, and we also
     // want to provide a visible indication that the download started.
     let isNew = aState == nsIDM.DOWNLOAD_NOTSTARTED ||
                 aState == nsIDM.DOWNLOAD_QUEUED;
 
     let dataItem = this._getOrAddDataItem(aDownload, isNew);
     if (!dataItem) {
@@ -862,22 +779,16 @@ DownloadsDataCtor.prototype = {
   },
 
   onProgressChange: function DD_onProgressChange(aWebProgress, aRequest,
                                                   aCurSelfProgress,
                                                   aMaxSelfProgress,
                                                   aCurTotalProgress,
                                                   aMaxTotalProgress, aDownload)
   {
-    if (aDownload.isPrivate != this._isPrivate) {
-      // Ignore the downloads with a privacy status other than what we are
-      // tracking.
-      return;
-    }
-
     let dataItem = this._getOrAddDataItem(aDownload, false);
     if (!dataItem) {
       return;
     }
 
     dataItem.currBytes = aDownload.amountTransferred;
     dataItem.maxBytes = aDownload.size;
     dataItem.speed = aDownload.speed;
@@ -917,41 +828,33 @@ DownloadsDataCtor.prototype = {
    */
   _notifyNewDownload: function DD_notifyNewDownload()
   {
     if (DownloadsCommon.useToolkitUI) {
       return;
     }
 
     // Show the panel in the most recent browser window, if present.
-    let browserWin = RecentWindow.getMostRecentBrowserWindow({ private: this._isPrivate });
+    let browserWin = gBrowserGlue.getMostRecentBrowserWindow();
     if (!browserWin) {
       return;
     }
 
     if (this.panelHasShownBefore) {
       // For new downloads after the first one, don't show the panel
       // automatically, but provide a visible notification in the topmost
       // browser window, if the status indicator is already visible.
       browserWin.DownloadsIndicatorView.showEventNotification();
       return;
     }
     this.panelHasShownBefore = true;
     browserWin.DownloadsPanel.showPanel();
   }
 };
 
-XPCOMUtils.defineLazyGetter(this, "PrivateDownloadsData", function() {
-  return new DownloadsDataCtor(true);
-});
-
-XPCOMUtils.defineLazyGetter(this, "DownloadsData", function() {
-  return new DownloadsDataCtor(false);
-});
-
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsDataItem
 
 /**
  * Represents a single item in the list of downloads.  This object either wraps
  * an existing nsIDownload from the Download Manager, or provides the same
  * information read directly from the downloads database, with the possibility
  * of querying the nsIDownload lazily, for performance reasons.
@@ -1208,46 +1111,32 @@ DownloadsDataItem.prototype = {
  */
 const DownloadsViewPrototype = {
   //////////////////////////////////////////////////////////////////////////////
   //// Registration of views
 
   /**
    * Array of view objects that should be notified when the available status
    * data changes.
-   *
-   * SUBCLASSES MUST OVERRIDE THIS PROPERTY.
    */
-  _views: null,
-
-  /**
-   * Determines whether this view object is over the private or non-private
-   * downloads.
-   *
-   * SUBCLASSES MUST OVERRIDE THIS PROPERTY.
-   */
-  _isPrivate: false,
+  _views: [],
 
   /**
    * Adds an object to be notified when the available status data changes.
    * The specified object is initialized with the currently available status.
    *
    * @param aView
    *        View object to be added.  This reference must be
    *        passed to removeView before termination.
    */
   addView: function DVP_addView(aView)
   {
     // Start receiving events when the first of our views is registered.
     if (this._views.length == 0) {
-      if (this._isPrivate) {
-        PrivateDownloadsData.addView(this);
-      } else {
-        DownloadsData.addView(this);
-      }
+      DownloadsCommon.data.addView(this);
     }
 
     this._views.push(aView);
     this.refreshView(aView);
   },
 
   /**
    * Updates the properties of an object previously added using addView.
@@ -1273,21 +1162,17 @@ const DownloadsViewPrototype = {
   {
     let index = this._views.indexOf(aView);
     if (index != -1) {
       this._views.splice(index, 1);
     }
 
     // Stop receiving events when the last of our views is unregistered.
     if (this._views.length == 0) {
-      if (this._isPrivate) {
-        PrivateDownloadsData.removeView(this);
-      } else {
-        DownloadsData.removeView(this);
-      }
+      DownloadsCommon.data.removeView(this);
     }
   },
 
   //////////////////////////////////////////////////////////////////////////////
   //// Callback functions from DownloadsData
 
   /**
    * Indicates whether we are still loading downloads data asynchronously.
@@ -1401,20 +1286,17 @@ const DownloadsViewPrototype = {
  * notifications it receives into overall status data, that is then broadcast to
  * the registered download status indicators.
  *
  * Note that using this object does not automatically start the Download Manager
  * service.  Consumers will see an empty list of downloads until the service is
  * actually started.  This is useful to display a neutral progress indicator in
  * the main browser window until the autostart timeout elapses.
  */
-function DownloadsIndicatorDataCtor(aPrivate) {
-  this._isPrivate = aPrivate;
-}
-DownloadsIndicatorDataCtor.prototype = {
+const DownloadsIndicatorData = {
   __proto__: DownloadsViewPrototype,
 
   /**
    * Removes an object previously added using addView.
    *
    * @param aView
    *        DownloadsIndicatorView object to be removed.
    */
@@ -1486,35 +1368,33 @@ DownloadsIndicatorDataCtor.prototype = {
    *
    * @param aDataItem
    *        DownloadsDataItem object for which the view item is requested.
    *
    * @return Object that can be used to notify item status events.
    */
   getViewItem: function DID_getViewItem(aDataItem)
   {
-    let data = this._isPrivate ? PrivateDownloadsIndicatorData
-                               : DownloadsIndicatorData;
     return Object.freeze({
       onStateChange: function DIVI_onStateChange()
       {
         if (aDataItem.state == nsIDM.DOWNLOAD_FINISHED ||
             aDataItem.state == nsIDM.DOWNLOAD_FAILED) {
-          data.attention = true;
+          DownloadsIndicatorData.attention = true;
         }
 
         // Since the state of a download changed, reset the estimated time left.
-        data._lastRawTimeLeft = -1;
-        data._lastTimeLeft = -1;
+        DownloadsIndicatorData._lastRawTimeLeft = -1;
+        DownloadsIndicatorData._lastTimeLeft = -1;
 
-        data._updateViews();
+        DownloadsIndicatorData._updateViews();
       },
       onProgressChange: function DIVI_onProgressChange()
       {
-        data._updateViews();
+        DownloadsIndicatorData._updateViews();
       }
     });
   },
 
   //////////////////////////////////////////////////////////////////////////////
   //// Propagation of properties to our views
 
   // The following properties are updated by _refreshProperties and are then
@@ -1604,19 +1484,17 @@ DownloadsIndicatorDataCtor.prototype = {
   /**
    * A generator function for the dataItems that this summary is currently
    * interested in. This generator is passed off to summarizeDownloads in order
    * to generate statistics about the dataItems we care about - in this case,
    * it's all dataItems for active downloads.
    */
   _activeDataItems: function DID_activeDataItems()
   {
-    let dataItems = this._isPrivate ? PrivateDownloadsData.dataItems
-                                    : DownloadsData.dataItems;
-    for each (let dataItem in dataItems) {
+    for each (let dataItem in DownloadsCommon.data.dataItems) {
       if (dataItem && dataItem.inProgress) {
         yield dataItem;
       }
     }
   },
 
   /**
    * Computes aggregate values based on the current state of downloads.
@@ -1646,48 +1524,38 @@ DownloadsIndicatorDataCtor.prototype = {
       if (this._lastRawTimeLeft != summary.rawTimeLeft) {
         this._lastRawTimeLeft = summary.rawTimeLeft;
         this._lastTimeLeft = DownloadsCommon.smoothSeconds(summary.rawTimeLeft,
                                                            this._lastTimeLeft);
       }
       this._counter = DownloadsCommon.formatTimeLeft(this._lastTimeLeft);
     }
   }
-};
-
-XPCOMUtils.defineLazyGetter(this, "PrivateDownloadsIndicatorData", function() {
-  return new DownloadsIndicatorDataCtor(true);
-});
-
-XPCOMUtils.defineLazyGetter(this, "DownloadsIndicatorData", function() {
-  return new DownloadsIndicatorDataCtor(false);
-});
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsSummaryData
 
 /**
  * DownloadsSummaryData is a view for DownloadsData that produces a summary
  * of all downloads after a certain exclusion point aNumToExclude. For example,
  * if there were 5 downloads in progress, and a DownloadsSummaryData was
  * constructed with aNumToExclude equal to 3, then that DownloadsSummaryData
  * would produce a summary of the last 2 downloads.
  *
- * @param aIsPrivate
- *        True if the browser window which owns the download button is a private
- *        window.
  * @param aNumToExclude
  *        The number of items to exclude from the summary, starting from the
  *        top of the list.
  */
-function DownloadsSummaryData(aIsPrivate, aNumToExclude) {
+function DownloadsSummaryData(aNumToExclude) {
   this._numToExclude = aNumToExclude;
   // Since we can have multiple instances of DownloadsSummaryData, we
   // override these values from the prototype so that each instance can be
   // completely separated from one another.
+  this._views = [];
   this._loading = false;
 
   this._dataItems = [];
 
   // Floating point value indicating the last number of seconds estimated until
   // the longest download will finish.  We need to store this value so that we
   // don't continuously apply smoothing if the actual download state has not
   // changed.  This is set to -1 if the previous value is unknown.
@@ -1701,19 +1569,16 @@ function DownloadsSummaryData(aIsPrivate
 
   // The following properties are updated by _refreshProperties and are then
   // propagated to the views.
   this._showingProgress = false;
   this._details = "";
   this._description = "";
   this._numActive = 0;
   this._percentComplete = -1;
-
-  this._isPrivate = aIsPrivate;
-  this._views = [];
 }
 
 DownloadsSummaryData.prototype = {
   __proto__: DownloadsViewPrototype,
 
   /**
    * Removes an object previously added using addView.
    *
--- a/browser/components/downloads/src/DownloadsStartup.js
+++ b/browser/components/downloads/src/DownloadsStartup.js
@@ -26,32 +26,26 @@ const Cr = Components.results;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
                                   "resource:///modules/DownloadsCommon.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "gSessionStartup",
                                    "@mozilla.org/browser/sessionstartup;1",
                                    "nsISessionStartup");
-#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
 XPCOMUtils.defineLazyServiceGetter(this, "gPrivateBrowsingService",
                                    "@mozilla.org/privatebrowsing;1",
                                    "nsIPrivateBrowsingService");
-#endif
 
 const kObservedTopics = [
   "sessionstore-windows-restored",
   "sessionstore-browser-state-restored",
   "download-manager-initialized",
   "download-manager-change-retention",
-#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
-  "last-pb-context-exited",
-#else
   "private-browsing-transition-complete",
-#endif
   "browser-lastwindow-close-granted",
   "quit-application",
   "profile-change-teardown",
 ];
 
 /**
  * CID of our implementation of nsIDownloadManagerUI.
  */
@@ -114,18 +108,18 @@ DownloadsStartup.prototype = {
         // are initializing the Download Manager service during shutdown.
         if (this._shuttingDown) {
           break;
         }
 
         // Start receiving events for active and new downloads before we return
         // from this observer function.  We can't defer the execution of this
         // step, to ensure that we don't lose events raised in the meantime.
-        DownloadsCommon.initializeAllDataLinks(
-                        aSubject.QueryInterface(Ci.nsIDownloadManager));
+        DownloadsCommon.data.initializeDataLink(
+                             aSubject.QueryInterface(Ci.nsIDownloadManager));
 
         this._downloadsServiceInitialized = true;
 
         // Since this notification is generated during the getService call and
         // we need to get the Download Manager service ourselves, we must post
         // the handler on the event queue to be executed later.
         Services.tm.mainThread.dispatch(this._ensureDataLoaded.bind(this),
                                         Ci.nsIThread.DISPATCH_NORMAL);
@@ -140,59 +134,47 @@ DownloadsStartup.prototype = {
         if (!DownloadsCommon.useToolkitUI) {
           let removeFinishedDownloads = Services.prefs.getBoolPref(
                             "browser.download.panel.removeFinishedDownloads");
           aSubject.QueryInterface(Ci.nsISupportsPRInt32)
                   .data = removeFinishedDownloads ? 0 : 2;
         }
         break;
 
-#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
       case "private-browsing-transition-complete":
         // Ensure that persistent data is reloaded only when the database
         // connection is available again.
         this._ensureDataLoaded();
         break;
-#endif
 
       case "browser-lastwindow-close-granted":
         // When using the panel interface, downloads that are already completed
         // should be removed when the last full browser window is closed.  This
         // event is invoked only if the application is not shutting down yet.
         // If the Download Manager service is not initialized, we don't want to
         // initialize it just to clean up completed downloads, because they can
         // be present only in case there was a browser crash or restart.
         if (this._downloadsServiceInitialized &&
             !DownloadsCommon.useToolkitUI) {
           Services.downloads.cleanUp();
         }
         break;
 
-#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
-      case "last-pb-context-exited":
-        // Similar to the above notification, but for private downloads.
-        if (this._downloadsServiceInitialized &&
-            !DownloadsCommon.useToolkitUI) {
-          Services.downloads.cleanUpPrivate();
-        }
-        break;
-#endif
-
       case "quit-application":
         // When the application is shutting down, we must free all resources in
         // addition to cleaning up completed downloads.  If the Download Manager
         // service is not initialized, we don't want to initialize it just to
         // clean up completed downloads, because they can be present only in
         // case there was a browser crash or restart.
         this._shuttingDown = true;
         if (!this._downloadsServiceInitialized) {
           break;
         }
 
-        DownloadsCommon.terminateAllDataLinks();
+        DownloadsCommon.data.terminateDataLink();
 
         // When using the panel interface, downloads that are already completed
         // should be removed when quitting the application.
         if (!DownloadsCommon.useToolkitUI && aData != "restart") {
           this._cleanupOnShutdown = true;
         }
         break;
 
@@ -271,27 +253,24 @@ DownloadsStartup.prototype = {
     return aValue;
   },
 
   /**
    * Ensures that persistent download data is reloaded at the appropriate time.
    */
   _ensureDataLoaded: function DS_ensureDataLoaded()
   {
-    if (!this._downloadsServiceInitialized
-#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
-        || gPrivateBrowsingService.privateBrowsingEnabled
-#endif
-       ) {
+    if (!this._downloadsServiceInitialized ||
+        gPrivateBrowsingService.privateBrowsingEnabled) {
       return;
     }
 
     // If the previous session has been already restored, then we ensure that
     // all the downloads are loaded.  Otherwise, we only ensure that the active
     // downloads from the previous session are loaded.
-    DownloadsCommon.ensureAllPersistentDataLoaded(!this._recoverAllDownloads);
+    DownloadsCommon.data.ensurePersistentDataLoaded(!this._recoverAllDownloads);
   }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Module
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DownloadsStartup]);
--- a/browser/components/downloads/src/Makefile.in
+++ b/browser/components/downloads/src/Makefile.in
@@ -6,20 +6,17 @@ DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 EXTRA_COMPONENTS = \
   BrowserDownloads.manifest \
+  DownloadsStartup.js \
   DownloadsUI.js \
   $(NULL)
 
-EXTRA_PP_COMPONENTS = \
-  DownloadsStartup.js \
-  $(NULL)
-
-EXTRA_PP_JS_MODULES = \
+EXTRA_JS_MODULES = \
   DownloadsCommon.jsm \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/components/downloads/test/browser/browser_basic_functionality.js
+++ b/browser/components/downloads/test/browser/browser_basic_functionality.js
@@ -28,23 +28,23 @@ function gen_test()
   var originalCountLimit = DownloadsView.kItemCountLimit;
   DownloadsView.kItemCountLimit = DownloadData.length;
   registerCleanupFunction(function () {
     DownloadsView.kItemCountLimit = originalCountLimit;
   });
 
   try {
     // Ensure that state is reset in case previous tests didn't finish.
-    for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield;
+    for (let yy in gen_resetState()) yield;
 
     // Populate the downloads database with the data required by this test.
     for (let yy in gen_addDownloadRows(DownloadData)) yield;
 
     // Open the user interface and wait for data to be fully loaded.
-    for (let yy in gen_openPanel(DownloadsCommon.getData(window))) yield;
+    for (let yy in gen_openPanel()) yield;
 
     // Test item data and count.  This also tests the ordering of the display.
     let richlistbox = document.getElementById("downloadsListBox");
 /* disabled for failing intermittently (bug 767828)
     is(richlistbox.children.length, DownloadData.length,
        "There is the correct number of richlistitems");
 */
     for (let i = 0; i < richlistbox.children.length; i++) {
@@ -52,11 +52,11 @@ function gen_test()
       let dataItem = new DownloadsViewItemController(element).dataItem;
       is(dataItem.target, DownloadData[i].name, "Download names match up");
       is(dataItem.state, DownloadData[i].state, "Download states match up");
       is(dataItem.file, DownloadData[i].target, "Download targets match up");
       is(dataItem.uri, DownloadData[i].source, "Download sources match up");
     }
   } finally {
     // Clean up when the test finishes.
-    for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield;
+    for (let yy in gen_resetState()) yield;
   }
 }
--- a/browser/components/downloads/test/browser/browser_first_download_panel.js
+++ b/browser/components/downloads/test/browser/browser_first_download_panel.js
@@ -7,42 +7,42 @@
  * Make sure the downloads panel only opens automatically on the first
  * download it notices. All subsequent downloads, even across sessions, should
  * not open the panel automatically.
  */
 function gen_test()
 {
   try {
     // Ensure that state is reset in case previous tests didn't finish.
-    for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield;
+    for (let yy in gen_resetState()) yield;
 
     // With this set to false, we should automatically open the panel
     // the first time a download is started.
-    DownloadsCommon.getData(window).panelHasShownBefore = false;
+    DownloadsCommon.data.panelHasShownBefore = false;
 
     prepareForPanelOpen();
-    DownloadsCommon.getData(window)._notifyNewDownload();
+    DownloadsCommon.data._notifyNewDownload();
     yield;
 
     // If we got here, that means the panel opened.
     DownloadsPanel.hidePanel();
 
-    ok(DownloadsCommon.getData(window).panelHasShownBefore,
+    ok(DownloadsCommon.data.panelHasShownBefore,
        "Should have recorded that the panel was opened on a download.")
 
     // Next, make sure that if we start another download, we don't open
     // the panel automatically.
     panelShouldNotOpen();
-    DownloadsCommon.getData(window)._notifyNewDownload();
+    DownloadsCommon.data._notifyNewDownload();
     yield waitFor(2);
   } catch(e) {
     ok(false, e);
   } finally {
     // Clean up when the test finishes.
-    for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield;
+    for (let yy in gen_resetState()) yield;
   }
 }
 
 /**
  * Call this to record a test failure for the next time the downloads panel
  * opens.
  */
 function panelShouldNotOpen()
--- a/browser/components/downloads/test/browser/head.js
+++ b/browser/components/downloads/test/browser/head.js
@@ -125,17 +125,17 @@ var testRunner = {
 //
 // The following functions are all generators that can be used inside the main
 // test generator to perform specific tasks asynchronously.  To invoke these
 // subroutines correctly, an iteration syntax should be used:
 //
 //   for (let yy in gen_example("Parameter")) yield;
 //
 
-function gen_resetState(aData)
+function gen_resetState()
 {
   let statement = Services.downloads.DBConnection.createAsyncStatement(
                   "DELETE FROM moz_downloads");
   try {
     statement.executeAsync({
       handleResult: function(aResultSet) { },
       handleError: function(aError)
       {
@@ -150,18 +150,18 @@ function gen_resetState(aData)
   } finally {
     statement.finalize();
   }
 
   // Reset any prefs that might have been changed.
   Services.prefs.clearUserPref("browser.download.panel.shown");
 
   // Ensure that the panel is closed and data is unloaded.
-  aData.clear();
-  aData._loadState = aData.kLoadNone;
+  DownloadsCommon.data.clear();
+  DownloadsCommon.data._loadState = DownloadsCommon.data.kLoadNone;
   DownloadsPanel.hidePanel();
 
   // Wait for focus on the main window.
   waitForFocus(testRunner.continueTest);
   yield;
 }
 
 function gen_addDownloadRows(aDataRows)
@@ -219,17 +219,17 @@ function gen_openPanel(aData)
   let originalOnViewLoadCompleted = DownloadsPanel.onViewLoadCompleted;
   DownloadsPanel.onViewLoadCompleted = function () {
     DownloadsPanel.onViewLoadCompleted = originalOnViewLoadCompleted;
     originalOnViewLoadCompleted.apply(this);
     testRunner.continueTest();
   };
 
   // Start loading all the downloads from the database asynchronously.
-  aData.ensurePersistentDataLoaded(false);
+  DownloadsCommon.data.ensurePersistentDataLoaded(false);
 
   // Wait for focus on the main window.
   waitForFocus(testRunner.continueTest);
   yield;
 
   // Open the downloads panel, waiting until loading is completed.
   DownloadsPanel.showPanel();
   yield;