Bug 972852 - Handle file errors and fix log messages that were causing addon manager failures. r=Mossop
authorIrving Reid <irving@mozilla.com>
Fri, 14 Feb 2014 16:40:57 -0500
changeset 169511 f7f9328980d0a49408716f73d98698d18062a48e
parent 169510 7dabe9719703448804d5e58b156b281869bef3ac
child 169512 d7fdc2f9d7b55ab9bf974988bedbda52c8eac58c
push id26255
push userryanvm@gmail.com
push dateWed, 19 Feb 2014 20:34:53 +0000
treeherdermozilla-central@8497ffecbacd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMossop
bugs972852
milestone30.0a1
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
Bug 972852 - Handle file errors and fix log messages that were causing addon manager failures. r=Mossop
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/mozapps/extensions/XPIProviderUtils.js
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -2079,27 +2079,33 @@ var XPIProvider = {
                                                AddonManager.checkCompatibility);
         } catch (e) { }
         this.addAddonsToCrashReporter();
       }
 
       try {
         AddonManagerPrivate.recordTimestamp("XPI_bootstrap_addons_begin");
         for (let id in this.bootstrappedAddons) {
-          let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
-          file.persistentDescriptor = this.bootstrappedAddons[id].descriptor;
-          let reason = BOOTSTRAP_REASONS.APP_STARTUP;
-          // Eventually set INSTALLED reason when a bootstrap addon
-          // is dropped in profile folder and automatically installed
-          if (AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_INSTALLED)
-                          .indexOf(id) !== -1)
-            reason = BOOTSTRAP_REASONS.ADDON_INSTALL;
-          this.callBootstrapMethod(id, this.bootstrappedAddons[id].version,
-                                   this.bootstrappedAddons[id].type, file,
-                                   "startup", reason);
+          try {
+            let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+            file.persistentDescriptor = this.bootstrappedAddons[id].descriptor;
+            let reason = BOOTSTRAP_REASONS.APP_STARTUP;
+            // Eventually set INSTALLED reason when a bootstrap addon
+            // is dropped in profile folder and automatically installed
+            if (AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_INSTALLED)
+                            .indexOf(id) !== -1)
+              reason = BOOTSTRAP_REASONS.ADDON_INSTALL;
+            this.callBootstrapMethod(id, this.bootstrappedAddons[id].version,
+                                     this.bootstrappedAddons[id].type, file,
+                                     "startup", reason);
+          }
+          catch (e) {
+            ERROR("Failed to load bootstrap addon " + id + " from " +
+                  this.bootstrappedAddons[id].descriptor, e);
+          }
         }
         AddonManagerPrivate.recordTimestamp("XPI_bootstrap_addons_end");
       }
       catch (e) {
         ERROR("bootstrap startup failed", e);
         AddonManagerPrivate.recordException("XPI-BOOTSTRAP", "startup failed", e);
       }
 
@@ -2156,18 +2162,18 @@ var XPIProvider = {
     this.allAppGlobal = true;
 
     this.inactiveAddonIDs = [];
 
     // If there are pending operations then we must update the list of active
     // add-ons
     if (Prefs.getBoolPref(PREF_PENDING_OPERATIONS, false)) {
       XPIDatabase.updateActiveAddons();
-      XPIDatabase.writeAddonsList();
-      Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, false);
+      Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS,
+                                 !XPIDatabase.writeAddonsList());
     }
 
     this.installs = null;
     this.installLocations = null;
     this.installLocationsByName = null;
 
     // This is needed to allow xpcshell tests to simulate a restart
     this.extensionsActive = false;
@@ -2239,18 +2245,18 @@ var XPIProvider = {
       // This *must* be modal as it has to block startup.
       var features = "chrome,centerscreen,dialog,titlebar,modal";
       var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
                getService(Ci.nsIWindowWatcher);
       ww.openWindow(null, URI_EXTENSION_UPDATE_DIALOG, "", features, variant);
     }
 
     // Ensure any changes to the add-ons list are flushed to disk
-    XPIDatabase.writeAddonsList();
-    Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, false);
+    Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS,
+                               !XPIDatabase.writeAddonsList());
   },
 
   /**
    * Persists changes to XPIProvider.bootstrappedAddons to its store (a pref).
    */
   persistBootstrappedAddons: function XPI_persistBootstrappedAddons() {
     Services.prefs.setCharPref(PREF_BOOTSTRAP_ADDONS,
                                JSON.stringify(this.bootstrappedAddons));
@@ -2415,34 +2421,34 @@ var XPIProvider = {
 
           if (addon.unpack || Prefs.getBoolPref(PREF_XPI_UNPACK, false)) {
             let targetDir = stagingDir.clone();
             targetDir.append(addon.id);
             try {
               targetDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
             }
             catch (e) {
-              ERROR("Failed to create staging directory for add-on " + id, e);
+              ERROR("Failed to create staging directory for add-on " + addon.id, e);
               continue;
             }
 
             try {
               extractFiles(stagedXPI, targetDir);
             }
             catch (e) {
-              ERROR("Failed to extract staged XPI for add-on " + id + " in " +
+              ERROR("Failed to extract staged XPI for add-on " + addon.id + " in " +
                     aLocation.name, e);
             }
           }
           else {
             try {
               stagedXPI.moveTo(stagingDir, addon.id + ".xpi");
             }
             catch (e) {
-              ERROR("Failed to move staged XPI for add-on " + id + " in " +
+              ERROR("Failed to move staged XPI for add-on " + addon.id + " in " +
                     aLocation.name, e);
             }
           }
         }
         entries.close();
       }
 
       if (stagedXPIDir.exists()) {
@@ -2450,18 +2456,24 @@ var XPIProvider = {
           recursiveRemove(stagedXPIDir);
         }
         catch (e) {
           // Non-critical, just saves some perf on startup if we clean this up.
           LOG("Error removing XPI staging dir " + stagedXPIDir.path, e);
         }
       }
 
-      if (!stagingDir || !stagingDir.exists() || !stagingDir.isDirectory())
+      try {
+        if (!stagingDir || !stagingDir.exists() || !stagingDir.isDirectory())
+          return;
+      }
+      catch (e) {
+        WARN("Failed to find staging directory", e);
         return;
+      }
 
       let seenFiles = [];
       // Use a snapshot of the directory contents to avoid possible issues with
       // iterating over a directory while removing files from it (the YAFFS2
       // embedded filesystem has this issue, see bug 772238), and to remove
       // normal files before their resource forks on OSX (see bug 733436).
       let stagingDirEntries = getDirectoryEntries(stagingDir, true);
       for (let stageDirEntry of stagingDirEntries) {
@@ -3582,18 +3594,18 @@ var XPIProvider = {
         }
       }
 
       // If the application crashed before completing any pending operations then
       // we should perform them now.
       if (extensionListChanged || hasPendingChanges) {
         LOG("Updating database with changes to installed add-ons");
         XPIDatabase.updateActiveAddons();
-        XPIDatabase.writeAddonsList();
-        Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, false);
+        Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS,
+                                   !XPIDatabase.writeAddonsList());
         Services.prefs.setCharPref(PREF_BOOTSTRAP_ADDONS,
                                    JSON.stringify(this.bootstrappedAddons));
         return true;
       }
 
       LOG("No changes found");
     }
     catch (e) {
--- a/toolkit/mozapps/extensions/XPIProviderUtils.js
+++ b/toolkit/mozapps/extensions/XPIProviderUtils.js
@@ -1404,16 +1404,17 @@ this.XPIDatabase = {
         addon.active = newActive;
         this.saveChanges();
       }
     }
   },
 
   /**
    * Writes out the XPI add-ons list for the platform to read.
+   * @return true if the file was successfully updated, false otherwise
    */
   writeAddonsList: function XPIDB_writeAddonsList() {
     if (!this.addonDB) {
       // force the DB to load
       AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_writeList",
           XPIProvider.runPhase);
       this.syncLoadDB(true);
     }
@@ -1468,27 +1469,41 @@ this.XPIDatabase = {
                            encodeURIComponent(row.version));
       }
       fullCount += count;
     }
 
     if (fullCount > 0) {
       LOG("Writing add-ons list");
 
-      let addonsListTmp = FileUtils.getFile(KEY_PROFILEDIR, [FILE_XPI_ADDONS_LIST + ".tmp"],
-                                            true);
-      var fos = FileUtils.openFileOutputStream(addonsListTmp);
-      fos.write(text, text.length);
-      fos.close();
-      addonsListTmp.moveTo(addonsListTmp.parent, FILE_XPI_ADDONS_LIST);
+      try {
+        let addonsListTmp = FileUtils.getFile(KEY_PROFILEDIR, [FILE_XPI_ADDONS_LIST + ".tmp"],
+                                              true);
+        var fos = FileUtils.openFileOutputStream(addonsListTmp);
+        fos.write(text, text.length);
+        fos.close();
+        addonsListTmp.moveTo(addonsListTmp.parent, FILE_XPI_ADDONS_LIST);
 
-      Services.prefs.setCharPref(PREF_EM_ENABLED_ADDONS, enabledAddons.join(","));
+        Services.prefs.setCharPref(PREF_EM_ENABLED_ADDONS, enabledAddons.join(","));
+      }
+      catch (e) {
+        ERROR("Failed to write add-ons list to " + addonsListTmp.parent + "/" +
+              FILE_XPI_ADDONS_LIST, e);
+        return false;
+      }
     }
     else {
       if (addonsList.exists()) {
         LOG("Deleting add-ons list");
-        addonsList.remove(false);
+        try {
+          addonsList.remove(false);
+        }
+        catch (e) {
+          ERROR("Failed to remove " + addonsList.path, e);
+          return false;
+        }
       }
 
       Services.prefs.clearUserPref(PREF_EM_ENABLED_ADDONS);
     }
+    return true;
   }
 };