In bug 1941961, Nimbus initialization moved from Normandy into ExperimentAPI. This updates BackgroundTaskUtils to call into the same API as the rest of the browser to initialize Nimbus. To support this, `ExperimentAPI.init()` now supports options for providing additional context to the ExperimentManager's targeting context and forcing a sync in the RemoteSettingsExperimentLoader. Differential Revision: https://phabricator.services.mozilla.com/D242800
175 lines
4.8 KiB
JavaScript
175 lines
4.8 KiB
JavaScript
/* 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/. */
|
|
|
|
const lazy = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
ExperimentAPI: "resource://nimbus/ExperimentAPI.sys.mjs",
|
|
FirefoxLabs: "resource://nimbus/FirefoxLabs.sys.mjs",
|
|
NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs",
|
|
NimbusTelemetry: "resource://nimbus/lib/Telemetry.sys.mjs",
|
|
});
|
|
|
|
ChromeUtils.defineLazyGetter(lazy, "log", () => {
|
|
const { Logger } = ChromeUtils.importESModule(
|
|
"resource://messaging-system/lib/Logger.sys.mjs"
|
|
);
|
|
return new Logger("NimbusMigrations");
|
|
});
|
|
|
|
function migration(name, fn) {
|
|
return { name, fn };
|
|
}
|
|
|
|
export const NIMBUS_MIGRATION_PREF = "nimbus.migrations.latest";
|
|
|
|
export const LABS_MIGRATION_FEATURE_MAP = {
|
|
"auto-pip": "firefox-labs-auto-pip",
|
|
"urlbar-ime-search": "firefox-labs-urlbar-ime-search",
|
|
"jpeg-xl": "firefox-labs-jpeg-xl",
|
|
};
|
|
|
|
async function migrateFirefoxLabsEnrollments() {
|
|
const bts = Cc["@mozilla.org/backgroundtasks;1"]?.getService(
|
|
Ci.nsIBackgroundTasks
|
|
);
|
|
|
|
if (bts?.isBackgroundTaskMode) {
|
|
// This migration does not apply to background task mode.
|
|
return;
|
|
}
|
|
|
|
await lazy.ExperimentAPI._rsLoader.finishedUpdating();
|
|
await lazy.ExperimentAPI._rsLoader.withUpdateLock(
|
|
async () => {
|
|
const labs = await lazy.FirefoxLabs.create();
|
|
|
|
let didEnroll = false;
|
|
|
|
for (const [feature, slug] of Object.entries(
|
|
LABS_MIGRATION_FEATURE_MAP
|
|
)) {
|
|
const pref =
|
|
lazy.NimbusFeatures[feature].manifest.variables.enabled.setPref.pref;
|
|
|
|
if (!labs.get(slug)) {
|
|
// If the recipe is not available then either it is no longer live or
|
|
// the targeting did not match.
|
|
continue;
|
|
}
|
|
|
|
if (!Services.prefs.getBoolPref(pref, false)) {
|
|
// Only enroll if the migration pref is set.
|
|
continue;
|
|
}
|
|
|
|
await labs.enroll(slug, "control");
|
|
|
|
// We need to overwrite the original pref value stored in the
|
|
// ExperimentStore so that unenrolling will disable the feature.
|
|
const enrollment = lazy.ExperimentAPI._manager.store.get(slug);
|
|
if (!enrollment) {
|
|
lazy.log.error(`Enrollment with ${slug} should exist but does not`);
|
|
continue;
|
|
}
|
|
if (!enrollment.active) {
|
|
lazy.log.error(
|
|
`Enrollment with slug ${slug} should be active but is not.`
|
|
);
|
|
continue;
|
|
}
|
|
|
|
const prefEntry = enrollment.prefs?.find(entry => entry.name === pref);
|
|
if (!prefEntry) {
|
|
lazy.log.error(
|
|
`Enrollment with slug ${slug} does not set pref ${pref}`
|
|
);
|
|
continue;
|
|
}
|
|
|
|
didEnroll = true;
|
|
prefEntry.originalValue = false;
|
|
}
|
|
|
|
if (didEnroll) {
|
|
// Trigger a save of the ExperimentStore since we've changed some data
|
|
// structures without using set().
|
|
// We do not have to sync these changes to child processes because the
|
|
// data is only used in the parent process.
|
|
lazy.ExperimentAPI._manager.store._store.saveSoon();
|
|
}
|
|
},
|
|
{ mode: "shared" }
|
|
);
|
|
}
|
|
|
|
export class MigrationError extends Error {
|
|
static Reason = Object.freeze({
|
|
UNKNOWN: "unknown",
|
|
});
|
|
|
|
constructor(reason) {
|
|
super(`Migration error: ${reason}`);
|
|
this.reason = reason;
|
|
}
|
|
}
|
|
|
|
export const NimbusMigrations = {
|
|
migration,
|
|
|
|
/**
|
|
* Apply any outstanding migrations.
|
|
*/
|
|
async applyMigrations() {
|
|
const latestMigration = Services.prefs.getIntPref(
|
|
NIMBUS_MIGRATION_PREF,
|
|
-1
|
|
);
|
|
let lastSuccess = latestMigration;
|
|
|
|
lazy.log.debug(`applyMigrations: latestMigration = ${latestMigration}`);
|
|
|
|
for (let i = latestMigration + 1; i < this.MIGRATIONS.length; i++) {
|
|
const migration = this.MIGRATIONS[i];
|
|
|
|
lazy.log.debug(
|
|
`applyMigrations: applying migration ${i}: ${migration.name}`
|
|
);
|
|
|
|
try {
|
|
await migration.fn();
|
|
} catch (e) {
|
|
lazy.log.error(
|
|
`applyMigrations: error running migration ${i} (${migration.name}): ${e}`
|
|
);
|
|
|
|
let reason = MigrationError.Reason.UNKNOWN;
|
|
if (e instanceof MigrationError) {
|
|
reason = e.reason;
|
|
}
|
|
|
|
lazy.NimbusTelemetry.recordMigration(migration.name, reason);
|
|
|
|
break;
|
|
}
|
|
|
|
lastSuccess = i;
|
|
|
|
lazy.log.debug(
|
|
`applyMigrations: applied migration ${i}: ${migration.name}`
|
|
);
|
|
|
|
lazy.NimbusTelemetry.recordMigration(migration.name);
|
|
}
|
|
|
|
if (latestMigration != lastSuccess) {
|
|
Services.prefs.setIntPref(NIMBUS_MIGRATION_PREF, lastSuccess);
|
|
}
|
|
},
|
|
|
|
MIGRATIONS: [
|
|
migration("firefox-labs-enrollments", migrateFirefoxLabsEnrollments),
|
|
],
|
|
};
|