Bug 1887980 - Report !UpdateService.disabled for the telemetry environment's update.enabled value r=nalexander,application-update-reviewers

In order to do this without initializing the update system this early, we move the functionality to the stub, add an XPCOM interface for it, and convert it to new-style class using the `class` keyword.

Differential Revision: https://phabricator.services.mozilla.com/D209128
This commit is contained in:
Robin Steuber 2024-05-16 20:01:54 +00:00
parent 2ef30b1bbb
commit 69f5302a38
6 changed files with 119 additions and 33 deletions

View file

@ -9,6 +9,7 @@ import { TelemetryUtils } from "resource://gre/modules/TelemetryUtils.sys.mjs";
import { ObjectUtils } from "resource://gre/modules/ObjectUtils.sys.mjs"; import { ObjectUtils } from "resource://gre/modules/ObjectUtils.sys.mjs";
import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
import { UpdateUtils } from "resource://gre/modules/UpdateUtils.sys.mjs"; import { UpdateUtils } from "resource://gre/modules/UpdateUtils.sys.mjs";
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
const Utils = TelemetryUtils; const Utils = TelemetryUtils;
@ -33,6 +34,15 @@ ChromeUtils.defineLazyGetter(lazy, "fxAccounts", () => {
).getFxAccountsSingleton(); ).getFxAccountsSingleton();
}); });
if (AppConstants.MOZ_UPDATER) {
XPCOMUtils.defineLazyServiceGetter(
lazy,
"UpdateServiceStub",
"@mozilla.org/updates/update-service-stub;1",
"nsIApplicationUpdateServiceStub"
);
}
// The maximum length of a string (e.g. description) in the addons section. // The maximum length of a string (e.g. description) in the addons section.
const MAX_ADDON_STRING_LENGTH = 100; const MAX_ADDON_STRING_LENGTH = 100;
// The maximum length of a string value in the settings.attribution object. // The maximum length of a string value in the settings.attribution object.
@ -1620,7 +1630,8 @@ EnvironmentCache.prototype = {
intl: Policy._intlLoaded ? getIntlSettings() : {}, intl: Policy._intlLoaded ? getIntlSettings() : {},
update: { update: {
channel: updateChannel, channel: updateChannel,
enabled: !Services.policies || Services.policies.isAllowed("appUpdate"), enabled:
AppConstants.MOZ_UPDATER && !lazy.UpdateServiceStub.updateDisabled,
}, },
userPrefs: this._getPrefData(), userPrefs: this._getPrefData(),
sandbox: this._getSandboxData(), sandbox: this._getSandboxData(),

View file

@ -54,25 +54,6 @@ XPCOMUtils.defineLazyServiceGetter(
"nsIApplicationUpdateServiceStub" "nsIApplicationUpdateServiceStub"
); );
if (AppConstants.ENABLE_WEBDRIVER) {
XPCOMUtils.defineLazyServiceGetter(
lazy,
"Marionette",
"@mozilla.org/remote/marionette;1",
"nsIMarionette"
);
XPCOMUtils.defineLazyServiceGetter(
lazy,
"RemoteAgent",
"@mozilla.org/remote/agent;1",
"nsIRemoteAgent"
);
} else {
lazy.Marionette = { running: false };
lazy.RemoteAgent = { running: false };
}
const UPDATESERVICE_CID = Components.ID( const UPDATESERVICE_CID = Components.ID(
"{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}" "{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}"
); );
@ -90,7 +71,6 @@ const PREF_APP_UPDATE_CHECK_ONLY_INSTANCE_INTERVAL =
"app.update.checkOnlyInstance.interval"; "app.update.checkOnlyInstance.interval";
const PREF_APP_UPDATE_CHECK_ONLY_INSTANCE_TIMEOUT = const PREF_APP_UPDATE_CHECK_ONLY_INSTANCE_TIMEOUT =
"app.update.checkOnlyInstance.timeout"; "app.update.checkOnlyInstance.timeout";
const PREF_APP_UPDATE_DISABLEDFORTESTING = "app.update.disabledForTesting";
const PREF_APP_UPDATE_DOWNLOAD_ATTEMPTS = "app.update.download.attempts"; const PREF_APP_UPDATE_DOWNLOAD_ATTEMPTS = "app.update.download.attempts";
const PREF_APP_UPDATE_DOWNLOAD_MAXATTEMPTS = "app.update.download.maxAttempts"; const PREF_APP_UPDATE_DOWNLOAD_MAXATTEMPTS = "app.update.download.maxAttempts";
const PREF_APP_UPDATE_ELEVATE_NEVER = "app.update.elevate.never"; const PREF_APP_UPDATE_ELEVATE_NEVER = "app.update.elevate.never";
@ -3891,23 +3871,14 @@ export class UpdateService {
} }
get disabledForTesting() { get disabledForTesting() {
return ( return lazy.UpdateServiceStub.updateDisabledForTesting;
(Cu.isInAutomation ||
lazy.Marionette.running ||
lazy.RemoteAgent.running) &&
Services.prefs.getBoolPref(PREF_APP_UPDATE_DISABLEDFORTESTING, false)
);
} }
/** /**
* See nsIUpdateService.idl * See nsIUpdateService.idl
*/ */
get disabled() { get disabled() {
return ( return lazy.UpdateServiceStub.updateDisabled;
(Services.policies && !Services.policies.isAllowed("appUpdate")) ||
this.disabledForTesting ||
Services.sysinfo.getProperty("isPackagedApp")
);
} }
/** /**

View file

@ -3,8 +3,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { FileUtils } from "resource://gre/modules/FileUtils.sys.mjs";
import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
import { FileUtils } from "resource://gre/modules/FileUtils.sys.mjs";
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
const lazy = {}; const lazy = {};
@ -12,6 +13,25 @@ ChromeUtils.defineESModuleGetters(lazy, {
UpdateLog: "resource://gre/modules/UpdateLog.sys.mjs", UpdateLog: "resource://gre/modules/UpdateLog.sys.mjs",
}); });
if (AppConstants.ENABLE_WEBDRIVER) {
XPCOMUtils.defineLazyServiceGetter(
lazy,
"Marionette",
"@mozilla.org/remote/marionette;1",
"nsIMarionette"
);
XPCOMUtils.defineLazyServiceGetter(
lazy,
"RemoteAgent",
"@mozilla.org/remote/agent;1",
"nsIRemoteAgent"
);
} else {
lazy.Marionette = { running: false };
lazy.RemoteAgent = { running: false };
}
const DIR_UPDATES = "updates"; const DIR_UPDATES = "updates";
const FILE_UPDATE_STATUS = "update.status"; const FILE_UPDATE_STATUS = "update.status";
@ -23,6 +43,7 @@ const KEY_OLD_UPDROOT = "OldUpdRootD";
// happens for every install rather than once per profile) // happens for every install rather than once per profile)
const PREF_PREFIX_UPDATE_DIR_MIGRATED = "app.update.migrated.updateDir3."; const PREF_PREFIX_UPDATE_DIR_MIGRATED = "app.update.migrated.updateDir3.";
const PREF_APP_UPDATE_ALTUPDATEDIRPATH = "app.update.altUpdateDirPath"; const PREF_APP_UPDATE_ALTUPDATEDIRPATH = "app.update.altUpdateDirPath";
const PREF_APP_UPDATE_DISABLEDFORTESTING = "app.update.disabledForTesting";
function getUpdateBaseDirNoCreate() { function getUpdateBaseDirNoCreate() {
if (Cu.isInAutomation) { if (Cu.isInAutomation) {
@ -108,6 +129,10 @@ export class UpdateServiceStub {
} }
async #init(force_update_init) { async #init(force_update_init) {
if (this.updateDisabled) {
return;
}
// We call into this from many places to ensure that initialization is done, // We call into this from many places to ensure that initialization is done,
// so we want to optimize for the case where initialization is already // so we want to optimize for the case where initialization is already
// finished. // finished.
@ -166,6 +191,29 @@ export class UpdateServiceStub {
} }
} }
/**
* See nsIUpdateService.idl
*/
get updateDisabledForTesting() {
return (
(Cu.isInAutomation ||
lazy.Marionette.running ||
lazy.RemoteAgent.running) &&
Services.prefs.getBoolPref(PREF_APP_UPDATE_DISABLEDFORTESTING, false)
);
}
/**
* See nsIUpdateService.idl
*/
get updateDisabled() {
return (
(Services.policies && !Services.policies.isAllowed("appUpdate")) ||
this.updateDisabledForTesting ||
Services.sysinfo.getProperty("isPackagedApp")
);
}
async observe(_subject, topic, _data) { async observe(_subject, topic, _data) {
switch (topic) { switch (topic) {
// This is sort of the "default" way of being initialized. The // This is sort of the "default" way of being initialized. The

View file

@ -986,4 +986,15 @@ interface nsIApplicationUpdateServiceStub : nsISupports
* @returns Promise<undefined> * @returns Promise<undefined>
*/ */
Promise initUpdate(); Promise initUpdate();
/**
* This is identical to `nsIApplicationUpdateService.disabled`.
*/
readonly attribute boolean updateDisabled;
/**
* This will be `true` if update is disabled specifically because we are
* running a test that didn't opt-in to updating.
*/
readonly attribute boolean updateDisabledForTesting;
}; };

View file

@ -0,0 +1,43 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
"use strict";
const { TelemetryEnvironment } = ChromeUtils.importESModule(
"resource://gre/modules/TelemetryEnvironment.sys.mjs"
);
/**
* This test ensures that packaged installations don't send an `update.enabled`
* value of `true` in the telemetry environment.
*/
add_task(async function telemetryEnvironmentUpdateEnabled() {
const origSysinfo = Services.sysinfo;
registerCleanupFunction(() => {
Services.sysinfo = origSysinfo;
});
const mockSysinfo = Object.create(origSysinfo, {
getProperty: {
configurable: true,
enumerable: true,
writable: false,
value: prop => {
if (prop == "isPackagedApp") {
return true;
}
return origSysinfo.getProperty(prop);
},
},
});
Services.sysinfo = mockSysinfo;
const environmentData = await TelemetryEnvironment.onInitialized();
Assert.equal(
environmentData.settings.update.enabled,
false,
"Update should not be reported as enabled in a packaged app"
);
});

View file

@ -77,6 +77,8 @@ reason = "Update pref migration is currently Windows only"
run-if = ["os == 'win'"] run-if = ["os == 'win'"]
reason = "Update directory migration is currently Windows only" reason = "Update directory migration is currently Windows only"
["updateEnabledTelemetry.js"]
["updateManagerXML.js"] ["updateManagerXML.js"]
["updateSyncManager.js"] ["updateSyncManager.js"]