Bug 849353 - Add basic app info section to top level of FHR payload. r=gps, a=bajaj
authorRichard Newman <rnewman@mozilla.com>
Thu, 14 Mar 2013 11:24:12 -0700
changeset 132440 1688de15d68b4476a47b6fc74f4188ca3323ef83
parent 132439 51893bbcd397bb8fa15a76a9dc5fb0f2fcad6ece
child 132441 0039a3b42035d3a8dd23ef72ca533371b69562f8
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps, bajaj
bugs849353
milestone21.0a2
Bug 849353 - Add basic app info section to top level of FHR payload. r=gps, a=bajaj
services/healthreport/healthreporter.jsm
services/healthreport/tests/xpcshell/test_healthreporter.js
--- a/services/healthreport/healthreporter.jsm
+++ b/services/healthreport/healthreporter.jsm
@@ -23,16 +23,18 @@ Cu.import("resource://services-common/pr
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
 Cu.import("resource://gre/modules/osfile.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/TelemetryStopwatch.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
+                                  "resource://gre/modules/UpdateChannel.jsm");
 
 // Oldest year to allow in date preferences. This module was implemented in
 // 2012 and no dates older than that should be encountered.
 const OLDEST_ALLOWED_YEAR = 2012;
 
 const DAYS_IN_PAYLOAD = 180;
 
 const DEFAULT_DATABASE_NAME = "healthreport.sqlite";
@@ -605,18 +607,19 @@ AbstractHealthReporter.prototype = Objec
     return deferred.promise;
   },
 
   _getJSONPayload: function (now, asObject=false) {
     let pingDateString = this._formatDate(now);
     this._log.info("Producing JSON payload for " + pingDateString);
 
     let o = {
-      version: 1,
+      version: 2,
       thisPingDate: pingDateString,
+      geckoAppInfo: this.obtainAppInfo(this._log),
       data: {last: {}, days: {}},
     };
 
     let outputDataDays = o.data.days;
 
     // Guard here in case we don't track this (e.g., on Android).
     let lastPingDate = this.lastPingDate;
     if (lastPingDate && lastPingDate.getTime() > 0) {
@@ -778,16 +781,62 @@ AbstractHealthReporter.prototype = Objec
         return Promise.reject(error);
       }
     );
   },
 
   _now: function _now() {
     return new Date();
   },
+
+  // These are stolen from AppInfoProvider.
+  appInfoVersion: 1,
+  appInfoFields: {
+    // From nsIXULAppInfo.
+    vendor: "vendor",
+    name: "name",
+    id: "ID",
+    version: "version",
+    appBuildID: "appBuildID",
+    platformVersion: "platformVersion",
+    platformBuildID: "platformBuildID",
+
+    // From nsIXULRuntime.
+    os: "OS",
+    xpcomabi: "XPCOMABI",
+  },
+
+  /**
+   * Statically return a bundle of app info data, a subset of that produced by
+   * AppInfoProvider._populateConstants. This allows us to more usefully handle
+   * payloads that, due to error, contain no data.
+   *
+   * Returns a very sparse object if Services.appinfo is unavailable.
+   */
+  obtainAppInfo: function () {
+    let out = {"_v": this.appInfoVersion};
+    try {
+      let ai = Services.appinfo;
+      for (let [k, v] in Iterator(this.appInfoFields)) {
+        out[k] = ai[v];
+      }
+    } catch (ex) {
+      this._log.warn("Could not obtain Services.appinfo: " +
+                     CommonUtils.exceptionStr(ex));
+    }
+
+    try {
+      out["updateChannel"] = UpdateChannel.get();
+    } catch (ex) {
+      this._log.warn("Could not obtain update channel: " +
+                     CommonUtils.exceptionStr(ex));
+    }
+
+    return out;
+  },
 });
 
 /**
  * HealthReporter and its abstract superclass coordinate collection and
  * submission of health report metrics.
  *
  * This is the main type for Firefox Health Report on desktop. It glues all the
  * lower-level components (such as collection and submission) together.
--- a/services/healthreport/tests/xpcshell/test_healthreporter.js
+++ b/services/healthreport/tests/xpcshell/test_healthreporter.js
@@ -246,17 +246,17 @@ add_task(function test_json_payload_simp
   let reporter = yield getReporter("json_payload_simple");
 
   try {
     let now = new Date();
     let payload = yield reporter.getJSONPayload();
     do_check_eq(typeof payload, "string");
     let original = JSON.parse(payload);
 
-    do_check_eq(original.version, 1);
+    do_check_eq(original.version, 2);
     do_check_eq(original.thisPingDate, reporter._formatDate(now));
     do_check_eq(Object.keys(original.data.last).length, 0);
     do_check_eq(Object.keys(original.data.days).length, 0);
 
     reporter.lastPingDate = new Date(now.getTime() - 24 * 60 * 60 * 1000 - 10);
 
     original = JSON.parse(yield reporter.getJSONPayload());
     do_check_eq(original.lastPingDate, reporter._formatDate(reporter.lastPingDate));
@@ -580,16 +580,41 @@ add_task(function test_error_message_scr
 
     reporter._recordError("Foo " + uri.spec);
     do_check_eq(reporter._errors[0], "Foo <AppDataURI>");
   } finally {
     reporter._shutdown();
   }
 });
 
+add_task(function test_basic_appinfo() {
+  function verify(d) {
+    do_check_eq(d["_v"], 1);
+    do_check_eq(d._v, 1);
+    do_check_eq(d.vendor, "Mozilla");
+    do_check_eq(d.name, "xpcshell");
+    do_check_eq(d.id, "xpcshell@tests.mozilla.org");
+    do_check_eq(d.version, "1");
+    do_check_eq(d.appBuildID, "20121107");
+    do_check_eq(d.platformVersion, "p-ver");
+    do_check_eq(d.platformBuildID, "20121106");
+    do_check_eq(d.os, "XPCShell");
+    do_check_eq(d.xpcomabi, "noarch-spidermonkey");
+    do_check_true("updateChannel" in d);
+  }
+  let reporter = yield getReporter("basic_appinfo");
+  try {
+    verify(reporter.obtainAppInfo());
+    let payload = yield reporter.collectAndObtainJSONPayload(true);
+    do_check_eq(payload["version"], 2);
+    verify(payload["geckoAppInfo"]);
+  } finally {
+    reporter._shutdown();
+  }
+});
 // Ensure collection occurs if upload is disabled.
 add_task(function test_collect_when_upload_disabled() {
   let reporter = getJustReporter("collect_when_upload_disabled");
   reporter._policy.recordHealthReportUploadEnabled(false, "testing-collect");
   do_check_false(reporter._policy.healthReportUploadEnabled);
 
   let name = "healthreport-testing-collect_when_upload_disabled-healthreport-lastDailyCollection";
   let pref = "app.update.lastUpdateTime." + name;