toolkit/xre/nsEmbedFunctions.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "mozilla/DebugOnly.h"
     7 #if defined(MOZ_WIDGET_QT)
     8 #include "nsQAppInstance.h"
     9 #endif
    11 #include "base/basictypes.h"
    13 #include "nsXULAppAPI.h"
    15 #include <stdlib.h>
    16 #if defined(MOZ_WIDGET_GTK)
    17 #include <glib.h>
    18 #endif
    20 #include "prenv.h"
    22 #include "nsIAppShell.h"
    23 #include "nsIAppStartupNotifier.h"
    24 #include "nsIDirectoryService.h"
    25 #include "nsIFile.h"
    26 #include "nsIToolkitChromeRegistry.h"
    27 #include "nsIToolkitProfile.h"
    29 #ifdef XP_WIN
    30 #include <process.h>
    31 #include "mozilla/ipc/WindowsMessageLoop.h"
    32 #endif
    34 #include "nsAppDirectoryServiceDefs.h"
    35 #include "nsAppRunner.h"
    36 #include "nsAutoRef.h"
    37 #include "nsDirectoryServiceDefs.h"
    38 #include "nsExceptionHandler.h"
    39 #include "nsString.h"
    40 #include "nsThreadUtils.h"
    41 #include "nsJSUtils.h"
    42 #include "nsWidgetsCID.h"
    43 #include "nsXREDirProvider.h"
    45 #include "mozilla/Omnijar.h"
    46 #if defined(XP_MACOSX)
    47 #include "nsVersionComparator.h"
    48 #include "chrome/common/mach_ipc_mac.h"
    49 #endif
    50 #include "nsX11ErrorHandler.h"
    51 #include "base/at_exit.h"
    52 #include "base/command_line.h"
    53 #include "base/message_loop.h"
    54 #include "base/process_util.h"
    55 #include "chrome/common/child_process.h"
    56 #include "chrome/common/notification_service.h"
    58 #include "mozilla/ipc/BrowserProcessSubThread.h"
    59 #include "mozilla/ipc/GeckoChildProcessHost.h"
    60 #include "mozilla/ipc/IOThreadChild.h"
    61 #include "mozilla/ipc/ProcessChild.h"
    62 #include "ScopedXREEmbed.h"
    64 #include "mozilla/plugins/PluginProcessChild.h"
    65 #include "mozilla/dom/ContentProcess.h"
    66 #include "mozilla/dom/ContentParent.h"
    67 #include "mozilla/dom/ContentChild.h"
    69 #include "mozilla/ipc/TestShellParent.h"
    70 #include "mozilla/ipc/XPCShellEnvironment.h"
    72 #include "GeckoProfiler.h"
    74 #ifdef MOZ_IPDL_TESTS
    75 #include "mozilla/_ipdltest/IPDLUnitTests.h"
    76 #include "mozilla/_ipdltest/IPDLUnitTestProcessChild.h"
    78 using mozilla::_ipdltest::IPDLUnitTestProcessChild;
    79 #endif  // ifdef MOZ_IPDL_TESTS
    81 using namespace mozilla;
    83 using mozilla::ipc::BrowserProcessSubThread;
    84 using mozilla::ipc::GeckoChildProcessHost;
    85 using mozilla::ipc::IOThreadChild;
    86 using mozilla::ipc::ProcessChild;
    87 using mozilla::ipc::ScopedXREEmbed;
    89 using mozilla::plugins::PluginProcessChild;
    90 using mozilla::dom::ContentProcess;
    91 using mozilla::dom::ContentParent;
    92 using mozilla::dom::ContentChild;
    94 using mozilla::ipc::TestShellParent;
    95 using mozilla::ipc::TestShellCommandParent;
    96 using mozilla::ipc::XPCShellEnvironment;
    98 using mozilla::startup::sChildProcessType;
   100 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
   102 #ifdef XP_WIN
   103 static const wchar_t kShellLibraryName[] =  L"shell32.dll";
   104 #endif
   106 nsresult
   107 XRE_LockProfileDirectory(nsIFile* aDirectory,
   108                          nsISupports* *aLockObject)
   109 {
   110   nsCOMPtr<nsIProfileLock> lock;
   112   nsresult rv = NS_LockProfilePath(aDirectory, nullptr, nullptr,
   113                                    getter_AddRefs(lock));
   114   if (NS_SUCCEEDED(rv))
   115     NS_ADDREF(*aLockObject = lock);
   117   return rv;
   118 }
   120 static int32_t sInitCounter;
   122 nsresult
   123 XRE_InitEmbedding2(nsIFile *aLibXULDirectory,
   124 		   nsIFile *aAppDirectory,
   125 		   nsIDirectoryServiceProvider *aAppDirProvider)
   126 {
   127   // Initialize some globals to make nsXREDirProvider happy
   128   static char* kNullCommandLine[] = { nullptr };
   129   gArgv = kNullCommandLine;
   130   gArgc = 0;
   132   NS_ENSURE_ARG(aLibXULDirectory);
   134   if (++sInitCounter > 1) // XXXbsmedberg is this really the right solution?
   135     return NS_OK;
   137   if (!aAppDirectory)
   138     aAppDirectory = aLibXULDirectory;
   140   nsresult rv;
   142   new nsXREDirProvider; // This sets gDirServiceProvider
   143   if (!gDirServiceProvider)
   144     return NS_ERROR_OUT_OF_MEMORY;
   146   rv = gDirServiceProvider->Initialize(aAppDirectory, aLibXULDirectory,
   147                                        aAppDirProvider);
   148   if (NS_FAILED(rv))
   149     return rv;
   151   rv = NS_InitXPCOM2(nullptr, aAppDirectory, gDirServiceProvider);
   152   if (NS_FAILED(rv))
   153     return rv;
   155   // We do not need to autoregister components here. The CheckCompatibility()
   156   // bits in nsAppRunner.cpp check for an invalidation flag in
   157   // compatibility.ini.
   158   // If the app wants to autoregister every time (for instance, if it's debug),
   159   // it can do so after we return from this function.
   161   nsCOMPtr<nsIObserver> startupNotifier
   162     (do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID));
   163   if (!startupNotifier)
   164     return NS_ERROR_FAILURE;
   166   startupNotifier->Observe(nullptr, APPSTARTUP_TOPIC, nullptr);
   168   return NS_OK;
   169 }
   171 void
   172 XRE_NotifyProfile()
   173 {
   174   NS_ASSERTION(gDirServiceProvider, "XRE_InitEmbedding was not called!");
   175   gDirServiceProvider->DoStartup();
   176 }
   178 void
   179 XRE_TermEmbedding()
   180 {
   181   if (--sInitCounter != 0)
   182     return;
   184   NS_ASSERTION(gDirServiceProvider,
   185                "XRE_TermEmbedding without XRE_InitEmbedding");
   187   gDirServiceProvider->DoShutdown();
   188   NS_ShutdownXPCOM(nullptr);
   189   delete gDirServiceProvider;
   190 }
   192 const char*
   193 XRE_ChildProcessTypeToString(GeckoProcessType aProcessType)
   194 {
   195   return (aProcessType < GeckoProcessType_End) ?
   196     kGeckoProcessTypeString[aProcessType] : nullptr;
   197 }
   199 GeckoProcessType
   200 XRE_StringToChildProcessType(const char* aProcessTypeString)
   201 {
   202   for (int i = 0;
   203        i < (int) ArrayLength(kGeckoProcessTypeString);
   204        ++i) {
   205     if (!strcmp(kGeckoProcessTypeString[i], aProcessTypeString)) {
   206       return static_cast<GeckoProcessType>(i);
   207     }
   208   }
   209   return GeckoProcessType_Invalid;
   210 }
   212 namespace mozilla {
   213 namespace startup {
   214 GeckoProcessType sChildProcessType = GeckoProcessType_Default;
   215 }
   216 }
   218 #if defined(MOZ_CRASHREPORTER)
   219 // FIXME/bug 539522: this out-of-place function is stuck here because
   220 // IPDL wants access to this crashreporter interface, and
   221 // crashreporter is built in such a way to make that awkward
   222 bool
   223 XRE_TakeMinidumpForChild(uint32_t aChildPid, nsIFile** aDump,
   224                          uint32_t* aSequence)
   225 {
   226   return CrashReporter::TakeMinidumpForChild(aChildPid, aDump, aSequence);
   227 }
   229 bool
   230 XRE_SetRemoteExceptionHandler(const char* aPipe/*= 0*/)
   231 {
   232 #if defined(XP_WIN) || defined(XP_MACOSX)
   233   return CrashReporter::SetRemoteExceptionHandler(nsDependentCString(aPipe));
   234 #elif defined(OS_LINUX)
   235   return CrashReporter::SetRemoteExceptionHandler();
   236 #else
   237 #  error "OOP crash reporter unsupported on this platform"
   238 #endif
   239 }
   240 #endif // if defined(MOZ_CRASHREPORTER)
   242 #if defined(XP_WIN)
   243 void
   244 SetTaskbarGroupId(const nsString& aId)
   245 {
   246     typedef HRESULT (WINAPI * SetCurrentProcessExplicitAppUserModelIDPtr)(PCWSTR AppID);
   248     SetCurrentProcessExplicitAppUserModelIDPtr funcAppUserModelID = nullptr;
   250     HMODULE hDLL = ::LoadLibraryW(kShellLibraryName);
   252     funcAppUserModelID = (SetCurrentProcessExplicitAppUserModelIDPtr)
   253                           GetProcAddress(hDLL, "SetCurrentProcessExplicitAppUserModelID");
   255     if (!funcAppUserModelID) {
   256         ::FreeLibrary(hDLL);
   257         return;
   258     }
   260     if (FAILED(funcAppUserModelID(aId.get()))) {
   261         NS_WARNING("SetCurrentProcessExplicitAppUserModelID failed for child process.");
   262     }
   264     if (hDLL)
   265         ::FreeLibrary(hDLL);
   266 }
   267 #endif
   269 nsresult
   270 XRE_InitChildProcess(int aArgc,
   271                      char* aArgv[],
   272                      GeckoProcessType aProcess)
   273 {
   274   NS_ENSURE_ARG_MIN(aArgc, 2);
   275   NS_ENSURE_ARG_POINTER(aArgv);
   276   NS_ENSURE_ARG_POINTER(aArgv[0]);
   278 #if defined(XP_WIN)
   279   // From the --attach-console support in nsNativeAppSupportWin.cpp, but
   280   // here we are a content child process, so we always attempt to attach
   281   // to the parent's (ie, the browser's) console.
   282   // Try to attach console to the parent process.
   283   // It will succeed when the parent process is a command line,
   284   // so that stdio will be displayed in it.
   285   if (AttachConsole(ATTACH_PARENT_PROCESS)) {
   286     // Change std handles to refer to new console handles.
   287     // Before doing so, ensure that stdout/stderr haven't been
   288     // redirected to a valid file
   289     if (_fileno(stdout) == -1 ||
   290         _get_osfhandle(fileno(stdout)) == -1)
   291         freopen("CONOUT$", "w", stdout);
   292     // Merge stderr into CONOUT$ since there isn't any `CONERR$`.
   293     // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
   294     if (_fileno(stderr) == -1 ||
   295         _get_osfhandle(fileno(stderr)) == -1)
   296         freopen("CONOUT$", "w", stderr);
   297     if (_fileno(stdin) == -1 || _get_osfhandle(fileno(stdin)) == -1)
   298         freopen("CONIN$", "r", stdin);
   299   }
   300 #endif
   302   char aLocal;
   303   profiler_init(&aLocal);
   304   PROFILER_LABEL("Startup", "XRE_InitChildProcess");
   306   sChildProcessType = aProcess;
   308   // Complete 'task_t' exchange for Mac OS X. This structure has the same size
   309   // regardless of architecture so we don't have any cross-arch issues here.
   310 #ifdef XP_MACOSX
   311   if (aArgc < 1)
   312     return NS_ERROR_FAILURE;
   313   const char* const mach_port_name = aArgv[--aArgc];
   315   const int kTimeoutMs = 1000;
   317   MachSendMessage child_message(0);
   318   if (!child_message.AddDescriptor(mach_task_self())) {
   319     NS_WARNING("child AddDescriptor(mach_task_self()) failed.");
   320     return NS_ERROR_FAILURE;
   321   }
   323   ReceivePort child_recv_port;
   324   mach_port_t raw_child_recv_port = child_recv_port.GetPort();
   325   if (!child_message.AddDescriptor(raw_child_recv_port)) {
   326     NS_WARNING("Adding descriptor to message failed");
   327     return NS_ERROR_FAILURE;
   328   }
   330   MachPortSender child_sender(mach_port_name);
   331   kern_return_t err = child_sender.SendMessage(child_message, kTimeoutMs);
   332   if (err != KERN_SUCCESS) {
   333     NS_WARNING("child SendMessage() failed");
   334     return NS_ERROR_FAILURE;
   335   }
   337   MachReceiveMessage parent_message;
   338   err = child_recv_port.WaitForMessage(&parent_message, kTimeoutMs);
   339   if (err != KERN_SUCCESS) {
   340     NS_WARNING("child WaitForMessage() failed");
   341     return NS_ERROR_FAILURE;
   342   }
   344   if (parent_message.GetTranslatedPort(0) == MACH_PORT_NULL) {
   345     NS_WARNING("child GetTranslatedPort(0) failed");
   346     return NS_ERROR_FAILURE;
   347   }
   348   err = task_set_bootstrap_port(mach_task_self(),
   349                                 parent_message.GetTranslatedPort(0));
   350   if (err != KERN_SUCCESS) {
   351     NS_WARNING("child task_set_bootstrap_port() failed");
   352     return NS_ERROR_FAILURE;
   353   }
   354 #endif
   356   SetupErrorHandling(aArgv[0]);  
   358 #if defined(MOZ_CRASHREPORTER)
   359   if (aArgc < 1)
   360     return NS_ERROR_FAILURE;
   361   const char* const crashReporterArg = aArgv[--aArgc];
   363 #  if defined(XP_WIN) || defined(XP_MACOSX)
   364   // on windows and mac, |crashReporterArg| is the named pipe on which the
   365   // server is listening for requests, or "-" if crash reporting is
   366   // disabled.
   367   if (0 != strcmp("-", crashReporterArg) && 
   368       !XRE_SetRemoteExceptionHandler(crashReporterArg)) {
   369     // Bug 684322 will add better visibility into this condition
   370     NS_WARNING("Could not setup crash reporting\n");
   371   }
   372 #  elif defined(OS_LINUX)
   373   // on POSIX, |crashReporterArg| is "true" if crash reporting is
   374   // enabled, false otherwise
   375   if (0 != strcmp("false", crashReporterArg) && 
   376       !XRE_SetRemoteExceptionHandler(nullptr)) {
   377     // Bug 684322 will add better visibility into this condition
   378     NS_WARNING("Could not setup crash reporting\n");
   379   }
   380 #  else
   381 #    error "OOP crash reporting unsupported on this platform"
   382 #  endif   
   383 #endif // if defined(MOZ_CRASHREPORTER)
   385   gArgv = aArgv;
   386   gArgc = aArgc;
   388 #if defined(MOZ_WIDGET_GTK)
   389   g_thread_init(nullptr);
   390 #endif
   392 #if defined(MOZ_WIDGET_QT)
   393   nsQAppInstance::AddRef();
   394 #endif
   396   if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS")) {
   397 #ifdef OS_POSIX
   398       printf("\n\nCHILDCHILDCHILDCHILD\n  debug me @ %d\n\n", getpid());
   399       sleep(30);
   400 #elif defined(OS_WIN)
   401       // Windows has a decent JIT debugging story, so NS_DebugBreak does the
   402       // right thing.
   403       NS_DebugBreak(NS_DEBUG_BREAK,
   404                     "Invoking NS_DebugBreak() to debug child process",
   405                     nullptr, __FILE__, __LINE__);
   406 #endif
   407   }
   409   // child processes launched by GeckoChildProcessHost get this magic
   410   // argument appended to their command lines
   411   const char* const parentPIDString = aArgv[aArgc-1];
   412   NS_ABORT_IF_FALSE(parentPIDString, "NULL parent PID");
   413   --aArgc;
   415   char* end = 0;
   416   base::ProcessId parentPID = strtol(parentPIDString, &end, 10);
   417   NS_ABORT_IF_FALSE(!*end, "invalid parent PID");
   419   base::ProcessHandle parentHandle;
   420   mozilla::DebugOnly<bool> ok = base::OpenProcessHandle(parentPID, &parentHandle);
   421   NS_ABORT_IF_FALSE(ok, "can't open handle to parent");
   423 #if defined(XP_WIN)
   424   // On Win7+, register the application user model id passed in by
   425   // parent. This insures windows created by the container properly
   426   // group with the parent app on the Win7 taskbar.
   427   const char* const appModelUserId = aArgv[--aArgc];
   428   if (appModelUserId) {
   429     // '-' implies no support
   430     if (*appModelUserId != '-') {
   431       nsString appId;
   432       appId.AssignWithConversion(nsDependentCString(appModelUserId));
   433       // The version string is encased in quotes
   434       appId.Trim(NS_LITERAL_CSTRING("\"").get());
   435       // Set the id
   436       SetTaskbarGroupId(appId);
   437     }
   438   }
   439 #endif
   441   base::AtExitManager exitManager;
   442   NotificationService notificationService;
   444   NS_LogInit();
   446   nsresult rv = XRE_InitCommandLine(aArgc, aArgv);
   447   if (NS_FAILED(rv)) {
   448     profiler_shutdown();
   449     NS_LogTerm();
   450     return NS_ERROR_FAILURE;
   451   }
   453   MessageLoop::Type uiLoopType;
   454   switch (aProcess) {
   455   case GeckoProcessType_Content:
   456       // Content processes need the XPCOM/chromium frankenventloop
   457       uiLoopType = MessageLoop::TYPE_MOZILLA_CHILD;
   458       break;
   459   default:
   460       uiLoopType = MessageLoop::TYPE_UI;
   461       break;
   462   }
   464   {
   465     // This is a lexical scope for the MessageLoop below.  We want it
   466     // to go out of scope before NS_LogTerm() so that we don't get
   467     // spurious warnings about XPCOM objects being destroyed from a
   468     // static context.
   470     // Associate this thread with a UI MessageLoop
   471     MessageLoop uiMessageLoop(uiLoopType);
   472     {
   473       nsAutoPtr<ProcessChild> process;
   475 #ifdef XP_WIN
   476       mozilla::ipc::windows::InitUIThread();
   477 #endif
   479       switch (aProcess) {
   480       case GeckoProcessType_Default:
   481         NS_RUNTIMEABORT("This makes no sense");
   482         break;
   484       case GeckoProcessType_Plugin:
   485         process = new PluginProcessChild(parentHandle);
   486         break;
   488       case GeckoProcessType_Content: {
   489           process = new ContentProcess(parentHandle);
   490           // If passed in grab the application path for xpcom init
   491           nsCString appDir;
   492           for (int idx = aArgc; idx > 0; idx--) {
   493             if (aArgv[idx] && !strcmp(aArgv[idx], "-appdir")) {
   494               appDir.Assign(nsDependentCString(aArgv[idx+1]));
   495               static_cast<ContentProcess*>(process.get())->SetAppDir(appDir);
   496               break;
   497             }
   498           }
   499         }
   500         break;
   502       case GeckoProcessType_IPDLUnitTest:
   503 #ifdef MOZ_IPDL_TESTS
   504         process = new IPDLUnitTestProcessChild(parentHandle);
   505 #else 
   506         NS_RUNTIMEABORT("rebuild with --enable-ipdl-tests");
   507 #endif
   508         break;
   510       default:
   511         NS_RUNTIMEABORT("Unknown main thread class");
   512       }
   514       if (!process->Init()) {
   515         profiler_shutdown();
   516         NS_LogTerm();
   517         return NS_ERROR_FAILURE;
   518       }
   520       // Run the UI event loop on the main thread.
   521       uiMessageLoop.MessageLoop::Run();
   523       // Allow ProcessChild to clean up after itself before going out of
   524       // scope and being deleted
   525       process->CleanUp();
   526       mozilla::Omnijar::CleanUp();
   527     }
   528   }
   530   profiler_shutdown();
   531   NS_LogTerm();
   532   return XRE_DeinitCommandLine();
   533 }
   535 MessageLoop*
   536 XRE_GetIOMessageLoop()
   537 {
   538   if (sChildProcessType == GeckoProcessType_Default) {
   539     return BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO);
   540   }
   541   return IOThreadChild::message_loop();
   542 }
   544 namespace {
   546 class MainFunctionRunnable : public nsRunnable
   547 {
   548 public:
   549   NS_DECL_NSIRUNNABLE
   551   MainFunctionRunnable(MainFunction aFunction,
   552                        void* aData)
   553   : mFunction(aFunction),
   554     mData(aData)
   555   { 
   556     NS_ASSERTION(aFunction, "Don't give me a null pointer!");
   557   }
   559 private:
   560   MainFunction mFunction;
   561   void* mData;
   562 };
   564 } /* anonymous namespace */
   566 NS_IMETHODIMP
   567 MainFunctionRunnable::Run()
   568 {
   569   mFunction(mData);
   570   return NS_OK;
   571 }
   573 nsresult
   574 XRE_InitParentProcess(int aArgc,
   575                       char* aArgv[],
   576                       MainFunction aMainFunction,
   577                       void* aMainFunctionData)
   578 {
   579   NS_ENSURE_ARG_MIN(aArgc, 1);
   580   NS_ENSURE_ARG_POINTER(aArgv);
   581   NS_ENSURE_ARG_POINTER(aArgv[0]);
   583   ScopedXREEmbed embed;
   585   gArgc = aArgc;
   586   gArgv = aArgv;
   587   nsresult rv = XRE_InitCommandLine(gArgc, gArgv);
   588   if (NS_FAILED(rv))
   589       return NS_ERROR_FAILURE;
   591   {
   592     embed.Start();
   594     nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
   595     NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
   597     if (aMainFunction) {
   598       nsCOMPtr<nsIRunnable> runnable =
   599         new MainFunctionRunnable(aMainFunction, aMainFunctionData);
   600       NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
   602       nsresult rv = NS_DispatchToCurrentThread(runnable);
   603       NS_ENSURE_SUCCESS(rv, rv);
   604     }
   606     // Do event loop
   607     if (NS_FAILED(appShell->Run())) {
   608       NS_WARNING("Failed to run appshell");
   609       return NS_ERROR_FAILURE;
   610     }
   611   }
   613   return XRE_DeinitCommandLine();
   614 }
   616 #ifdef MOZ_IPDL_TESTS
   617 //-----------------------------------------------------------------------------
   618 // IPDL unit test
   620 int
   621 XRE_RunIPDLTest(int aArgc, char** aArgv)
   622 {
   623     if (aArgc < 2) {
   624         fprintf(stderr, "TEST-UNEXPECTED-FAIL | <---> | insufficient #args, need at least 2\n");
   625         return 1;
   626     }
   628     void* data = reinterpret_cast<void*>(aArgv[aArgc-1]);
   630     nsresult rv =
   631         XRE_InitParentProcess(
   632             --aArgc, aArgv, mozilla::_ipdltest::IPDLUnitTestMain, data);
   633     NS_ENSURE_SUCCESS(rv, 1);
   635     return 0;
   636 }
   637 #endif  // ifdef MOZ_IPDL_TESTS
   639 nsresult
   640 XRE_RunAppShell()
   641 {
   642     nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
   643     NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
   644 #if defined(XP_MACOSX)
   645     {
   646       // In content processes that want XPCOM (and hence want
   647       // AppShell), we usually run our hybrid event loop through
   648       // MessagePump::Run(), by way of nsBaseAppShell::Run().  The
   649       // Cocoa nsAppShell impl, however, implements its own Run()
   650       // that's unaware of MessagePump.  That's all rather suboptimal,
   651       // but oddly enough not a problem... usually.
   652       // 
   653       // The problem with this setup comes during startup.
   654       // XPCOM-in-subprocesses depends on IPC, e.g. to init the pref
   655       // service, so we have to init IPC first.  But, IPC also
   656       // indirectly kinda-depends on XPCOM, because MessagePump
   657       // schedules work from off-main threads (e.g. IO thread) by
   658       // using NS_DispatchToMainThread().  If the IO thread receives a
   659       // Message from the parent before nsThreadManager is
   660       // initialized, then DispatchToMainThread() will fail, although
   661       // MessagePump will remember the task.  This race condition
   662       // isn't a problem when appShell->Run() ends up in
   663       // MessagePump::Run(), because MessagePump will immediate see it
   664       // has work to do.  It *is* a problem when we end up in [NSApp
   665       // run], because it's not aware that MessagePump has work that
   666       // needs to be processed; that was supposed to be signaled by
   667       // nsIRunnable(s).
   668       // 
   669       // So instead of hacking Cocoa nsAppShell or rewriting the
   670       // event-loop system, we compromise here by processing any tasks
   671       // that might have been enqueued on MessagePump, *before*
   672       // MessagePump::ScheduleWork was able to successfully
   673       // DispatchToMainThread().
   674       MessageLoop* loop = MessageLoop::current();
   675       bool couldNest = loop->NestableTasksAllowed();
   677       loop->SetNestableTasksAllowed(true);
   678       loop->PostTask(FROM_HERE, new MessageLoop::QuitTask());
   679       loop->Run();
   681       loop->SetNestableTasksAllowed(couldNest);
   682     }
   683 #endif  // XP_MACOSX
   684     return appShell->Run();
   685 }
   687 template<>
   688 struct RunnableMethodTraits<ContentChild>
   689 {
   690     static void RetainCallee(ContentChild* obj) { }
   691     static void ReleaseCallee(ContentChild* obj) { }
   692 };
   694 void
   695 XRE_ShutdownChildProcess()
   696 {
   697   NS_ABORT_IF_FALSE(MessageLoopForUI::current(), "Wrong thread!");
   699   mozilla::DebugOnly<MessageLoop*> ioLoop = XRE_GetIOMessageLoop();
   700   NS_ABORT_IF_FALSE(!!ioLoop, "Bad shutdown order");
   702   // Quit() sets off the following chain of events
   703   //  (1) UI loop starts quitting
   704   //  (2) UI loop returns from Run() in XRE_InitChildProcess()
   705   //  (3) ProcessChild goes out of scope and terminates the IO thread
   706   //  (4) ProcessChild joins the IO thread
   707   //  (5) exit()
   708   MessageLoop::current()->Quit();
   709 #if defined(XP_MACOSX)
   710   nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
   711   if (appShell) {
   712       // On Mac, we might be only above nsAppShell::Run(), not
   713       // MessagePump::Run().  See XRE_RunAppShell(). To account for
   714       // that case, we fire off an Exit() here.  If we were indeed
   715       // above MessagePump::Run(), this Exit() is just superfluous.
   716       appShell->Exit();
   717   }
   718 #endif // XP_MACOSX
   719 }
   721 namespace {
   722 ContentParent* gContentParent; //long-lived, manually refcounted
   723 TestShellParent* GetOrCreateTestShellParent()
   724 {
   725     if (!gContentParent) {
   726         nsRefPtr<ContentParent> parent = ContentParent::GetNewOrUsed();
   727         parent.forget(&gContentParent);
   728     } else if (!gContentParent->IsAlive()) {
   729         return nullptr;
   730     }
   731     TestShellParent* tsp = gContentParent->GetTestShellSingleton();
   732     if (!tsp) {
   733         tsp = gContentParent->CreateTestShell();
   734     }
   735     return tsp;
   736 }
   737 }
   739 bool
   740 XRE_SendTestShellCommand(JSContext* aCx,
   741                          JSString* aCommand,
   742                          void* aCallback)
   743 {
   744     JS::RootedString cmd(aCx, aCommand);
   745     TestShellParent* tsp = GetOrCreateTestShellParent();
   746     NS_ENSURE_TRUE(tsp, false);
   748     nsDependentJSString command;
   749     NS_ENSURE_TRUE(command.init(aCx, cmd), false);
   751     if (!aCallback) {
   752         return tsp->SendExecuteCommand(command);
   753     }
   755     TestShellCommandParent* callback = static_cast<TestShellCommandParent*>(
   756         tsp->SendPTestShellCommandConstructor(command));
   757     NS_ENSURE_TRUE(callback, false);
   759     JS::Value callbackVal = *reinterpret_cast<JS::Value*>(aCallback);
   760     NS_ENSURE_TRUE(callback->SetCallback(aCx, callbackVal), false);
   762     return true;
   763 }
   765 bool
   766 XRE_ShutdownTestShell()
   767 {
   768     if (!gContentParent) {
   769         return true;
   770     }
   771     bool ret = true;
   772     if (gContentParent->IsAlive()) {
   773         ret = gContentParent->DestroyTestShell(
   774             gContentParent->GetTestShellSingleton());
   775     }
   776     NS_RELEASE(gContentParent);
   777     return ret;
   778 }
   780 #ifdef MOZ_X11
   781 void
   782 XRE_InstallX11ErrorHandler()
   783 {
   784   InstallX11ErrorHandler();
   785 }
   786 #endif
   788 #ifdef XP_WIN
   789 static WindowsEnvironmentType
   790 sWindowsEnvironmentType = WindowsEnvironmentType_Desktop;
   792 void
   793 SetWindowsEnvironment(WindowsEnvironmentType aEnvID)
   794 {
   795   sWindowsEnvironmentType = aEnvID;
   796 }
   798 WindowsEnvironmentType
   799 XRE_GetWindowsEnvironment()
   800 {
   801   return sWindowsEnvironmentType;
   802 }
   803 #endif // XP_WIN

mercurial