Bug 1074021 - Get SeaMonkey to launch with the new .app bundle structure r=stefanh r=Neil a=Callek/Neil for -aurora/-beta CLOSED TREE
authorRobert Strong <robert.strong.bugs@gmail.com>
Mon, 13 Oct 2014 12:30:57 +0800
changeset 20858 cbfb56b50760c0244d0860ae2c61f3d0c0eb4917
parent 20857 e567470af025ac6488493d586316d8362aed4060
child 20859 2f62c4401cef92c7ee75b6f68cf8ed0c9907e9cf
push id1235
push userphilip.chee@gmail.com
push dateTue, 14 Oct 2014 10:21:39 +0000
treeherdercomm-beta@2f62c4401cef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersstefanh, Neil, Callek, Neil
bugs1074021
Bug 1074021 - Get SeaMonkey to launch with the new .app bundle structure r=stefanh r=Neil a=Callek/Neil for -aurora/-beta CLOSED TREE
suite/app/nsSuiteApp.cpp
--- a/suite/app/nsSuiteApp.cpp
+++ b/suite/app/nsSuiteApp.cpp
@@ -1,22 +1,24 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsXULAppAPI.h"
+#include "mozilla/AppData.h"
 #include "application.ini.h"
 #include "nsXPCOMGlue.h"
 #if defined(XP_WIN)
 #include <windows.h>
 #include <stdlib.h>
 #elif defined(XP_UNIX)
 #include <sys/time.h>
 #include <sys/resource.h>
+#include <unistd.h>
 #endif
 
 #ifdef XP_MACOSX
 #include "MacQuirks.h"
 #endif
 
 #include <stdio.h>
 #include <stdarg.h>
@@ -38,16 +40,22 @@
 #endif
 #include "BinaryPath.h"
 
 #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
 
 #include "mozilla/Telemetry.h"
 #include "mozilla/WindowsDllBlocklist.h"
 
+using namespace mozilla;
+
+#ifdef XP_MACOSX
+#define kOSXResourcesFolder "Resources"
+#endif
+
 static void Output(const char *fmt, ... )
 {
   va_list ap;
   va_start(ap, fmt);
 
 #ifdef XP_WIN
   char msg[2048];
 
@@ -120,20 +128,21 @@ static const nsDynamicFunctionLoad kXULF
     { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
     { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
     { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData },
     { "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate },
     { "XRE_main", (NSFuncPtr*) &XRE_main },
     { nullptr, nullptr }
 };
 
-static int do_main(const char *exePath, int argc, char* argv[])
+static int do_main(int argc, char* argv[], nsIFile *xreDirectory)
 {
   nsCOMPtr<nsIFile> appini;
   nsresult rv;
+  uint32_t mainFlags = 0;
   
   // Allow seamonkey.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 = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini));
     if (NS_FAILED(rv)) {
       Output("Invalid path found: '%s'", appDataFile);
@@ -166,93 +175,195 @@ static int do_main(const char *exePath, 
   int result;
   if (appini) {
     nsXREAppData *appData;
     rv = XRE_CreateAppData(appini, &appData);
     if (NS_FAILED(rv)) {
       Output("Couldn't read application.ini");
       return 255;
     }
+    // xreDirectory already has a refcount from NS_NewLocalFile
+    appData->xreDirectory = xreDirectory;
     result = XRE_main(argc, argv, appData, 0);
     XRE_FreeAppData(appData);
   } else {
-#ifdef XP_WIN
-    // exePath comes from mozilla::BinaryPath::Get, which returns a UTF-8
-    // encoded path, so it is safe to convert it
-    rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(exePath), false,
-                         getter_AddRefs(appini));
-#else
-    rv = NS_NewNativeLocalFile(nsDependentCString(exePath), false,
-                               getter_AddRefs(appini));
-#endif
+    ScopedAppData 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;
     }
-    result = XRE_main(argc, argv, &sAppData, 0);
+
+    nsCOMPtr<nsIFile> greDir;
+    exeFile->GetParent(getter_AddRefs(greDir));
+#ifdef XP_MACOSX
+    greDir->SetNativeLeafName(NS_LITERAL_CSTRING(kOSXResourcesFolder));
+#endif
+    SetStrongPtr(appData.directory, static_cast<nsIFile*>(greDir.get()));
+    // xreDirectory already has a refcount from NS_NewLocalFile
+    appData.xreDirectory = xreDirectory;
+
+    result = XRE_main(argc, argv, &appData, mainFlags);
   }
   
   return result;
 }
-int main(int argc, char* argv[])
+
+static bool
+FileExists(const char *path)
+{
+#ifdef XP_WIN
+  wchar_t wideDir[MAX_PATH];
+  MultiByteToWideChar(CP_UTF8, 0, path, -1, wideDir, MAX_PATH);
+  DWORD fileAttrs = GetFileAttributesW(wideDir);
+  return fileAttrs != INVALID_FILE_ATTRIBUTES;
+#else
+  return access(path, R_OK) == 0;
+#endif
+}
+
+#ifdef LIBXUL_SDK
+#  define XPCOM_PATH "xulrunner" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL
+#else
+#  define XPCOM_PATH XPCOM_DLL
+#endif
+static nsresult
+InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory)
 {
   char exePath[MAXPATHLEN];
 
+  nsresult rv = mozilla::BinaryPath::Get(argv0, exePath);
+  if (NS_FAILED(rv)) {
+    Output("Couldn't find the application directory.\n");
+    return rv;
+  }
+
+  char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]);
+  if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_PATH) - 1))
+    return NS_ERROR_FAILURE;
+
+  strcpy(lastSlash + 1, XPCOM_PATH);
+  lastSlash += sizeof(XPCOM_PATH) - sizeof(XPCOM_DLL);
+
+  if (!FileExists(exePath)) {
+#if defined(LIBXUL_SDK) && defined(XP_MACOSX)
+    // Check for <bundle>/Contents/Frameworks/XUL.framework/libxpcom.dylib
+    bool greFound = false;
+    CFBundleRef appBundle = CFBundleGetMainBundle();
+    if (!appBundle)
+      return NS_ERROR_FAILURE;
+    CFURLRef fwurl = CFBundleCopyPrivateFrameworksURL(appBundle);
+    CFURLRef absfwurl = nullptr;
+    if (fwurl) {
+      absfwurl = CFURLCopyAbsoluteURL(fwurl);
+      CFRelease(fwurl);
+    }
+    if (absfwurl) {
+      CFURLRef xulurl =
+        CFURLCreateCopyAppendingPathComponent(nullptr, absfwurl,
+                                              CFSTR("XUL.framework"),
+                                              true);
+
+      if (xulurl) {
+        CFURLRef xpcomurl =
+          CFURLCreateCopyAppendingPathComponent(nullptr, xulurl,
+                                                CFSTR("libxpcom.dylib"),
+                                                false);
+
+        if (xpcomurl) {
+          if (CFURLGetFileSystemRepresentation(xpcomurl, true,
+                                               (UInt8*) exePath,
+                                               sizeof(exePath)) &&
+              access(tbuffer, R_OK | X_OK) == 0) {
+            if (realpath(tbuffer, exePath)) {
+              greFound = true;
+            }
+          }
+          CFRelease(xpcomurl);
+        }
+        CFRelease(xulurl);
+      }
+      CFRelease(absfwurl);
+    }
+  }
+  if (!greFound) {
+#endif
+    Output("Could not find the Mozilla runtime.\n");
+    return NS_ERROR_FAILURE;
+  }
+
+  // We do this because of data in bug 771745
+  XPCOMGlueEnablePreload();
+
+  rv = XPCOMGlueStartup(exePath);
+  if (NS_FAILED(rv)) {
+    Output("Couldn't load XPCOM.\n");
+    return rv;
+  }
+
+  rv = XPCOMGlueLoadXULFunctions(kXULFuncs);
+  if (NS_FAILED(rv)) {
+    Output("Couldn't load XRE functions.\n");
+    return rv;
+  }
+
+  NS_LogInit();
+
+  // chop XPCOM_DLL off exePath
+  *lastSlash = '\0';
+#ifdef XP_MACOSX
+  lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]);
+  strcpy(lastSlash + 1, kOSXResourcesFolder);
+#endif
+#ifdef XP_WIN
+  rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(exePath), false,
+                       xreDirectory);
+#else
+  rv = NS_NewNativeLocalFile(nsDependentCString(exePath), false,
+                             xreDirectory);
+#endif
+
+  return rv;
+}
+
+int main(int argc, char* argv[])
+{
 #ifdef XP_MACOSX
   TriggerQuirks();
 #endif
 
-  nsresult rv = mozilla::BinaryPath::Get(argv[0], exePath);
-  if (NS_FAILED(rv)) {
-    Output("Couldn't calculate the application directory.\n");
-    return 255;
-  }
-
-  char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]);
-  if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_DLL) - 1))
-    return 255;
-
-  strcpy(++lastSlash, XPCOM_DLL);
-
   int gotCounters;
 #if defined(XP_UNIX)
   struct rusage initialRUsage;
   gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage);
 #elif defined(XP_WIN)
   IO_COUNTERS ioCounters;
   gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
 #endif
   
+  nsIFile *xreDirectory;
+
 #ifdef HAS_DLL_BLOCKLIST
   DllBlocklist_Initialize();
 
 #ifdef DEBUG
   // In order to be effective against AppInit DLLs, the blocklist must be
   // initialized before user32.dll is loaded into the process (bug 932100).
   if (GetModuleHandleA("user32.dll")) {
     fprintf(stderr, "DLL blocklist was unable to intercept AppInit DLLs.\n");
   }
 #endif
 #endif
 
-  XPCOMGlueEnablePreload();
-
-  rv = XPCOMGlueStartup(exePath);
-    if (NS_FAILED(rv)) {
-    Output("Couldn't load XPCOM.\n");
+  nsresult rv = InitXPCOMGlue(argv[0], &xreDirectory);
+  if (NS_FAILED(rv)) {
     return 255;
   }
-  // Reset exePath so that it is the directory name and not the xpcom dll name
-  *lastSlash = 0;
 
-  rv = XPCOMGlueLoadXULFunctions(kXULFuncs);
-  if (NS_FAILED(rv)) {
-    Output("Couldn't load XRE functions.\n");
-    return 255;
-  }
-  
   if (gotCounters) {
 #if defined(XP_WIN)
     XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_OPS,
                             int(ioCounters.ReadOperationCount));
     XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_TRANSFER,
                             int(ioCounters.ReadTransferCount / 1024));
     IO_COUNTERS newIoCounters;
     if (GetProcessIoCounters(GetCurrentProcess(), &newIoCounters)) {
@@ -270,13 +381,13 @@ int main(int argc, char* argv[])
                               int(newRUsage.ru_majflt - initialRUsage.ru_majflt));
     }
 #endif
   }
   
   int result;
   {
     ScopedLogging log;
-    result = do_main(exePath, argc, argv);
+    result = do_main(argc, argv, xreDirectory);
   }
   
   return result;
 }