Bug 1736876 - Stop migrating profiles into App Package builds. r=agashlin

The product experience migrating a profile when a non-MSIX Firefox is
running is not ideal, so we're going to always start with a fresh
profile for simplicity.

This is a straight backout of the "meat" of Bug 1709969 - Migrate from
an existing profile when running from an app package for the first
time, namely `hg backout -r 5136d2f684012dc3d586dcb10374f8c6eda8b6d7`.
The changes from follow-up Bug 1723298 (correcting test failures on
devedition), namely revision a4bca433c8f7003a90fda61248f38d9b389c394e,
were manually reverted and the test files deleted.

Differential Revision: https://phabricator.services.mozilla.com/D129066
This commit is contained in:
Nick Alexander 2021-10-20 21:54:07 +00:00
parent 7ba4305a9d
commit bf2b677248
11 changed files with 43 additions and 352 deletions

View File

@ -5581,7 +5581,6 @@ startup:
- 1522934
- 1570652
- 1623406
- 1709969
description: >
How the profile was selected during startup. One of the following reasons:
unknown:
@ -5612,9 +5611,6 @@ startup:
the old default profile and created a new profile.
firstrun-created-default:
A first run of the application created a new profile to use.
firstrun-migrated-default:
A first run of the application created a new profile to use, based on
migrating an existing profile from the same application.
default:
The default profile was selected as normal.
expires: "99"

View File

@ -19,7 +19,6 @@
# include <windows.h>
# include <shlobj.h>
# include "mozilla/PolicyChecks.h"
# include "WinUtils.h"
#endif
#ifdef XP_UNIX
# include <unistd.h>
@ -55,12 +54,9 @@
#include "nsProxyRelease.h"
#include "prinrval.h"
#include "prthread.h"
#include "mozilla/XREAppData.h"
using namespace mozilla;
extern const char gToolkitBuildID[];
#define DEV_EDITION_NAME "dev-edition-default"
#define DEFAULT_NAME "default"
#define COMPAT_FILE u"compatibility.ini"_ns
@ -1535,114 +1531,6 @@ nsresult nsToolkitProfileService::SelectStartupProfile(
}
}
if (IsWinPackageEnvironment() && mIsFirstRun && !mProfiles.isEmpty()) {
// Unlike with Snap packages, Windows packages do use dedicated profiles,
// so we don't need any special behavior to create a profile for them.
// However, it's likely that a user of an app package was previously using
// a non-packaged installation, and so has a dedicated profile for that
// installation, or possibly a "normal" default profile, and we want that
// user to have some level of continuity when they make the switch. What
// that means is that we need to identify the profile that is most likely to
// be the one the user was last working in, and run a profile migration into
// our new dedicated profile for this installation. This code handles the
// first part, identifying the profile, and then hands off to the regular
// profile cleanup code in XREMain to run the actual migration.
nsCOMPtr<nsIToolkitProfile> oldProfile;
// Packages aren't really associated with any non-packaged installation, so
// we have no way to look up any specific dedicated profile. The next best
// way we have to identify the most relevant profile is to find the one
// that was used most recently.
PRTime latestTime = 0;
// We'll also check whether each profile would be a downgrade, unless
// downgrades are being allowed.
bool allowDowngrade =
EnvHasValue("MOZ_ALLOW_DOWNGRADE") ||
CheckArg(*aArgc, aArgv, "allow-downgrade",
static_cast<const char**>(nullptr), CheckArgFlag::None);
for (nsCOMPtr<nsIToolkitProfile> profile : mProfiles) {
// Get this profile's last used time by checking the modified time on
// its lock file. This isn't an ideal way to decide when the profile was
// used last, but that time doesn't seem to be reliably written anywhere
// else that we can read from here.
nsCOMPtr<nsIFile> rootDir;
profile->GetRootDir(getter_AddRefs(rootDir));
nsCOMPtr<nsIFile> lockFile;
rootDir->Clone(getter_AddRefs(lockFile));
lockFile->Append(u"parent.lock"_ns);
PRTime lastLockTime = 0;
lockFile->GetLastModifiedTime(&lastLockTime);
if (lastLockTime <= latestTime) {
continue;
}
// This is (currently) the most recently used profile, but we need to
// make sure it hasn't been used by a newer version of the application,
// because if it has then we won't be able to load it. But also, this
// whole check is a waste of time if downgrade is enabled, so check for
// that condition first.
if (allowDowngrade) {
oldProfile = profile;
latestTime = lastLockTime;
continue;
}
nsCOMPtr<nsIFile> compatIniFile;
rootDir->Clone(getter_AddRefs(compatIniFile));
if (!compatIniFile) {
continue;
}
compatIniFile->Append(COMPAT_FILE);
nsINIParser compatIniParser;
if (NS_FAILED(compatIniParser.Init(compatIniFile))) {
continue;
}
nsAutoCString lastVersion;
if (NS_FAILED(compatIniParser.GetString("Compatibility", "LastVersion",
lastVersion))) {
continue;
}
nsAutoCString currentVersion;
if (gAppData) {
BuildCompatVersion(gAppData->version, gAppData->buildID,
gToolkitBuildID, currentVersion);
} else {
// gAppData is the preferred way to get the app version and build ID,
// but xpcshell doesn't initialize it, so we need a fallback. This
// assumes that the app and toolkit version/build ID are the same, which
// is not good to assume in general, but should be fine for xpcshell.
BuildCompatVersion(MOZILLA_VERSION, gToolkitBuildID, gToolkitBuildID,
currentVersion);
}
if (CompareCompatVersions(lastVersion, currentVersion) > 0) {
continue;
}
oldProfile = profile;
latestTime = lastLockTime;
}
// We can't invoke the migrator directly from here because the component
// manager isn't running yet, so signal to our caller that it should start a
// migration whenever possible. We need to do that before creating a new
// profile here because the refresh procedure will create one later.
if (oldProfile) {
mCurrent = oldProfile.forget();
mCurrent->GetRootDir(aRootDir);
mCurrent->GetLocalDir(aLocalDir);
NS_ADDREF(*aProfile = mCurrent);
mStartupReason = u"firstrun-migrated-default"_ns;
return NS_MIGRATE_INTO_PACKAGE;
}
}
// If this is a first run then create a new profile.
if (mIsFirstRun) {
// If we're configured to always show the profile manager then don't create
@ -1735,8 +1623,8 @@ nsresult nsToolkitProfileService::SelectStartupProfile(
GetDefaultProfile(getter_AddRefs(mCurrent));
// None of the profiles was marked as default (generally only happens if
// the user modifies profiles.ini manually). Let the user choose.
// None of the profiles was marked as default (generally only happens if the
// user modifies profiles.ini manually). Let the user choose.
if (!mCurrent) {
return NS_ERROR_SHOW_PROFILE_MANAGER;
}
@ -1790,22 +1678,14 @@ nsresult nsToolkitProfileService::CreateResetProfile(
* default as well.
*/
nsresult nsToolkitProfileService::ApplyResetProfile(
nsIToolkitProfile* aOldProfile, bool aDeleteOldProfile) {
nsIToolkitProfile* aOldProfile) {
// If the old profile would have been the default for old installs then mark
// the new profile as such.
if (mNormalDefault == aOldProfile) {
SetNormalDefault(mCurrent);
}
// For a "standard" profile reset, the current dedicated profile (the one that
// we've just created and reset into) should match the one that we've migrated
// from; that means we want to make this one our new dedicated default.
// If they don't match, it might be because we migrated from a different
// installation's dedicated profile, or a non-dedicated profile; in that case
// we aren't deleting the old profile, but we still need to set the new one as
// this installation's default.
if (mUseDedicatedProfile &&
(mDedicatedProfile == aOldProfile || !aDeleteOldProfile)) {
if (mUseDedicatedProfile && mDedicatedProfile == aOldProfile) {
bool wasLocked = false;
nsCString val;
if (NS_SUCCEEDED(
@ -1821,31 +1701,27 @@ nsresult nsToolkitProfileService::ApplyResetProfile(
}
}
if (aDeleteOldProfile) {
nsCString name;
nsresult rv = aOldProfile->GetName(name);
NS_ENSURE_SUCCESS(rv, rv);
// Don't remove the old profile's files until after we've successfully
// flushed the profile changes to disk.
rv = aOldProfile->Remove(false);
NS_ENSURE_SUCCESS(rv, rv);
// Switching the name will make this the default for dev-edition if
// appropriate.
rv = mCurrent->SetName(name);
NS_ENSURE_SUCCESS(rv, rv);
}
nsresult rv = Flush();
nsCString name;
nsresult rv = aOldProfile->GetName(name);
NS_ENSURE_SUCCESS(rv, rv);
if (aDeleteOldProfile) {
// Now that the profile changes are flushed, try to remove the old profile's
// files. If we fail the worst that will happen is that an orphan directory
// is left. Let this run in the background while we start up.
RemoveProfileFiles(aOldProfile, true);
}
// Don't remove the old profile's files until after we've successfully flushed
// the profile changes to disk.
rv = aOldProfile->Remove(false);
NS_ENSURE_SUCCESS(rv, rv);
// Switching the name will make this the default for dev-edition if
// appropriate.
rv = mCurrent->SetName(name);
NS_ENSURE_SUCCESS(rv, rv);
rv = Flush();
NS_ENSURE_SUCCESS(rv, rv);
// Now that the profile changes are flushed, try to remove the old profile's
// files. If we fail the worst that will happen is that an orphan directory is
// left. Let this run in the background while we start up.
RemoveProfileFiles(aOldProfile, true);
return NS_OK;
}
@ -2058,25 +1934,6 @@ bool nsToolkitProfileService::IsSnapEnvironment() {
return (strcmp(snapName, MOZ_APP_NAME) == 0);
}
/**
* Like Snaps, Windows app packages
* (https://docs.microsoft.com/en-us/windows/msix/overview) use a
* different installation directory for every version of the application, but
* we have an alternative method of obtaining a per-installation hash for such
* packages. Because of that, we don't disable dedicated profiles for them.
* We still need to know when we're in one though, because we have special
* migration behavior there; see comments in SelectStartupProfile.
*/
bool nsToolkitProfileService::IsWinPackageEnvironment() {
#ifdef XP_WIN
if (EnvHasValue("MOZ_TEST_EMULATE_PACKAGE") ||
mozilla::widget::WinUtils::HasPackageIdentity()) {
return true;
}
#endif
return false;
}
/**
* In some situations dedicated profile support does not work well. This
* includes a handful of linux distributions which always install different

View File

@ -82,8 +82,7 @@ class nsToolkitProfileService final : public nsIToolkitProfileService {
nsIToolkitProfile** aProfile, bool* aDidCreate,
bool* aWasDefaultSelection);
nsresult CreateResetProfile(nsIToolkitProfile** aNewProfile);
nsresult ApplyResetProfile(nsIToolkitProfile* aOldProfile,
bool aDeleteOldProfile = true);
nsresult ApplyResetProfile(nsIToolkitProfile* aOldProfile);
void CompleteStartup();
private:
@ -107,7 +106,6 @@ class nsToolkitProfileService final : public nsIToolkitProfileService {
nsresult MaybeMakeDefaultDedicatedProfile(nsIToolkitProfile* aProfile,
bool* aResult);
bool IsSnapEnvironment();
bool IsWinPackageEnvironment();
bool UseLegacyProfiles();
nsresult CreateDefaultProfile(nsIToolkitProfile** aResult);
void SetNormalDefault(nsIToolkitProfile* aProfile);

View File

@ -78,19 +78,6 @@ function simulateSnapEnvironment() {
gIsLegacy = true;
}
// This doesn't actually simulate running as a Windows package, because that
// isn't really possible. We're just telling the profile service to pretend it
// found a package environment running.
// Use of this function is not limited to Windows.
function simulateWinPackageEnvironment() {
let env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment
);
env.set("MOZ_TEST_EMULATE_PACKAGE", "1");
gIsLegacy = false;
}
function enableLegacyProfiles() {
let env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment
@ -195,8 +182,7 @@ function safeGet(ini, section, key) {
function writeCompatibilityIni(
dir,
appDir = FileUtils.getDir("CurProcD", []),
greDir = FileUtils.getDir("GreD", []),
options = { downgrade: false }
greDir = FileUtils.getDir("GreD", [])
) {
let target = dir.clone();
target.append("compatibility.ini");
@ -206,23 +192,12 @@ function writeCompatibilityIni(
);
let ini = factory.createINIParser().QueryInterface(Ci.nsIINIParserWriter);
if (options.downgrade) {
// Simulate attempting to downgrade a profile.
ini.setString(
"Compatibility",
"LastVersion",
"9999.0a1_99991231235959/99991231235959"
);
} else {
// Simulate attempting to upgrade a profile.
ini.setString(
"Compatibility",
"LastVersion",
"64.0a1_20180919123806/20180919123806"
);
}
// The profile service doesn't care about these so just use fixed values.
// The profile service doesn't care about these so just use fixed values
ini.setString(
"Compatibility",
"LastVersion",
"64.0a1_20180919123806/20180919123806"
);
ini.setString("Compatibility", "LastOSABI", "Darwin_x86_64-gcc3");
ini.setString(

View File

@ -1,49 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*
* Tests that we create a new, migrated profile when running out of a package.
*/
add_task(async () => {
// Create a default profile to migrate from.
let dir = makeRandomProfileDir(DEDICATED_NAME);
let profileData = {
options: {
startWithLastProfile: true,
},
profiles: [
{
name: DEDICATED_NAME,
path: dir.leafName,
default: true,
},
],
};
writeProfilesIni(profileData);
checkProfileService(profileData);
// Create a lockfile to make it look like this profile has been used recently.
let lockFile = dir.clone();
lockFile.append("parent.lock");
// Don't fail if the file already exists.
try {
lockFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o777);
} catch (_e) {}
await IOUtils.touch(lockFile.path);
// We need to have a compatibility.ini present for the package logic's
// downgrade check to pass.
writeCompatibilityIni(dir);
// Switch on simulated package mode and try to select a profile.
simulateWinPackageEnvironment();
let { rootDir, profile, didCreate } = selectStartupProfile();
checkStartupReason("firstrun-migrated-default");
Assert.ok(!didCreate, "Should not have created a new profile yet.");
Assert.ok(profile, "Should have selected an existing profile.");
Assert.ok(rootDir.equals(dir), "Should have selected our root dir.");
// The localDir will likely be different, but it doesn't really matter.
});

View File

@ -1,56 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*
* Tests that when running out of a package we won't migrate from an existing
profile that is out of date.
*/
add_task(async () => {
// Create a default profile to migrate from.
let dir = makeRandomProfileDir(DEDICATED_NAME);
let profileData = {
options: {
startWithLastProfile: true,
},
profiles: [
{
name: DEDICATED_NAME,
path: dir.leafName,
default: true,
},
],
};
writeProfilesIni(profileData);
checkProfileService(profileData);
// Create a lockfile to make it look like this profile has been used recently.
let lockFile = dir.clone();
lockFile.append("parent.lock");
// Don't fail if the file already exists.
try {
lockFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o777);
} catch (_e) {}
await IOUtils.touch(lockFile.path);
// Write a compatibility that will simulate attempting a downgrade.
writeCompatibilityIni(dir, undefined, undefined, { downgrade: true });
// Switch on simulated package mode and try to select a profile.
simulateWinPackageEnvironment();
let { rootDir, profile, didCreate } = selectStartupProfile();
// If the package-specific migration logic selects a profile to migrate, then
// we'll have "firstrun-migrated-default" set as the reason. But since we set
// up a downgrade, we should skip through that logic and get into the "normal"
// selection code for a dedicated profile. That code doesn't do any downgrade
// check (that wouldn't happen until later), so it should decide to claim our
// only profile as the new dedicated default.
checkStartupReason("firstrun-claimed-default");
Assert.ok(!didCreate, "Should not have created a new profile.");
Assert.ok(profile, "Should have selected an existing profile.");
Assert.ok(rootDir.equals(dir), "Should have selected our root dir.");
// The localDir will likely be different, but it doesn't really matter.
});

View File

@ -45,7 +45,3 @@ skip-if = devedition
[test_select_profile_argument.js]
[test_select_profile_argument_new.js]
[test_register_app_services_logger.js]
[test_select_profile_package.js]
skip-if = os != "win" # Package migration only runs on Windows
[test_select_profile_package_downgrade.js]
skip-if = os != "win" # Package migration only runs on Windows

View File

@ -30,7 +30,13 @@ extern const XREAppData* gAppData;
static const char kProfileProperties[] =
"chrome://mozapps/locale/profile/profileSelection.properties";
static nsresult ProfileResetCreateBackup(nsIToolkitProfile* aOldProfile) {
/**
* Spin up a thread to backup the old profile's main directory and delete the
* profile's local directory. Once complete have the profile service remove the
* old profile and if necessary make the new profile the default.
*/
nsresult ProfileResetCleanup(nsToolkitProfileService* aService,
nsIToolkitProfile* aOldProfile) {
nsresult rv;
nsCOMPtr<nsIFile> profileDir;
rv = aOldProfile->GetRootDir(getter_AddRefs(profileDir));
@ -138,22 +144,5 @@ static nsresult ProfileResetCreateBackup(nsIToolkitProfile* aOldProfile) {
auto* piWindow = nsPIDOMWindowOuter::From(progressWindow);
piWindow->Close();
return rv;
}
/**
* Spin up a thread to backup the old profile's main directory and delete the
* profile's local directory. Once complete have the profile service remove the
* old profile and if necessary make the new profile the default.
*/
nsresult ProfileResetCleanup(nsToolkitProfileService* aService,
nsIToolkitProfile* aOldProfile,
bool aDeleteOldProfile) {
// If we're leaving the old profile in place, then there's nothing to back up.
if (aDeleteOldProfile) {
nsresult rv = ProfileResetCreateBackup(aOldProfile);
NS_ENSURE_SUCCESS(rv, rv);
}
return aService->ApplyResetProfile(aOldProfile, aDeleteOldProfile);
return aService->ApplyResetProfile(aOldProfile);
}

View File

@ -13,8 +13,7 @@ static const char kResetProgressURL[] =
"chrome://global/content/resetProfileProgress.xhtml";
nsresult ProfileResetCleanup(nsToolkitProfileService* aService,
nsIToolkitProfile* aOldProfile,
bool aDeleteOldProfile);
nsIToolkitProfile* aOldProfile);
class ProfileResetCleanupResultTask : public mozilla::Runnable {
public:

View File

@ -2617,7 +2617,6 @@ static ReturnAbortOnError ShowProfileManager(
static bool gDoMigration = false;
static bool gDoProfileReset = false;
static bool gResetDeleteOldProfile = true;
static nsCOMPtr<nsIToolkitProfile> gResetOldProfile;
static nsresult LockProfile(nsINativeAppSupport* aNative, nsIFile* aRootDir,
@ -2720,19 +2719,6 @@ static nsresult SelectProfile(nsToolkitProfileService* aProfileSvc,
NS_ENSURE_SUCCESS(rv, rv);
if (rv == NS_MIGRATE_INTO_PACKAGE) {
if (!*aProfile) {
NS_WARNING(
"Attempted package profile migration without existing profile.");
return NS_ERROR_ABORT;
}
gDoProfileReset = true;
gResetDeleteOldProfile = false;
gDoMigration = true;
return NS_OK;
}
if (didCreate) {
// For a fresh install, we would like to let users decide
// to do profile migration on their own later after using.
@ -4989,8 +4975,9 @@ nsresult XREMain::XRE_mainRun() {
initializedJSContext = true;
}
if (NS_FAILED(ProfileResetCleanup(mProfileSvc, gResetOldProfile,
gResetDeleteOldProfile))) {
nsresult backupCreated =
ProfileResetCleanup(mProfileSvc, gResetOldProfile);
if (NS_FAILED(backupCreated)) {
NS_WARNING("Could not cleanup the profile that was reset");
}
}

View File

@ -872,7 +872,6 @@ with modules["PROFILE"]:
errors["NS_ERROR_LAUNCHED_CHILD_PROCESS"] = FAILURE(200)
errors["NS_ERROR_SHOW_PROFILE_MANAGER"] = FAILURE(201)
errors["NS_ERROR_DATABASE_CHANGED"] = FAILURE(202)
errors["NS_MIGRATE_INTO_PACKAGE"] = SUCCESS(203)
# =======================================================================