Bug 930548: collect more per-addon Telemetry details; r=unfocused
authorIrving Reid <irving@mozilla.com>
Tue, 05 Nov 2013 10:41:14 -0500
changeset 153599 eb5d47884a27eb2817d4b4ae8de842a41a6de8cf
parent 153598 ec8042ab407537bd0c5cdea49e65f05bb48c290c
child 153600 34307fd1289e8fd02567124e07a26bd9a22a2d9a
push id25595
push userryanvm@gmail.com
push dateTue, 05 Nov 2013 20:19:27 +0000
treeherdermozilla-central@2ada3a06d5e7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersunfocused
bugs930548
milestone28.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 930548: collect more per-addon Telemetry details; r=unfocused
toolkit/mozapps/extensions/XPIProvider.jsm
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -2196,17 +2196,17 @@ var XPIProvider = {
    *         The install location to retrieve the add-on states for
    * @return a dictionary mapping add-on IDs to objects with a descriptor
    *         property which contains the add-ons dir/file descriptor and an
    *         mtime property which contains the add-on's last modified time as
    *         the number of milliseconds since the epoch.
    */
   getAddonStates: function XPI_getAddonStates(aLocation) {
     let addonStates = {};
-    aLocation.addonLocations.forEach(function(file) {
+    for (let file of aLocation.addonLocations) {
       let id = aLocation.getIDForLocation(file);
       let unpacked = 0;
       let [modFile, modTime] = recursiveLastModifiedTime(file);
       addonStates[id] = {
         descriptor: file.persistentDescriptor,
         mtime: modTime
       };
       try {
@@ -2214,17 +2214,18 @@ var XPIProvider = {
         file.append(FILE_INSTALL_MANIFEST);
         let rdfTime = file.lastModifiedTime;
         addonStates[id].rdfTime = rdfTime;
         unpacked = 1;
       }
       catch (e) { }
       this._mostRecentlyModifiedFile[id] = modFile;
       this.setTelemetry(id, "unpacked", unpacked);
-    }, this);
+      this.setTelemetry(id, "location", aLocation.name);
+    }
 
     return addonStates;
   },
 
   /**
    * Gets an array of install location states which uniquely describes all
    * installed add-ons with the add-on's InstallLocation name and last modified
    * time. This function may be expensive because of the getAddonStates() call.
@@ -3177,30 +3178,30 @@ var XPIProvider = {
     }
 
     let changed = false;
     let knownLocations = XPIDatabase.getInstallLocations();
 
     // The install locations are iterated in reverse order of priority so when
     // there are multiple add-ons installed with the same ID the one that
     // should be visible is the first one encountered.
-    aState.reverse().forEach(function(aSt) {
+    for (let aSt of aState.reverse()) {
 
       // We can't include the install location directly in the state as it has
       // to be cached as JSON.
       let installLocation = this.installLocationsByName[aSt.name];
       let addonStates = aSt.addons;
 
       // Check if the database knows about any add-ons in this install location.
       if (knownLocations.has(installLocation.name)) {
         knownLocations.delete(installLocation.name);
         let addons = XPIDatabase.getAddonsInLocation(installLocation.name);
         // Iterate through the add-ons installed the last time the application
         // ran
-        addons.forEach(function(aOldAddon) {
+        for (let aOldAddon of addons) {
           // If a version of this add-on has been installed in an higher
           // priority install location then count it as changed
           if (AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_INSTALLED)
                           .indexOf(aOldAddon.id) != -1) {
             AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED,
                                                  aOldAddon.id);
           }
 
@@ -3208,20 +3209,35 @@ var XPIProvider = {
           if (aOldAddon.id in addonStates) {
             let addonState = addonStates[aOldAddon.id];
             delete addonStates[aOldAddon.id];
 
             // Remember add-ons that were inactive during startup
             if (aOldAddon.visible && !aOldAddon.active)
               XPIProvider.inactiveAddonIDs.push(aOldAddon.id);
 
+            // record a bit more per-addon telemetry
+            let loc = aOldAddon.defaultLocale;
+            if (loc) {
+              XPIProvider.setTelemetry(aOldAddon.id, "name", loc.name);
+              XPIProvider.setTelemetry(aOldAddon.id, "creator", loc.creator);
+            }
+
             // Check if the add-on has been changed outside the XPI provider
             if (aOldAddon.updateDate != addonState.mtime) {
+              // Did time change in the wrong direction?
+              if (addonState.mtime < aOldAddon.updateDate) {
+                this.setTelemetry(aOldAddon.id, "olderFile", {
+                  name: this._mostRecentlyModifiedFile[aOldAddon.id],
+                  mtime: addonState.mtime,
+                  oldtime: aOldAddon.updateDate
+                });
+              }
               // Is the add-on unpacked?
-              if (addonState.rdfTime) {
+              else if (addonState.rdfTime) {
                 // Was the addon manifest "install.rdf" modified, or some other file?
                 if (addonState.rdfTime > aOldAddon.updateDate) {
                   this.setTelemetry(aOldAddon.id, "modifiedInstallRDF", 1);
                 }
                 else {
                   this.setTelemetry(aOldAddon.id, "modifiedFile",
                                     this._mostRecentlyModifiedFile[aOldAddon.id]);
                 }
@@ -3251,40 +3267,40 @@ var XPIProvider = {
                         changed;
             }
             if (aOldAddon.visible && aOldAddon._installLocation.name != KEY_APP_GLOBAL)
               XPIProvider.allAppGlobal = false;
           }
           else {
             changed = removeMetadata(aOldAddon) || changed;
           }
-        }, this);
+        }
       }
 
       // All the remaining add-ons in this install location must be new.
 
       // Get the migration data for this install location.
       let locMigrateData = {};
       if (XPIDatabase.migrateData && installLocation.name in XPIDatabase.migrateData)
         locMigrateData = XPIDatabase.migrateData[installLocation.name];
       for (let id in addonStates) {
         changed = addMetadata(installLocation, id, addonStates[id],
                               locMigrateData[id]) || changed;
       }
-    }, this);
+    }
 
     // The remaining locations that had add-ons installed in them no longer
     // have any add-ons installed in them, or the locations no longer exist.
     // The metadata for the add-ons that were in them must be removed from the
     // database.
     for (let location of knownLocations) {
       let addons = XPIDatabase.getAddonsInLocation(location);
-      addons.forEach(function(aOldAddon) {
+      for (let aOldAddon of addons) {
         changed = removeMetadata(aOldAddon) || changed;
-      }, this);
+      }
     }
 
     // Cache the new install location states
     let cache = JSON.stringify(this.getInstallLocationStates());
     Services.prefs.setCharPref(PREF_INSTALL_CACHE, cache);
     this.persistBootstrappedAddons();
 
     // Clear out any cached migration data.
@@ -5397,26 +5413,28 @@ AddonInstall.prototype = {
     AddonManagerPrivate.callAddonListeners("onInstalling",
                                            createWrapper(this.addon),
                                            requiresRestart);
 
     let stagingDir = this.installLocation.getStagingDir();
     let stagedAddon = stagingDir.clone();
 
     Task.spawn((function() {
+      let installedUnpacked = 0;
       yield this.installLocation.requestStagingDir();
 
       // First stage the file regardless of whether restarting is necessary
       if (this.addon.unpack || Prefs.getBoolPref(PREF_XPI_UNPACK, false)) {
         LOG("Addon " + this.addon.id + " will be installed as " +
             "an unpacked directory");
         stagedAddon.append(this.addon.id);
         yield recursiveRemoveAsync(stagedAddon);
         yield OS.File.makeDir(stagedAddon.path);
         yield extractFilesAsync(this.file, stagedAddon);
+        installedUnpacked = 1;
       }
       else {
         LOG("Addon " + this.addon.id + " will be installed as " +
             "a packed xpi");
         stagedAddon.append(this.addon.id + ".xpi");
         yield recursiveRemoveAsync(stagedAddon);
         yield OS.File.copy(this.file.path, stagedAddon.path);
       }
@@ -5541,21 +5559,28 @@ AddonInstall.prototype = {
 
         if (this.addon.bootstrap) {
           if (this.addon.active) {
             XPIProvider.callBootstrapMethod(this.addon.id, this.addon.version,
                                             this.addon.type, file, "startup",
                                             reason, extraParams);
           }
           else {
-            // XXX this makes it dangerous to do many things in onInstallEnded
+            // XXX this makes it dangerous to do some things in onInstallEnded
             // listeners because important cleanup hasn't been done yet
             XPIProvider.unloadBootstrapScope(this.addon.id);
           }
         }
+        XPIProvider.setTelemetry(this.addon.id, "unpacked", installedUnpacked);
+        XPIProvider.setTelemetry(this.addon.id, "location", this.installLocation.name);
+        let loc = this.addon.defaultLocale;
+        if (loc) {
+          XPIProvider.setTelemetry(this.addon.id, "name", loc.name);
+          XPIProvider.setTelemetry(this.addon.id, "creator", loc.creator);
+        }
       }
     }).bind(this)).then(null, (e) => {
       WARN("Failed to install " + this.file.path + " from " + this.sourceURI.spec, e);
       if (stagedAddon.exists())
         recursiveRemove(stagedAddon);
       this.state = AddonManager.STATE_INSTALL_FAILED;
       this.error = AddonManager.ERROR_FILE_ACCESS;
       XPIProvider.removeActiveInstall(this);