Bug 1306327 - Move reading application.ini to XRE_main. r=bsmedberg draft
authorMike Hommey <mh+mozilla@glandium.org>
Tue, 10 Jan 2017 16:43:23 +0900
changeset 462691 604ba9db47bc2dbcef3bb7bfebf6833cb660564d
parent 462690 62e78b11055282e0b07d8b220da09c7bfb020b13
child 462692 0392b89e52281f982069297cb07aa3a9017cb91e
push id41842
push userbmo:mh+mozilla@glandium.org
push dateTue, 17 Jan 2017 22:08:05 +0000
reviewersbsmedberg
bugs1306327
milestone53.0a1
Bug 1306327 - Move reading application.ini to XRE_main. r=bsmedberg Reading application.ini involves using nsCOMPtr<nsIFile>, and that can only happen through the XPCOM glue, which we eventually want to get rid of. So, while keeping the command line argument/environment variable handling in nsBrowserApp, we move the actually parsing of the file to XRE_main, where things can be handled without the XPCOM glue.
browser/app/nsBrowserApp.cpp
toolkit/xre/Bootstrap.cpp
toolkit/xre/Bootstrap.h
toolkit/xre/nsAndroidStartup.cpp
toolkit/xre/nsAppRunner.cpp
xpcom/build/XREAppData.h
xpcom/build/nsXULAppAPI.h
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -171,40 +171,26 @@ int libfuzzer_main(int argc, char **argv
 void libFuzzerGetFuncs(const char* moduleName, LibFuzzerInitFunc* initFunc,
                        LibFuzzerTestingFunc* testingFunc) {
   return gBootstrap->XRE_LibFuzzerGetFuncs(moduleName, initFunc, testingFunc);
 }
 #endif
 
 static int do_main(int argc, char* argv[], char* envp[])
 {
-  nsCOMPtr<nsIFile> appini;
-  nsresult rv;
-
   // Allow firefox.exe to launch XULRunner apps via -app <application.ini>
   // Note that -app must be the *first* argument.
   const char *appDataFile = getenv("XUL_APP_FILE");
-  if (appDataFile && *appDataFile) {
-    rv = gBootstrap->XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini));
-    if (NS_FAILED(rv)) {
-      Output("Invalid path found: '%s'", appDataFile);
-      return 255;
-    }
-  }
-  else if (argc > 1 && IsArg(argv[1], "app")) {
+  if ((!appDataFile || !*appDataFile) &&
+      (argc > 1 && IsArg(argv[1], "app"))) {
     if (argc == 2) {
       Output("Incorrect number of arguments passed to -app");
       return 255;
     }
-
-    rv = gBootstrap->XRE_GetFileFromPath(argv[2], getter_AddRefs(appini));
-    if (NS_FAILED(rv)) {
-      Output("application.ini path not recognized: '%s'", argv[2]);
-      return 255;
-    }
+    appDataFile = argv[2];
 
     char appEnv[MAXPATHLEN];
     SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]);
     if (putenv(strdup(appEnv))) {
       Output("Couldn't set %s.\n", appEnv);
       return 255;
     }
     argv[2] = argv[0];
@@ -219,66 +205,45 @@ static int do_main(int argc, char* argv[
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
     shellData.sandboxBrokerServices =
       sandboxing::GetInitializedBrokerServices();
 #endif
 
     return gBootstrap->XRE_XPCShellMain(--argc, argv, envp, &shellData);
   }
 
-  XREAppData appData;
+  BootstrapConfig config;
 
-  if (appini) {
-    rv = gBootstrap->XRE_ParseAppData(appini, appData);
-    if (NS_FAILED(rv)) {
-      Output("Couldn't read application.ini");
-      return 255;
-    }
-
-    appini->GetParent(getter_AddRefs(appData.directory));
+  if (appDataFile && *appDataFile) {
+    config.appData = nullptr;
+    config.appDataPath = appDataFile;
   } else {
     // no -app flag so we use the compiled-in app data
-    appData = sAppData;
-
-    nsCOMPtr<nsIFile> exeFile;
-    rv = mozilla::BinaryPath::GetFile(argv[0], getter_AddRefs(exeFile));
-    if (NS_FAILED(rv)) {
-      Output("Couldn't find the application directory.\n");
-      return 255;
-    }
-
-    nsCOMPtr<nsIFile> greDir;
-    exeFile->GetParent(getter_AddRefs(greDir));
-#ifdef XP_MACOSX
-    greDir->SetNativeLeafName(NS_LITERAL_CSTRING(kOSXResourcesFolder));
-#endif
-    nsCOMPtr<nsIFile> appSubdir;
-    greDir->Clone(getter_AddRefs(appSubdir));
-    appSubdir->Append(NS_LITERAL_STRING(kDesktopFolder));
-    appData.directory = appSubdir;
+    config.appData = &sAppData;
+    config.appDataPath = kDesktopFolder;
   }
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
   sandbox::BrokerServices* brokerServices =
     sandboxing::GetInitializedBrokerServices();
 #if defined(MOZ_CONTENT_SANDBOX)
   if (!brokerServices) {
     Output("Couldn't initialize the broker services.\n");
     return 255;
   }
 #endif
-  appData.sandboxBrokerServices = brokerServices;
+  config.sandboxBrokerServices = brokerServices;
 #endif
 
 #ifdef LIBFUZZER
   if (getenv("LIBFUZZER"))
     gBootstrap->XRE_LibFuzzerSetMain(argc, argv, libfuzzer_main);
 #endif
 
-  return gBootstrap->XRE_main(argc, argv, appData);
+  return gBootstrap->XRE_main(argc, argv, config);
 }
 
 static bool
 FileExists(const char *path)
 {
 #ifdef XP_WIN
   wchar_t wideDir[MAX_PATH];
   MultiByteToWideChar(CP_UTF8, 0, path, -1, wideDir, MAX_PATH);
--- a/toolkit/xre/Bootstrap.cpp
+++ b/toolkit/xre/Bootstrap.cpp
@@ -28,34 +28,26 @@ public:
   virtual void NS_LogInit() override {
     ::NS_LogInit();
   }
 
   virtual void NS_LogTerm() override {
     ::NS_LogTerm();
   }
 
-  virtual nsresult XRE_GetFileFromPath(const char* aPath, nsIFile** aResult) override {
-    return ::XRE_GetFileFromPath(aPath, aResult);
-  }
-
-  virtual nsresult XRE_ParseAppData(nsIFile* aINIFile, mozilla::XREAppData& aAppData) override {
-    return ::XRE_ParseAppData(aINIFile, aAppData);
-  }
-
   virtual void XRE_TelemetryAccumulate(int aID, uint32_t aSample) override {
     ::XRE_TelemetryAccumulate(aID, aSample);
   }
 
   virtual void XRE_StartupTimelineRecord(int aEvent, mozilla::TimeStamp aWhen) override {
     ::XRE_StartupTimelineRecord(aEvent, aWhen);
   }
 
-  virtual int XRE_main(int argc, char* argv[], const mozilla::XREAppData& aAppData) override {
-    return ::XRE_main(argc, argv, aAppData);
+  virtual int XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) override {
+    return ::XRE_main(argc, argv, aConfig);
   }
 
   virtual void XRE_StopLateWriteChecks() override {
     ::XRE_StopLateWriteChecks();
   }
 
   virtual int XRE_XPCShellMain(int argc, char** argv, char** envp, const XREShellData* aShellData) override {
     return ::XRE_XPCShellMain(argc, argv, envp, aShellData);
--- a/toolkit/xre/Bootstrap.h
+++ b/toolkit/xre/Bootstrap.h
@@ -18,18 +18,39 @@
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "jni.h"
 
 extern "C" NS_EXPORT
 void GeckoStart(JNIEnv* aEnv, char** argv, int argc, const mozilla::StaticXREAppData& aAppData);
 #endif
 
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+namespace sandbox {
+class BrokerServices;
+}
+#endif
+
 namespace mozilla {
 
+struct BootstrapConfig
+{
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+  /* Chromium sandbox BrokerServices. */
+  sandbox::BrokerServices* sandboxBrokerServices;
+#endif
+  /* Pointer to static XRE AppData from application.ini.h */
+  const StaticXREAppData* appData;
+  /* When the pointer above is null, points to the (string) path of an
+   * application.ini file to open and parse.
+   * When the pointer above is non-null, may indicate the directory where
+   * application files are, relative to the XRE. */
+  const char* appDataPath;
+};
+
 /**
  * This class is virtual abstract so that using it does not require linking
  * any symbols. The singleton instance of this class is obtained from the
  * exported method XRE_GetBootstrap.
  */
 class Bootstrap
 {
 protected:
@@ -59,25 +80,21 @@ protected:
 
 public:
   typedef mozilla::UniquePtr<Bootstrap, BootstrapDelete> UniquePtr;
 
   virtual void NS_LogInit() = 0;
 
   virtual void NS_LogTerm() = 0;
 
-  virtual nsresult XRE_GetFileFromPath(const char* aPath, nsIFile** aResult) = 0;
-
-  virtual nsresult XRE_ParseAppData(nsIFile* aINIFile, mozilla::XREAppData& aAppData) = 0;
-
   virtual void XRE_TelemetryAccumulate(int aID, uint32_t aSample) = 0;
 
   virtual void XRE_StartupTimelineRecord(int aEvent, mozilla::TimeStamp aWhen) = 0;
 
-  virtual int XRE_main(int argc, char* argv[], const mozilla::XREAppData& aAppData) = 0;
+  virtual int XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) = 0;
 
   virtual void XRE_StopLateWriteChecks() = 0;
 
   virtual int XRE_XPCShellMain(int argc, char** argv, char** envp, const XREShellData* aShellData) = 0;
 
   virtual GeckoProcessType XRE_GetProcessType() = 0;
 
   virtual void XRE_SetProcessType(const char* aProcessTypeString) = 0;
--- a/toolkit/xre/nsAndroidStartup.cpp
+++ b/toolkit/xre/nsAndroidStartup.cpp
@@ -13,16 +13,17 @@
 
 #include "mozilla/jni/Utils.h"
 #include "nsTArray.h"
 #include "nsString.h"
 #include "nsIFile.h"
 #include "nsAppRunner.h"
 #include "APKOpen.h"
 #include "nsExceptionHandler.h"
+#include "mozilla/Bootstrap.h"
 
 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, MOZ_APP_NAME, args)
 
 using namespace mozilla;
 
 extern "C" NS_EXPORT void
 GeckoStart(JNIEnv* env, char** argv, int argc, const StaticXREAppData& aAppData)
 {
@@ -37,16 +38,17 @@ GeckoStart(JNIEnv* env, char** argv, int
     }
 #endif
 
     if (!argv) {
         LOG("Failed to get arguments for GeckoStart\n");
         return;
     }
 
-    XREAppData appData;
-    appData = aAppData;
+    BootstrapConfig config;
+    config.appData = &aAppData;
+    config.appDataPath = nullptr;
 
-    int result = XRE_main(argc, argv, appData);
+    int result = XRE_main(argc, argv, config);
 
     if (result)
         LOG("XRE_main returned %d", result);
 }
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/Poison.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 
 #include "nsAppRunner.h"
 #include "mozilla/XREAppData.h"
+#include "mozilla/Bootstrap.h"
 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
 #include "nsUpdateDriver.h"
 #endif
 #include "ProfileReset.h"
 
 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
 #include "EventTracer.h"
 #endif
@@ -3019,17 +3020,17 @@ public:
 #endif
   {};
 
   ~XREMain() {
     mScopedXPCOM = nullptr;
     mAppData = nullptr;
   }
 
-  int XRE_main(int argc, char* argv[], const XREAppData& aAppData);
+  int XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig);
   int XRE_mainInit(bool* aExitFlag);
   int XRE_mainStartup(bool* aExitFlag);
   nsresult XRE_mainRun();
 
   nsCOMPtr<nsINativeAppSupport> mNativeApp;
   nsCOMPtr<nsIToolkitProfileService> mProfileSvc;
   nsCOMPtr<nsIFile> mProfD;
   nsCOMPtr<nsIFile> mProfLD;
@@ -3179,41 +3180,16 @@ XREMain::XRE_mainInit(bool* aExitFlag)
   if (!mAppData->buildID) {
     Output(true, "Error: App:BuildID not specified in application.ini\n");
     return 1;
   }
 
   // XXX Originally ScopedLogging was here? Now it's in XRE_main above
   // XRE_mainInit.
 
-  if (!mAppData->xreDirectory) {
-    nsCOMPtr<nsIFile> lf;
-    rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
-    if (NS_FAILED(rv))
-      return 2;
-
-    nsCOMPtr<nsIFile> greDir;
-    rv = lf->GetParent(getter_AddRefs(greDir));
-    if (NS_FAILED(rv))
-      return 2;
-
-#ifdef XP_MACOSX
-    nsCOMPtr<nsIFile> parent;
-    greDir->GetParent(getter_AddRefs(parent));
-    greDir = parent.forget();
-    greDir->AppendNative(NS_LITERAL_CSTRING("Resources"));
-#endif
-
-    mAppData->xreDirectory = greDir;
-  }
-
-  if (!mAppData->directory) {
-    mAppData->directory = mAppData->xreDirectory;
-  }
-
   if (!mAppData->minVersion) {
     Output(true, "Error: Gecko:MinVersion not specified in application.ini\n");
     return 1;
   }
 
   if (!mAppData->maxVersion) {
     // If no maxVersion is specified, we assume the app is only compatible
     // with the initial preview release. Do not increment this number ever!
@@ -4521,17 +4497,17 @@ XRE_CreateStatsObject()
 }
 
 /*
  * XRE_main - A class based main entry point used by most platforms.
  *            Note that on OSX, aAppData->xreDirectory will point to
  *            .app/Contents/Resources.
  */
 int
-XREMain::XRE_main(int argc, char* argv[], const XREAppData& aAppData)
+XREMain::XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig)
 {
   ScopedLogging log;
 
   // NB: this must happen after the creation of |ScopedLogging log| since
   // ScopedLogging::ScopedLogging calls NS_LogInit, and
   // XRE_CreateStatsObject calls Telemetry::CreateStatisticsRecorder,
   // and NS_LogInit must be called before Telemetry::CreateStatisticsRecorder.
   // NS_LogInit must be called before Telemetry::CreateStatisticsRecorder
@@ -4550,30 +4526,84 @@ XREMain::XRE_main(int argc, char* argv[]
   PROFILER_LABEL("Startup", "XRE_Main",
     js::ProfileEntry::Category::OTHER);
 
   nsresult rv = NS_OK;
 
   gArgc = argc;
   gArgv = argv;
 
-  mAppData = MakeUnique<XREAppData>(aAppData);
+  if (aConfig.appData) {
+      mAppData = MakeUnique<XREAppData>(*aConfig.appData);
+  } else {
+    MOZ_RELEASE_ASSERT(aConfig.appDataPath);
+    nsCOMPtr<nsIFile> appini;
+    rv = XRE_GetFileFromPath(aConfig.appDataPath, getter_AddRefs(appini));
+    if (NS_FAILED(rv)) {
+      Output(true, "Error: unrecognized path: %s\n", aConfig.appDataPath);
+      return 1;
+    }
+
+    mAppData = MakeUnique<XREAppData>();
+    rv = XRE_ParseAppData(appini, *mAppData);
+    if (NS_FAILED(rv)) {
+      Output(true, "Couldn't read application.ini");
+      return 1;
+    }
+
+    appini->GetParent(getter_AddRefs(mAppData->directory));
+  }
+
   if (!mAppData->remotingName) {
     mAppData->remotingName = mAppData->name;
   }
   // used throughout this file
   gAppData = mAppData.get();
 
   nsCOMPtr<nsIFile> binFile;
   rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(binFile));
   NS_ENSURE_SUCCESS(rv, 1);
 
   rv = binFile->GetPath(gAbsoluteArgv0Path);
   NS_ENSURE_SUCCESS(rv, 1);
 
+  if (!mAppData->xreDirectory) {
+    nsCOMPtr<nsIFile> lf;
+    rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
+    if (NS_FAILED(rv))
+      return 2;
+
+    nsCOMPtr<nsIFile> greDir;
+    rv = lf->GetParent(getter_AddRefs(greDir));
+    if (NS_FAILED(rv))
+      return 2;
+
+#ifdef XP_MACOSX
+    nsCOMPtr<nsIFile> parent;
+    greDir->GetParent(getter_AddRefs(parent));
+    greDir = parent.forget();
+    greDir->AppendNative(NS_LITERAL_CSTRING("Resources"));
+#endif
+
+    mAppData->xreDirectory = greDir;
+  }
+
+  if (aConfig.appData && aConfig.appDataPath) {
+    mAppData->xreDirectory->Clone(getter_AddRefs(mAppData->directory));
+    mAppData->directory->AppendNative(nsDependentCString(aConfig.appDataPath));
+  }
+
+  if (!mAppData->directory) {
+    mAppData->directory = mAppData->xreDirectory;
+  }
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+  mAppData->sandboxBrokerServices = aConfig.sandboxBrokerServices;
+#endif
+
   mozilla::IOInterposerInit ioInterposerGuard;
 
 #if defined(XP_WIN)
   // Some COM settings are global to the process and must be set before any non-
   // trivial COM is run in the application. Since these settings may affect
   // stability, we should instantiate COM ASAP so that we can ensure that these
   // global settings are configured before anything can interfere.
   mozilla::mscom::MainThreadRuntime msCOMRuntime;
@@ -4687,21 +4717,21 @@ XREMain::XRE_main(int argc, char* argv[]
 }
 
 void
 XRE_StopLateWriteChecks(void) {
   mozilla::StopLateWriteChecks();
 }
 
 int
-XRE_main(int argc, char* argv[], const XREAppData& aAppData)
+XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig)
 {
   XREMain main;
 
-  int result = main.XRE_main(argc, argv, aAppData);
+  int result = main.XRE_main(argc, argv, aConfig);
   mozilla::RecordShutdownEndTimeStamp();
   return result;
 }
 
 nsresult
 XRE_InitCommandLine(int aArgc, char* aArgv[])
 {
   nsresult rv = NS_OK;
--- a/xpcom/build/XREAppData.h
+++ b/xpcom/build/XREAppData.h
@@ -31,16 +31,21 @@ class XREAppData
 public:
   XREAppData() { }
   ~XREAppData() { }
   XREAppData(const XREAppData& aOther)
   {
     *this = aOther;
   }
 
+  explicit XREAppData(const StaticXREAppData& aOther)
+  {
+    *this = aOther;
+  }
+
   XREAppData& operator=(const StaticXREAppData& aOther);
   XREAppData& operator=(const XREAppData& aOther);
   XREAppData& operator=(XREAppData&& aOther) = default;
 
   struct NSFreePolicy
   {
     void operator()(const void* ptr) {
       NS_Free(const_cast<void*>(ptr));
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -189,25 +189,28 @@
 /**
  * Begin an XUL application. Does not return until the user exits the
  * application.
  *
  * @param argc/argv Command-line parameters to pass to the application. On
  *                  Windows, these should be in UTF8. On unix-like platforms
  *                  these are in the "native" character set.
  *
- * @param aAppData  Information about the application to be run.
+ * @param aConfig  Information about the application to be run.
  *
  * @return         A native result code suitable for returning from main().
  *
  * @note           If the binary is linked against the standalone XPCOM glue,
  *                 XPCOMGlueStartup() should be called before this method.
  */
+namespace mozilla {
+struct BootstrapConfig;
+}
 XRE_API(int,
-        XRE_main, (int argc, char* argv[], const mozilla::XREAppData& aAppData))
+        XRE_main, (int argc, char* argv[], const mozilla::BootstrapConfig& aConfig))
 
 /**
  * Given a path relative to the current working directory (or an absolute
  * path), return an appropriate nsIFile object.
  *
  * @note Pass UTF8 strings on Windows... native charset on other platforms.
  */
 XRE_API(nsresult,