summaryrefslogtreecommitdiff
path: root/toolkit/xre
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/xre')
-rw-r--r--toolkit/xre/nsAppRunner.cpp100
-rw-r--r--toolkit/xre/nsEmbedFunctions.cpp140
-rw-r--r--toolkit/xre/nsSigHandlers.cpp16
-rw-r--r--toolkit/xre/nsUpdateDriver.cpp143
-rw-r--r--toolkit/xre/nsXREDirProvider.cpp153
-rw-r--r--toolkit/xre/nsXREDirProvider.h2
6 files changed, 528 insertions, 26 deletions
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
index b15335ade3..274631aac8 100644
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -31,6 +31,16 @@
#include "EventTracer.h"
#endif
+#ifdef XP_MACOSX
+#include "nsVersionComparator.h"
+#include "MacLaunchHelper.h"
+#include "MacApplicationDelegate.h"
+#include "MacAutoreleasePool.h"
+// these are needed for sysctl
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
#include "prmem.h"
#include "prnetdb.h"
#include "prprf.h"
@@ -144,6 +154,11 @@
#include "WinUtils.h"
#endif
+#ifdef XP_MACOSX
+#include "nsILocalFileMac.h"
+#include "nsCommandLineServiceMac.h"
+#endif
+
// for X remote support
#ifdef MOZ_ENABLE_XREMOTE
#include "XRemoteClient.h"
@@ -159,6 +174,10 @@
#include <malloc.h>
#endif
+#if defined (XP_MACOSX)
+#include <Carbon/Carbon.h>
+#endif
+
#ifdef DEBUG
#include "mozilla/Logging.h"
#endif
@@ -1072,6 +1091,12 @@ ScopedXPCOMStartup::~ScopedXPCOMStartup()
NS_IF_RELEASE(gNativeAppSupport);
if (mServiceManager) {
+#ifdef XP_MACOSX
+ // On OS X, we need a pool to catch cocoa objects that are autoreleased
+ // during teardown.
+ mozilla::MacAutoreleasePool pool;
+#endif
+
nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID));
if (appStartup)
appStartup->DestroyHiddenWindow();
@@ -1457,6 +1482,10 @@ static nsresult LaunchChild(nsINativeAppSupport* aNative,
SaveToEnv("MOZ_LAUNCHED_CHILD=1");
+#if defined(XP_MACOSX)
+ CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
+ LaunchChildMac(gRestartArgc, gRestartArgv);
+#else
nsCOMPtr<nsIFile> lf;
nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
if (NS_FAILED(rv))
@@ -1491,6 +1520,7 @@ static nsresult LaunchChild(nsINativeAppSupport* aNative,
return NS_ERROR_FAILURE;
#endif // XP_UNIX
#endif // WP_WIN
+#endif // WP_MACOSX
return NS_ERROR_LAUNCHED_CHILD_PROCESS;
}
@@ -1559,9 +1589,15 @@ ProfileLockedDialog(nsIFile* aProfileDir, nsIFile* aProfileLocalDir,
const char16_t* params[] = {appName.get(), appName.get()};
nsXPIDLString killMessage;
+#ifndef XP_MACOSX
sb->FormatStringFromName(aUnlocker ? u"restartMessageUnlocker"
: u"restartMessageNoUnlocker",
params, 2, getter_Copies(killMessage));
+#else
+ sb->FormatStringFromName(aUnlocker ? u"restartMessageUnlockerMac"
+ : u"restartMessageNoUnlockerMac",
+ params, 2, getter_Copies(killMessage));
+#endif
nsXPIDLString killTitle;
sb->FormatStringFromName(u"restartTitle",
@@ -1705,6 +1741,10 @@ ShowProfileManager(nsIToolkitProfileService* aProfileSvc,
rv = xpcom.SetWindowCreator(aNative);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+#ifdef XP_MACOSX
+ CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
+#endif
+
#ifdef XP_WIN
// we don't have to wait here because profile manager window will pump
// and DDE message will be handled
@@ -2810,6 +2850,13 @@ XREMain::XRE_mainInit(bool* aExitFlag)
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
+
greDir.forget(&mAppData->xreDirectory);
}
@@ -2843,6 +2890,40 @@ XREMain::XRE_mainInit(bool* aExitFlag)
if (NS_FAILED(rv))
return 1;
+#ifdef XP_MACOSX
+ // Set up ability to respond to system (Apple) events. This must occur before
+ // ProcessUpdates to ensure that links clicked in external applications aren't
+ // lost when updates are pending.
+ SetupMacApplicationDelegate();
+
+ if (EnvHasValue("MOZ_LAUNCHED_CHILD")) {
+ // This is needed, on relaunch, to force the OS to use the "Cocoa Dock
+ // API". Otherwise the call to ReceiveNextEvent() below will make it
+ // use the "Carbon Dock API". For more info see bmo bug 377166.
+ EnsureUseCocoaDockAPI();
+
+ // When the app relaunches, the original process exits. This causes
+ // the dock tile to stop bouncing, lose the "running" triangle, and
+ // if the tile does not permanently reside in the Dock, even disappear.
+ // This can be confusing to the user, who is expecting the app to launch.
+ // Calling ReceiveNextEvent without requesting any event is enough to
+ // cause a dock tile for the child process to appear.
+ const EventTypeSpec kFakeEventList[] = { { INT_MAX, INT_MAX } };
+ EventRef event;
+ ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList,
+ kEventDurationNoWait, false, &event);
+ }
+
+ if (CheckArg("foreground")) {
+ // The original process communicates that it was in the foreground by
+ // adding this argument. This new process, which is taking over for
+ // the old one, should make itself the active application.
+ ProcessSerialNumber psn;
+ if (::GetCurrentProcess(&psn) == noErr)
+ ::SetFrontProcess(&psn);
+ }
+#endif
+
SaveToEnv("MOZ_LAUNCHED_CHILD=");
gRestartArgc = gArgc;
@@ -2893,6 +2974,12 @@ XREMain::XRE_mainInit(bool* aExitFlag)
}
#endif
+#ifdef XP_MACOSX
+ if ((GetCurrentEventKeyModifiers() & optionKey) &&
+ !EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY"))
+ gSafeMode = true;
+#endif
+
#ifdef XP_WIN
{
// Add CPU microcode version to the crash report as "CPUMicrocodeVersion".
@@ -3666,6 +3753,19 @@ XREMain::XRE_mainRun()
g_unsetenv ("DESKTOP_STARTUP_ID");
#endif
+#ifdef XP_MACOSX
+ // we re-initialize the command-line service and do appleevents munging
+ // after we are sure that we're not restarting
+ cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
+ NS_ENSURE_TRUE(cmdLine, NS_ERROR_FAILURE);
+
+ CommandLineServiceMac::SetupMacCommandLine(gArgc, gArgv, false);
+
+ rv = cmdLine->Init(gArgc, gArgv,
+ workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
+ NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+#endif
+
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService();
if (obsService)
diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp
index 841ea2a2d0..109782b5f8 100644
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -39,6 +39,10 @@
#include "nsXREDirProvider.h"
#include "mozilla/Omnijar.h"
+#if defined(XP_MACOSX)
+#include "nsVersionComparator.h"
+#include "chrome/common/mach_ipc_mac.h"
+#endif
#include "nsX11ErrorHandler.h"
#include "nsGDKErrorHandler.h"
#include "base/at_exit.h"
@@ -280,6 +284,81 @@ XRE_InitChildProcess(int aArgc,
PROFILER_LABEL("Startup", "XRE_InitChildProcess",
js::ProfileEntry::Category::OTHER);
+ // Complete 'task_t' exchange for Mac OS X. This structure has the same size
+ // regardless of architecture so we don't have any cross-arch issues here.
+#ifdef XP_MACOSX
+ if (aArgc < 1)
+ return NS_ERROR_FAILURE;
+ const char* const mach_port_name = aArgv[--aArgc];
+
+ const int kTimeoutMs = 1000;
+
+ MachSendMessage child_message(0);
+ if (!child_message.AddDescriptor(MachMsgPortDescriptor(mach_task_self()))) {
+ NS_WARNING("child AddDescriptor(mach_task_self()) failed.");
+ return NS_ERROR_FAILURE;
+ }
+
+ ReceivePort child_recv_port;
+ mach_port_t raw_child_recv_port = child_recv_port.GetPort();
+ if (!child_message.AddDescriptor(MachMsgPortDescriptor(raw_child_recv_port))) {
+ NS_WARNING("Adding descriptor to message failed");
+ return NS_ERROR_FAILURE;
+ }
+
+ ReceivePort* ports_out_receiver = new ReceivePort();
+ if (!child_message.AddDescriptor(MachMsgPortDescriptor(ports_out_receiver->GetPort()))) {
+ NS_WARNING("Adding descriptor to message failed");
+ return NS_ERROR_FAILURE;
+ }
+
+ ReceivePort* ports_in_receiver = new ReceivePort();
+ if (!child_message.AddDescriptor(MachMsgPortDescriptor(ports_in_receiver->GetPort()))) {
+ NS_WARNING("Adding descriptor to message failed");
+ return NS_ERROR_FAILURE;
+ }
+
+ MachPortSender child_sender(mach_port_name);
+ kern_return_t err = child_sender.SendMessage(child_message, kTimeoutMs);
+ if (err != KERN_SUCCESS) {
+ NS_WARNING("child SendMessage() failed");
+ return NS_ERROR_FAILURE;
+ }
+
+ MachReceiveMessage parent_message;
+ err = child_recv_port.WaitForMessage(&parent_message, kTimeoutMs);
+ if (err != KERN_SUCCESS) {
+ NS_WARNING("child WaitForMessage() failed");
+ return NS_ERROR_FAILURE;
+ }
+
+ if (parent_message.GetTranslatedPort(0) == MACH_PORT_NULL) {
+ NS_WARNING("child GetTranslatedPort(0) failed");
+ return NS_ERROR_FAILURE;
+ }
+
+ err = task_set_bootstrap_port(mach_task_self(),
+ parent_message.GetTranslatedPort(0));
+
+ if (parent_message.GetTranslatedPort(1) == MACH_PORT_NULL) {
+ NS_WARNING("child GetTranslatedPort(1) failed");
+ return NS_ERROR_FAILURE;
+ }
+ MachPortSender* ports_out_sender = new MachPortSender(parent_message.GetTranslatedPort(1));
+
+ if (parent_message.GetTranslatedPort(2) == MACH_PORT_NULL) {
+ NS_WARNING("child GetTranslatedPort(2) failed");
+ return NS_ERROR_FAILURE;
+ }
+ MachPortSender* ports_in_sender = new MachPortSender(parent_message.GetTranslatedPort(2));
+
+ if (err != KERN_SUCCESS) {
+ NS_WARNING("child task_set_bootstrap_port() failed");
+ return NS_ERROR_FAILURE;
+ }
+
+#endif
+
SetupErrorHandling(aArgv[0]);
gArgv = aArgv;
@@ -325,6 +404,11 @@ XRE_InitChildProcess(int aArgc,
base::ProcessId parentPID = strtol(parentPIDString, &end, 10);
MOZ_ASSERT(!*end, "invalid parent PID");
+#ifdef XP_MACOSX
+ mozilla::ipc::SharedMemoryBasic::SetupMachMemory(parentPID, ports_in_receiver, ports_in_sender,
+ ports_out_sender, ports_out_receiver, true);
+#endif
+
#if defined(XP_WIN)
// On Win7+, register the application user model id passed in by
// parent. This insures windows created by the container properly
@@ -456,6 +540,11 @@ XRE_InitChildProcess(int aArgc,
// scope and being deleted
process->CleanUp();
mozilla::Omnijar::CleanUp();
+
+#if defined(XP_MACOSX)
+ // Everybody should be done using shared memory by now.
+ mozilla::ipc::SharedMemoryBasic::Shutdown();
+#endif
}
}
@@ -571,6 +660,47 @@ XRE_RunAppShell()
{
nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
+#if defined(XP_MACOSX)
+ {
+ // In content processes that want XPCOM (and hence want
+ // AppShell), we usually run our hybrid event loop through
+ // MessagePump::Run(), by way of nsBaseAppShell::Run(). The
+ // Cocoa nsAppShell impl, however, implements its own Run()
+ // that's unaware of MessagePump. That's all rather suboptimal,
+ // but oddly enough not a problem... usually.
+ //
+ // The problem with this setup comes during startup.
+ // XPCOM-in-subprocesses depends on IPC, e.g. to init the pref
+ // service, so we have to init IPC first. But, IPC also
+ // indirectly kinda-depends on XPCOM, because MessagePump
+ // schedules work from off-main threads (e.g. IO thread) by
+ // using NS_DispatchToMainThread(). If the IO thread receives a
+ // Message from the parent before nsThreadManager is
+ // initialized, then DispatchToMainThread() will fail, although
+ // MessagePump will remember the task. This race condition
+ // isn't a problem when appShell->Run() ends up in
+ // MessagePump::Run(), because MessagePump will immediate see it
+ // has work to do. It *is* a problem when we end up in [NSApp
+ // run], because it's not aware that MessagePump has work that
+ // needs to be processed; that was supposed to be signaled by
+ // nsIRunnable(s).
+ //
+ // So instead of hacking Cocoa nsAppShell or rewriting the
+ // event-loop system, we compromise here by processing any tasks
+ // that might have been enqueued on MessagePump, *before*
+ // MessagePump::ScheduleWork was able to successfully
+ // DispatchToMainThread().
+ MessageLoop* loop = MessageLoop::current();
+ bool couldNest = loop->NestableTasksAllowed();
+
+ loop->SetNestableTasksAllowed(true);
+ RefPtr<Runnable> task = new MessageLoop::QuitTask();
+ loop->PostTask(task.forget());
+ loop->Run();
+
+ loop->SetNestableTasksAllowed(couldNest);
+ }
+#endif // XP_MACOSX
return appShell->Run();
}
@@ -589,6 +719,16 @@ XRE_ShutdownChildProcess()
// (4) ProcessChild joins the IO thread
// (5) exit()
MessageLoop::current()->Quit();
+#if defined(XP_MACOSX)
+ nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
+ if (appShell) {
+ // On Mac, we might be only above nsAppShell::Run(), not
+ // MessagePump::Run(). See XRE_RunAppShell(). To account for
+ // that case, we fire off an Exit() here. If we were indeed
+ // above MessagePump::Run(), this Exit() is just superfluous.
+ appShell->Exit();
+ }
+#endif // XP_MACOSX
}
namespace {
diff --git a/toolkit/xre/nsSigHandlers.cpp b/toolkit/xre/nsSigHandlers.cpp
index 68d909848c..11648e45ac 100644
--- a/toolkit/xre/nsSigHandlers.cpp
+++ b/toolkit/xre/nsSigHandlers.cpp
@@ -154,6 +154,22 @@ static void fpehandler(int signum, siginfo_t *si, void *context)
NS_DebugBreak(NS_DEBUG_ABORT, "Divide by zero", nullptr, __FILE__, __LINE__);
}
+#ifdef XP_MACOSX
+ ucontext_t *uc = (ucontext_t *)context;
+
+#if defined(__i386__) || defined(__amd64__)
+ _STRUCT_FP_CONTROL *ctrl = &uc->uc_mcontext->__fs.__fpu_fcw;
+ ctrl->__invalid = ctrl->__denorm = ctrl->__zdiv = ctrl->__ovrfl = ctrl->__undfl = ctrl->__precis = 1;
+
+ _STRUCT_FP_STATUS *status = &uc->uc_mcontext->__fs.__fpu_fsw;
+ status->__invalid = status->__denorm = status->__zdiv = status->__ovrfl = status->__undfl =
+ status->__precis = status->__stkflt = status->__errsumm = 0;
+
+ uint32_t *mxcsr = &uc->uc_mcontext->__fs.__fpu_mxcsr;
+ *mxcsr |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
+ *mxcsr &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
+#endif
+#endif
#if defined(LINUX)
ucontext_t *uc = (ucontext_t *)context;
diff --git a/toolkit/xre/nsUpdateDriver.cpp b/toolkit/xre/nsUpdateDriver.cpp
index 812818788c..4994458852 100644
--- a/toolkit/xre/nsUpdateDriver.cpp
+++ b/toolkit/xre/nsUpdateDriver.cpp
@@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
@@ -26,6 +27,13 @@
#include "nsPrintfCString.h"
#include "mozilla/DebugOnly.h"
+#ifdef XP_MACOSX
+#include "nsILocalFileMac.h"
+#include "nsCommandLineServiceMac.h"
+#include "MacLaunchHelper.h"
+#include "updaterfileutils_osx.h"
+#endif
+
#if defined(XP_WIN)
# include <direct.h>
# include <process.h>
@@ -53,11 +61,16 @@ GetUpdateLog()
#ifdef XP_WIN
#define UPDATER_BIN "updater.exe"
+#elif XP_MACOSX
+#define UPDATER_BIN "org.mozilla.updater"
#else
#define UPDATER_BIN "updater"
#endif
#define UPDATER_INI "updater.ini"
-#if defined(XP_UNIX)
+#ifdef XP_MACOSX
+#define UPDATER_APP "updater.app"
+#endif
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
#define UPDATER_PNG "updater.png"
#endif
@@ -96,7 +109,18 @@ static nsresult
GetInstallDirPath(nsIFile *appDir, nsACString& installDirPath)
{
nsresult rv;
-#if XP_WIN
+#ifdef XP_MACOSX
+ nsCOMPtr<nsIFile> parentDir1, parentDir2;
+ rv = appDir->GetParent(getter_AddRefs(parentDir1));
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = parentDir1->GetParent(getter_AddRefs(parentDir2));
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = parentDir2->GetNativePath(installDirPath);
+#elif XP_WIN
nsAutoString installDirPathW;
rv = appDir->GetPath(installDirPathW);
if (NS_FAILED(rv)) {
@@ -112,6 +136,35 @@ GetInstallDirPath(nsIFile *appDir, nsACString& installDirPath)
return NS_OK;
}
+#if defined(XP_MACOSX)
+// This is a copy of OS X's XRE_GetBinaryPath from nsAppRunner.cpp with the
+// gBinaryPath check removed so that the updater can reload the stub executable
+// instead of xulrunner-bin. See bug 349737.
+static nsresult
+GetXULRunnerStubPath(const char* argv0, nsIFile* *aResult)
+{
+ // Works even if we're not bundled.
+ CFBundleRef appBundle = ::CFBundleGetMainBundle();
+ if (!appBundle)
+ return NS_ERROR_FAILURE;
+
+ CFURLRef bundleURL = ::CFBundleCopyExecutableURL(appBundle);
+ if (!bundleURL)
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsILocalFileMac> lfm;
+ nsresult rv = NS_NewLocalFileWithCFURL(bundleURL, true, getter_AddRefs(lfm));
+
+ ::CFRelease(bundleURL);
+
+ if (NS_FAILED(rv))
+ return rv;
+
+ lfm.forget(aResult);
+ return NS_OK;
+}
+#endif /* XP_MACOSX */
+
static bool
GetFile(nsIFile *dir, const nsCSubstring &name, nsCOMPtr<nsIFile> &result)
{
@@ -271,10 +324,16 @@ CopyUpdaterIntoUpdateDir(nsIFile *greDir, nsIFile *appDir, nsIFile *updateDir,
nsCOMPtr<nsIFile> &updater)
{
// Copy the updater application from the GRE and the updater ini from the app
+#if defined(XP_MACOSX)
+ if (!CopyFileIntoUpdateDir(appDir, NS_LITERAL_CSTRING(UPDATER_APP), updateDir))
+ return false;
+ CopyFileIntoUpdateDir(greDir, NS_LITERAL_CSTRING(UPDATER_INI), updateDir);
+#else
if (!CopyFileIntoUpdateDir(greDir, NS_LITERAL_CSTRING(UPDATER_BIN), updateDir))
return false;
CopyFileIntoUpdateDir(appDir, NS_LITERAL_CSTRING(UPDATER_INI), updateDir);
-#if defined(XP_UNIX)
+#endif
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
nsCOMPtr<nsIFile> iconDir;
appDir->Clone(getter_AddRefs(iconDir));
iconDir->AppendNative(NS_LITERAL_CSTRING("icons"));
@@ -285,6 +344,16 @@ CopyUpdaterIntoUpdateDir(nsIFile *greDir, nsIFile *appDir, nsIFile *updateDir,
nsresult rv = updateDir->Clone(getter_AddRefs(updater));
if (NS_FAILED(rv))
return false;
+#if defined(XP_MACOSX)
+ rv = updater->AppendNative(NS_LITERAL_CSTRING(UPDATER_APP));
+ nsresult tmp = updater->AppendNative(NS_LITERAL_CSTRING("Contents"));
+ if (NS_FAILED(tmp)) {
+ rv = tmp;
+ }
+ tmp = updater->AppendNative(NS_LITERAL_CSTRING("MacOS"));
+ if (NS_FAILED(tmp) || NS_FAILED(rv))
+ return false;
+#endif
rv = updater->AppendNative(NS_LITERAL_CSTRING(UPDATER_BIN));
return NS_SUCCEEDED(rv);
}
@@ -295,7 +364,8 @@ CopyUpdaterIntoUpdateDir(nsIFile *greDir, nsIFile *appDir, nsIFile *updateDir,
*
* @param pathToAppend A new library path to prepend to LD_LIBRARY_PATH
*/
-#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN)
+#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \
+ !defined(XP_MACOSX)
#include "prprf.h"
#define PATH_SEPARATOR ":"
#define LD_LIBRARY_PATH_ENVVAR_NAME "LD_LIBRARY_PATH"
@@ -372,7 +442,13 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir,
// to restart the running application.
nsCOMPtr<nsIFile> appFile;
+#if defined(XP_MACOSX)
+ // On OS X we need to pass the location of the xulrunner-stub executable
+ // rather than xulrunner-bin. See bug 349737.
+ GetXULRunnerStubPath(appArgv[0], getter_AddRefs(appFile));
+#else
XRE_GetBinaryPath(appArgv[0], getter_AddRefs(appFile));
+#endif
if (!appFile)
return;
@@ -424,7 +500,11 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir,
// Get the directory where the update will be staged.
nsAutoCString applyToDir;
nsCOMPtr<nsIFile> updatedDir;
+#ifdef XP_MACOSX
+ if (!GetFile(updateDir, NS_LITERAL_CSTRING("Updated.app"), updatedDir)) {
+#else
if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir)) {
+#endif
return;
}
#ifdef XP_WIN
@@ -468,7 +548,7 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir,
// Construct the PID argument for this process. We start the updater using
// execv on all Unix platforms except Mac, so on those platforms we pass 0
// instead of a good PID to signal the updater not to try and wait for us.
-#if defined(XP_UNIX)
+#if defined(XP_UNIX) & !defined(XP_MACOSX)
nsAutoCString pid("0");
#else
nsAutoCString pid;
@@ -508,13 +588,14 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir,
if (gSafeMode) {
PR_SetEnv("MOZ_SAFE_MODE_RESTART=1");
}
-#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN)
+#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \
+ !defined(XP_MACOSX)
AppendToLibPath(installDirPath.get());
#endif
LOG(("spawning updater process for replacing [%s]\n", updaterPath.get()));
-#if defined(XP_UNIX)
+#if defined(XP_UNIX) & !defined(XP_MACOSX)
exit(execv(updaterPath.get(), argv));
#elif defined(XP_WIN)
// Switch the application using updater.exe
@@ -522,6 +603,10 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir,
return;
}
_exit(0);
+#elif defined(XP_MACOSX)
+ CommandLineServiceMac::SetupMacCommandLine(argc, argv, true);
+ LaunchChildMac(argc, argv);
+ exit(0);
#else
PR_CreateProcessDetached(updaterPath.get(), argv, nullptr, nullptr);
exit(0);
@@ -567,7 +652,13 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
// to restart the running application.
nsCOMPtr<nsIFile> appFile;
+#if defined(XP_MACOSX)
+ // On OS X we need to pass the location of the xulrunner-stub executable
+ // rather than xulrunner-bin. See bug 349737.
+ GetXULRunnerStubPath(appArgv[0], getter_AddRefs(appFile));
+#else
XRE_GetBinaryPath(appArgv[0], getter_AddRefs(appFile));
+#endif
if (!appFile)
return;
@@ -623,7 +714,11 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
if (restart && !isOSUpdate) {
applyToDir.Assign(installDirPath);
} else {
+#ifdef XP_MACOSX
+ if (!GetFile(updateDir, NS_LITERAL_CSTRING("Updated.app"), updatedDir)) {
+#else
if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir)) {
+#endif
return;
}
#ifdef XP_WIN
@@ -678,7 +773,7 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
// Signal the updater application that it should stage the update.
pid.AssignASCII("-1");
} else {
-#if defined(XP_UNIX)
+#if defined(XP_UNIX) & !defined(XP_MACOSX)
pid.AssignASCII("0");
#else
pid.AppendInt((int32_t) getpid());
@@ -714,7 +809,8 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
if (gSafeMode) {
PR_SetEnv("MOZ_SAFE_MODE_RESTART=1");
}
-#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN)
+#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \
+ !defined(XP_MACOSX)
AppendToLibPath(installDirPath.get());
#endif
@@ -724,10 +820,10 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
LOG(("spawning updater process [%s]\n", updaterPath.get()));
-#if defined(XP_UNIX)
- // We use execv to spawn the updater process on all UNIX-like systems.
- // Windows has execv, but it is a faked implementation that doesn't really
- // replace the current process.
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
+ // We use execv to spawn the updater process on all UNIX systems except Mac OSX
+ // since it is known to cause problems on the Mac. Windows has execv, but it
+ // is a faked implementation that doesn't really replace the current process.
// Instead it spawns a new process, so we gain nothing from using execv on
// Windows.
if (restart) {
@@ -749,6 +845,24 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
// We are going to process an update so we should exit now
_exit(0);
}
+#elif defined(XP_MACOSX)
+ CommandLineServiceMac::SetupMacCommandLine(argc, argv, restart);
+ // We need to detect whether elevation is required for this update. This can
+ // occur when an admin user installs the application, but another admin
+ // user attempts to update (see bug 394984).
+ if (restart && !IsRecursivelyWritable(installDirPath.get())) {
+ if (!LaunchElevatedUpdate(argc, argv, outpid)) {
+ LOG(("Failed to launch elevated update!"));
+ exit(1);
+ }
+ exit(0);
+ } else {
+ if (restart) {
+ LaunchChildMac(argc, argv);
+ exit(0);
+ }
+ LaunchChildMac(argc, argv, outpid);
+ }
#else
*outpid = PR_CreateProcess(updaterPath.get(), argv, nullptr, nullptr);
if (restart) {
@@ -769,6 +883,9 @@ ProcessHasTerminated(ProcessType pt)
}
CloseHandle(pt);
return true;
+#elif defined(XP_MACOSX)
+ // We're waiting for the process to terminate in LaunchChildMac.
+ return true;
#elif defined(XP_UNIX)
int exitStatus;
pid_t exited = waitpid(pt, &exitStatus, WNOHANG);
diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp
index fdeee8d0f9..e38cc4f35b 100644
--- a/toolkit/xre/nsXREDirProvider.cpp
+++ b/toolkit/xre/nsXREDirProvider.cpp
@@ -48,11 +48,19 @@
#include <windows.h>
#include <shlobj.h>
#endif
+#ifdef XP_MACOSX
+#include "nsILocalFileMac.h"
+// for chflags()
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
#ifdef XP_UNIX
#include <ctype.h>
#endif
-#if defined(XP_WIN)
+#if defined(XP_MACOSX)
+#define APP_REGISTRY_NAME "Application Registry"
+#elif defined(XP_WIN)
#define APP_REGISTRY_NAME "registry.dat"
#else
#define APP_REGISTRY_NAME "appreg"
@@ -100,6 +108,9 @@ nsXREDirProvider::Initialize(nsIFile *aXULAppDir,
mXULAppDir = aXULAppDir;
mGREDir = aGREDir;
mGREDir->Clone(getter_AddRefs(mGREBinDir));
+#ifdef XP_MACOSX
+ mGREBinDir->SetNativeLeafName(NS_LITERAL_CSTRING("MacOS"));
+#endif
if (!mProfileDir) {
nsCOMPtr<nsIDirectoryServiceProvider> app(do_QueryInterface(mAppProvider));
@@ -129,6 +140,30 @@ nsXREDirProvider::SetProfile(nsIFile* aDir, nsIFile* aLocalDir)
if (NS_FAILED(rv))
return rv;
+#ifdef XP_MACOSX
+ bool same;
+ if (NS_SUCCEEDED(aDir->Equals(aLocalDir, &same)) && !same) {
+ // Ensure that the cache directory is not indexed by Spotlight
+ // (bug 718910). At least on OS X, the cache directory (under
+ // ~/Library/Caches/) is always the "local" user profile
+ // directory. This is confusing, since *both* user profile
+ // directories are "local" (they both exist under the user's
+ // home directory). But this usage dates back at least as far
+ // as the patch for bug 291033, where "local" seems to mean
+ // "suitable for temporary storage". Don't hide the cache
+ // directory if by some chance it and the "non-local" profile
+ // directory are the same -- there are bad side effects from
+ // hiding a profile directory under /Library/Application Support/
+ // (see bug 801883).
+ nsAutoCString cacheDir;
+ if (NS_SUCCEEDED(aLocalDir->GetNativePath(cacheDir))) {
+ if (chflags(cacheDir.get(), UF_HIDDEN)) {
+ NS_WARNING("Failed to set Cache directory to HIDDEN.");
+ }
+ }
+ }
+#endif
+
mProfileDir = aDir;
mProfileLocalDir = aLocalDir;
return NS_OK;
@@ -163,7 +198,7 @@ nsXREDirProvider::GetUserProfilesRootDir(nsIFile** aResult,
aProfileName, aAppName, aVendorName);
if (NS_SUCCEEDED(rv)) {
-#if !defined(XP_UNIX)
+#if !defined(XP_UNIX) || defined(XP_MACOSX)
rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
#endif
// We must create the profile directory here if it does not exist.
@@ -188,7 +223,7 @@ nsXREDirProvider::GetUserProfilesLocalDir(nsIFile** aResult,
aProfileName, aAppName, aVendorName);
if (NS_SUCCEEDED(rv)) {
-#if !defined(XP_UNIX)
+#if !defined(XP_UNIX) || defined(XP_MACOSX)
rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
#endif
// We must create the profile directory here if it does not exist.
@@ -201,7 +236,7 @@ nsXREDirProvider::GetUserProfilesLocalDir(nsIFile** aResult,
return NS_OK;
}
-#if defined(XP_UNIX)
+#if defined(XP_UNIX) || defined(XP_MACOSX)
/**
* Get the directory that is the parent of the system-wide directories
* for extensions and native-messaing manifests.
@@ -215,6 +250,12 @@ GetSystemParentDirectory(nsIFile** aFile)
{
nsresult rv;
nsCOMPtr<nsIFile> localDir;
+#if defined(XP_MACOSX)
+ rv = GetOSXFolderType(kOnSystemDisk, kApplicationSupportFolderType, getter_AddRefs(localDir));
+ if (NS_SUCCEEDED(rv)) {
+ rv = localDir->AppendNative(NS_LITERAL_CSTRING("Mozilla"));
+ }
+#else
NS_NAMED_LITERAL_CSTRING(dirname,
#ifdef HAVE_USR_LIB64_DIR
"/usr/lib64/mozilla"
@@ -225,6 +266,7 @@ GetSystemParentDirectory(nsIFile** aFile)
#endif
);
rv = NS_NewNativeLocalFile(dirname, false, getter_AddRefs(localDir));
+#endif
if (NS_SUCCEEDED(rv)) {
localDir.forget(aFile);
@@ -308,14 +350,18 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
!strcmp(aProperty, XRE_USER_APP_DATA_DIR)) {
rv = GetUserAppDataDirectory(getter_AddRefs(file));
}
-#if defined(XP_UNIX)
+#if defined(XP_UNIX) || defined(XP_MACOSX)
else if (!strcmp(aProperty, XRE_SYS_NATIVE_MESSAGING_MANIFESTS)) {
nsCOMPtr<nsIFile> localDir;
rv = ::GetSystemParentDirectory(getter_AddRefs(localDir));
if (NS_SUCCEEDED(rv)) {
NS_NAMED_LITERAL_CSTRING(dirname,
+#if defined(XP_MACOSX)
+ "NativeMessagingHosts"
+#else
"native-messaging-hosts"
+#endif
);
rv = localDir->AppendNative(dirname);
if (NS_SUCCEEDED(rv)) {
@@ -327,10 +373,17 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
nsCOMPtr<nsIFile> localDir;
rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), false);
if (NS_SUCCEEDED(rv)) {
+#if defined(XP_MACOSX)
+ rv = localDir->AppendNative(NS_LITERAL_CSTRING("Mozilla"));
+ if (NS_SUCCEEDED(rv)) {
+ rv = localDir->AppendNative(NS_LITERAL_CSTRING("NativeMessagingHosts"));
+ }
+#else
rv = localDir->AppendNative(NS_LITERAL_CSTRING(".mozilla"));
if (NS_SUCCEEDED(rv)) {
rv = localDir->AppendNative(NS_LITERAL_CSTRING("native-messaging-hosts"));
}
+#endif
}
if (NS_SUCCEEDED(rv)) {
localDir.swap(file);
@@ -372,7 +425,7 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
return mAppProvider->GetFile(NS_APP_PROFILE_DIR_STARTUP, aPersistent,
aFile);
}
-#if defined(XP_UNIX)
+#if defined(XP_UNIX) || defined(XP_MACOSX)
else if (!strcmp(aProperty, XRE_SYS_LOCAL_EXTENSION_PARENT_DIR)) {
#ifdef ENABLE_SYSTEM_EXTENSION_DIRS
return GetSystemExtensionsDirectory(aFile);
@@ -381,7 +434,7 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
#endif
}
#endif
-#if defined(XP_UNIX)
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
else if (!strcmp(aProperty, XRE_SYS_SHARE_EXTENSION_PARENT_DIR)) {
#ifdef ENABLE_SYSTEM_EXTENSION_DIRS
#if defined(__OpenBSD__) || defined(__FreeBSD__)
@@ -1050,7 +1103,42 @@ nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
rv = appFile->GetParent(getter_AddRefs(updRoot));
NS_ENSURE_SUCCESS(rv, rv);
-#if XP_WIN
+#ifdef XP_MACOSX
+ nsCOMPtr<nsIFile> appRootDirFile;
+ nsCOMPtr<nsIFile> localDir;
+ nsAutoString appDirPath;
+ if (NS_FAILED(appFile->GetParent(getter_AddRefs(appRootDirFile))) ||
+ NS_FAILED(appRootDirFile->GetPath(appDirPath)) ||
+ NS_FAILED(GetUserDataDirectoryHome(getter_AddRefs(localDir), true))) {
+ return NS_ERROR_FAILURE;
+ }
+
+ int32_t dotIndex = appDirPath.RFind(".app");
+ if (dotIndex == kNotFound) {
+ dotIndex = appDirPath.Length();
+ }
+ appDirPath = Substring(appDirPath, 1, dotIndex - 1);
+
+ bool hasVendor = gAppData->vendor && strlen(gAppData->vendor) != 0;
+ if (hasVendor || gAppData->name) {
+ if (NS_FAILED(localDir->AppendNative(nsDependentCString(hasVendor ?
+ gAppData->vendor :
+ gAppData->name)))) {
+ return NS_ERROR_FAILURE;
+ }
+ } else if (NS_FAILED(localDir->AppendNative(NS_LITERAL_CSTRING("Mozilla")))) {
+ return NS_ERROR_FAILURE;
+ }
+
+ if (NS_FAILED(localDir->Append(NS_LITERAL_STRING("updates"))) ||
+ NS_FAILED(localDir->AppendRelativePath(appDirPath))) {
+ return NS_ERROR_FAILURE;
+ }
+
+ localDir.forget(aResult);
+ return NS_OK;
+
+#elif XP_WIN
nsAutoString pathHash;
bool pathHashResult = false;
bool hasVendor = gAppData->vendor && strlen(gAppData->vendor) != 0;
@@ -1192,7 +1280,32 @@ nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile, bool aLocal)
nsresult rv;
nsCOMPtr<nsIFile> localDir;
-#if defined(XP_WIN)
+#if defined(XP_MACOSX)
+ FSRef fsRef;
+ OSType folderType;
+ if (aLocal) {
+ folderType = kCachedDataFolderType;
+ } else {
+#ifdef MOZ_THUNDERBIRD
+ folderType = kDomainLibraryFolderType;
+#else
+ folderType = kApplicationSupportFolderType;
+#endif
+ }
+ OSErr err = ::FSFindFolder(kUserDomain, folderType, kCreateFolder, &fsRef);
+ NS_ENSURE_FALSE(err, NS_ERROR_FAILURE);
+
+ rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(localDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(localDir);
+ NS_ENSURE_TRUE(dirFileMac, NS_ERROR_UNEXPECTED);
+
+ rv = dirFileMac->InitWithFSRef(&fsRef);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ localDir = do_QueryInterface(dirFileMac, &rv);
+#elif defined(XP_WIN)
nsString path;
if (aLocal) {
rv = GetShellFolderPath(CSIDL_LOCAL_APPDATA, path);
@@ -1255,7 +1368,7 @@ nsXREDirProvider::GetSysUserExtensionsDirectory(nsIFile** aFile)
return NS_OK;
}
-#if defined(XP_UNIX)
+#if defined(XP_UNIX) || defined(XP_MACOSX)
nsresult
nsXREDirProvider::GetSystemExtensionsDirectory(nsIFile** aFile)
{
@@ -1265,7 +1378,11 @@ nsXREDirProvider::GetSystemExtensionsDirectory(nsIFile** aFile)
rv = GetSystemParentDirectory(getter_AddRefs(localDir));
if (NS_SUCCEEDED(rv)) {
NS_NAMED_LITERAL_CSTRING(sExtensions,
+#if defined(XP_MACOSX)
+ "Extensions"
+#else
"extensions"
+#endif
);
rv = localDir->AppendNative(sExtensions);
@@ -1332,7 +1449,7 @@ nsXREDirProvider::AppendSysUserExtensionPath(nsIFile* aFile)
nsresult rv;
-#if defined(XP_WIN)
+#if defined (XP_MACOSX) || defined(XP_WIN)
static const char* const sXR = "Mozilla";
rv = aFile->AppendNative(nsDependentCString(sXR));
@@ -1391,7 +1508,19 @@ nsXREDirProvider::AppendProfilePath(nsIFile* aFile,
nsresult rv;
-#if defined(XP_WIN)
+#if defined (XP_MACOSX)
+ if (!profile.IsEmpty()) {
+ rv = AppendProfileString(aFile, profile.get());
+ }
+ else {
+ // Note that MacOS ignores the vendor when creating the profile hierarchy -
+ // all application preferences directories live alongside one another in
+ // ~/Library/Application Support/
+ rv = aFile->AppendNative(appName);
+ }
+ NS_ENSURE_SUCCESS(rv, rv);
+
+#elif defined(XP_WIN)
if (!profile.IsEmpty()) {
rv = AppendProfileString(aFile, profile.get());
}
diff --git a/toolkit/xre/nsXREDirProvider.h b/toolkit/xre/nsXREDirProvider.h
index 014317e641..655f664e6d 100644
--- a/toolkit/xre/nsXREDirProvider.h
+++ b/toolkit/xre/nsXREDirProvider.h
@@ -102,7 +102,7 @@ protected:
nsresult GetFilesInternal(const char* aProperty, nsISimpleEnumerator** aResult);
static nsresult GetUserDataDirectoryHome(nsIFile* *aFile, bool aLocal);
static nsresult GetSysUserExtensionsDirectory(nsIFile* *aFile);
-#if defined(XP_UNIX)
+#if defined(XP_UNIX) || defined(XP_MACOSX)
static nsresult GetSystemExtensionsDirectory(nsIFile** aFile);
#endif
static nsresult EnsureDirectoryExists(nsIFile* aDirectory);