Bug 1249786 - Sanitize on startup prefs are broken. r=yoric draft
authorMarco Bonardo <mbonardo@mozilla.com>
Fri, 19 Feb 2016 23:22:24 +0100
changeset 332857 187d877b366840736e16dda672a33f360edd7454
parent 332855 758daaf1723f377d853d2547b072d49559d8b494
child 514621 248157eb0499977c117da2f9122d84becfd7b132
push id11245
push usermak77@bonardo.net
push dateMon, 22 Feb 2016 10:39:51 +0000
reviewersyoric
bugs1249786
milestone47.0a1
Bug 1249786 - Sanitize on startup prefs are broken. r=yoric MozReview-Commit-ID: LDmK7G1BhGP
browser/base/content/sanitize.js
--- a/browser/base/content/sanitize.js
+++ b/browser/base/content/sanitize.js
@@ -672,20 +672,28 @@ Sanitizer.prototype = {
         }
         newWindow.focus();
         yield promiseReady;
       })
     },
   }
 };
 
-// "Static" members
+// The preferences branch for the sanitizer.
 Sanitizer.PREF_DOMAIN = "privacy.sanitize.";
+// Whether we should sanitize on shutdown.
 Sanitizer.PREF_SANITIZE_ON_SHUTDOWN = "privacy.sanitize.sanitizeOnShutdown";
+// During a sanitization this is set to a json containing the array of items
+// being sanitized, then cleared once the sanitization is complete.
+// This allows to retry a sanitization on startup in case it was interrupted
+// by a crash.
 Sanitizer.PREF_SANITIZE_IN_PROGRESS = "privacy.sanitize.sanitizeInProgress";
+// Whether the previous shutdown sanitization completed successfully.
+// Note that PREF_SANITIZE_IN_PROGRESS would be enough to detect an interrupted
+// sanitization, but this is still supported for backwards compatibility.
 Sanitizer.PREF_SANITIZE_DID_SHUTDOWN = "privacy.sanitize.didShutdownSanitize";
 
 // Time span constants corresponding to values of the privacy.sanitize.timeSpan
 // pref.  Used to determine how much history to clear, for various items
 Sanitizer.TIMESPAN_EVERYTHING = 0;
 Sanitizer.TIMESPAN_HOUR       = 1;
 Sanitizer.TIMESPAN_2HOURS     = 2;
 Sanitizer.TIMESPAN_4HOURS     = 3;
@@ -761,16 +769,26 @@ Sanitizer.showUI = function(aParentWindo
  * sanitize UI, according to user preferences
  */
 Sanitizer.sanitize = function(aParentWindow)
 {
   Sanitizer.showUI(aParentWindow);
 };
 
 Sanitizer.onStartup = Task.async(function*() {
+  // Check if we were interrupted during the last shutdown sanitization.
+  let shutownSanitizationWasInterrupted =
+    Preferences.get(Sanitizer.PREF_SANITIZE_ON_SHUTDOWN, false) &&
+    !Preferences.has(Sanitizer.PREF_SANITIZE_DID_SHUTDOWN);
+  // Regardless, reset the pref, since we will check it again at the next start.
+  Preferences.reset(Sanitizer.PREF_SANITIZE_DID_SHUTDOWN);
+  // Ensure the pref is stored, if we crash during this sanitization we may
+  // enter a never ending crash loop.
+  Services.prefs.savePrefFile(null);
+
   // Make sure that we are triggered during shutdown, at the right time,
   // and only once.
   let placesClient = Cc["@mozilla.org/browser/nav-history-service;1"]
                        .getService(Ci.nsPIPlacesDatabase)
                        .shutdownClient
                        .jsclient;
 
   let deferredSanitization = PromiseUtils.defer();
@@ -781,34 +799,38 @@ Sanitizer.onStartup = Task.async(functio
       Sanitizer.onShutdown().catch(er => {Promise.reject(er) /* Do not return rejected promise */;}).then(() =>
         deferredSanitization.resolve()
       );
     }
     return deferredSanitization.promise;
   }
   placesClient.addBlocker("sanitize.js: Sanitize on shutdown", doSanitize);
 
-  // Handle incomplete sanitizations
-  if (Preferences.has(Sanitizer.PREF_SANITIZE_IN_PROGRESS)) {
-    // Firefox crashed during sanitization.
+  // Check if Firefox crashed before completing a sanitization.
+  let lastInterruptedSanitization = Preferences.get(Sanitizer.PREF_SANITIZE_IN_PROGRESS, "");
+  if (lastInterruptedSanitization) {
     let s = new Sanitizer();
-    let json = Preferences.get(Sanitizer.PREF_SANITIZE_IN_PROGRESS);
-    let itemsToClear = JSON.parse(json);
+    // If the json is invalid this will just throw and reject the Task.
+    let itemsToClear = JSON.parse(lastInterruptedSanitization);
     yield s.sanitize(itemsToClear);
-  }
-  if (Preferences.has(Sanitizer.PREF_SANITIZE_DID_SHUTDOWN)) {
-    // Firefox crashed before having a chance to sanitize during shutdown.
-    // (note that if Firefox crashed during shutdown sanitization, we
-    // will hit both `if` so we will run a second double-sanitization).
+  } else if (shutownSanitizationWasInterrupted) {
+    // Ideally lastInterruptedSanitization should always be set when a
+    // sanitization is interrupted, but some add-ons or Firefox previous
+    // versions may not set the pref.
+    // In such a case, we can still detect an interrupted shutdown sanitization,
+    // and just redo it.
     yield Sanitizer.onShutdown();
   }
 });
 
 Sanitizer.onShutdown = Task.async(function*() {
   if (!Preferences.get(Sanitizer.PREF_SANITIZE_ON_SHUTDOWN)) {
     return;
   }
   // Need to sanitize upon shutdown
   let s = new Sanitizer();
   s.prefDomain = "privacy.clearOnShutdown.";
   yield s.sanitize();
+  // We didn't crash during shutdown sanitization, so annotate it to avoid
+  // sanitizing again on startup.
   Preferences.set(Sanitizer.PREF_SANITIZE_DID_SHUTDOWN, true);
+  Services.prefs.savePrefFile(null);
 });