Bug 1354262 - remove MOZ_DEV_EDITION in favor of a pref; b?bsmedberg draft
authorTom Tromey <tom@tromey.com>
Wed, 12 Apr 2017 12:06:29 -0600
changeset 562899 8dd05a4c2bcba81b8cac4f39435d994f2062d5f7
parent 562898 204ab9447d903af13f224b2ae64c0e0e242033d4
child 624352 10122f77644f70f73fa023faef66baf5b97fcdef
push id54157
push userbmo:ttromey@mozilla.com
push dateFri, 14 Apr 2017 17:17:11 +0000
bugs1354262
milestone55.0a1
Bug 1354262 - remove MOZ_DEV_EDITION in favor of a pref; b?bsmedberg This changes MOZ_DEV_EDITION from a compile-time flag to a runtime flag, in particular allowing it to be set in a repack. It adds a new special "devEdition" method to nsIToolkitProfileService so that the devedition flag can be propagated from nsAppRunner. MozReview-Commit-ID: JbdNmv3PX3V
browser/app/profile/firefox.js
devtools/client/preferences/devtools.js
devtools/client/webide/moz.build
devtools/client/webide/webide-prefs.js
old-configure.in
toolkit/profile/nsIToolkitProfileService.idl
toolkit/profile/nsToolkitProfileService.cpp
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsAppRunner.h
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -930,21 +930,17 @@ pref("toolkit.crashreporter.infoURL",
 
 // base URL for web-based support pages
 pref("app.support.baseURL", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/");
 
 // a11y conflicts with e10s support page
 pref("app.support.e10sAccessibilityUrl", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/accessibility-ppt");
 
 // base url for web-based feedback pages
-#ifdef MOZ_DEV_EDITION
-pref("app.feedback.baseURL", "https://input.mozilla.org/%LOCALE%/feedback/firefoxdev/%VERSION%/");
-#else
 pref("app.feedback.baseURL", "https://input.mozilla.org/%LOCALE%/feedback/%APP%/%VERSION%/");
-#endif
 
 
 // Name of alternate about: page for certificate errors (when undefined, defaults to about:neterror)
 pref("security.alternate_certificate_error_page", "certerror");
 
 // Whether to start the private browsing mode at application startup
 pref("browser.privatebrowsing.autostart", false);
 
@@ -1171,28 +1167,19 @@ pref("services.sync.prefs.sync.xpinstall
 // A preference that controls whether we should show the icon for a remote tab.
 // This pref has no UI but exists because some people may be concerned that
 // fetching these icons to show remote tabs may leak information about that
 // user's tabs and bookmarks. Note this pref is also synced.
 pref("services.sync.syncedTabs.showRemoteIcons", true);
 
 pref("services.sync.sendTabToDevice.enabled", true);
 
-#ifdef MOZ_DEV_EDITION
-pref("devtools.devedition", true);
-#else
 pref("devtools.devedition", false);
-#endif
 
-// Developer edition preferences
-#ifdef MOZ_DEV_EDITION
-sticky_pref("lightweightThemes.selectedThemeID", "firefox-compact-dark@mozilla.org");
-#else
 sticky_pref("lightweightThemes.selectedThemeID", "");
-#endif
 
 // Whether the character encoding menu is under the main Firefox button. This
 // preference is a string so that localizers can alter it.
 pref("browser.menu.showCharacterEncoding", "chrome://browser/locale/browser.properties");
 
 // Allow using tab-modal prompts when possible.
 pref("prompts.tab_modal.enabled", true);
 
@@ -1379,21 +1366,17 @@ pref("identity.sync.tokenserver.uri", "h
 
 // URLs for promo links to mobile browsers. Note that consumers are expected to
 // append a value for utm_campaign.
 pref("identity.mobilepromo.android", "https://www.mozilla.org/firefox/android/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=");
 pref("identity.mobilepromo.ios", "https://www.mozilla.org/firefox/ios/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=");
 
 // Migrate any existing Firefox Account data from the default profile to the
 // Developer Edition profile.
-#ifdef MOZ_DEV_EDITION
-pref("identity.fxaccounts.migrateToDevEdition", true);
-#else
 pref("identity.fxaccounts.migrateToDevEdition", false);
-#endif
 
 // On GTK, we now default to showing the menubar only when alt is pressed:
 #ifdef MOZ_WIDGET_GTK
 pref("ui.key.menuAccessKeyFocuses", true);
 #endif
 
 // Encrypted media extensions.
 #ifdef XP_LINUX
--- a/devtools/client/preferences/devtools.js
+++ b/devtools/client/preferences/devtools.js
@@ -210,21 +210,17 @@ pref("devtools.scratchpad.enabled", fals
 
 // Make sure the DOM panel is hidden by default
 pref("devtools.dom.enabled", false);
 
 // Web Audio Editor Inspector Width should be a preference
 pref("devtools.webaudioeditor.inspectorWidth", 300);
 
 // Default theme ("dark" or "light")
-#ifdef MOZ_DEV_EDITION
-sticky_pref("devtools.theme", "dark");
-#else
 sticky_pref("devtools.theme", "light");
-#endif
 
 // Web console filters
 pref("devtools.webconsole.filter.error", true);
 pref("devtools.webconsole.filter.warn", true);
 pref("devtools.webconsole.filter.info", true);
 pref("devtools.webconsole.filter.log", true);
 pref("devtools.webconsole.filter.debug", true);
 pref("devtools.webconsole.filter.css", false);
--- a/devtools/client/webide/moz.build
+++ b/devtools/client/webide/moz.build
@@ -13,14 +13,14 @@ DIRS += [
 
 BROWSER_CHROME_MANIFESTS += [
     'test/browser.ini'
 ]
 MOCHITEST_CHROME_MANIFESTS += [
     'test/chrome.ini'
 ]
 
-JS_PREFERENCE_PP_FILES += [
+JS_PREFERENCE_FILES += [
     'webide-prefs.js',
 ]
 
 with Files('**'):
     BUG_COMPONENT = ('Firefox', 'Developer Tools: WebIDE')
--- a/devtools/client/webide/webide-prefs.js
+++ b/devtools/client/webide/webide-prefs.js
@@ -18,18 +18,13 @@ pref("devtools.webide.adbAddonURL", "htt
 pref("devtools.webide.adbAddonID", "adbhelper@mozilla.org");
 pref("devtools.webide.adaptersAddonURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/valence/#OS#/valence-#OS#-latest.xpi");
 pref("devtools.webide.adaptersAddonID", "fxdevtools-adapters@mozilla.org");
 pref("devtools.webide.monitorWebSocketURL", "ws://localhost:9000");
 pref("devtools.webide.lastConnectedRuntime", "");
 pref("devtools.webide.lastSelectedProject", "");
 pref("devtools.webide.logSimulatorOutput", false);
 pref("devtools.webide.widget.autoinstall", true);
-#ifdef MOZ_DEV_EDITION
-pref("devtools.webide.widget.enabled", true);
-pref("devtools.webide.widget.inNavbarByDefault", true);
-#else
 pref("devtools.webide.widget.enabled", false);
 pref("devtools.webide.widget.inNavbarByDefault", false);
-#endif
 pref("devtools.webide.zoom", "1");
 pref("devtools.webide.busyTimeout", 10000);
 pref("devtools.webide.autosaveFiles", true);
--- a/old-configure.in
+++ b/old-configure.in
@@ -5417,20 +5417,16 @@ if test "$ACCESSIBILITY" -a "$MOZ_ENABLE
     ATK_MAJOR_VERSION=`echo ${ATK_FULL_VERSION} | $AWK -F\. '{ print $1 }'`
     ATK_MINOR_VERSION=`echo ${ATK_FULL_VERSION} | $AWK -F\. '{ print $2 }'`
     ATK_REV_VERSION=`echo ${ATK_FULL_VERSION} | $AWK -F\. '{ print $3 }'`
     AC_DEFINE_UNQUOTED(ATK_MAJOR_VERSION, $ATK_MAJOR_VERSION)
     AC_DEFINE_UNQUOTED(ATK_MINOR_VERSION, $ATK_MINOR_VERSION)
     AC_DEFINE_UNQUOTED(ATK_REV_VERSION, $ATK_REV_VERSION)
 fi
 
-if test -n "$MOZ_DEV_EDITION"; then
-    AC_DEFINE(MOZ_DEV_EDITION)
-fi
-
 if test "$MOZ_DEBUG"; then
     A11Y_LOG=1
 fi
 case "$MOZ_UPDATE_CHANNEL" in
 aurora|beta|release|esr)
     ;;
 *)
     A11Y_LOG=1
--- a/toolkit/profile/nsIToolkitProfileService.idl
+++ b/toolkit/profile/nsIToolkitProfileService.idl
@@ -87,16 +87,22 @@ interface nsIToolkitProfileService : nsI
      *         The name of the vendor
      * @return The created profile.
      */                                    
     nsIToolkitProfile createDefaultProfileForApp(in AUTF8String aProfileName,
                                                  in AUTF8String aAppName,
                                                  in AUTF8String aVendorName);
 
     /**
+     * Set special "devedition" flag.  This changes some aspects of
+     * default profile selection.  Once set this cannot be undone.
+     */
+    void developerEdition();
+
+    /**
      * Returns the number of profiles.
      * @return 0, 1, or 2. More than 2 profiles will always return 2.
      */
     readonly attribute unsigned long profileCount;
 
     /**
      * Flush the profiles list file.
      */
--- a/toolkit/profile/nsToolkitProfileService.cpp
+++ b/toolkit/profile/nsToolkitProfileService.cpp
@@ -107,22 +107,23 @@ class nsToolkitProfileService final : pu
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSITOOLKITPROFILESERVICE
 
 private:
     friend class nsToolkitProfile;
     friend class nsToolkitProfileFactory;
-    friend nsresult NS_NewToolkitProfileService(nsIToolkitProfileService**);
+    friend nsresult NS_NewToolkitProfileService(nsIToolkitProfileService**, bool);
 
-    nsToolkitProfileService() :
+    nsToolkitProfileService(bool aDevEdition) :
         mDirty(false),
         mStartWithLast(true),
-        mStartOffline(false)
+        mStartOffline(false),
+        mDevEdition(aDevEdition)
     {
         gService = this;
     }
     ~nsToolkitProfileService()
     {
         gService = nullptr;
     }
 
@@ -142,16 +143,17 @@ private:
     nsCOMPtr<nsIToolkitProfile> mChosen;
     nsCOMPtr<nsIToolkitProfile> mDefault;
     nsCOMPtr<nsIFile>           mAppData;
     nsCOMPtr<nsIFile>           mTempData;
     nsCOMPtr<nsIFile>           mListFile;
     bool mDirty;
     bool mStartWithLast;
     bool mStartOffline;
+    bool mDevEdition;
 
     static nsToolkitProfileService *gService;
 
     class ProfileEnumerator final : public nsISimpleEnumerator
     {
     public:
         NS_DECL_ISUPPORTS
         NS_DECL_NSISIMPLEENUMERATOR
@@ -420,31 +422,31 @@ nsToolkitProfileService::Init()
 
     nsAutoCString buffer;
     rv = parser.GetString("General", "StartWithLastProfile", buffer);
     if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("0"))
         mStartWithLast = false;
 
     nsToolkitProfile* currentProfile = nullptr;
 
-#ifdef MOZ_DEV_EDITION
-    nsCOMPtr<nsIFile> ignoreSeparateProfile;
-    rv = mAppData->Clone(getter_AddRefs(ignoreSeparateProfile));
-    if (NS_FAILED(rv))
-        return rv;
+    bool shouldIgnoreSeparateProfile = false;
+    if (mDevEdition) {
+        nsCOMPtr<nsIFile> ignoreSeparateProfile;
+        rv = mAppData->Clone(getter_AddRefs(ignoreSeparateProfile));
+        if (NS_FAILED(rv))
+            return rv;
 
-    rv = ignoreSeparateProfile->AppendNative(NS_LITERAL_CSTRING("ignore-dev-edition-profile"));
-    if (NS_FAILED(rv))
-        return rv;
+        rv = ignoreSeparateProfile->AppendNative(NS_LITERAL_CSTRING("ignore-dev-edition-profile"));
+        if (NS_FAILED(rv))
+            return rv;
 
-    bool shouldIgnoreSeparateProfile;
-    rv = ignoreSeparateProfile->Exists(&shouldIgnoreSeparateProfile);
-    if (NS_FAILED(rv))
-        return rv;
-#endif
+        rv = ignoreSeparateProfile->Exists(&shouldIgnoreSeparateProfile);
+        if (NS_FAILED(rv))
+            return rv;
+    }
 
     unsigned int c = 0;
     bool foundAuroraDefault = false;
     for (c = 0; true; ++c) {
         nsAutoCString profileID("Profile");
         profileID.AppendInt(c);
 
         rv = parser.GetString(profileID.get(), "IsRelative", buffer);
@@ -496,44 +498,44 @@ nsToolkitProfileService::Init()
                                               currentProfile, false);
         NS_ENSURE_TRUE(currentProfile, NS_ERROR_OUT_OF_MEMORY);
 
         rv = parser.GetString(profileID.get(), "Default", buffer);
         if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("1") && !foundAuroraDefault) {
             mChosen = currentProfile;
             this->SetDefaultProfile(currentProfile);
         }
-#ifdef MOZ_DEV_EDITION
-        // Use the dev-edition-default profile if this is an Aurora build and
-        // ignore-dev-edition-profile is not present.
-        if (name.EqualsLiteral("dev-edition-default") && !shouldIgnoreSeparateProfile) {
-            mChosen = currentProfile;
-            foundAuroraDefault = true;
+        if (mDevEdition) {
+            // Use the dev-edition-default profile if this is an Aurora build and
+            // ignore-dev-edition-profile is not present.
+            if (name.EqualsLiteral("dev-edition-default") && !shouldIgnoreSeparateProfile) {
+                mChosen = currentProfile;
+                foundAuroraDefault = true;
+            }
         }
-#endif
     }
 
-#ifdef MOZ_DEV_EDITION
-    if (!foundAuroraDefault && !shouldIgnoreSeparateProfile) {
-        // If a single profile exists, it may not be already marked as default.
-        // Do it now to avoid problems when we create the dev-edition-default profile.
-        if (!mChosen && mFirst && !mFirst->mNext)
-            this->SetDefaultProfile(mFirst);
+    if (mDevEdition) {
+        if (!foundAuroraDefault && !shouldIgnoreSeparateProfile) {
+            // If a single profile exists, it may not be already marked as default.
+            // Do it now to avoid problems when we create the dev-edition-default profile.
+            if (!mChosen && mFirst && !mFirst->mNext)
+                this->SetDefaultProfile(mFirst);
 
-        // Create a default profile for aurora, if none was found.
-        nsCOMPtr<nsIToolkitProfile> profile;
-        rv = CreateProfile(nullptr,
-                           NS_LITERAL_CSTRING("dev-edition-default"),
-                           getter_AddRefs(profile));
-        if (NS_FAILED(rv)) return rv;
-        mChosen = profile;
-        rv = Flush();
-        if (NS_FAILED(rv)) return rv;
+            // Create a default profile for aurora, if none was found.
+            nsCOMPtr<nsIToolkitProfile> profile;
+            rv = CreateProfile(nullptr,
+                               NS_LITERAL_CSTRING("dev-edition-default"),
+                               getter_AddRefs(profile));
+            if (NS_FAILED(rv)) return rv;
+            mChosen = profile;
+            rv = Flush();
+            if (NS_FAILED(rv)) return rv;
+        }
     }
-#endif
 
     if (!mChosen && mFirst && !mFirst->mNext) // only one profile
         mChosen = mFirst;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsToolkitProfileService::SetStartWithLastProfile(bool aValue)
@@ -930,16 +932,23 @@ nsToolkitProfileService::GetProfileCount
         *aResult = 1;
     else
         *aResult = 2;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
+nsToolkitProfileService::DeveloperEdition()
+{
+    mDevEdition = true;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 nsToolkitProfileService::Flush()
 {
     // Errors during writing might cause unhappy semi-written files.
     // To avoid this, write the entire thing to a buffer, then write
     // that buffer to disk.
 
     nsresult rv;
     uint32_t pCount = 0;
@@ -1019,17 +1028,17 @@ nsToolkitProfileFactory::CreateInstance(
                                         void** aResult)
 {
     if (aOuter)
         return NS_ERROR_NO_AGGREGATION;
 
     nsCOMPtr<nsIToolkitProfileService> profileService =
         nsToolkitProfileService::gService;
     if (!profileService) {
-        nsresult rv = NS_NewToolkitProfileService(getter_AddRefs(profileService));
+        nsresult rv = NS_NewToolkitProfileService(getter_AddRefs(profileService), false);
         if (NS_FAILED(rv))
             return rv;
     }
     return profileService->QueryInterface(aIID, aResult);
 }
 
 NS_IMETHODIMP
 nsToolkitProfileFactory::LockFactory(bool aVal)
@@ -1044,19 +1053,19 @@ NS_NewToolkitProfileFactory(nsIFactory* 
     if (!*aResult)
         return NS_ERROR_OUT_OF_MEMORY;
 
     NS_ADDREF(*aResult);
     return NS_OK;
 }
 
 nsresult
-NS_NewToolkitProfileService(nsIToolkitProfileService* *aResult)
+NS_NewToolkitProfileService(nsIToolkitProfileService* *aResult, bool aDevEdition)
 {
-    nsToolkitProfileService* profileService = new nsToolkitProfileService();
+    nsToolkitProfileService* profileService = new nsToolkitProfileService(aDevEdition);
     if (!profileService)
         return NS_ERROR_OUT_OF_MEMORY;
     nsresult rv = profileService->Init();
     if (NS_FAILED(rv)) {
         NS_ERROR("nsToolkitProfileService::Init failed!");
         delete profileService;
         return rv;
     }
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -2218,17 +2218,17 @@ static nsAutoCString gResetOldProfileNam
 // 1) check for --profile <path>
 // 2) check for -P <name>
 // 3) check for --ProfileManager
 // 4) use the default profile, if there is one
 // 5) if there are *no* profiles, set up profile-migration
 // 6) display the profile-manager UI
 static nsresult
 SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, nsINativeAppSupport* aNative,
-              bool* aStartOffline, nsACString* aProfileName)
+              bool* aStartOffline, nsACString* aProfileName, bool aDevEdition)
 {
   StartupTimeline::Record(StartupTimeline::SELECT_PROFILE);
 
   nsresult rv;
   ArgResult ar;
   const char* arg;
   *aResult = nullptr;
   *aStartOffline = false;
@@ -2475,57 +2475,56 @@ SelectProfile(nsIProfileLock* *aResult, 
   if (ar == ARG_BAD) {
     PR_fprintf(PR_STDERR, "Error: argument --profilemanager is invalid when argument --osint is specified\n");
     return NS_ERROR_FAILURE;
   }
   if (ar == ARG_FOUND && CanShowProfileManager()) {
     return ShowProfileManager(aProfileSvc, aNative);
   }
 
-#ifndef MOZ_DEV_EDITION
-  // If the only existing profile is the dev-edition-profile and this is not
-  // Developer Edition, then no valid profiles were found.
-  if (count == 1) {
-    nsCOMPtr<nsIToolkitProfile> deProfile;
-    // GetSelectedProfile will auto-select the only profile if there's just one
-    aProfileSvc->GetSelectedProfile(getter_AddRefs(deProfile));
-    nsAutoCString profileName;
-    deProfile->GetName(profileName);
-    if (profileName.EqualsLiteral("dev-edition-default")) {
-      count = 0;
+  if (aDevEdition) {
+    // If the only existing profile is the dev-edition-profile and this is not
+    // Developer Edition, then no valid profiles were found.
+    if (count == 1) {
+      nsCOMPtr<nsIToolkitProfile> deProfile;
+      // GetSelectedProfile will auto-select the only profile if there's just one
+      aProfileSvc->GetSelectedProfile(getter_AddRefs(deProfile));
+      nsAutoCString profileName;
+      deProfile->GetName(profileName);
+      if (profileName.EqualsLiteral("dev-edition-default")) {
+        count = 0;
+      }
     }
   }
-#endif
 
   if (!count) {
     gDoMigration = true;
     gDoProfileReset = false;
 
     // create a default profile
     nsCOMPtr<nsIToolkitProfile> profile;
     nsresult rv = aProfileSvc->CreateProfile(nullptr, // choose a default dir for us
-#ifdef MOZ_DEV_EDITION
-                                             NS_LITERAL_CSTRING("dev-edition-default"),
-#else
+                                             aDevEdition ?
+                                             NS_LITERAL_CSTRING("dev-edition-default") :
                                              NS_LITERAL_CSTRING("default"),
-#endif
                                              getter_AddRefs(profile));
     if (NS_SUCCEEDED(rv)) {
-#ifndef MOZ_DEV_EDITION
-      aProfileSvc->SetDefaultProfile(profile);
-#endif
+      if (!aDevEdition) {
+        aProfileSvc->SetDefaultProfile(profile);
+      }
       aProfileSvc->Flush();
       rv = profile->Lock(nullptr, aResult);
       if (NS_SUCCEEDED(rv)) {
-        if (aProfileName)
-#ifdef MOZ_DEV_EDITION
-          aProfileName->AssignLiteral("dev-edition-default");
-#else
-          aProfileName->AssignLiteral("default");
-#endif
+        if (aProfileName) {
+          if (aDevEdition) {
+            aProfileName->AssignLiteral("dev-edition-default");
+          } else {
+            aProfileName->AssignLiteral("default");
+          }
+        }
         return NS_OK;
       }
     }
   }
 
   bool useDefault = true;
   if (count > 1 && CanShowProfileManager()) {
     aProfileSvc->GetStartWithLastProfile(&useDefault);
@@ -3059,16 +3058,18 @@ public:
     mScopedXPCOM = nullptr;
     mAppData = nullptr;
   }
 
   int XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig);
   int XRE_mainInit(bool* aExitFlag);
   int XRE_mainStartup(bool* aExitFlag);
   nsresult XRE_mainRun();
+  void readINI();
+  bool isDevEdition();
 
   nsCOMPtr<nsINativeAppSupport> mNativeApp;
   nsCOMPtr<nsIToolkitProfileService> mProfileSvc;
   nsCOMPtr<nsIFile> mProfD;
   nsCOMPtr<nsIFile> mProfLD;
   nsCOMPtr<nsIProfileLock> mProfileLock;
 #ifdef MOZ_ENABLE_XREMOTE
   nsCOMPtr<nsIRemoteService> mRemoteService;
@@ -3087,16 +3088,19 @@ public:
   bool mShuttingDown;
 #ifdef MOZ_ENABLE_XREMOTE
   bool mDisableRemote;
 #endif
 
 #if defined(MOZ_WIDGET_GTK)
   GdkDisplay* mGdkDisplay;
 #endif
+
+  nsresult mINIParserResult;
+  UniquePtr<nsINIParser> mINIParser;
 };
 
 /*
  * XRE_mainInit - Initial setup and command line parameter processing.
  * Main() will exit early if either return value != 0 or if aExitFlag is
  * true.
  */
 int
@@ -3241,16 +3245,18 @@ XREMain::XRE_mainInit(bool* aExitFlag)
            (const char*) mAppData->maxVersion);
     return 1;
   }
 
   rv = mDirProvider.Initialize(mAppData->directory, mAppData->xreDirectory);
   if (NS_FAILED(rv))
     return 1;
 
+  readINI();
+
 #ifdef MOZ_CRASHREPORTER
   if (EnvHasValue("MOZ_CRASHREPORTER")) {
     mAppData->flags |= NS_XRE_ENABLE_CRASH_REPORTER;
   }
 
   nsCOMPtr<nsIFile> xreBinDirectory;
   xreBinDirectory = mDirProvider.GetGREBinDir();
 
@@ -4017,29 +4023,30 @@ XREMain::XRE_mainStartup(bool* aExitFlag
                  mAppData->version);
   if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
     SaveToEnv("MOZ_TEST_PROCESS_UPDATES=");
     *aExitFlag = true;
     return 0;
   }
 #endif
 
-  rv = NS_NewToolkitProfileService(getter_AddRefs(mProfileSvc));
+  bool devEdition = isDevEdition();
+  rv = NS_NewToolkitProfileService(getter_AddRefs(mProfileSvc), devEdition);
   if (rv == NS_ERROR_FILE_ACCESS_DENIED) {
     PR_fprintf(PR_STDERR, "Error: Access was denied while trying to open files in " \
                 "your profile directory.\n");
   }
   if (NS_FAILED(rv)) {
     // We failed to choose or create profile - notify user and quit
     ProfileMissingDialog(mNativeApp);
     return 1;
   }
 
   rv = SelectProfile(getter_AddRefs(mProfileLock), mProfileSvc, mNativeApp, &mStartOffline,
-                      &mProfileName);
+                      &mProfileName, devEdition);
   if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ||
       rv == NS_ERROR_ABORT) {
     *aExitFlag = true;
     return 0;
   }
 
   if (NS_FAILED(rv)) {
     // We failed to choose or create profile - notify user and quit
@@ -4185,16 +4192,48 @@ void AddSandboxAnnotations()
 
   CrashReporter::AnnotateCrashReport(
     NS_LITERAL_CSTRING("ContentSandboxCapable"),
     sandboxCapable ? NS_LITERAL_CSTRING("1") : NS_LITERAL_CSTRING("0"));
 }
 #endif /* MOZ_CONTENT_SANDBOX && !MOZ_WIDGET_GONK */
 #endif /* MOZ_CRASHREPORTER */
 
+void
+XREMain::readINI()
+{
+  nsCOMPtr<nsIFile> file;
+  mDirProvider.GetAppDir()->Clone(getter_AddRefs(file));
+  file->AppendNative(NS_LITERAL_CSTRING("override.ini"));
+  mINIParser = MakeUnique<nsINIParser>();
+  mINIParserResult = mINIParser->Init(file);
+  // if override.ini doesn't exist, also check for distribution.ini
+  if (NS_FAILED(mINIParserResult)) {
+    bool persistent;
+    mDirProvider.GetFile(XRE_APP_DISTRIBUTION_DIR, &persistent,
+                         getter_AddRefs(file));
+    file->AppendNative(NS_LITERAL_CSTRING("distribution.ini"));
+    mINIParserResult = mINIParser->Init(file);
+  }
+}
+
+bool
+XREMain::isDevEdition()
+{
+  if (NS_FAILED(mINIParserResult)) {
+    return false;
+  }
+  nsAutoCString buf;
+  nsresult rv = mINIParser->GetString("Preferences", "devtools.devedition", buf);
+  if (NS_FAILED(rv)) {
+    return false;
+  }
+  return buf == "true";
+}
+
 /*
  * XRE_mainRun - Command line startup, profile migration, and
  * the calling of appStartup->Run().
  */
 nsresult
 XREMain::XRE_mainRun()
 {
   nsresult rv = NS_OK;
@@ -4272,40 +4311,30 @@ XREMain::XRE_mainRun()
     startupNotifier->Observe(nullptr, APPSTARTUP_TOPIC, nullptr);
   }
 
   nsCOMPtr<nsIAppStartup> appStartup
     (do_GetService(NS_APPSTARTUP_CONTRACTID));
   NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
 
   if (gDoMigration) {
-    nsCOMPtr<nsIFile> file;
-    mDirProvider.GetAppDir()->Clone(getter_AddRefs(file));
-    file->AppendNative(NS_LITERAL_CSTRING("override.ini"));
-    nsINIParser parser;
-    nsresult rv = parser.Init(file);
-    // if override.ini doesn't exist, also check for distribution.ini
-    if (NS_FAILED(rv)) {
-      bool persistent;
-      mDirProvider.GetFile(XRE_APP_DISTRIBUTION_DIR, &persistent,
-                           getter_AddRefs(file));
-      file->AppendNative(NS_LITERAL_CSTRING("distribution.ini"));
-      rv = parser.Init(file);
-    }
-    if (NS_SUCCEEDED(rv)) {
+    if (NS_SUCCEEDED(mINIParserResult)) {
       nsAutoCString buf;
-      rv = parser.GetString("XRE", "EnableProfileMigrator", buf);
+      rv = mINIParser->GetString("XRE", "EnableProfileMigrator", buf);
       if (NS_SUCCEEDED(rv)) {
         if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
           gDoMigration = false;
         }
       }
     }
   }
 
+  // We don't need this any more.
+  mINIParser.reset(nullptr);
+
   {
     nsCOMPtr<nsIToolkitProfile> profileBeingReset;
     bool profileWasSelected = false;
     if (gDoProfileReset) {
       if (gResetOldProfileName.IsEmpty()) {
         NS_WARNING("Not resetting profile as the profile has no name.");
         gDoProfileReset = false;
       } else {
--- a/toolkit/xre/nsAppRunner.h
+++ b/toolkit/xre/nsAppRunner.h
@@ -58,17 +58,17 @@ extern bool gIsGtest;
 /**
  * Create the nativeappsupport implementation.
  *
  * @note XPCOMInit has not happened yet.
  */
 nsresult NS_CreateNativeAppSupport(nsINativeAppSupport* *aResult);
 
 nsresult
-NS_NewToolkitProfileService(nsIToolkitProfileService* *aResult);
+NS_NewToolkitProfileService(nsIToolkitProfileService* *aResult, bool aDevEdition);
 
 nsresult
 NS_NewToolkitProfileFactory(nsIFactory* *aResult);
 
 /**
  * Try to acquire exclusive access to the specified profile directory.
  *
  * @param aPath