Bug 1528082: Add an environment variable to disable dedicated profiles for enterprise use. r=froydnj a=jcristau
authorDave Townsend <dtownsend@oxymoronical.com>
Thu, 20 Jun 2019 13:47:42 +0000
changeset 537076 5c9288e6d56a6f27610ceca5e418431fca93119f
parent 537075 1d577a6a7cd16bfa7f25c02dcfef10e32aa3bfc0
child 537077 66f621aa4cfa7d3edb7a410a8c98c9b3d8c8a13c
push id2082
push userffxbld-merge
push dateMon, 01 Jul 2019 08:34:18 +0000
treeherdermozilla-release@2fb19d0466d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj, jcristau
bugs1528082
milestone68.0
Bug 1528082: Add an environment variable to disable dedicated profiles for enterprise use. r=froydnj a=jcristau In some situations dedicated profile support does not work well. This includes a handful of linux distributions which always install different application versions to different locations, some application sandboxing systems as well as enterprise deployments. This environment variable provides a way to opt out of dedicated profiles for these cases. Differential Revision: https://phabricator.services.mozilla.com/D35249
toolkit/profile/nsToolkitProfileService.cpp
toolkit/profile/nsToolkitProfileService.h
toolkit/profile/xpcshell/head.js
toolkit/profile/xpcshell/test_legacy_empty.js
toolkit/profile/xpcshell/test_legacy_select.js
toolkit/profile/xpcshell/xpcshell.ini
--- a/toolkit/profile/nsToolkitProfileService.cpp
+++ b/toolkit/profile/nsToolkitProfileService.cpp
@@ -377,17 +377,17 @@ nsToolkitProfileService* nsToolkitProfil
 NS_IMPL_ISUPPORTS(nsToolkitProfileService, nsIToolkitProfileService)
 
 nsToolkitProfileService::nsToolkitProfileService()
     : mStartupProfileSelected(false),
       mStartWithLast(true),
       mIsFirstRun(true),
       mUseDevEditionProfile(false),
 #ifdef MOZ_DEDICATED_PROFILES
-      mUseDedicatedProfile(!IsSnapEnvironment()),
+      mUseDedicatedProfile(!IsSnapEnvironment() && !UseLegacyProfiles()),
 #else
       mUseDedicatedProfile(false),
 #endif
       mCreatedAlternateProfile(false),
       mStartupReason(NS_LITERAL_STRING("unknown")),
       mMaybeLockProfile(false),
       mUpdateChannel(NS_STRINGIFY(MOZ_UPDATE_CHANNEL)),
       mProfileDBExists(false),
@@ -1747,16 +1747,27 @@ nsToolkitProfileService::CreateProfile(n
  * So we can just disable dedicated profile support in this case and revert
  * back to the old method of just having a single default profile and still
  * get essentially the same benefits as dedicated profiles provides.
  */
 bool nsToolkitProfileService::IsSnapEnvironment() {
   return !!PR_GetEnv("SNAP_NAME");
 }
 
+/**
+ * In some situations dedicated profile support does not work well. This
+ * includes a handful of linux distributions which always install different
+ * application versions to different locations, some application sandboxing
+ * systems as well as enterprise deployments. This environment variable provides
+ * a way to opt out of dedicated profiles for these cases.
+ */
+bool nsToolkitProfileService::UseLegacyProfiles() {
+  return !!PR_GetEnv("MOZ_LEGACY_PROFILES");
+}
+
 struct FindInstallsClosure {
   nsINIParser* installData;
   nsTArray<nsCString>* installs;
 };
 
 static bool FindInstalls(const char* aSection, void* aClosure) {
   FindInstallsClosure* closure = static_cast<FindInstallsClosure*>(aClosure);
 
--- a/toolkit/profile/nsToolkitProfileService.h
+++ b/toolkit/profile/nsToolkitProfileService.h
@@ -100,16 +100,17 @@ class nsToolkitProfileService final : pu
 
   nsresult GetProfileDescriptor(nsIToolkitProfile* aProfile,
                                 nsACString& aDescriptor, bool* aIsRelative);
   bool IsProfileForCurrentInstall(nsIToolkitProfile* aProfile);
   void ClearProfileFromOtherInstalls(nsIToolkitProfile* aProfile);
   nsresult MaybeMakeDefaultDedicatedProfile(nsIToolkitProfile* aProfile,
                                             bool* aResult);
   bool IsSnapEnvironment();
+  bool UseLegacyProfiles();
   nsresult CreateDefaultProfile(nsIToolkitProfile** aResult);
   void SetNormalDefault(nsIToolkitProfile* aProfile);
 
   // Returns the known install hashes from the installs database. Modifying the
   // installs database is safe while iterating the returned array.
   nsTArray<nsCString> GetKnownInstalls();
 
   // Tracks whether SelectStartupProfile has been called.
--- a/toolkit/profile/xpcshell/head.js
+++ b/toolkit/profile/xpcshell/head.js
@@ -50,24 +50,32 @@ const ShellService = {
 
   QueryInterface: ChromeUtils.generateQI([Ci.nsIToolkitShellService]),
   ID: Components.ID("{ce724e0c-ed70-41c9-ab31-1033b0b591be}"),
   CONTRACT: "@mozilla.org/toolkit/shell-service;1",
 };
 
 ShellService.register();
 
-let gIsSnap = false;
+let gIsLegacy = false;
 
 function simulateSnapEnvironment() {
   let env = Cc["@mozilla.org/process/environment;1"].
           getService(Ci.nsIEnvironment);
   env.set("SNAP_NAME", "foo");
 
-  gIsSnap = true;
+  gIsLegacy = true;
+}
+
+function enableLegacyProfiles() {
+  let env = Cc["@mozilla.org/process/environment;1"].
+          getService(Ci.nsIEnvironment);
+  env.set("MOZ_LEGACY_PROFILES", "1");
+
+  gIsLegacy = true;
 }
 
 function getProfileService() {
   return Cc["@mozilla.org/toolkit/profile-service;1"].
          getService(Ci.nsIToolkitProfileService);
 }
 
 let PROFILE_DEFAULT = "default";
@@ -393,17 +401,17 @@ function checkProfileService(profileData
   // Sort to make matching easy.
   serviceProfiles.sort((a, b) => a.name.localeCompare(b.name));
   profileData.profiles.sort((a, b) => a.name.localeCompare(b.name));
 
   let hash = xreDirProvider.getInstallHash();
   let defaultPath = (profileData.installs && hash in profileData.installs) ?
                     profileData.installs[hash].default : null;
   let dedicatedProfile = null;
-  let snapProfile = null;
+  let legacyProfile = null;
 
   for (let i = 0; i < serviceProfiles.length; i++) {
     let serviceProfile = serviceProfiles[i];
     let expectedProfile = profileData.profiles[i];
 
     Assert.equal(serviceProfile.name, expectedProfile.name, "Should have the same name.");
 
     let expectedPath = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
@@ -411,25 +419,25 @@ function checkProfileService(profileData
     Assert.equal(serviceProfile.rootDir.path, expectedPath.path, "Should have the same path.");
 
     if (expectedProfile.path == defaultPath) {
       dedicatedProfile = serviceProfile;
     }
 
     if (AppConstants.MOZ_DEV_EDITION) {
       if (expectedProfile.name == PROFILE_DEFAULT) {
-        snapProfile = serviceProfile;
+        legacyProfile = serviceProfile;
       }
     } else if (expectedProfile.default) {
-      snapProfile = serviceProfile;
+      legacyProfile = serviceProfile;
     }
   }
 
-  if (gIsSnap) {
-    Assert.equal(service.defaultProfile, snapProfile, "Should have seen the right profile selected.");
+  if (gIsLegacy) {
+    Assert.equal(service.defaultProfile, legacyProfile, "Should have seen the right profile selected.");
   } else {
     Assert.equal(service.defaultProfile, dedicatedProfile, "Should have seen the right profile selected.");
   }
 
   if (verifyBackup) {
     checkBackup(profileData);
   }
 }
new file mode 100644
--- /dev/null
+++ b/toolkit/profile/xpcshell/test_legacy_empty.js
@@ -0,0 +1,24 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * Tests that setting MOZ_LEGACY_PROFILES disables dedicated profiles.
+ */
+
+add_task(async () => {
+  enableLegacyProfiles();
+
+  let service = getProfileService();
+  let { profile, didCreate } = selectStartupProfile();
+  checkStartupReason("firstrun-created-default");
+
+  Assert.ok(didCreate, "Should have created a new profile.");
+  Assert.equal(profile.name, PROFILE_DEFAULT, "Should have used the normal name.");
+  if (AppConstants.MOZ_DEV_EDITION) {
+    Assert.equal(service.profileCount, 2, "Should be two profiles.");
+  } else {
+    Assert.equal(service.profileCount, 1, "Should be only one profile.");
+  }
+
+  checkProfileService();
+});
new file mode 100644
--- /dev/null
+++ b/toolkit/profile/xpcshell/test_legacy_select.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * Tests that an old-style default profile not previously used by this build
+ * gets selected when configured for legacy profiles.
+ */
+
+add_task(async () => {
+  let defaultProfile = makeRandomProfileDir("default");
+
+  // Just pretend this profile was last used by something in the profile dir.
+  let greDir = gProfD.clone();
+  greDir.append("app");
+  writeCompatibilityIni(defaultProfile, greDir, greDir);
+
+  writeProfilesIni({
+    profiles: [{
+      name: PROFILE_DEFAULT,
+      path: defaultProfile.leafName,
+      default: true,
+    }],
+  });
+
+  enableLegacyProfiles();
+
+  let { profile: selectedProfile, didCreate } = selectStartupProfile();
+  checkStartupReason("default");
+
+  let profileData = readProfilesIni();
+  let installsINI = gDataHome.clone();
+  installsINI.append("installs.ini");
+  Assert.ok(!installsINI.exists(), "Installs database should not have been created.");
+
+  Assert.ok(profileData.options.startWithLastProfile, "Should be set to start with the last profile.");
+  Assert.equal(profileData.profiles.length, 1, "Should have the right number of profiles.");
+
+  let profile = profileData.profiles[0];
+  Assert.equal(profile.name, PROFILE_DEFAULT, "Should have the right name.");
+  Assert.equal(profile.path, defaultProfile.leafName, "Should be the original default profile.");
+  Assert.ok(profile.default, "Should be marked as the old-style default.");
+
+  checkProfileService(profileData);
+
+  Assert.ok(!didCreate, "Should not have created a new profile.");
+  Assert.ok(selectedProfile.rootDir.equals(defaultProfile), "Should be using the right directory.");
+  Assert.equal(selectedProfile.name, PROFILE_DEFAULT);
+});
--- a/toolkit/profile/xpcshell/xpcshell.ini
+++ b/toolkit/profile/xpcshell/xpcshell.ini
@@ -33,8 +33,10 @@ skip-if = devedition
 [test_skip_locked_environment.js]
 [test_snatch_environment_default.js]
 [test_check_backup.js]
 [test_missing_profilesini.js]
 [test_remove.js]
 [test_conflict_profiles.js]
 [test_conflict_installs.js]
 [test_invalid_descriptor.js]
+[test_legacy_empty.js]
+[test_legacy_select.js]