Bug 1499004 - Fix for the crash in AsyncShutdownTimeout | profile-before-change | UpdateManager: writing update xml data. r=mhowell, a=RyanVM
authorRobert Strong <robert.bugzilla@gmail.com>
Wed, 09 Jan 2019 10:19:00 -0500
changeset 509378 164c06dff9393673905e45faae10670d4b3cb70c
parent 509377 9831c2f7aec0926e59d29aa555f178950260ca80
child 509379 7ce6302e38fd1af3e9b17ac1a49320b603f83477
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmhowell, RyanVM
bugs1499004
milestone65.0
Bug 1499004 - Fix for the crash in AsyncShutdownTimeout | profile-before-change | UpdateManager: writing update xml data. r=mhowell, a=RyanVM
toolkit/mozapps/update/UpdateTelemetry.jsm
toolkit/mozapps/update/nsUpdateService.js
toolkit/mozapps/update/tests/browser/head.js
toolkit/mozapps/update/tests/chrome/test_0073_notify_verifyFailPartialComplete.xul
toolkit/mozapps/update/tests/chrome/test_0074_notify_verifyFailPartial_successComplete.xul
toolkit/mozapps/update/tests/chrome/test_0083_error_patchApplyFailure_partial_complete.xul
toolkit/mozapps/update/tests/chrome/test_0084_error_patchApplyFailure_verify_failed.xul
toolkit/mozapps/update/tests/chrome/test_0085_error_patchApplyFailure_partial_complete_staging.xul
toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul
toolkit/mozapps/update/tests/chrome/utils.js
toolkit/mozapps/update/tests/data/shared.js
toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js
toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedNoRecovery.js
toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedOffline.js
toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js
toolkit/mozapps/update/tests/unit_aus_update/downloadInvalidSizeMar.js
toolkit/mozapps/update/tests/unit_aus_update/downloadMissingMar.js
toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js
toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js
toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js
toolkit/mozapps/update/tests/unit_aus_update/updateAutoPrefMigrate.js
toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js
toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageOldVersionFailure.js
--- a/toolkit/mozapps/update/UpdateTelemetry.jsm
+++ b/toolkit/mozapps/update/UpdateTelemetry.jsm
@@ -171,16 +171,18 @@ var AUSTLMY = {
   DWNLD_ERR_PATCH_SIZE_LARGER: 8,
   DWNLD_ERR_PATCH_SIZE_NOT_EQUAL: 9,
   DWNLD_ERR_BINDING_ABORTED: 10,
   DWNLD_ERR_ABORT: 11,
   DWNLD_ERR_DOCUMENT_NOT_CACHED: 12,
   DWNLD_ERR_VERIFY_NO_REQUEST: 13,
   DWNLD_ERR_VERIFY_PATCH_SIZE_NOT_EQUAL: 14,
   DWNLD_ERR_WRITE_FAILURE: 15,
+  // Temporary failure code to see if there are failures without an update phase
+  DWNLD_UNKNOWN_PHASE_ERR_WRITE_FAILURE: 40,
 
   /**
    * Submit a telemetry ping for the update download result code.
    *
    * @param  aIsComplete
    *         If true the histogram is for a patch type complete, if false the
    *         histogram is for a patch type partial, and when undefined the
    *         histogram is for an unknown patch type. This is used to determine
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -182,18 +182,23 @@ const APPID_TO_TOPIC = {
   // Firefox
   "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}": "sessionstore-windows-restored",
   // SeaMonkey
   "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}": "sessionstore-windows-restored",
   // Thunderbird
   "{3550f703-e582-4d05-9a08-453d09bdfdc6}": "mail-startup-done",
 };
 
-// A var is used for the delay so tests can set a smaller value.
-var gSaveUpdateXMLDelay = 2000;
+// The interval for the update xml write deferred task.
+const XML_SAVER_INTERVAL_MS = 200;
+
+// Object to keep track of the current phase of the update and whether there
+// has been a write failure for the phase so only one telemetry ping is made
+// for the phase.
+var gUpdateFileWriteInfo = {phase: null, failure: false};
 var gUpdateMutexHandle = null;
 // The permissions of the update directory should be fixed no more than once per
 // session
 var gUpdateDirPermissionFixAttempted = false;
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
   CertUtils: "resource://gre/modules/CertUtils.jsm",
@@ -1096,52 +1101,52 @@ function pingStateAndStatusCodes(aUpdate
  * Returns false if the permission-fixing process cannot be started. Since this
  * is asynchronous, a true return value does not mean that the permissions were
  * actually fixed.
  *
  * @param path A string representing the path that could not be written. This
  *             value will only be used for logging purposes.
  */
 function handleCriticalWriteFailure(path) {
-  LOG("Unable to write to critical update file: " + path);
-
-  let updateManager = Cc["@mozilla.org/updates/update-manager;1"].
-                      getService(Ci.nsIUpdateManager);
-
-  let update = updateManager.activeUpdate;
-  if (update) {
-    let patch = update.selectedPatch;
+  LOG("handleCriticalWriteFailure - Unable to write to critical update file: " +
+      path);
+  if (!gUpdateFileWriteInfo.failure) {
+    gUpdateFileWriteInfo.failure = true;
     let patchType = AUSTLMY.PATCH_UNKNOWN;
-    if (patch.type == "complete") {
-      patchType = AUSTLMY.PATCH_COMPLETE;
-    } else if (patch.type == "partial") {
-      patchType = AUSTLMY.PATCH_PARTIAL;
+    let update = Cc["@mozilla.org/updates/update-manager;1"].
+                 getService(Ci.nsIUpdateManager).activeUpdate;
+    if (update) {
+      let patch = update.selectedPatch;
+      if (patch.type == "complete") {
+        patchType = AUSTLMY.PATCH_COMPLETE;
+      } else if (patch.type == "partial") {
+        patchType = AUSTLMY.PATCH_PARTIAL;
+      }
     }
-    if (update.state == STATE_DOWNLOADING) {
-      if (!patch.downloadWriteFailureTelemetrySent) {
-        AUSTLMY.pingDownloadCode(patchType, AUSTLMY.DWNLD_ERR_WRITE_FAILURE);
-        patch.downloadWriteFailureTelemetrySent = true;
+
+    if (gUpdateFileWriteInfo.phase == "check") {
+      let updateServiceInstance = UpdateServiceFactory.createInstance();
+      let pingSuffix = updateServiceInstance._pingSuffix;
+      if (!pingSuffix) {
+        // If pingSuffix isn't defined then this this is a manual check which
+        // isn't recorded at this time.
+        AUSTLMY.pingCheckCode(pingSuffix, AUSTLMY.CHK_ERR_WRITE_FAILURE);
       }
-    } else if (!patch.applyWriteFailureTelemetrySent) {
-      // It's not ideal to hardcode AUSTLMY.STARTUP below (it could be
-      // AUSTLMY.STAGE). But staging is not used anymore and neither value
-      // really makes sense for this code. For the other codes it indicates when
-      // that code was read from the update status file, but this code was never
-      // read from the update status file.
+    } else if (gUpdateFileWriteInfo.phase == "download") {
+      AUSTLMY.pingDownloadCode(patchType, AUSTLMY.DWNLD_ERR_WRITE_FAILURE);
+    } else if (gUpdateFileWriteInfo.phase == "stage") {
+      let suffix = patchType + "_" + AUSTLMY.STAGE;
+      AUSTLMY.pingStateCode(suffix, AUSTLMY.STATE_WRITE_FAILURE);
+    } else if (gUpdateFileWriteInfo.phase == "startup") {
       let suffix = patchType + "_" + AUSTLMY.STARTUP;
       AUSTLMY.pingStateCode(suffix, AUSTLMY.STATE_WRITE_FAILURE);
-      patch.applyWriteFailureTelemetrySent = true;
-    }
-  } else {
-    let updateServiceInstance = UpdateServiceFactory.createInstance();
-    let request = updateServiceInstance.backgroundChecker._request;
-    if (!request.checkWriteFailureTelemetrySent) {
-      let pingSuffix = updateServiceInstance._pingSuffix;
-      AUSTLMY.pingCheckCode(pingSuffix, AUSTLMY.CHK_ERR_WRITE_FAILURE);
-      request.checkWriteFailureTelemetrySent = true;
+    } else {
+      // Temporary failure code to see if there are failures without an update
+      // phase.
+      AUSTLMY.pingDownloadCode(patchType, AUSTLMY.DWNLD_UNKNOWN_PHASE_ERR_WRITE_FAILURE);
     }
   }
 
   if (!gUpdateDirPermissionFixAttempted) {
     // Currently, we only have a mechanism for fixing update directory permissions
     // on Windows.
     if (AppConstants.platform != "win") {
       LOG("There is currently no implementation for fixing update directory " +
@@ -1736,16 +1741,19 @@ UpdateService.prototype = {
         }
         if (this._retryTimer) {
           this._retryTimer.cancel();
         }
 
         this.pauseDownload();
         // Prevent leaking the downloader (bug 454964)
         this._downloader = null;
+        // In case an update check is in progress.
+        Cc["@mozilla.org/updates/update-checker;1"].
+          createInstance(Ci.nsIUpdateChecker).stopCurrentCheck();
         break;
     }
   },
 
   /**
    * The following needs to happen during the post-update-processing
    * notification from nsUpdateServiceStub.js:
    * 1. post update processing
@@ -1756,16 +1764,17 @@ UpdateService.prototype = {
 
   /**
    * Perform post-processing on updates lingering in the updates directory
    * from a previous application session - either report install failures (and
    * optionally attempt to fetch a different version if appropriate) or
    * notify the user of install success.
    */
   _postUpdateProcessing: function AUS__postUpdateProcessing() {
+    gUpdateFileWriteInfo = {phase: "startup", failure: false};
     if (!this.canCheckForUpdates) {
       LOG("UpdateService:_postUpdateProcessing - unable to check for " +
           "updates... returning early");
       return;
     }
 
     if (!this.canApplyUpdates) {
       LOG("UpdateService:_postUpdateProcessing - unable to apply " +
@@ -2610,22 +2619,16 @@ UpdateService.prototype = {
                                           Ci.nsIObserver]),
 };
 
 /**
  * A service to manage active and past updates.
  * @constructor
  */
 function UpdateManager() {
-  if (Services.appinfo.ID == "xpcshell@tests.mozilla.org") {
-    // Use a smaller value for xpcshell tests so they don't have to wait as
-    // long for the files to be saved.
-    gSaveUpdateXMLDelay = 0;
-  }
-
   // Load the active-update.xml file to see if there is an active update.
   let activeUpdates = this._loadXMLFileIntoArray(FILE_ACTIVE_UPDATE_XML);
   if (activeUpdates.length > 0) {
     // Set the active update directly on the var used to cache the value.
     this._activeUpdate = activeUpdates[0];
     // This check is performed here since UpdateService:_postUpdateProcessing
     // won't be called when there isn't an update.status file.
     if (readStatusFile(getUpdatesDir()) == STATE_NONE) {
@@ -2659,33 +2662,34 @@ UpdateManager.prototype = {
   _updatesDirty: false,
 
   /**
    * See nsIObserver.idl
    */
   observe: function UM_observe(subject, topic, data) {
     // Hack to be able to run and cleanup tests by reloading the update data.
     if (topic == "um-reload-update-data") {
+      if (!Cu.isInAutomation) {
+        return;
+      }
       if (this._updatesXMLSaver) {
         this._updatesXMLSaver.disarm();
-        AsyncShutdown.profileBeforeChange.removeBlocker(this._updatesXMLSaverCallback);
-        this._updatesXMLSaver = null;
-        this._updatesXMLSaverCallback = null;
       }
-      // Set the write delay to 0 for mochitest-chrome and mochitest-browser
-      // tests.
-      gSaveUpdateXMLDelay = 0;
+
+      let updates = [];
+      this._updatesDirty = true;
       this._activeUpdate = null;
-      let activeUpdates = this._loadXMLFileIntoArray(FILE_ACTIVE_UPDATE_XML);
-      if (activeUpdates.length > 0) {
-        this._activeUpdate = activeUpdates[0];
+      if (data != "skip-files") {
+        let activeUpdates = this._loadXMLFileIntoArray(FILE_ACTIVE_UPDATE_XML);
+        if (activeUpdates.length > 0) {
+          this._activeUpdate = activeUpdates[0];
+        }
+        updates = this._loadXMLFileIntoArray(FILE_UPDATES_XML);
       }
-      this._updatesDirty = true;
       delete this._updates;
-      let updates = this._loadXMLFileIntoArray(FILE_UPDATES_XML);
       Object.defineProperty(this, "_updates", {
         value: updates,
         writable: true,
         configurable: true,
         enumerable: true,
       });
     }
   },
@@ -2861,53 +2865,53 @@ UpdateManager.prototype = {
   /**
    * See nsIUpdateService.idl
    */
   saveUpdates: function UM_saveUpdates() {
     if (!this._updatesXMLSaver) {
       this._updatesXMLSaverCallback = () => this._updatesXMLSaver.finalize();
 
       this._updatesXMLSaver = new DeferredTask(() => this._saveUpdatesXML(),
-                                               gSaveUpdateXMLDelay);
+                                               XML_SAVER_INTERVAL_MS);
       AsyncShutdown.profileBeforeChange.addBlocker(
         "UpdateManager: writing update xml data", this._updatesXMLSaverCallback);
     } else {
       this._updatesXMLSaver.disarm();
     }
 
     this._updatesXMLSaver.arm();
   },
 
   /**
    * Saves the active-updates.xml and updates.xml when the updates history has
    * been modified files.
    */
   _saveUpdatesXML: function UM__saveUpdatesXML() {
-    AsyncShutdown.profileBeforeChange.removeBlocker(this._updatesXMLSaverCallback);
-    this._updatesXMLSaver = null;
-    this._updatesXMLSaverCallback = null;
-
     // The active update stored in the active-update.xml file will change during
     // the lifetime of an active update and the file should always be updated
     // when saveUpdates is called.
-    this._writeUpdatesToXMLFile(this._activeUpdate ? [this._activeUpdate] : [],
-                                FILE_ACTIVE_UPDATE_XML).then(
+    let updates = this._activeUpdate ? [this._activeUpdate] : [];
+    let promises = [];
+    promises[0] = this._writeUpdatesToXMLFile(updates,
+                                              FILE_ACTIVE_UPDATE_XML).then(
       wroteSuccessfully => handleCriticalWriteResult(wroteSuccessfully,
                                                      FILE_ACTIVE_UPDATE_XML)
     );
     // The update history stored in the updates.xml file should only need to be
     // updated when an active update has been added to it in which case
     // |_updatesDirty| will be true.
     if (this._updatesDirty) {
       this._updatesDirty = false;
-      this._writeUpdatesToXMLFile(this._updates, FILE_UPDATES_XML).then(
+      promises[1] = this._writeUpdatesToXMLFile(this._updates,
+                                                FILE_UPDATES_XML).then(
         wroteSuccessfully => handleCriticalWriteResult(wroteSuccessfully,
                                                        FILE_UPDATES_XML)
       );
     }
+    return Promise.all(promises);
   },
 
   /**
    * See nsIUpdateService.idl
    */
   refreshUpdateStatus: function UM_refreshUpdateStatus() {
     var update = this._activeUpdate;
     if (!update) {
@@ -3108,16 +3112,17 @@ Checker.prototype = {
     return url;
   },
 
   /**
    * See nsIUpdateService.idl
    */
   checkForUpdates: function UC_checkForUpdates(listener, force) {
     LOG("Checker: checkForUpdates, force: " + force);
+    gUpdateFileWriteInfo = {phase: "check", failure: false};
     if (!listener) {
       throw Cr.NS_ERROR_NULL_POINTER;
     }
 
     let UpdateServiceInstance = UpdateServiceFactory.createInstance();
     // |force| can override |canCheckForUpdates| since |force| indicates a
     // manual update check. But nothing should override enterprise policies.
     if (UpdateServiceInstance.disabledByPolicy) {
@@ -3526,16 +3531,17 @@ Downloader.prototype = {
 
   /**
    * Download and stage the given update.
    * @param   update
    *          A nsIUpdate object to download a patch for. Cannot be null.
    */
   downloadUpdate: function Downloader_downloadUpdate(update) {
     LOG("UpdateService:_downloadUpdate");
+    gUpdateFileWriteInfo = {phase: "download", failure: false};
     if (!update) {
       AUSTLMY.pingDownloadCode(undefined, AUSTLMY.DWNLD_ERR_NO_UPDATE);
       throw Cr.NS_ERROR_NULL_POINTER;
     }
 
     var updateDir = getUpdatesDir();
 
     this._update = update;
@@ -3918,18 +3924,18 @@ Downloader.prototype = {
       return;
     }
 
     if (state == STATE_PENDING || state == STATE_PENDING_SERVICE ||
         state == STATE_PENDING_ELEVATE) {
       if (getCanStageUpdates()) {
         LOG("Downloader:onStopRequest - attempting to stage update: " +
             this._update.name);
-
-        // Initiate the update in the background
+        gUpdateFileWriteInfo = {phase: "stage", failure: false};
+        // Stage the update
         try {
           Cc["@mozilla.org/updates/update-processor;1"].
             createInstance(Ci.nsIUpdateProcessor).
             processUpdate(this._update);
         } catch (e) {
           // Fail gracefully in case the application does not support the update
           // processor service.
           LOG("Downloader:onStopRequest - failed to stage update. Exception: " +
--- a/toolkit/mozapps/update/tests/browser/head.js
+++ b/toolkit/mozapps/update/tests/browser/head.js
@@ -70,19 +70,17 @@ function getVersionParams(aAppVersion) {
   let appInfo = Services.appinfo;
   return "&appVersion=" + (aAppVersion ? aAppVersion : appInfo.version);
 }
 
 /**
  * Clean up updates list and the updates directory.
  */
 function cleanUpUpdates() {
-  gUpdateManager.activeUpdate = null;
-  gUpdateManager.saveUpdates();
-
+  reloadUpdateManagerData(true);
   removeUpdateDirsAndFiles();
 }
 
 /**
  * Prevent nsIUpdateTimerManager from notifying nsIApplicationUpdateService
  * to check for updates by setting the app update last update time to the
  * current time minus one minute in seconds and the interval time to 12 hours
  * in seconds.
@@ -141,16 +139,17 @@ function runUpdateTest(updateParams, che
     registerCleanupFunction(() => {
       gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
       UpdateListener.reset();
       cleanUpUpdates();
     });
 
     gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
     setUpdateTimerPrefs();
+    removeUpdateDirsAndFiles();
     await SpecialPowers.pushPrefEnv({
       set: [
         [PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS, 0],
         [PREF_APP_UPDATE_DISABLEDFORTESTING, false],
         [PREF_APP_UPDATE_IDLETIME, 0],
         [PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE],
       ]});
 
@@ -194,18 +193,19 @@ function runUpdateTest(updateParams, che
 function runUpdateProcessingTest(updates, steps) {
   return (async function() {
     registerCleanupFunction(() => {
       gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
       UpdateListener.reset();
       cleanUpUpdates();
     });
 
+    gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
     setUpdateTimerPrefs();
-    gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
+    removeUpdateDirsAndFiles();
     await SpecialPowers.pushPrefEnv({
       set: [
         [PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS, 0],
         [PREF_APP_UPDATE_DISABLEDFORTESTING, false],
         [PREF_APP_UPDATE_IDLETIME, 0],
         [PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE],
       ]});
 
--- a/toolkit/mozapps/update/tests/chrome/test_0073_notify_verifyFailPartialComplete.xul
+++ b/toolkit/mozapps/update/tests/chrome/test_0073_notify_verifyFailPartialComplete.xul
@@ -27,17 +27,18 @@ const TESTS = [ {
 function runTest() {
   debugDump("entering");
 
   let patchProps = {type: "partial",
                     size: "1234",
                     state: STATE_DOWNLOADING};
   let patches = getLocalPatchString(patchProps);
   patchProps = {size: "1234",
-                selected: "false"};
+                selected: "false",
+                state: null};
   patches += getLocalPatchString(patchProps);
   let updateProps = {isCompleteUpdate: "false"};
   let updates = getLocalUpdateString(updateProps, patches);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
   writeStatusFile(STATE_DOWNLOADING);
--- a/toolkit/mozapps/update/tests/chrome/test_0074_notify_verifyFailPartial_successComplete.xul
+++ b/toolkit/mozapps/update/tests/chrome/test_0074_notify_verifyFailPartial_successComplete.xul
@@ -26,17 +26,18 @@ const TESTS = [ {
 
 function runTest() {
   debugDump("entering");
 
   let patchProps = {type: "partial",
                     size: "1234",
                     state: STATE_DOWNLOADING};
   let patches = getLocalPatchString(patchProps);
-  patchProps = {selected: "false"};
+  patchProps = {selected: "false",
+                state: null};
   patches += getLocalPatchString(patchProps);
   let updateProps = {isCompleteUpdate: "false"};
   let updates = getLocalUpdateString(updateProps, patches);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
   writeStatusFile(STATE_DOWNLOADING);
--- a/toolkit/mozapps/update/tests/chrome/test_0083_error_patchApplyFailure_partial_complete.xul
+++ b/toolkit/mozapps/update/tests/chrome/test_0083_error_patchApplyFailure_partial_complete.xul
@@ -38,17 +38,18 @@ function runTest() {
 
   // Specify the url to update.sjs with a slowDownloadMar param so the ui can
   // load before the download completes.
   let slowDownloadURL = URL_HTTP_UPDATE_XML + "?slowDownloadMar=1";
   let patchProps = {type: "partial",
                     state: STATE_PENDING};
   let patches = getLocalPatchString(patchProps);
   patchProps = {url: slowDownloadURL,
-                selected: "false"};
+                selected: "false",
+                state: null};
   patches += getLocalPatchString(patchProps);
   let updateProps = {isCompleteUpdate: "false"};
   let updates = getLocalUpdateString(updateProps, patches);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
   writeStatusFile(STATE_FAILED_CRC_ERROR);
--- a/toolkit/mozapps/update/tests/chrome/test_0084_error_patchApplyFailure_verify_failed.xul
+++ b/toolkit/mozapps/update/tests/chrome/test_0084_error_patchApplyFailure_verify_failed.xul
@@ -39,17 +39,18 @@ function runTest() {
   // Specify the url to update.sjs with a slowDownloadMar param so the ui can
   // load before the download completes.
   let slowDownloadURL = URL_HTTP_UPDATE_XML + "?slowDownloadMar=1";
   let patchProps = {type: "partial",
                     state: STATE_PENDING};
   let patches = getLocalPatchString(patchProps);
   patchProps = {url: slowDownloadURL,
                 size: "1234",
-                selected: "false"};
+                selected: "false",
+                state: null};
   patches += getLocalPatchString(patchProps);
   let updateProps = {isCompleteUpdate: "false"};
   let updates = getLocalUpdateString(updateProps, patches);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
   writeStatusFile(STATE_FAILED_CRC_ERROR);
--- a/toolkit/mozapps/update/tests/chrome/test_0085_error_patchApplyFailure_partial_complete_staging.xul
+++ b/toolkit/mozapps/update/tests/chrome/test_0085_error_patchApplyFailure_partial_complete_staging.xul
@@ -61,17 +61,18 @@ function runTest() {
 
   // Specify the url to update.sjs with a slowDownloadMar param so the ui can
   // load before the download completes.
   let slowDownloadURL = URL_HTTP_UPDATE_XML + "?slowDownloadMar=1";
   let patchProps = {type: "partial",
                     state: STATE_PENDING};
   let patches = getLocalPatchString(patchProps);
   patchProps = {url: slowDownloadURL,
-                selected: "false"};
+                selected: "false",
+                state: null};
   patches += getLocalPatchString(patchProps);
   let updateProps = {isCompleteUpdate: "false"};
   let updates = getLocalUpdateString(updateProps, patches);
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
   writeStatusFile(STATE_FAILED_READ_ERROR);
 
   Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, true);
 
--- a/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul
+++ b/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul
@@ -43,18 +43,35 @@ function runTest() {
   closeUpdateWindow();
 
   // Always disable updates and update staging when cleaning up.
   Services.prefs.setBoolPref(PREF_APP_UPDATE_DISABLEDFORTESTING, true);
   Services.prefs.setBoolPref(PREF_DISABLE_SECURITY, true);  // Needed to disable updates
   Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, false);
 
   resetFiles();
+  reloadUpdateManagerData(true);
   removeUpdateDirsAndFiles();
-  reloadUpdateManagerData();
+
+  // The updates directory is located outside of the application directory and
+  // needs to be removed on Windows and Mac OS X.
+  if (IS_WIN || IS_MACOSX) {
+    let updatesDir = getUpdatesRootDir();
+    // Try to remove the directory used to apply updates. Since the test has
+    // already finished this is non-fatal for the test.
+    if (updatesDir.exists()) {
+      debugDump("attempting to remove directory. Path: " + updatesDir.path);
+      try {
+        removeDirRecursive(updatesDir);
+      } catch (e) {
+        logTestInfo("non-fatal error removing directory. Path: " +
+                    updatesDir.path + ", Exception: " + e);
+      }
+    }
+  }
 
   let file = getUpdatesXMLFile(true);
   ok(!file.exists(), file.path + " should not exist");
 
   file = getUpdatesXMLFile(false);
   ok(!file.exists(), file.path + " should not exist");
 
   let dir = getUpdatesDir();
--- a/toolkit/mozapps/update/tests/chrome/utils.js
+++ b/toolkit/mozapps/update/tests/chrome/utils.js
@@ -282,17 +282,17 @@ function finishTestDefault() {
   }
 
   verifyTestsRan();
 
   resetPrefs();
   gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
   resetFiles();
   removeUpdateDirsAndFiles();
-  reloadUpdateManagerData();
+  reloadUpdateManagerData(true);
 
   Services.ww.unregisterNotification(gWindowObserver);
   if (gDocElem) {
     gDocElem.removeEventListener("pageshow", onPageShowDefault);
   }
 
   finishTestRestoreUpdaterBackup();
 }
--- a/toolkit/mozapps/update/tests/data/shared.js
+++ b/toolkit/mozapps/update/tests/data/shared.js
@@ -134,19 +134,20 @@ function testPostUpdateProcessing() {
 
 /* Initializes the update service stub */
 function initUpdateServiceStub() {
   Cc["@mozilla.org/updates/update-service-stub;1"].
   createInstance(Ci.nsISupports);
 }
 
 /* Reloads the update metadata from disk */
-function reloadUpdateManagerData() {
+function reloadUpdateManagerData(skipFiles = false) {
+  let observeData = skipFiles ? "skip-files" : "";
   gUpdateManager.QueryInterface(Ci.nsIObserver).
-  observe(null, "um-reload-update-data", "");
+  observe(null, "um-reload-update-data", observeData);
 }
 
 const observer = {
   observe(aSubject, aTopic, aData) {
     if (aTopic == "nsPref:changed" && aData == PREF_APP_UPDATE_CHANNEL) {
       let channel = gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL);
       if (channel != gChannel) {
         debugDump("Changing channel from " + channel + " to " + gChannel);
--- a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
+++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
@@ -725,16 +725,20 @@ var gTestDirsCommon = [
     subDirs: ["970/", "971/"],
     subDirFiles: ["97xtext0", "97xtext1"],
   }, {
     relPathDir: DIR_RESOURCES + "9/98/",
     dirRemoved: true,
   }, {
     relPathDir: DIR_RESOURCES + "9/99/",
     dirRemoved: true,
+  }, {
+    description: "Silences 'WARNING: Failed to resolve XUL App Dir.' in debug builds",
+    relPathDir: DIR_RESOURCES + "browser",
+    dirRemoved: false,
   }];
 
 // Directories for a complete successful update. This array can be used for a
 // complete failed update by calling setTestFilesAndDirsForFailure.
 var gTestDirsCompleteSuccess = [
   {
     description: "Removed by precomplete (rmdir)",
     relPathDir: DIR_RESOURCES + "2/20/",
@@ -889,23 +893,16 @@ function setupTestCommon(aAppUpdateAutoE
  */
 function cleanupTestCommon() {
   debugDump("start - general test cleanup");
 
   if (gChannel) {
     gPrefRoot.removeObserver(PREF_APP_UPDATE_CHANNEL, observer);
   }
 
-  // Call app update's observe method passing quit-application to test that the
-  // shutdown of app update runs without throwing or leaking. The observer
-  // method is used directly instead of calling notifyObservers so components
-  // outside of the scope of this test don't assert and thereby cause app update
-  // tests to fail.
-  gAUS.observe(null, "quit-application", "");
-
   gTestserver = null;
 
   if (IS_UNIX) {
     // This will delete the launch script if it exists.
     getLaunchScript();
   }
 
   if (IS_WIN && MOZ_APP_BASENAME) {
@@ -1019,103 +1016,27 @@ function dumpOverride(aText) {
 function doTestFinish() {
   if (DEBUG_AUS_TEST) {
     // This prevents do_print errors from being printed by the xpcshell test
     // harness due to nsUpdateService.js logging to the console when the
     // app.update.log preference is true.
     Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, false);
     gAUS.observe(null, "nsPref:changed", PREF_APP_UPDATE_LOG);
   }
-  executeSoon(testFinishWaitForUpdateXMLFiles);
-}
-
-/**
- * Waits until the update files don't exist and then calls do_test_finished to
- * end the test. This is necessary due to the update xml files being written
- * asynchronously by nsIUpdateManager. Uses do_timeout instead of
- * do_execute_soon to lessen log spew.
- */
-function testFinishWaitForUpdateXMLFiles() {
-  /**
-   * Waits until the update tmp files don't exist and then calls
-   * testFinishReloadUpdateXMLFiles.
-   */
-  function testFinishWaitForUpdateTmpXMLFiles() {
-    let tmpActiveUpdateXML = getUpdatesRootDir();
-    tmpActiveUpdateXML.append(FILE_ACTIVE_UPDATE_XML + ".tmp");
-    if (tmpActiveUpdateXML.exists()) {
-      // The xml files are written asynchronously so wait until it has been
-      // removed.
-      do_timeout(10, testFinishWaitForUpdateTmpXMLFiles);
-      return;
-    }
-
-    let tmpUpdatesXML = getUpdatesRootDir();
-    tmpUpdatesXML.append(FILE_UPDATES_XML + ".tmp");
-    if (tmpUpdatesXML.exists()) {
-      // The xml files are written asynchronously so wait until it has been
-      // removed.
-      do_timeout(10, testFinishWaitForUpdateTmpXMLFiles);
-      return;
-    }
-
-    do_timeout(10, testFinishReloadUpdateXMLFiles);
-  }
-
-  /**
-   * Creates empty update xml files, reloads / saves the update data, and then
-   * calls testFinishWaitForUpdateXMLFiles.
-   */
-  function testFinishReloadUpdateXMLFiles() {
-    try {
-      // Wrapped in a try catch since the file can be in the middle of a write.
-      writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), true);
-    } catch (e) {
-      do_timeout(10, testFinishReloadUpdateXMLFiles);
-      return;
-    }
-    try {
-      // Wrapped in a try catch since the file can be in the middle of a write.
-      writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
-    } catch (e) {
-      do_timeout(10, testFinishReloadUpdateXMLFiles);
-      return;
-    }
-
-    reloadUpdateManagerData();
-    gUpdateManager.saveUpdates();
-    do_timeout(10, testFinishWaitForUpdateXMLFilesDelete);
-  }
-
-  /**
-   * Waits until the active-update.xml and updates.xml files don't exist and
-   * then calls do_test_finished to end the test. This is necessary due to the
-   * update xml files being written asynchronously by nsIUpdateManager.
-   */
-  function testFinishWaitForUpdateXMLFilesDelete() {
-    let activeUpdateXML = getUpdatesXMLFile(true);
-    if (activeUpdateXML.exists()) {
-      // Since the file is removed asynchronously wait until it has been
-      // removed. Uses do_timeout instead of do_execute_soon to lessen log spew.
-      do_timeout(10, testFinishWaitForUpdateXMLFilesDelete);
-      return;
-    }
-
-    let updatesXML = getUpdatesXMLFile(false);
-    if (updatesXML.exists()) {
-      // Since the file is removed asynchronously wait until it has been
-      // removed. Uses do_timeout instead of do_execute_soon to lessen log spew.
-      do_timeout(10, testFinishWaitForUpdateXMLFilesDelete);
-      return;
-    }
-
-    do_timeout(10, do_test_finished);
-  }
-
-  do_timeout(10, testFinishWaitForUpdateTmpXMLFiles);
+
+  reloadUpdateManagerData(true);
+
+  // Call app update's observe method passing quit-application to test that the
+  // shutdown of app update runs without throwing or leaking. The observer
+  // method is used directly instead of calling notifyObservers so components
+  // outside of the scope of this test don't assert and thereby cause app update
+  // tests to fail.
+  gAUS.observe(null, "quit-application", "");
+
+  executeSoon(do_test_finished);
 }
 
 /**
  * Sets the most commonly used preferences used by tests
  */
 function setDefaultPrefs() {
   Services.prefs.setBoolPref(PREF_APP_UPDATE_DISABLEDFORTESTING, false);
   if (DEBUG_AUS_TEST) {
@@ -2877,19 +2798,22 @@ function waitForHelperExit() {
  * @param   aMarFile
  *          The mar file for the update test.
  * @param   aPostUpdateAsync
  *          When null the updater.ini is not created otherwise this parameter
  *          is passed to createUpdaterINI.
  * @param   aPostUpdateExeRelPathPrefix
  *          When aPostUpdateAsync null this value is ignored otherwise it is
  *          passed to createUpdaterINI.
+ * @param   aSetupActiveUpdate
+ *          Whether to setup the active update.
  */
 function setupUpdaterTest(aMarFile, aPostUpdateAsync,
-                          aPostUpdateExeRelPathPrefix = "") {
+                          aPostUpdateExeRelPathPrefix = "",
+                          aSetupActiveUpdate = true) {
   debugDump("start - updater test setup");
   let updatesPatchDir = getUpdatesPatchDir();
   if (!updatesPatchDir.exists()) {
     updatesPatchDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
   }
   // Copy the mar that will be applied
   let mar = getTestDirFile(aMarFile);
   mar.copyToFollowingLinks(updatesPatchDir, FILE_UPDATE_MAR);
@@ -2966,17 +2890,19 @@ function setupUpdaterTest(aMarFile, aPos
             }
           });
         }
       });
     }
     debugDump("finish - setup test directory: " + aTestDir.relPathDir);
   });
 
-  setupActiveUpdate();
+  if (aSetupActiveUpdate) {
+    setupActiveUpdate();
+  }
 
   if (aPostUpdateAsync !== null) {
     createUpdaterINI(aPostUpdateAsync, aPostUpdateExeRelPathPrefix);
   }
 
   debugDump("finish - updater test setup");
   setupAppFilesAsync();
 }
@@ -3990,17 +3916,19 @@ function getLaunchScript() {
 
 /**
  * Makes GreD, XREExeF, and UpdRootD point to unique file system locations so
  * xpcshell tests can run in parallel and to keep the environment clean.
  */
 function adjustGeneralPaths() {
   let dirProvider = {
     getFile: function AGP_DP_getFile(aProp, aPersistent) {
-      aPersistent.value = true;
+      // Set the value of persistent to false so when this directory provider is
+      // unregistered it will revert back to the original provider.
+      aPersistent.value = false;
       switch (aProp) {
         case NS_GRE_DIR:
           return getApplyDirFile(DIR_RESOURCES, true);
         case NS_GRE_BIN_DIR:
           return getApplyDirFile(DIR_MACOS, true);
         case XRE_EXECUTABLE_FILE:
           return getApplyDirFile(DIR_MACOS + FILE_APP_BIN, true);
         case XRE_UPDATE_ROOT_DIR:
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js
@@ -12,21 +12,17 @@ const WindowWatcher = {
         Assert.equal(aTitle, title,
                      "the ui string for title" + MSG_SHOULD_EQUAL);
         let text = gUpdateBundle.formatStringFromName("updaterIOErrorMsg",
                                                       [Services.appinfo.name,
                                                        Services.appinfo.name], 2);
         Assert.equal(aText, text,
                      "the ui string for message" + MSG_SHOULD_EQUAL);
 
-        // Cleaning up the active update along with reloading the update manager
-        // in doTestFinish will prevent writing the update xml files during
-        // shutdown.
-        gUpdateManager.cleanupActiveUpdate();
-        executeSoon(waitForUpdateXMLFiles);
+        executeSoon(doTestFinish);
       },
     };
   },
 
   QueryInterface: ChromeUtils.generateQI([Ci.nsIWindowWatcher]),
 };
 
 function run_test() {
@@ -59,15 +55,8 @@ function run_test() {
   reloadUpdateManagerData();
 
   let update = gUpdateManager.activeUpdate;
   update.errorCode = WRITE_ERROR;
   let prompter = Cc["@mozilla.org/updates/update-prompt;1"].
                  createInstance(Ci.nsIUpdatePrompt);
   prompter.showUpdateError(update);
 }
-
-/**
- * Called after the call to waitForUpdateXMLFiles finishes.
- */
-function waitForUpdateXMLFilesFinished() {
-  executeSoon(doTestFinish);
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedNoRecovery.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedNoRecovery.js
@@ -39,18 +39,10 @@ function updateCheckCompleted() {
 
 /**
  * Called after the download listener onStopRequest is called.
  */
 function downloadListenerStop() {
   Assert.equal(gStatusResult, Cr.NS_ERROR_NET_RESET,
                "the download status result" + MSG_SHOULD_EQUAL);
   gAUS.removeDownloadListener(downloadListener);
-  executeSoon(waitForUpdateXMLFiles);
-}
-
-/**
- * Called after the call to waitForUpdateXMLFiles finishes.
- */
-function waitForUpdateXMLFilesFinished() {
-  // The HttpServer must be stopped before calling do_test_finished
   stop_httpserver(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedOffline.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedOffline.js
@@ -37,19 +37,10 @@ function updateCheckCompleted() {
 
 /**
  * Called after the download listener onStopRequest is called.
  */
 function downloadListenerStop() {
   Assert.equal(gStatusResult, Cr.NS_OK,
                "the download status result" + MSG_SHOULD_EQUAL);
   gAUS.removeDownloadListener(downloadListener);
-  gUpdateManager.cleanupActiveUpdate();
-  executeSoon(waitForUpdateXMLFiles);
-}
-
-/**
- * Called after the call to waitForUpdateXMLFiles finishes.
- */
-function waitForUpdateXMLFilesFinished() {
-  // The HttpServer must be stopped before calling do_test_finished
   stop_httpserver(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js
@@ -47,19 +47,10 @@ function updateCheckCompleted() {
 
 /**
  * Called after the download listener onStopRequest is called.
  */
 function downloadListenerStop() {
   Assert.equal(gStatusResult, Cr.NS_OK,
                "the download status result" + MSG_SHOULD_EQUAL);
   gAUS.removeDownloadListener(downloadListener);
-  gUpdateManager.cleanupActiveUpdate();
-  executeSoon(waitForUpdateXMLFiles);
-}
-
-/**
- * Called after the call to waitForUpdateXMLFiles finishes.
- */
-function waitForUpdateXMLFilesFinished() {
-  // The HttpServer must be stopped before calling do_test_finished
   stop_httpserver(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadInvalidSizeMar.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInvalidSizeMar.js
@@ -44,22 +44,18 @@ function check_test_helper_pt1_1() {
 
 /**
  * Called after the download listener onStopRequest is called.
  */
 function downloadListenerStop() {
   Assert.equal(gStatusResult, Cr.NS_ERROR_UNEXPECTED,
                "the download status result" + MSG_SHOULD_EQUAL);
   gAUS.removeDownloadListener(downloadListener);
-
-  // Cleaning up the active update along with reloading the update manager
-  // in doTestFinish will prevent writing the update xml files during shutdown.
-  gUpdateManager.cleanupActiveUpdate();
+  // There is a pending write to the xml files.
   executeSoon(waitForUpdateXMLFiles);
 }
 
 /**
  * Called after the call to waitForUpdateXMLFiles finishes.
  */
 function waitForUpdateXMLFilesFinished() {
-  // The HttpServer must be stopped before calling do_test_finished
   stop_httpserver(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadMissingMar.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadMissingMar.js
@@ -47,18 +47,18 @@ function check_test_helper_pt1_1() {
 
 /**
  * Called after the download listener onStopRequest is called.
  */
 function downloadListenerStop() {
   Assert.equal(gStatusResult, Cr.NS_ERROR_UNEXPECTED,
                "the download status result" + MSG_SHOULD_EQUAL);
   gAUS.removeDownloadListener(downloadListener);
+  // There is a pending write to the xml files.
   executeSoon(waitForUpdateXMLFiles);
 }
 
 /**
  * Called after the call to waitForUpdateXMLFiles finishes.
  */
 function waitForUpdateXMLFilesFinished() {
-  // The HttpServer must be stopped before calling do_test_finished
   stop_httpserver(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js
@@ -19,21 +19,13 @@ function run_test() {
   standardInit();
 
   Assert.equal(gUpdateManager.updateCount, 0,
                "the update manager updateCount attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(gUpdateManager.activeUpdate.state, STATE_DOWNLOADING,
                "the update manager activeUpdate state attribute" +
                MSG_SHOULD_EQUAL);
 
-  // Pausing the download along with reloading the update manager in
-  // doTestFinish will prevent writing the update xml files during shutdown.
+  // Pause the download early to prevent it writing the update xml files during
+  // shutdown.
   gAUS.pauseDownload();
-  gUpdateManager.cleanupActiveUpdate();
-  executeSoon(waitForUpdateXMLFiles);
-}
-
-/**
- * Called after the call to waitForUpdateXMLFiles finishes.
- */
-function waitForUpdateXMLFilesFinished() {
   executeSoon(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js
@@ -282,10 +282,10 @@ function run_test_pt11() {
 function check_test_pt11() {
   let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount);
   Assert.ok(!!bestUpdate,
             "there should be one update available");
   Assert.equal(bestUpdate.appVersion, "1.0",
                "the update appVersion attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(bestUpdate.displayVersion, "1.0",
                "the update displayVersion attribute" + MSG_SHOULD_EQUAL);
-  doTestFinish();
+  stop_httpserver(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js
@@ -49,18 +49,10 @@ function run_test() {
   logTestInfo("testing showUpdateError should not call getNewPrompter");
   update.errorCode = WRITE_ERROR;
   gUP.showUpdateError(update);
   // Report a successful check after the call to showUpdateError since it
   // didn't throw and otherwise it would report no tests run.
   Assert.ok(true,
             "calling showUpdateError should not attempt to open a window");
 
-  gUpdateManager.cleanupActiveUpdate();
-  executeSoon(waitForUpdateXMLFiles);
+  executeSoon(doTestFinish);
 }
-
-/**
- * Called after the call to waitForUpdateXMLFiles finishes.
- */
-function waitForUpdateXMLFilesFinished() {
-  doTestFinish();
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/updateAutoPrefMigrate.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/updateAutoPrefMigrate.js
@@ -32,17 +32,17 @@ async function run_test() {
   await verifyPref(configFile, false);
 
   // Test that migration doesn't happen twice
   Services.prefs.setBoolPref("app.update.auto", true);
   await verifyPref(configFile, false);
 
   // If the file is deleted after migration, the default value should be
   // returned, regardless of the pref value.
-  debugDump(`about to remove config file`);
+  debugDump("about to remove config file");
   configFile.remove(false);
   Assert.ok(!configFile.exists(), "Pref file should have been removed");
   let configValue = await UpdateUtils.getAppUpdateAutoEnabled();
   Assert.equal(configValue, true, "getAppUpdateAutoEnabled should have " +
                                   "returned the default value (true)");
 
   // Setting a new value should cause the value to get written out again
   await UpdateUtils.setAppUpdateAutoEnabled(false);
--- a/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js
@@ -170,21 +170,10 @@ function run_test() {
                "the update patch URL attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.size, "75",
                "the update patch size attribute" + MSG_SHOULD_EQUAL);
   Assert.ok(!!patch.selected,
             "the update patch selected attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.state, STATE_FAILED,
                "the update patch state attribute" + MSG_SHOULD_EQUAL);
 
-  // Cleaning up the active update along with reloading the update manager
-  // in doTestFinish will prevent writing the update xml files during
-  // shutdown.
-  gUpdateManager.cleanupActiveUpdate();
-  executeSoon(waitForUpdateXMLFiles);
-}
-
-/**
- * Called after the call to waitForUpdateXMLFiles finishes.
- */
-function waitForUpdateXMLFilesFinished() {
   executeSoon(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageOldVersionFailure.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageOldVersionFailure.js
@@ -13,58 +13,45 @@ const STATE_AFTER_STAGE = STATE_APPLIED;
 
 function run_test() {
   if (!setupTestCommon()) {
     return;
   }
 
   gTestFiles = gTestFilesCompleteSuccess;
   gTestDirs = gTestDirsCompleteSuccess;
-  setupUpdaterTest(FILE_COMPLETE_MAR);
+  setupUpdaterTest(FILE_COMPLETE_MAR, null, "", false);
 }
 
 /**
  * Called after the call to setupUpdaterTest finishes.
  */
 function setupUpdaterTestFinished() {
-  stageUpdate(false);
-}
-
-/**
- * Called after the call to stageUpdate finishes.
- */
-function stageUpdateFinished() {
-  checkPostUpdateRunningFile(false);
-  checkFilesAfterUpdateSuccess(getStageDirFile, true);
-  checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true);
-  // Change the version file to an older version to simulate installing a new
+  let patchProps = {state: STATE_AFTER_STAGE};
+  let patches = getLocalPatchString(patchProps);
+  let updateProps = {appVersion: "0.9"};
+  let updates = getLocalUpdateString(updateProps, patches);
+  writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
+  getUpdateLog(FILE_UPDATE_LOG).create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE);
+  writeStatusFile(STATE_AFTER_STAGE);
+  // Create the version file with an older version to simulate installing a new
   // version of the application while there is an update that has been staged.
   writeVersionFile("0.9");
-  // Try to switch the application to the staged application that was updated.
+  // Try to switch the application to the fake staged application.
   runUpdateUsingApp(STATE_AFTER_STAGE);
 }
 
 /**
  * Called after the call to runUpdateUsingApp finishes.
  */
 function runUpdateFinished() {
-  // Change the active update to an older version to simulate installing a new
-  // version of the application while there is an update that has been staged.
-  let patchProps = {state: STATE_AFTER_STAGE};
-  let patches = getLocalPatchString(patchProps);
-  let updateProps = {appVersion: "0.9"};
-  let updates = getLocalUpdateString(updateProps, patches);
-  getUpdatesXMLFile(true).remove(false);
-  writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
-  reloadUpdateManagerData();
-
   standardInit();
   checkPostUpdateRunningFile(false);
   setTestFilesAndDirsForFailure();
-  checkFilesAfterUpdateFailure(getApplyDirFile, !IS_MACOSX, false);
+  checkFilesAfterUpdateFailure(getApplyDirFile);
 
   executeSoon(waitForUpdateXMLFiles);
 }
 
 /**
  * Called after the call to waitForUpdateXMLFiles finishes.
  */
 function waitForUpdateXMLFilesFinished() {