Bug 1678488 - Only show skeleton UI if autoselecting profile r=mossop

So this is an ugly solution, but it was the best I could come up with. We do
not want to show the skeleton UI if we're going to show the profile manager,
and we *will* show the profile manager if StartWithLastProfile=0 is under
[General] in profiles.ini. Accordingly the only ways to do the correct thing
here are to try to mirror edits that firefox makes to the profiles.ini file
to the registry, or to simply read the profiles.ini file ourselves. There are
many ways that profiles.ini could get out of sync with the registry if we
tried to mirror its state there, so going straight to the source of truth
seemed the best option.

There is one case which is still not covered here: if there is no profile for
our install marked as Default=1, then we will show the profile manager. This
should only be possible if the user manually edits their profiles.ini file,
however, and then it should resolve itself after one run, so I don't consider
it a significant enough problem to jump through all the hoops we would need
to jump through to solve it.

Depends on D98525

Differential Revision: https://phabricator.services.mozilla.com/D98936
This commit is contained in:
Doug Thayer 2020-12-17 16:44:01 +00:00
parent 12602737b0
commit 42a30153d4
2 changed files with 74 additions and 3 deletions

View File

@ -18,9 +18,10 @@
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/BaseProfilerMarkers.h"
#include "mozilla/FStream.h"
#include "mozilla/HelperMacros.h"
#include "mozilla/glue/Debug.h"
#include "mozilla/BaseProfilerMarkers.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/UniquePtrExtensions.h"
@ -331,6 +332,58 @@ static bool TryGetSkeletonUILock() {
return lockFile != INVALID_HANDLE_VALUE;
}
const char kGeneralSection[] = "[General]";
const char kStartWithLastProfile[] = "StartWithLastProfile=";
static bool ProfileDbHasStartWithLastProfile(IFStream& iniContents) {
bool inGeneral = false;
std::string line;
while (std::getline(iniContents, line)) {
int whitespace = 0;
while (line.length() > whitespace &&
(line[whitespace] == ' ' || line[whitespace] == '\t')) {
whitespace++;
}
line.erase(0, whitespace);
if (line.compare(kGeneralSection) == 0) {
inGeneral = true;
} else if (inGeneral) {
if (line[0] == '[') {
inGeneral = false;
} else {
if (line.find(kStartWithLastProfile) == 0) {
char val = line.c_str()[sizeof(kStartWithLastProfile) - 1];
if (val == '0') {
return false;
} else if (val == '1') {
return true;
}
}
}
}
}
// If we don't find it in the .ini file, we interpret that as true
return true;
}
static bool CheckForStartWithLastProfile() {
auto roamingAppData = GetKnownFolderPath(FOLDERID_RoamingAppData);
if (!roamingAppData) {
return false;
}
std::wstring profileDbPath(roamingAppData.get());
profileDbPath.append(
L"\\" MOZ_APP_VENDOR L"\\" MOZ_APP_BASENAME L"\\profiles.ini");
IFStream profileDb(profileDbPath.c_str());
if (profileDb.fail()) {
return false;
}
return ProfileDbHasStartWithLastProfile(profileDb);
}
// We could use nsAutoRegKey, but including nsWindowsHelpers.h causes build
// failures in random places because we're in mozglue. Overall it should be
// simpler and cleaner to just step around that issue with this class:
@ -1470,7 +1523,8 @@ static bool EnvHasValue(const char* name) {
// which is visually jarring and can also be unpredictable - there's no
// guarantee that the code which handles the non-default window is set up to
// properly handle the transition from the skeleton UI window.
bool AreAllCmdlineArgumentsApproved(int argc, char** argv) {
bool AreAllCmdlineArgumentsApproved(int argc, char** argv,
bool* explicitProfile) {
const char* approvedArgumentsArray[] = {
// These won't cause the browser to be visualy different in any way
"new-instance", "no-remote", "browser", "foreground", "setDefaultBrowser",
@ -1515,6 +1569,7 @@ bool AreAllCmdlineArgumentsApproved(int argc, char** argv) {
}
#ifdef MOZILLA_OFFICIAL
int profileArgIndex = -1;
// If we're running mochitests or direct marionette tests, those specify a
// temporary profile, and we want to ensure that we get the added coverage
// from those.
@ -1524,10 +1579,13 @@ bool AreAllCmdlineArgumentsApproved(int argc, char** argv) {
if (!approvedArguments.append("profile")) {
return false;
}
profileArgIndex = approvedArguments.length() - 1;
break;
}
}
#else
int profileArgIndex = approvedArguments.length() - 1;
#endif
for (int i = 1; i < argc; ++i) {
@ -1558,6 +1616,10 @@ bool AreAllCmdlineArgumentsApproved(int argc, char** argv) {
// casing would visually alter the firefox window.
if (!_stricmp(flag, approvedArg)) {
approved = true;
if (i == profileArgIndex) {
*explicitProfile = true;
}
break;
}
}
@ -1581,7 +1643,8 @@ void CreateAndStorePreXULSkeletonUI(HINSTANCE hInstance, int argc,
const TimeStamp skeletonStart = TimeStamp::NowUnfuzzed();
#endif
if (!AreAllCmdlineArgumentsApproved(argc, argv) ||
bool explicitProfile = false;
if (!AreAllCmdlineArgumentsApproved(argc, argv, &explicitProfile) ||
EnvHasValue("MOZ_SAFE_MODE_RESTART") || EnvHasValue("XRE_PROFILE_PATH") ||
EnvHasValue("MOZ_RESET_PROFILE_RESTART")) {
sPreXULSkeletonUIDisallowed = true;
@ -1619,6 +1682,10 @@ void CreateAndStorePreXULSkeletonUI(HINSTANCE hInstance, int argc,
return;
}
if (!explicitProfile && !CheckForStartWithLastProfile()) {
return;
}
WNDCLASSW wc;
wc.style = CS_DBLCLKS;
wc.lpfnWndProc = PreXULSkeletonUIProc;

View File

@ -949,6 +949,10 @@ nsresult nsToolkitProfileService::Init() {
NS_IMETHODIMP
nsToolkitProfileService::SetStartWithLastProfile(bool aValue) {
if (mStartWithLast != aValue) {
// Note: the skeleton ui (see PreXULSkeletonUI.cpp) depends on this
// having this name and being under General. If that ever changes,
// the skeleton UI will just need to be updated. If it changes frequently,
// it's probably best we just mirror the value to the registry here.
nsresult rv = mProfileDB.SetString("General", "StartWithLastProfile",
aValue ? "1" : "0");
NS_ENSURE_SUCCESS(rv, rv);