commit 4cbe981d6d500a5d551cca33e10bf9a6b55bc91a
parent 97f2a0770ea2e72a77b7028c9f530f61fda2fb7d
Author: Harsheet <hsohaney@mozilla.com>
Date: Fri, 12 Dec 2025 13:56:25 +0000
Bug 2003079 - Switch to using a lazy pref getter for the backup file name to sync the state and pref. r=mconley
Differential Revision: https://phabricator.services.mozilla.com/D274604
Diffstat:
2 files changed, 71 insertions(+), 27 deletions(-)
diff --git a/browser/components/backup/BackupService.sys.mjs b/browser/components/backup/BackupService.sys.mjs
@@ -210,7 +210,19 @@ XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"lastBackupFileName",
LAST_BACKUP_FILE_NAME_PREF_NAME,
- ""
+ "",
+ function onUpdateLastBackupFileName(_pref, _prevVal, newVal) {
+ let bs;
+ try {
+ bs = BackupService.get();
+ } catch (e) {
+ // This can throw if the BackupService hasn't initialized yet, which
+ // is a case we're okay to ignore.
+ }
+ if (bs) {
+ bs.onUpdateLastBackupFileName(newVal);
+ }
+ }
);
XPCOMUtils.defineLazyServiceGetter(
@@ -860,7 +872,7 @@ export class BackupService extends EventTarget {
encryptionEnabled: false,
/** @type {number?} Number of seconds since UNIX epoch */
lastBackupDate: null,
- lastBackupFileName: "",
+ lastBackupFileName: lazy.lastBackupFileName,
supportBaseLink: Services.urlFormatter.formatURLPref("app.support.baseURL"),
recoveryInProgress: false,
/**
@@ -1245,12 +1257,15 @@ export class BackupService extends EventTarget {
/**
* Returns a reference to a BackupService singleton. If this is the first time
* that this getter is accessed, this causes the BackupService singleton to be
- * be instantiated.
+ * instantiated.
*
* @static
- * @type {BackupService}
+ * @param {object} BackupResources
+ * Optional object containing BackupResource classes to initialize the instance with.
+ * @returns {BackupService}
+ * The BackupService singleton instance.
*/
- static init() {
+ static init(BackupResources = DefaultBackupResources) {
if (this.#instance) {
return this.#instance;
}
@@ -1258,7 +1273,7 @@ export class BackupService extends EventTarget {
// If there is unsent restore telemetry, send it now.
GleanPings.profileRestore.submit();
- this.#instance = new BackupService(DefaultBackupResources);
+ this.#instance = new BackupService(BackupResources);
this.#instance.checkForPostRecovery();
this.#instance.initBackupScheduler();
@@ -1267,6 +1282,22 @@ export class BackupService extends EventTarget {
}
/**
+ * Clears the BackupService singleton instance.
+ * This should only be used in tests.
+ *
+ * @static
+ */
+ static uninit() {
+ if (this.#instance) {
+ lazy.logConsole.debug("Uninitting the BackupService");
+
+ this.#instance.uninitBackupScheduler();
+ this.#instance.uninitStatusObservers();
+ this.#instance = null;
+ }
+ }
+
+ /**
* Returns a reference to the BackupService singleton. If the singleton has
* not been initialized, an error is thrown.
*
@@ -1916,9 +1947,6 @@ export class BackupService extends EventTarget {
await IOUtils.move(sourcePath, destPath);
Services.prefs.setStringPref(LAST_BACKUP_FILE_NAME_PREF_NAME, FILENAME);
- // It is expected that our caller will call stateUpdate(), so we skip doing
- // that here. This is done via the backupInProgress setter in createBackup.
- this.#_state.lastBackupFileName = FILENAME;
for (let childFilePath of existingChildren) {
let childFileName = PathUtils.filename(childFilePath);
@@ -3661,6 +3689,32 @@ export class BackupService extends EventTarget {
}
/**
+ * Updates lastBackupFileName in the backup service state. Should be called every time
+ * the value for browser.backup.scheduled.last-backup-file changes.
+ *
+ * @param {string} newLastBackupFileName
+ * Name of the last known backup file
+ */
+ onUpdateLastBackupFileName(newLastBackupFileName) {
+ lazy.logConsole.debug(
+ `The last backup file name is being updated to ${newLastBackupFileName}`
+ );
+
+ this.#_state.lastBackupFileName = newLastBackupFileName;
+
+ if (!newLastBackupFileName) {
+ lazy.logConsole.debug(
+ `Looks like we've cleared the last backup file name, let's also clear the last backup date`
+ );
+
+ this.#_state.lastBackupDate = null;
+ Services.prefs.clearUserPref(LAST_BACKUP_TIMESTAMP_PREF_NAME);
+ }
+
+ this.stateUpdate();
+ }
+
+ /**
* Returns the moz-icon URL of a file. To get the moz-icon URL, the
* file path is convered to a fileURI. If there is a problem retreiving
* the moz-icon due to an invalid file path, return null instead.
@@ -4006,16 +4060,8 @@ export class BackupService extends EventTarget {
LAST_BACKUP_TIMESTAMP_PREF_NAME,
0
);
- if (!lastBackupPrefValue) {
- this.#_state.lastBackupDate = null;
- } else {
- this.#_state.lastBackupDate = lastBackupPrefValue;
- }
- this.#_state.lastBackupFileName = Services.prefs.getStringPref(
- LAST_BACKUP_FILE_NAME_PREF_NAME,
- ""
- );
+ this.#_state.lastBackupDate = lastBackupPrefValue || null;
this.stateUpdate();
@@ -4587,7 +4633,7 @@ export class BackupService extends EventTarget {
async showBackupLocation() {
let backupFilePath = PathUtils.join(
lazy.backupDirPref,
- this.#_state.lastBackupFileName
+ lazy.lastBackupFileName
);
if (await IOUtils.exists(backupFilePath)) {
new lazy.nsLocalFile(backupFilePath).reveal();
@@ -4621,7 +4667,7 @@ export class BackupService extends EventTarget {
speedUpHeuristic = false,
} = {}) {
// Do we already have a backup for this browser? if so, we don't need to do any searching!
- if (this.#_state.lastBackupFileName) {
+ if (lazy.lastBackupFileName) {
return {
found: true,
multipleBackupsFound: false,
@@ -4862,13 +4908,7 @@ export class BackupService extends EventTarget {
});
}
- this.#_state.lastBackupDate = null;
- Services.prefs.clearUserPref(LAST_BACKUP_TIMESTAMP_PREF_NAME);
-
- this.#_state.lastBackupFileName = "";
Services.prefs.clearUserPref(LAST_BACKUP_FILE_NAME_PREF_NAME);
-
- this.stateUpdate();
} else {
lazy.logConsole.log(
"Not deleting last backup file, since none is known about."
diff --git a/browser/components/backup/tests/xpcshell/test_BackupService.js b/browser/components/backup/tests/xpcshell/test_BackupService.js
@@ -114,7 +114,7 @@ async function testCreateBackupHelper(sandbox, taskFn) {
.stub(FakeBackupResource3.prototype, "recover")
.resolves(fake3PostRecoveryEntry);
- let bs = new BackupService({
+ let bs = BackupService.init({
FakeBackupResource1,
FakeBackupResource2,
FakeBackupResource3,
@@ -392,6 +392,10 @@ async function testCreateBackupHelper(sandbox, taskFn) {
await maybeRemovePath(fakeProfilePath);
await maybeRemovePath(recoveredProfilePath);
await maybeRemovePath(EXPECTED_ARCHIVE_PATH);
+
+ Services.prefs.clearUserPref(LAST_BACKUP_FILE_NAME_PREF_NAME);
+
+ BackupService.uninit();
}
/**