diff --git a/toolkit/components/telemetry/TelemetryEnvironment.jsm b/toolkit/components/telemetry/TelemetryEnvironment.jsm index 58473eaac703..2d5328ea193e 100644 --- a/toolkit/components/telemetry/TelemetryEnvironment.jsm +++ b/toolkit/components/telemetry/TelemetryEnvironment.jsm @@ -174,6 +174,7 @@ const EXPERIMENTS_CHANGED_TOPIC = "experiments-changed"; const SEARCH_ENGINE_MODIFIED_TOPIC = "browser-search-engine-modified"; const SEARCH_SERVICE_TOPIC = "browser-search-service"; const COMPOSITOR_CREATED_TOPIC = "compositor:created"; +const DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC = "distribution-customization-complete"; /** * Get the current browser. @@ -683,6 +684,7 @@ function EnvironmentCache() { this._updateSettings(); // Fill in the default search engine, if the search provider is already initialized. this._updateSearchEngine(); + this._addObservers(); // Build the remaining asynchronous parts of the environment. Don't register change listeners // until the initial environment has been built. @@ -706,7 +708,6 @@ function EnvironmentCache() { this._initTask = null; this._startWatchingPrefs(); this._addonBuilder.watchForChanges(); - this._addObservers(); this._updateGraphicsFeatures(); return this.currentEnvironment; }; @@ -847,6 +848,7 @@ EnvironmentCache.prototype = { Services.obs.addObserver(this, SEARCH_ENGINE_MODIFIED_TOPIC, false); Services.obs.addObserver(this, SEARCH_SERVICE_TOPIC, false); Services.obs.addObserver(this, COMPOSITOR_CREATED_TOPIC, false); + Services.obs.addObserver(this, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC, false); }, _removeObservers: function () { @@ -854,6 +856,9 @@ EnvironmentCache.prototype = { Services.obs.removeObserver(this, SEARCH_ENGINE_MODIFIED_TOPIC); Services.obs.removeObserver(this, SEARCH_SERVICE_TOPIC); Services.obs.removeObserver(this, COMPOSITOR_CREATED_TOPIC); + try { + Services.obs.removeObserver(this, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC); + } catch(ex) {}; }, observe: function (aSubject, aTopic, aData) { @@ -879,6 +884,12 @@ EnvironmentCache.prototype = { // first compositor to be created and then query nsIGfxInfo again. this._updateGraphicsFeatures(); break; + case DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC: + // Distribution customizations are applied after final-ui-startup. query + // partner prefs again when they are ready. + this._updatePartner(); + Services.obs.removeObserver(this, aTopic); + break; } }, @@ -958,6 +969,13 @@ EnvironmentCache.prototype = { } }, + /** + * Update the partner prefs. + */ + _updatePartner: function() { + this._currentEnvironment.partner = this._getPartner(); + }, + /** * Get the build data in object form. * @return Object containing the build data. diff --git a/toolkit/components/telemetry/docs/environment.rst b/toolkit/components/telemetry/docs/environment.rst index 4494eec4ec6b..5472a56ede53 100644 --- a/toolkit/components/telemetry/docs/environment.rst +++ b/toolkit/components/telemetry/docs/environment.rst @@ -63,7 +63,7 @@ Structure:: creationDate: , // integer days since UNIX epoch, e.g. 16446 resetDate: , // integer days since UNIX epoch, e.g. 16446 - optional }, - partner: { + partner: { // This section may not be immediately available on startup distributionId: , // pref "distribution.id", null on failure distributionVersion: , // pref "distribution.version", null on failure partnerId: , // pref mozilla.partner.id, null on failure @@ -300,6 +300,11 @@ The following is a partial list of collected preferences. - ``browser.urlbar.userMadeSearchSuggestionsChoice``: True if the user has clicked Yes or No in the urlbar's opt-in notification. Defaults to false. +partner +~~~~~~~ + +If the user is using a partner repack, this contains information identifying the repack being used, otherwise "partnerNames" will be an empty array and other entries will be null. The information may be missing when the profile just becomes available. In Firefox for desktop, the information along with other customizations defined in distribution.ini are processed later in the startup phase, and will be fully applied when "distribution-customization-complete" notification is sent. + activeAddons ~~~~~~~~~~~~ diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js index 307eaf9e4b6c..13e2c4dc2ebb 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js @@ -40,6 +40,7 @@ const DISTRIBUTOR_NAME = "Some Distributor"; const DISTRIBUTOR_CHANNEL = "A Channel"; const PARTNER_NAME = "test"; const PARTNER_ID = "NicePartner-ID-3785"; +const DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC = "distribution-customization-complete"; const GFX_VENDOR_ID = "0xabcd"; const GFX_DEVICE_ID = "0x1234"; @@ -303,7 +304,7 @@ function checkProfileSection(data) { Assert.equal(data.profile.resetDate, truncateToDays(PROFILE_RESET_DATE_MS)); } -function checkPartnerSection(data) { +function checkPartnerSection(data, isInitial) { const EXPECTED_FIELDS = { distributionId: DISTRIBUTION_ID, distributionVersion: DISTRIBUTION_VERSION, @@ -315,12 +316,17 @@ function checkPartnerSection(data) { Assert.ok("partner" in data, "There must be a partner section in Environment."); for (let f in EXPECTED_FIELDS) { - Assert.equal(data.partner[f], EXPECTED_FIELDS[f], f + " must have the correct value."); + let expected = isInitial ? null : EXPECTED_FIELDS[f]; + Assert.strictEqual(data.partner[f], expected, f + " must have the correct value."); } // Check that "partnerNames" exists and contains the correct element. Assert.ok(Array.isArray(data.partner.partnerNames)); - Assert.ok(data.partner.partnerNames.indexOf(PARTNER_NAME) >= 0); + if (isInitial) { + Assert.equal(data.partner.partnerNames.length, 0); + } else { + Assert.ok(data.partner.partnerNames.indexOf(PARTNER_NAME) >= 0); + } } function checkGfxAdapter(data) { @@ -611,11 +617,11 @@ function checkAddonsSection(data) { Assert.ok(checkNullOrString(data.addons.persona)); } -function checkEnvironmentData(data) { +function checkEnvironmentData(data, isInitial = false) { checkBuildSection(data); checkSettingsSection(data); checkProfileSection(data); - checkPartnerSection(data); + checkPartnerSection(data, isInitial); checkSystemSection(data); checkAddonsSection(data); } @@ -645,7 +651,6 @@ function run_test() { gHttpServer.registerDirectory("/data/", do_get_cwd()); do_register_cleanup(() => gHttpServer.stop(() => {})); - spoofPartnerInfo(); // Spoof the the hotfixVersion Preferences.set("extensions.hotfix.lastVersion", APP_HOTFIX_VERSION); @@ -664,6 +669,12 @@ add_task(function* asyncSetup() { add_task(function* test_checkEnvironment() { let environmentData = yield TelemetryEnvironment.onInitialized(); + checkEnvironmentData(environmentData, true); + + spoofPartnerInfo(); + Services.obs.notifyObservers(null, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC, null); + + environmentData = TelemetryEnvironment.currentEnvironment; checkEnvironmentData(environmentData); });