Bug 1231415 - Save to disk the list of slow add-ons;r?felipe,f?glind draft
authorDavid Rajchenbach-Teller <dteller@mozilla.com>
Thu, 07 Jan 2016 15:35:50 +0100
changeset 319659 60cfddaf91fe0d6181c3888dcbb2cf9a2f07db13
parent 318506 d7a0ad85d9fb77916f9d77d62697b852f3dc63e6
child 512628 b179879dc337902d61094f7709eaf302844d42be
push id9070
push userdteller@mozilla.com
push dateThu, 07 Jan 2016 14:37:09 +0000
reviewersfelipe
bugs1231415
milestone46.0a1
Bug 1231415 - Save to disk the list of slow add-ons;r?felipe,f?glind
toolkit/components/perfmonitoring/AddonWatcher.jsm
--- a/toolkit/components/perfmonitoring/AddonWatcher.jsm
+++ b/toolkit/components/perfmonitoring/AddonWatcher.jsm
@@ -46,16 +46,18 @@ this.AddonWatcher = {
       // probably some malformed JSON, ignore and carry on
       this._ignoreList = new Set();
     }
 
     this._warmupPeriod = Preferences.get("browser.addon-watch.warmup-ms", 60 * 1000 /* 1 minute */);
     this._idleThreshold = Preferences.get("browser.addon-watch.deactivate-after-idle-ms", 3000);
     this.paused = false;
     this.callback = callback;
+
+    OS.File.shutdown.addBlocker("AddonWatcher: Writing latest alerts to disk", () => this.saveAlertsToDisk());
   },
   uninit: function() {
     this.paused = true;
   },
   _initializedTimeStamp: 0,
 
   set callback(callback) {
     this._callback = callback;
@@ -220,9 +222,77 @@ this.AddonWatcher = {
    */
   get alerts() {
     let result = new Map();
     for (let [k, v] of this._alerts) {
       result.set(k, Cu.cloneInto(v, this));
     }
     return result;
   },
+
+  /**
+   * Write to disk the list of alerts encountered in the session so far.
+   *
+   * Noop if we consider that the session was too short for any measure to be
+   * meaningful. The threshold is controlled by pref
+   * "browser.addon-watch.minimal-meaningful-session-duration-us".
+   *
+   * @return Promise
+   */
+  saveAlertsToDisk: function() {
+    let minimalMeaningfulDurationUS = Preferences.get("browser.addon-watch.minimal-meaningful-session-duration-us", /* 1 hour */ 3600 * 1000 * 1000);
+    if (Cu.now() - this._initializedTimeStamp <= minimalMeaningfulDurationUS) {
+      // The session was short, so we probably don't have enough data to figure
+      // out whether add-ons actually slowed down Firefox.
+      return;
+    }
+
+    let data = {
+      format: ["addonwatcher", 1],
+      alerts: {},
+    };
+    for (let [k, v] of this._alerts) {
+      data.alerts[k] = v;
+    }
+
+    let path = OS.Path.join(OS.Constants.Path.profileDir, "extensions", "addonwatcher.json");
+    return OS.File.writeAtomic(path, JSON.stringify(data), { encoding: "utf-8" });
+  },
+
+  /**
+   * Read the latest list of alerts written to disk.
+   *
+   * @return Promise
+   * @resolve Map<String, Object> a map with the same format as `get alerts()`.
+   *  The map is empty if no list was written to disk.
+   * @reject OS.File.Error in case of I/O error.
+   * @reject TypeError if the format of the file is incorrect.
+   */
+  readAlertsFromDisk: function() {
+    return Task.async(function*() {
+      let path = OS.Path.join(OS.Constants.Path.profileDir, "extensions", "addonwatcher.json");
+      try {
+        let data = JSON.parse((yield OS.File.read(path, { encoding: "utf-8" })));
+      } catch (ex) {
+        if (ex.becauseNoSuchFile) {
+          return new Map();
+        }
+        throw ex;
+      }
+
+      // Sanity check.
+      let [name, version] = data.format;
+      if (name != "addonwatcher") {
+        throw new TypeError("Unexpected format " + name);
+      }
+      if (version != 1) {
+        throw new TypeError("Unexpected format version " + version);
+      }
+
+      let result = new Map();
+
+      for (let k of Object.keys(data.alerts)) {
+        result.set(k, data.alerts[k]);
+      }
+      return result;
+    });
+  }
 };