Bug 1893722: Recover StoreID from prefs in the event of a profiles.ini reset. r=jhirsch
Differential Revision: https://phabricator.services.mozilla.com/D226806
This commit is contained in:
@@ -91,6 +91,7 @@ class SelectableProfileServiceClass {
|
|||||||
#asyncShutdownBlocker = null;
|
#asyncShutdownBlocker = null;
|
||||||
#initialized = false;
|
#initialized = false;
|
||||||
#groupToolkitProfile = null;
|
#groupToolkitProfile = null;
|
||||||
|
#storeID = null;
|
||||||
#currentProfile = null;
|
#currentProfile = null;
|
||||||
#everyWindowCallbackId = "SelectableProfileService";
|
#everyWindowCallbackId = "SelectableProfileService";
|
||||||
#defaultAvatars = [
|
#defaultAvatars = [
|
||||||
@@ -101,6 +102,7 @@ class SelectableProfileServiceClass {
|
|||||||
"shopping",
|
"shopping",
|
||||||
"star",
|
"star",
|
||||||
];
|
];
|
||||||
|
#initPromise = null;
|
||||||
static #dirSvc = null;
|
static #dirSvc = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -111,6 +113,23 @@ class SelectableProfileServiceClass {
|
|||||||
|
|
||||||
this.#groupToolkitProfile =
|
this.#groupToolkitProfile =
|
||||||
this.#profileService.currentProfile ?? this.#profileService.groupProfile;
|
this.#profileService.currentProfile ?? this.#profileService.groupProfile;
|
||||||
|
|
||||||
|
this.#storeID = this.#groupToolkitProfile?.storeID;
|
||||||
|
|
||||||
|
if (!this.#storeID) {
|
||||||
|
this.#storeID = Services.prefs.getCharPref(
|
||||||
|
"toolkit.profiles.storeID",
|
||||||
|
""
|
||||||
|
);
|
||||||
|
if (this.#storeID) {
|
||||||
|
// This can happen if profiles.ini has been reset by a version of Firefox prior to 67 and
|
||||||
|
// the current profile is not the current default for the group. We can recover by
|
||||||
|
// attempting to find the group profile from the database.
|
||||||
|
this.#initPromise = this.restoreStoreID()
|
||||||
|
.catch(console.error)
|
||||||
|
.finally(() => (this.#initPromise = null));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -167,6 +186,10 @@ class SelectableProfileServiceClass {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get storeID() {
|
||||||
|
return this.#storeID;
|
||||||
|
}
|
||||||
|
|
||||||
get groupToolkitProfile() {
|
get groupToolkitProfile() {
|
||||||
return this.#groupToolkitProfile;
|
return this.#groupToolkitProfile;
|
||||||
}
|
}
|
||||||
@@ -188,7 +211,7 @@ class SelectableProfileServiceClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async maybeCreateProfilesStorePath() {
|
async maybeCreateProfilesStorePath() {
|
||||||
if (!this.#groupToolkitProfile || this.#groupToolkitProfile.storeID) {
|
if (this.storeID) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,6 +225,7 @@ class SelectableProfileServiceClass {
|
|||||||
.replace("{", "")
|
.replace("{", "")
|
||||||
.split("-")[0];
|
.split("-")[0];
|
||||||
this.#groupToolkitProfile.storeID = storageID;
|
this.#groupToolkitProfile.storeID = storageID;
|
||||||
|
this.#storeID = storageID;
|
||||||
await this.#attemptFlushProfileService();
|
await this.#attemptFlushProfileService();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,22 +234,34 @@ class SelectableProfileServiceClass {
|
|||||||
|
|
||||||
return PathUtils.join(
|
return PathUtils.join(
|
||||||
SelectableProfileServiceClass.PROFILE_GROUPS_DIR,
|
SelectableProfileServiceClass.PROFILE_GROUPS_DIR,
|
||||||
`${this.#groupToolkitProfile.storeID}.sqlite`
|
`${this.storeID}.sqlite`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* At startup, store the nsToolkitProfile for the group.
|
* At startup, store the nsToolkitProfile for the group.
|
||||||
* Get the groupDBPath from the nsToolkitProfile, and connect to it.
|
* Get the groupDBPath from the nsToolkitProfile, and connect to it.
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
async init() {
|
init() {
|
||||||
|
if (!this.#initPromise) {
|
||||||
|
this.#initPromise = this.#init().finally(
|
||||||
|
() => (this.#initPromise = null)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.#initPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
async #init() {
|
||||||
if (this.#initialized || !this.groupToolkitProfile) {
|
if (this.#initialized || !this.groupToolkitProfile) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the storeID doesn't exist, we don't want to create the db until we
|
// If the storeID doesn't exist, we don't want to create the db until we
|
||||||
// need to so we early return.
|
// need to so we early return.
|
||||||
if (!this.groupToolkitProfile.storeID) {
|
if (!this.storeID) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,6 +383,33 @@ class SelectableProfileServiceClass {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async restoreStoreID() {
|
||||||
|
try {
|
||||||
|
await this.#init();
|
||||||
|
|
||||||
|
for (let profile of await this.getAllProfiles()) {
|
||||||
|
let groupProfile = this.#profileService.getProfileByDir(
|
||||||
|
await profile.rootDir
|
||||||
|
);
|
||||||
|
|
||||||
|
if (groupProfile) {
|
||||||
|
this.#groupToolkitProfile = groupProfile;
|
||||||
|
this.#groupToolkitProfile.storeID = this.storeID;
|
||||||
|
await this.#profileService.asyncFlush();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we were unable to find a matching toolkit profile then assume the
|
||||||
|
// store ID is bogus so clear it and uninit.
|
||||||
|
this.#storeID = null;
|
||||||
|
await this.uninit();
|
||||||
|
Services.prefs.clearUserPref("toolkit.profiles.storeID");
|
||||||
|
}
|
||||||
|
|
||||||
async handleEvent(event) {
|
async handleEvent(event) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case "activate": {
|
case "activate": {
|
||||||
@@ -422,11 +485,12 @@ class SelectableProfileServiceClass {
|
|||||||
* and vacuum the group DB.
|
* and vacuum the group DB.
|
||||||
*/
|
*/
|
||||||
async deleteProfileGroup() {
|
async deleteProfileGroup() {
|
||||||
if (this.getAllProfiles().length) {
|
if ((await this.getAllProfiles()).length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#groupToolkitProfile.storeID = null;
|
this.#groupToolkitProfile.storeID = null;
|
||||||
|
this.#storeID = null;
|
||||||
await this.#attemptFlushProfileService();
|
await this.#attemptFlushProfileService();
|
||||||
await this.vacuumAndCloseGroupDB();
|
await this.vacuumAndCloseGroupDB();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,18 @@ async function initSelectableProfileService() {
|
|||||||
await SelectableProfileService.maybeSetupDataStore();
|
await SelectableProfileService.maybeSetupDataStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRelativeProfilePath(path) {
|
||||||
|
let relativePath = path.getRelativePath(
|
||||||
|
Services.dirsvc.get("UAppData", Ci.nsIFile)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (AppConstants.platform === "win") {
|
||||||
|
relativePath = relativePath.replace("/", "\\");
|
||||||
|
}
|
||||||
|
|
||||||
|
return relativePath;
|
||||||
|
}
|
||||||
|
|
||||||
async function createTestProfile(profileData = {}) {
|
async function createTestProfile(profileData = {}) {
|
||||||
const SelectableProfileService = getSelectableProfileService();
|
const SelectableProfileService = getSelectableProfileService();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
add_task(
|
||||||
|
{
|
||||||
|
skip_if: () => !AppConstants.MOZ_SELECTABLE_PROFILES,
|
||||||
|
},
|
||||||
|
async function test_recover_storeID() {
|
||||||
|
startProfileService();
|
||||||
|
Services.prefs.setCharPref("toolkit.profiles.storeID", "foobar");
|
||||||
|
|
||||||
|
const SelectableProfileService = getSelectableProfileService();
|
||||||
|
await SelectableProfileService.init();
|
||||||
|
Assert.ok(
|
||||||
|
!SelectableProfileService.initialized,
|
||||||
|
"Didn't initialize the service"
|
||||||
|
);
|
||||||
|
|
||||||
|
let profile = SelectableProfileService.currentProfile;
|
||||||
|
Assert.ok(!profile, "Should not have a current profile");
|
||||||
|
Assert.equal(
|
||||||
|
getProfileService().currentProfile.storeID,
|
||||||
|
null,
|
||||||
|
"Should not have updated the store ID on the profile"
|
||||||
|
);
|
||||||
|
|
||||||
|
Assert.ok(
|
||||||
|
!Services.prefs.prefHasUserValue("toolkit.profiles.storeID"),
|
||||||
|
"Should have cleared the storeID pref"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { Sqlite } = ChromeUtils.importESModule(
|
||||||
|
"resource://gre/modules/Sqlite.sys.mjs"
|
||||||
|
);
|
||||||
|
|
||||||
|
add_task(
|
||||||
|
{
|
||||||
|
skip_if: () => !AppConstants.MOZ_SELECTABLE_PROFILES,
|
||||||
|
},
|
||||||
|
async function test_recover_storeID() {
|
||||||
|
startProfileService();
|
||||||
|
Services.prefs.setCharPref("toolkit.profiles.storeID", "foobar");
|
||||||
|
|
||||||
|
// The database needs to exist already
|
||||||
|
let groupsPath = PathUtils.join(
|
||||||
|
Services.dirsvc.get("UAppData", Ci.nsIFile).path,
|
||||||
|
"Profile Groups"
|
||||||
|
);
|
||||||
|
|
||||||
|
await IOUtils.makeDirectory(groupsPath);
|
||||||
|
let dbFile = PathUtils.join(groupsPath, "foobar.sqlite");
|
||||||
|
let db = await Sqlite.openConnection({
|
||||||
|
path: dbFile,
|
||||||
|
openNotExclusive: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
let path = getRelativeProfilePath(
|
||||||
|
getProfileService().currentProfile.rootDir
|
||||||
|
);
|
||||||
|
|
||||||
|
// Slightly annoying we have to replicate this...
|
||||||
|
await db.execute(`CREATE TABLE IF NOT EXISTS "Profiles" (
|
||||||
|
id INTEGER NOT NULL,
|
||||||
|
path TEXT NOT NULL UNIQUE,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
avatar TEXT NOT NULL,
|
||||||
|
themeL10nId TEXT NOT NULL,
|
||||||
|
themeFg TEXT NOT NULL,
|
||||||
|
themeBg TEXT NOT NULL,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);`);
|
||||||
|
await db.execute(
|
||||||
|
`INSERT INTO Profiles VALUES (NULL, :path, :name, :avatar, :themeL10nId, :themeFg, :themeBg);`,
|
||||||
|
{
|
||||||
|
path,
|
||||||
|
name: "Fake Profile",
|
||||||
|
avatar: "book",
|
||||||
|
themeL10nId: "default",
|
||||||
|
themeFg: "",
|
||||||
|
themeBg: "",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await db.close();
|
||||||
|
|
||||||
|
const SelectableProfileService = getSelectableProfileService();
|
||||||
|
await SelectableProfileService.init();
|
||||||
|
Assert.ok(
|
||||||
|
SelectableProfileService.initialized,
|
||||||
|
"Did initialize the service"
|
||||||
|
);
|
||||||
|
|
||||||
|
let profile = SelectableProfileService.currentProfile;
|
||||||
|
Assert.ok(profile, "Should have a current profile");
|
||||||
|
Assert.equal(profile.name, "Fake Profile");
|
||||||
|
Assert.equal(
|
||||||
|
getProfileService().currentProfile.storeID,
|
||||||
|
"foobar",
|
||||||
|
"Should have updated the store ID on the profile"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -2,6 +2,10 @@
|
|||||||
head = "../../../../../toolkit/profile/test/xpcshell/head.js head.js"
|
head = "../../../../../toolkit/profile/test/xpcshell/head.js head.js"
|
||||||
firefox-appdir = "browser"
|
firefox-appdir = "browser"
|
||||||
|
|
||||||
|
["test_fail_recover_storeID.js"]
|
||||||
|
|
||||||
|
["test_recover_storeID.js"]
|
||||||
|
|
||||||
["test_selectable_profile_launch.js"]
|
["test_selectable_profile_launch.js"]
|
||||||
|
|
||||||
["test_selectable_profile_service_exists.js"]
|
["test_selectable_profile_service_exists.js"]
|
||||||
|
|||||||
@@ -103,6 +103,14 @@ interface nsIToolkitProfileService : nsISupports
|
|||||||
*/
|
*/
|
||||||
nsIToolkitProfile getProfileByName(in AUTF8String aName);
|
nsIToolkitProfile getProfileByName(in AUTF8String aName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a profile by directory. Finds a profile with the matching root directory
|
||||||
|
*
|
||||||
|
* @param aRootDir The root directory to match against.
|
||||||
|
* @param aLocalDir And optional local directory to also match against.
|
||||||
|
*/
|
||||||
|
nsIToolkitProfile getProfileByDir(in nsIFile aRootDir, [optional] in nsIFile aLocalDir);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new profile.
|
* Create a new profile.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ using namespace mozilla;
|
|||||||
#define PROFILE_DB_VERSION "2"
|
#define PROFILE_DB_VERSION "2"
|
||||||
#define INSTALL_PREFIX "Install"
|
#define INSTALL_PREFIX "Install"
|
||||||
#define INSTALL_PREFIX_LENGTH 7
|
#define INSTALL_PREFIX_LENGTH 7
|
||||||
|
#define STORE_ID_PREF "toolkit.profiles.storeID"
|
||||||
|
|
||||||
struct KeyValue {
|
struct KeyValue {
|
||||||
KeyValue(const char* aKey, const char* aValue) : key(aKey), value(aValue) {}
|
KeyValue(const char* aKey, const char* aValue) : key(aKey), value(aValue) {}
|
||||||
@@ -357,32 +358,35 @@ nsToolkitProfile::SetStoreID(const nsACString& aStoreID) {
|
|||||||
mSection.get(), "StoreID", PromiseFlatCString(aStoreID).get());
|
mSection.get(), "StoreID", PromiseFlatCString(aStoreID).get());
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
rv = prefs->SetCharPref("toolkit.profiles.storeID", aStoreID);
|
rv = nsToolkitProfileService::gService->mProfileDB.SetString(
|
||||||
|
mSection.get(), "ShowSelector", mShowProfileSelector ? "1" : "0");
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
nsToolkitProfileService::gService->mGroupProfile = this;
|
if (nsToolkitProfileService::gService->mCurrent == this) {
|
||||||
} else {
|
rv = prefs->SetCharPref(STORE_ID_PREF, aStoreID);
|
||||||
rv = nsToolkitProfileService::gService->mProfileDB.DeleteString(
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
mSection.get(), "StoreID");
|
|
||||||
|
|
||||||
// If the string was not present in the ini file, just ignore the error.
|
nsToolkitProfileService::gService->mGroupProfile = this;
|
||||||
if (rv == NS_ERROR_FAILURE) {
|
|
||||||
rv = NS_OK;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// If the string was not present in the ini file, just ignore the error.
|
||||||
|
nsToolkitProfileService::gService->mProfileDB.DeleteString(mSection.get(),
|
||||||
|
"StoreID");
|
||||||
|
|
||||||
// We need a StoreID to show the profile selector, so if StoreID has been
|
// We need a StoreID to show the profile selector, so if StoreID has been
|
||||||
// removed, then remove ShowSelector also.
|
// removed, then remove ShowSelector also.
|
||||||
mShowProfileSelector = false;
|
mShowProfileSelector = false;
|
||||||
rv = nsToolkitProfileService::gService->mProfileDB.DeleteString(
|
|
||||||
mSection.get(), "ShowSelector");
|
// If the string was not present in the ini file, just ignore the error.
|
||||||
if (rv == NS_ERROR_FAILURE) {
|
nsToolkitProfileService::gService->mProfileDB.DeleteString(mSection.get(),
|
||||||
rv = NS_OK;
|
"ShowSelector");
|
||||||
|
|
||||||
|
if (nsToolkitProfileService::gService->mCurrent == this) {
|
||||||
|
rv = prefs->ClearUserPref(STORE_ID_PREF);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsToolkitProfileService::gService->mGroupProfile = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = prefs->ClearUserPref("toolkit.profiles.storeID");
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
nsToolkitProfileService::gService->mGroupProfile = nullptr;
|
|
||||||
}
|
}
|
||||||
mStoreID = aStoreID;
|
mStoreID = aStoreID;
|
||||||
|
|
||||||
@@ -670,13 +674,15 @@ void nsToolkitProfileService::CompleteStartup() {
|
|||||||
glean::startup::profile_database_version.Set(mStartupFileVersion);
|
glean::startup::profile_database_version.Set(mStartupFileVersion);
|
||||||
glean::startup::profile_count.Set(static_cast<uint32_t>(mProfiles.length()));
|
glean::startup::profile_count.Set(static_cast<uint32_t>(mProfiles.length()));
|
||||||
|
|
||||||
|
nsresult rv;
|
||||||
|
bool needsFlush = false;
|
||||||
|
|
||||||
// If we started into an unmanaged profile in a profile group, set the group
|
// If we started into an unmanaged profile in a profile group, set the group
|
||||||
// profile to be the managed profile belonging to the group.
|
// profile to be the managed profile belonging to the group.
|
||||||
nsresult rv;
|
|
||||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||||
if (!mCurrent) {
|
if (!mCurrent) {
|
||||||
nsCString storeID;
|
nsCString storeID;
|
||||||
rv = prefs->GetCharPref("toolkit.profiles.storeID", storeID);
|
rv = prefs->GetCharPref(STORE_ID_PREF, storeID);
|
||||||
if (NS_SUCCEEDED(rv) && !storeID.IsEmpty()) {
|
if (NS_SUCCEEDED(rv) && !storeID.IsEmpty()) {
|
||||||
mGroupProfile = GetProfileByStoreID(storeID);
|
mGroupProfile = GetProfileByStoreID(storeID);
|
||||||
}
|
}
|
||||||
@@ -685,32 +691,44 @@ void nsToolkitProfileService::CompleteStartup() {
|
|||||||
// profile for some group.
|
// profile for some group.
|
||||||
if (!mCurrent->mStoreID.IsVoid()) {
|
if (!mCurrent->mStoreID.IsVoid()) {
|
||||||
mGroupProfile = mCurrent;
|
mGroupProfile = mCurrent;
|
||||||
rv = prefs->SetCharPref("toolkit.profiles.storeID", mCurrent->mStoreID);
|
rv = prefs->SetCharPref(STORE_ID_PREF, mCurrent->mStoreID);
|
||||||
NS_ENSURE_SUCCESS_VOID(rv);
|
NS_ENSURE_SUCCESS_VOID(rv);
|
||||||
|
} else {
|
||||||
|
// Otherwise if the current profile has a store ID set in prefs but not in
|
||||||
|
// the database then restore it. This can happen if a version of Firefox
|
||||||
|
// prior to 67 has overwritten the database.
|
||||||
|
nsCString storeID;
|
||||||
|
rv = prefs->GetCharPref(STORE_ID_PREF, storeID);
|
||||||
|
if (NS_SUCCEEDED(rv) && !storeID.IsEmpty()) {
|
||||||
|
rv = mCurrent->SetStoreID(storeID);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
needsFlush = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mMaybeLockProfile) {
|
if (mMaybeLockProfile) {
|
||||||
nsCOMPtr<nsIToolkitShellService> shell =
|
nsCOMPtr<nsIToolkitShellService> shell =
|
||||||
do_GetService(NS_TOOLKITSHELLSERVICE_CONTRACTID);
|
do_GetService(NS_TOOLKITSHELLSERVICE_CONTRACTID);
|
||||||
if (!shell) {
|
if (shell) {
|
||||||
return;
|
bool isDefaultApp;
|
||||||
|
rv = shell->IsDefaultApplication(&isDefaultApp);
|
||||||
|
if (NS_SUCCEEDED(rv) && isDefaultApp) {
|
||||||
|
mProfileDB.SetString(mInstallSection.get(), "Locked", "1");
|
||||||
|
|
||||||
|
needsFlush = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool isDefaultApp;
|
if (needsFlush) {
|
||||||
nsresult rv = shell->IsDefaultApplication(&isDefaultApp);
|
// There is a very small chance that this could fail if something else
|
||||||
NS_ENSURE_SUCCESS_VOID(rv);
|
// overwrote the profiles database since we started up, probably less than
|
||||||
|
// a second ago. There isn't really a sane response here, all the other
|
||||||
if (isDefaultApp) {
|
// profile changes are already flushed so whether we fail to flush here or
|
||||||
mProfileDB.SetString(mInstallSection.get(), "Locked", "1");
|
// force quit the app makes no difference.
|
||||||
|
NS_ENSURE_SUCCESS_VOID(Flush());
|
||||||
// There is a very small chance that this could fail if something else
|
|
||||||
// overwrote the profiles database since we started up, probably less than
|
|
||||||
// a second ago. There isn't really a sane response here, all the other
|
|
||||||
// profile changes are already flushed so whether we fail to flush here or
|
|
||||||
// force quit the app makes no difference.
|
|
||||||
NS_ENSURE_SUCCESS_VOID(Flush());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2077,6 +2095,16 @@ void nsToolkitProfileService::GetProfileByDir(nsIFile* aRootDir,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsToolkitProfileService::GetProfileByDir(nsIFile* aRootDir, nsIFile* aLocalDir,
|
||||||
|
nsIToolkitProfile** aResult) {
|
||||||
|
RefPtr<nsToolkitProfile> result;
|
||||||
|
GetProfileByDir(aRootDir, aLocalDir, getter_AddRefs(result));
|
||||||
|
result.forget(aResult);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult NS_LockProfilePath(nsIFile* aPath, nsIFile* aTempPath,
|
nsresult NS_LockProfilePath(nsIFile* aPath, nsIFile* aTempPath,
|
||||||
nsIProfileUnlocker** aUnlocker,
|
nsIProfileUnlocker** aUnlocker,
|
||||||
nsIProfileLock** aResult) {
|
nsIProfileLock** aResult) {
|
||||||
|
|||||||
42
toolkit/profile/test/xpcshell/test_restore_storeID.js
Normal file
42
toolkit/profile/test/xpcshell/test_restore_storeID.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tests that the StoreID is restored if available in prefs.
|
||||||
|
*/
|
||||||
|
add_task(
|
||||||
|
{
|
||||||
|
skip_if: () => !AppConstants.MOZ_SELECTABLE_PROFILES,
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
|
let hash = xreDirProvider.getInstallHash();
|
||||||
|
let defaultProfile = makeRandomProfileDir("default");
|
||||||
|
let profilesIni = {
|
||||||
|
profiles: [
|
||||||
|
{
|
||||||
|
name: "default",
|
||||||
|
path: defaultProfile.leafName,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
installs: {
|
||||||
|
[hash]: {
|
||||||
|
default: defaultProfile.leafName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
writeProfilesIni(profilesIni);
|
||||||
|
|
||||||
|
Services.prefs.setCharPref("toolkit.profiles.storeID", "bishbashbosh");
|
||||||
|
|
||||||
|
let service = getProfileService();
|
||||||
|
let { profile } = selectStartupProfile();
|
||||||
|
|
||||||
|
Assert.equal(profile.rootDir.path, defaultProfile.path);
|
||||||
|
Assert.equal(service.currentProfile, profile);
|
||||||
|
Assert.equal(service.groupProfile, profile);
|
||||||
|
Assert.equal(profile.storeID, "bishbashbosh");
|
||||||
|
|
||||||
|
checkProfileService();
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -40,6 +40,8 @@ skip-if = ["os == 'android'"]
|
|||||||
|
|
||||||
["test_remove_default.js"]
|
["test_remove_default.js"]
|
||||||
|
|
||||||
|
["test_restore_storeID.js"]
|
||||||
|
|
||||||
["test_select_backgroundtasks_ephemeral.js"]
|
["test_select_backgroundtasks_ephemeral.js"]
|
||||||
|
|
||||||
["test_select_backgroundtasks_not_ephemeral_create.js"]
|
["test_select_backgroundtasks_not_ephemeral_create.js"]
|
||||||
|
|||||||
Reference in New Issue
Block a user