Bug 942937 - Clean up places init and remove deprecated PlacesBackups calls. r=IanN a=IanN
authorFrank-Rainer Grahl <frgrahl@gmx.net>
Mon, 07 May 2018 12:41:29 +0200
changeset 31467 e7ec4d4f2a40
parent 31466 85fef84f3604
child 31468 a59b0b5ac649
push id383
push userclokep@gmail.com
push date2018-05-07 21:52 +0000
reviewersIanN, IanN
bugs942937, 1371677, 1433979
Bug 942937 - Clean up places init and remove deprecated PlacesBackups calls. r=IanN a=IanN Port Bug 1371677 [Delay the database connection in the history service as far as possible]. Port Bug 1433979 [Remove deprecated code from PlacesBackups.jsm].
suite/common/bindings/notification.xml
suite/common/src/nsSuiteGlue.js
suite/locales/en-US/chrome/common/notification.properties
suite/locales/en-US/chrome/common/places/places.properties
--- a/suite/common/bindings/notification.xml
+++ b/suite/common/bindings/notification.xml
@@ -30,16 +30,22 @@
       <field name="_brandStringBundle" readonly="true">
         <![CDATA[
           Cc["@mozilla.org/intl/stringbundle;1"]
             .getService(Ci.nsIStringBundleService)
             .createBundle("chrome://branding/locale/brand.properties");
         ]]>
       </field>
 
+      <field name="_placesBundle" readonly="true">
+        <![CDATA[
+         Services.strings.createBundle("chrome://communicator/locale/places/places.properties");
+        ]]>
+      </field>
+
       <field name="_prefs" readonly="true">
         <![CDATA[
           Cc["@mozilla.org/preferences-service;1"]
             .getService(Ci.nsIPrefBranch);
         ]]>
       </field>
 
       <field name="_urlFormatter" readonly="true">
@@ -1207,20 +1213,20 @@
           ]]>
         </body>
       </method>
 
       <method name="showPlacesLockedWarning">
         <body>
           <![CDATA[
             var brandShortName = this._brandStringBundle.GetStringFromName("brandShortName");
-            var message = this._stringBundle.formatStringFromName("lockPrompt.text", [brandShortName], 1);
+            var message = this._placesBundle.formatStringFromName("lockPrompt.text", [brandShortName], 1);
             var buttons = [{
-              label: this._stringBundle.GetStringFromName("lockPromptInfoButton.label"),
-              accessKey: this._stringBundle.GetStringFromName("lockPromptInfoButton.accesskey"),
+              label: this._placesBundle.GetStringFromName("lockPromptInfoButton.label"),
+              accessKey: this._placesBundle.GetStringFromName("lockPromptInfoButton.accesskey"),
               popup: null,
               callback: function() {
                 openHelp("places-locked", "chrome://communicator/locale/help/suitehelp.rdf");
               }
             }];
             var box = this.appendNotification(message, "places-locked", null,
                                               this.PRIORITY_CRITICAL_MEDIUM,
                                               buttons);
--- a/suite/common/src/nsSuiteGlue.js
+++ b/suite/common/src/nsSuiteGlue.js
@@ -20,16 +20,19 @@ ChromeUtils.defineModuleGetter(this, "Fi
                                "resource://gre/modules/FileUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "PlacesUtils",
                                "resource://gre/modules/PlacesUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "PlacesBackups",
                                "resource://gre/modules/PlacesBackups.jsm");
 
+ChromeUtils.defineModuleGetter(this, "AsyncShutdown",
+                               "resource://gre/modules/AsyncShutdown.jsm");
+
 ChromeUtils.defineModuleGetter(this, "AutoCompletePopup",
                                "resource://gre/modules/AutoCompletePopup.jsm");
 
 ChromeUtils.defineModuleGetter(this, "BookmarkHTMLUtils",
                                "resource://gre/modules/BookmarkHTMLUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "BookmarkJSONUtils",
                                "resource://gre/modules/BookmarkJSONUtils.jsm");
@@ -73,22 +76,22 @@ const listeners = {
     let receiveMessageMM = this.receiveMessage.bind(this, this.mm);
     for (let message of Object.keys(this.mm)) {
       Services.mm.addMessageListener(message, receiveMessageMM);
     }
   }
 };
 
 // We try to backup bookmarks at idle times, to avoid doing that at shutdown.
-// Number of idle seconds before trying to backup bookmarks.  15 minutes.
-const BOOKMARKS_BACKUP_IDLE_TIME = 15 * 60;
-// Minimum interval in milliseconds between backups.
-const BOOKMARKS_BACKUP_INTERVAL = 86400 * 1000;
-// Maximum number of backups to create.  Old ones will be purged.
-const BOOKMARKS_BACKUP_MAX_BACKUPS = 10;
+// Number of idle seconds before trying to backup bookmarks 8 minutes.
+const BOOKMARKS_BACKUP_IDLE_TIME_SEC = 15 * 60;
+// Minimum interval between backups. We try to not create more than one backup
+// per interval.
+const BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS = 1;
+
 // Devtools Preferences
 const DEBUGGER_REMOTE_ENABLED = "devtools.debugger.remote-enabled";
 const DEBUGGER_REMOTE_PORT = "devtools.debugger.remote-port";
 const DEBUGGER_FORCE_LOCAL = "devtools.debugger.force-local";
 const DEBUGGER_WIFI_VISIBLE = "devtools.remote.wifi.visible";
 const DOWNLOAD_MANAGER_URL = "chrome://communicator/content/downloads/downloadmanager.xul";
 const PROGRESS_DIALOG_URL = "chrome://communicator/content/downloads/progressDialog.xul";
 const PREF_FOCUS_WHEN_STARTING = "browser.download.manager.focusWhenStarting";
@@ -305,33 +308,24 @@ SuiteGlue.prototype = {
       case "dl-done":
         this._playDownloadSound();
         break;
       case "places-init-complete":
         if (!this._migrationImportsDefaultBookmarks)
           this._initPlaces(false);
 
         Services.obs.removeObserver(this, "places-init-complete");
-        // No longer needed, since history was initialized completely.
-        Services.obs.removeObserver(this, "places-database-locked");
-        break;
-      case "places-database-locked":
-        this._isPlacesDatabaseLocked = true;
-        // Stop observing, so further attempts to load history service
-        // will not show the prompt.
-        Services.obs.removeObserver(this, "places-database-locked");
         break;
       case "places-shutdown":
         Services.obs.removeObserver(this, "places-shutdown");
         // places-shutdown is fired when the profile is about to disappear.
         this._onPlacesShutdown();
         break;
       case "idle":
-        if (this._idleService.idleTime > BOOKMARKS_BACKUP_IDLE_TIME * 1000)
-          this._backupBookmarks();
+        this._backupBookmarks();
         break;
       case "initial-migration":
         this._initialMigrationPerformed = true;
         break;
       case "browser-search-engine-modified":
         break;
       case "notifications-open-settings":
         // Since this is a web notification, there's probably a browser window.
@@ -410,29 +404,32 @@ SuiteGlue.prototype = {
     Services.obs.addObserver(this, "browser-lastwindow-close-requested", true);
     Services.obs.addObserver(this, "browser-lastwindow-close-granted", true);
     Services.obs.addObserver(this, "console-api-log-event", true);
     Services.obs.addObserver(this, "weave:service:ready", true);
     Services.obs.addObserver(this, "weave:engine:clients:display-uri", true);
     Services.obs.addObserver(this, "session-save", true);
     Services.obs.addObserver(this, "dl-done", true);
     Services.obs.addObserver(this, "places-init-complete", true);
-    Services.obs.addObserver(this, "places-database-locked", true);
     Services.obs.addObserver(this, "places-shutdown", true);
     Services.obs.addObserver(this, "browser-search-engine-modified", true);
     Services.obs.addObserver(this, "notifications-open-settings", true);
     Services.prefs.addObserver("devtools.debugger.", this, true);
     Services.obs.addObserver(this, "handle-xul-text-link", true);
     Cc['@mozilla.org/docloaderservice;1']
       .getService(Ci.nsIWebProgress)
       .addProgressListener(this, Ci.nsIWebProgress.NOTIFY_LOCATION);
   },
 
   // cleanup (called on application shutdown)
   _dispose: function BG__dispose() {
+    if (this._isIdleObserver) {
+      this._idleService.removeIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME_SEC);
+      delete this._isIdleObserver;
+    }
   },
 
   // profile is available
   _onProfileAfterChange: function()
   {
     // check if we're in safe mode
     if (Services.appinfo.inSafeMode) {
       Services.ww.openWindow(null, "chrome://communicator/content/safeMode.xul",
@@ -646,18 +643,19 @@ SuiteGlue.prototype = {
           .getService(Ci.nsIWinTaskbar).available) {
       let temp = {};
       ChromeUtils.import("resource:///modules/WindowsJumpLists.jsm", temp);
       temp.WinTaskbarJumpList.startup();
     }
 
     // Load the "more info" page for a locked places.sqlite
     // This property is set earlier by places-database-locked topic.
-    if (this._isPlacesDatabaseLocked)
+    if (this._isPlacesDatabaseLocked) {
       notifyBox.showPlacesLockedWarning();
+    }
 
     // Detect if updates are off and warn for outdated builds.
     if (this._shouldShowUpdateWarning())
       notifyBox.showUpdateWarning();
 
     this._checkForDefaultClient(aWindow);
   },
 
@@ -666,20 +664,16 @@ SuiteGlue.prototype = {
    */
   _onQuitApplicationGranted: function()
   {
     if (this._saveSession) {
       this._setPrefToSaveSession();
     }
     Sanitizer.checkSettings();
     AutoCompletePopup.uninit();
-
-    if (!Sanitizer.doPendingSanitize()) {
-      Services.prefs.setBoolPref("privacy.sanitize.didShutdownSanitize", true);
-    }
   },
 
   _promptForMasterPassword: function()
   {
     if (!Services.prefs.getBoolPref("signon.startup.prompt"))
       return;
 
     // Try to avoid the multiple master password prompts on startup scenario
@@ -965,214 +959,201 @@ SuiteGlue.prototype = {
    * - browser.places.smartBookmarksVersion
    *   Set during HTML import to indicate that Smart Bookmarks were created.
    *   Set to -1 to disable Smart Bookmarks creation.
    *   Set to 0 to restore current Smart Bookmarks.
    * - browser.bookmarks.restore_default_bookmarks
    *   Set to true by safe-mode dialog to indicate we must restore default
    *   bookmarks.
    */
-  async _initPlaces(aInitialMigrationPerformed) {
+  _initPlaces: function BG__initPlaces(aInitialMigrationPerformed) {
     // We must instantiate the history service since it will tell us if we
     // need to import or restore bookmarks due to first-run, corruption or
     // forced migration (due to a major schema change).
-    var bookmarksBackupFile = await PlacesBackups.getMostRecentBackup();
+    // If the database is corrupt or has been newly created we should
+    // import bookmarks.
+    let dbStatus = PlacesUtils.history.databaseStatus;
 
-    // If the database is corrupt or has been newly created we should
-    // import bookmarks. Same if we don't have any JSON backups, which
-    // probably means that we never have used bookmarks in places yet.
-    var dbStatus = PlacesUtils.history.databaseStatus;
-    var importBookmarks = !aInitialMigrationPerformed &&
+    // The places.sqlite database is locked. We show a notification box for
+    // it in _onBrowserStartup.
+    if (dbStatus == PlacesUtils.history.DATABASE_STATUS_LOCKED) {
+      this._isPlacesDatabaseLocked = true;
+      Services.console.logStringMessage("places.sqlite is locked");
+      // Note: initPlaces should always happen when the first window is ready,
+      // in any case, better safe than sorry.
+      Services.obs.notifyObservers(null, "places-browser-init-complete");
+      return;
+    }
+
+    let importBookmarks = !aInitialMigrationPerformed &&
                           (dbStatus == PlacesUtils.history.DATABASE_STATUS_CREATE ||
-                           dbStatus == PlacesUtils.history.DATABASE_STATUS_CORRUPT ||
-                           !bookmarksBackupFile);
+                           dbStatus == PlacesUtils.history.DATABASE_STATUS_CORRUPT);
 
-    // Check if user or an extension has required to import bookmarks.html
-    var importBookmarksHTML = false;
+    // Check if user or an extension has required to import bookmarks.html.
+    let importBookmarksHTML = false;
     try {
       importBookmarksHTML =
         Services.prefs.getBoolPref("browser.places.importBookmarksHTML");
       if (importBookmarksHTML)
         importBookmarks = true;
-    } catch(ex) {}
+    } catch (ex) {}
 
-    // Check if Safe Mode or the user has required to restore bookmarks from
-    // default profile's bookmarks.html
-    var restoreDefaultBookmarks = false;
-    try {
-      restoreDefaultBookmarks =
-        Services.prefs.getBoolPref("browser.bookmarks.restore_default_bookmarks");
-      if (restoreDefaultBookmarks) {
-        // Ensure that we already have a bookmarks backup for today.
-        this._backupBookmarks();
-        importBookmarks = true;
-      }
-    } catch(ex) {}
+    // Support legacy bookmarks.html format for apps that depend on that format.
+    // Default if the pref does not exists is 'Do not export'.
+    let autoExportHTML = Services.prefs.getBoolPref("browser.bookmarks.autoExportHTML", false);
 
-    // If the user did not require to restore default bookmarks, or import
-    // from bookmarks.html, we will try to restore from JSON.
-    if (importBookmarks && !restoreDefaultBookmarks && !importBookmarksHTML) {
-      // Get latest JSON backup.
-      if (bookmarksBackupFile) {
-        // Restore from JSON backup.
-        await BookmarkJSONUtils.importFromFile(bookmarksBackupFile, true);
-        importBookmarks = false;
-      }
-      else if (dbStatus == PlacesUtils.history.DATABASE_STATUS_OK) {
-        importBookmarks = false;
-      }
-      else {
-        // We have created a new database but we don't have any backup available.
-        importBookmarks = true;
-        var bookmarksHTMLFile = Services.dirsvc.get("BMarks", Ci.nsIFile);
-        if (bookmarksHTMLFile.exists()) {
-          // If bookmarks.html is available in current profile import it...
-          importBookmarksHTML = true;
-        }
-        else {
-          // ...otherwise we will restore defaults.
-          restoreDefaultBookmarks = true;
-        }
-      }
+    if (autoExportHTML) {
+      // Sqlite.jsm and Places shutdown happen at profile-before-change, thus,
+      // to be on the safe side, this should run earlier.
+      AsyncShutdown.profileChangeTeardown.addBlocker(
+        "Places: export bookmarks.html",
+        () => BookmarkHTMLUtils.exportToFile(Services.dirsvc.get("BMarks",
+                                                                 Ci.nsIFile).path));
     }
 
-    // If bookmarks are not imported, then initialize smart bookmarks. This
-    // happens during a common startup.
-    // Otherwise, if any kind of import runs, smart bookmarks creation should
-    // be delayed till the import operations has finished. Not doing so would
-    // cause them to be overwritten by the newly imported bookmarks.
-    if (!importBookmarks) {
-      try {
-        await this.ensurePlacesDefaultQueriesInitialized();
-      } catch (e) {
-        Cu.reportError(e);
-      }
-    } else {
-      // An import operation is about to run.
-      // Don't try to recreate smart bookmarks if autoExportHTML is true or
-      // smart bookmarks are disabled.
-      var autoExportHTML = false;
+    (async () => {
+      // Check if Safe Mode or the user has required to restore bookmarks from
+      // default profile's bookmarks.html.
+      let restoreDefaultBookmarks = false;
       try {
-        autoExportHTML = Services.prefs.getBoolPref("browser.bookmarks.autoExportHTML");
-      } catch(ex) {}
-      var smartBookmarksVersion = 0;
-      try {
-        smartBookmarksVersion = Services.prefs.getIntPref("browser.places.smartBookmarksVersion");
-      } catch(ex) {}
-      if (!autoExportHTML && smartBookmarksVersion != -1)
-        Services.prefs.setIntPref("browser.places.smartBookmarksVersion", 0);
+        restoreDefaultBookmarks =
+          Services.prefs.getBoolPref("browser.bookmarks.restore_default_bookmarks");
+        if (restoreDefaultBookmarks) {
+          // Ensure that we already have a bookmarks backup for today.
+          await this._backupBookmarks();
+          importBookmarks = true;
+        }
+      } catch (ex) {}
+
+      // This may be reused later, check for "=== undefined" to see if it has
+      // been populated already.
+      let lastBackupFile;
 
-      var bookmarksURI = null;
-      if (restoreDefaultBookmarks) {
-        // User wants to restore bookmarks.html file from default profile folder.
-        bookmarksURI = Services.io.newURI("resource:///defaults/profile/bookmarks.html");
-      }
-      else {
-        // Get bookmarks.html file location.
-        var bookmarksFile = Services.dirsvc.get("BMarks", Ci.nsIFile);
-        if (bookmarksFile.exists())
-          bookmarksURI = Services.io.newFileURI(bookmarksFile);
+      // If the user did not require to restore default bookmarks, or import
+      // from bookmarks.html, we will try to restore from JSON.
+      if (importBookmarks && !restoreDefaultBookmarks && !importBookmarksHTML) {
+        // Get latest JSON backup.
+        lastBackupFile = await PlacesBackups.getMostRecentBackup();
+        if (lastBackupFile) {
+          // Restore from JSON backup.
+          await BookmarkJSONUtils.importFromFile(lastBackupFile, true);
+          importBookmarks = false;
+        } else {
+          // We have created a new database but we don't have any backup available.
+          importBookmarks = true;
+          let bookmarksHTMLFile = Services.dirsvc.get("BMarks", Ci.nsIFile);
+          if (bookmarksHTMLFile.exists(bookmarksHTMLFile)) {
+            // If bookmarks.html is available in current profile import it...
+            importBookmarksHTML = true;
+          } else {
+            // ...otherwise we will restore defaults.
+            restoreDefaultBookmarks = true;
+          }
+        }
       }
 
-      if (bookmarksURI) {
-        // Import from bookmarks.html file.
+      // If bookmarks are not imported, then initialize smart bookmarks.  This
+      // happens during a common startup.
+      // Otherwise, if any kind of import runs, smart bookmarks creation should
+      // be delayed till the import operations has finished. Not doing so would
+      // cause them to be overwritten by the newly imported bookmarks.
+      if (!importBookmarks) {
         try {
-          BookmarkHTMLUtils.importFromURL(bookmarksURI.spec, true).then(null,
-            function onFailure() {
-              Cu.reportError("Bookmarks.html file could be corrupt.");
-            }
-          ).then(
+          await this.ensurePlacesDefaultQueriesInitialized();
+        } catch (e) {
+          Cu.reportError(e);
+        }
+      } else {
+        // An import operation is about to run.
+        // Don't try to recreate smart bookmarks if autoExportHTML is true or
+        // smart bookmarks are disabled.
+        let smartBookmarksVersion = Services.prefs.getIntPref("browser.places.smartBookmarksVersion", 0);
+        if (!autoExportHTML && smartBookmarksVersion != -1)
+          Services.prefs.setIntPref("browser.places.smartBookmarksVersion", 0);
+
+        let bookmarksURI = null;
+        if (restoreDefaultBookmarks) {
+          // User wants to restore bookmarks.html file from default profile folder
+          bookmarksURI = Services.io.newURI("resource:///defaults/profile/bookmarks.html");
+        } else {
+          let bookmarksFile = Services.dirsvc.get("BMarks", Ci.nsIFile);
+          if (bookmarksFile.exists(bookmarksFile)) {
+            bookmarksURI = Services.io.newFileURI(bookmarksFile);
+          }
+        }
+
+        if (bookmarksURI) {
+          // Import from bookmarks.html file.
+          try {
+            await BookmarkHTMLUtils.importFromURL(bookmarksURI.spec, true);
+          } catch (e) {
+            Cu.reportError("Bookmarks.html file could be corrupt. " + e);
+          }
+          try {
             // Ensure that smart bookmarks are created once the operation is
             // complete.
-            await this.ensurePlacesDefaultQueriesInitialized.bind(this)
-          );
+            await this.ensurePlacesDefaultQueriesInitialized();
+          } catch (e) {
+            Cu.reportError(e);
+          }
+        } else {
+          Cu.reportError(new Error("Unable to find bookmarks.html file."));
         }
-        catch(ex) {
-          Cu.reportError("bookmarks.html file could be corrupt. " + ex);
-        }
-      }
-      else {
-        Cu.reportError("Unable to find bookmarks.html file.");
+
+        // Reset preferences, so we won't try to import again at next run
+        if (importBookmarksHTML)
+          Services.prefs.setBoolPref("browser.places.importBookmarksHTML", false);
+        if (restoreDefaultBookmarks)
+          Services.prefs.setBoolPref("browser.bookmarks.restore_default_bookmarks",
+                                     false);
       }
 
-      // Reset preferences, so we won't try to import again at next run.
-      if (importBookmarksHTML)
-        Services.prefs.setBoolPref("browser.places.importBookmarksHTML", false);
-      if (restoreDefaultBookmarks)
-        Services.prefs.setBoolPref("browser.bookmarks.restore_default_bookmarks",
-                                   false);
-    }
+      AsyncShutdown.quitApplicationGranted.addBlocker(
+        "Places: export bookmarks at dawn",
+        () => this._backupBookmarks());
+
+      // Initialize bookmark archiving on idle.
+      if (!this._isIdleObserver) {
+        this._idleService.addIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME_SEC);
+        this._isIdleObserver = true;
+      }
 
-    // Initialize bookmark archiving on idle.
-    // Once a day, either on idle or shutdown, bookmarks are backed up.
-    if (!this._isIdleObserver) {
-      this._idleService.addIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
-      this._isIdleObserver = true;
+    })().catch(ex => {
+      Cu.reportError(ex);
+    }).then(() => {
+      // NB: deliberately after the catch so that we always do this, even if
+      // we threw halfway through initializing in the Task above.
+      Services.obs.notifyObservers(null, "places-browser-init-complete");
+    });
+  },
+
+  /**
+   * Places shut-down tasks
+   * - finalize components depending on Places.
+   */
+  _onPlacesShutdown: function() {
+    if (!Sanitizer.doPendingSanitize()) {
+      Services.prefs.setBoolPref("privacy.sanitize.didShutdownSanitize", true);
     }
   },
 
   /**
-   * Places shut-down tasks
-   * - back up bookmarks if needed.
-   * - export bookmarks as HTML, if so configured.
-   * - finalize components depending on Places.
+   * If a backup for today doesn't exist, this creates one.
    */
-  _onPlacesShutdown: function() {
-    if (this._isIdleObserver) {
-      this._idleService.removeIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
-      this._isIdleObserver = false;
-    }
-    this._backupBookmarks();
-
-    // Backup bookmarks to bookmarks.html to support apps that depend
-    // on the legacy format.
-    try {
-      // If this fails to get the preference value, we don't export.
-      if (Services.prefs.getBoolPref("browser.bookmarks.autoExportHTML")) {
-        // Exceptionally, since this is a non-default setting and HTML format is
-        // discouraged in favor of the JSON backups, we spin the event loop on
-        // shutdown, to wait for the export to finish.  We cannot safely spin
-        // the event loop on shutdown until we include a watchdog to prevent
-        // potential hangs (bug 518683).  The asynchronous shutdown operations
-        // will then be handled by a shutdown service (bug 435058).
-        var shutdownComplete = false;
-        BookmarkHTMLUtils.exportToFile(Services.dirsvc.get("BMarks", Ci.nsIFile)).then(
-          function onSuccess() {
-            shutdownComplete = true;
-          },
-          function onFailure() {
-            // There is no point in reporting errors since we are shutting down.
-            shutdownComplete = true;
-          }
-        );
-        var thread = Services.tm.currentThread;
-        while (!shutdownComplete) {
-          thread.processNextEvent(true);
-        }
+  _backupBookmarks: function BG__backupBookmarks() {
+    return (async function() {
+      let lastBackupFile = await PlacesBackups.getMostRecentBackup();
+      // Should backup bookmarks if there are no backups or the maximum
+      // interval between backups elapsed.
+      if (!lastBackupFile ||
+          new Date() - PlacesBackups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS * 86400000) {
+        let maxBackups = Services.prefs.getIntPref("browser.bookmarks.max_backups");
+        await PlacesBackups.create(maxBackups);
       }
-    } catch(ex) { /* Don't export */ }
-  },
-
-  /**
-   * Backup bookmarks if needed.
-   */
-  _backupBookmarks: function() {
-    let lastBackupFile = PlacesBackups.getMostRecent();
-
-    // Backup bookmarks if there are no backups or the maximum interval between
-    // backups elapsed.
-    if (!lastBackupFile ||
-        new Date() - PlacesBackups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_INTERVAL) {
-      let maxBackups = BOOKMARKS_BACKUP_MAX_BACKUPS;
-      try {
-        maxBackups = Services.prefs.getIntPref("browser.bookmarks.max_backups");
-      } catch(ex) { /* Use default. */ }
-
-      PlacesBackups.create(maxBackups); // Don't force creation.
-    }
+    })();
   },
 
   _updatePrefs: function()
   {
     // Make sure that the doNotTrack value conforms to the conversion from
     // three-state to two-state. (This reverts a setting of "please track me"
     // to the default "don't say anything").
     try {
--- a/suite/locales/en-US/chrome/common/notification.properties
+++ b/suite/locales/en-US/chrome/common/notification.properties
@@ -162,22 +162,16 @@ offlineApps.never=Never for This Site
 offlineApps.never.accesskey=e
 
 # Block autorefresh
 refreshBlocked.goButton=Allow
 refreshBlocked.goButton.accesskey=A
 refreshBlocked.refreshLabel=%S prevented this page from automatically reloading.
 refreshBlocked.redirectLabel=%S prevented this page from automatically redirecting to another page.
 
-# LOCALIZATION NOTE (lockPrompt.text)
-# %S will be replaced with the application name.
-lockPrompt.text=The bookmarks and history system will not be functional because one of %S's files is in use by another application. Some security software can cause this problem.
-lockPromptInfoButton.label=Learn More
-lockPromptInfoButton.accesskey=L
-
 # LOCALIZATION NOTE (updatePrompt.text)
 # %S will be replaced with the application name.
 updatePrompt.text=Your copy of %S is old and probably has known security flaws, but you have disabled automated update checks. Please update to a newer version.
 updatePromptCheckButton.label=Check for Updates
 updatePromptCheckButton.accesskey=C
 
 SecurityTitle=Security Warning
 MixedContentMessage=You have requested an encrypted page that contains some unencrypted information. Information that you see or enter on this page could easily be read by a third party.
--- a/suite/locales/en-US/chrome/common/places/places.properties
+++ b/suite/locales/en-US/chrome/common/places/places.properties
@@ -80,20 +80,19 @@ tagResultLabel=Tag
 bookmarkResultLabel=Bookmark
 switchtabResultLabel=Tab
 keywordResultLabel=Keyword
 searchengineResultLabel=Search
 
 
 # LOCALIZATION NOTE (lockPrompt.text)
 # %S will be replaced with the application name.
-lockPrompt.title=Browser Startup Error
 lockPrompt.text=The bookmarks and history system will not be functional because one of %S’s files is in use by another application. Some security software can cause this problem.
 lockPromptInfoButton.label=Learn More
-lockPromptInfoButton.accessKey=L
+lockPromptInfoButton.accesskey=L
 
 # LOCALIZATION NOTE (deletePagesLabel): Semi-colon list of plural forms.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 cmd.deletePages.label=Delete Page;Delete Pages
 cmd.deletePages.accesskey=D
 
 # LOCALIZATION NOTE (bookmarkPagesLabel): Semi-colon list of plural forms.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals