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 169929 f7f9328980d0a49408716f73d98698d18062a48e
parent 169928 7dabe9719703448804d5e58b156b281869bef3ac
child 169930 d7fdc2f9d7b55ab9bf974988bedbda52c8eac58c
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersMossop
bugs972852
milestone30.0a1
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;
   }
 };