diff options
Diffstat (limited to 'toolkit/xre')
-rw-r--r-- | toolkit/xre/nsAppRunner.cpp | 100 | ||||
-rw-r--r-- | toolkit/xre/nsEmbedFunctions.cpp | 140 | ||||
-rw-r--r-- | toolkit/xre/nsSigHandlers.cpp | 16 | ||||
-rw-r--r-- | toolkit/xre/nsUpdateDriver.cpp | 143 | ||||
-rw-r--r-- | toolkit/xre/nsXREDirProvider.cpp | 153 | ||||
-rw-r--r-- | toolkit/xre/nsXREDirProvider.h | 2 |
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); |