1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/xre/nsEmbedFunctions.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,804 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "mozilla/DebugOnly.h" 1.9 + 1.10 +#if defined(MOZ_WIDGET_QT) 1.11 +#include "nsQAppInstance.h" 1.12 +#endif 1.13 + 1.14 +#include "base/basictypes.h" 1.15 + 1.16 +#include "nsXULAppAPI.h" 1.17 + 1.18 +#include <stdlib.h> 1.19 +#if defined(MOZ_WIDGET_GTK) 1.20 +#include <glib.h> 1.21 +#endif 1.22 + 1.23 +#include "prenv.h" 1.24 + 1.25 +#include "nsIAppShell.h" 1.26 +#include "nsIAppStartupNotifier.h" 1.27 +#include "nsIDirectoryService.h" 1.28 +#include "nsIFile.h" 1.29 +#include "nsIToolkitChromeRegistry.h" 1.30 +#include "nsIToolkitProfile.h" 1.31 + 1.32 +#ifdef XP_WIN 1.33 +#include <process.h> 1.34 +#include "mozilla/ipc/WindowsMessageLoop.h" 1.35 +#endif 1.36 + 1.37 +#include "nsAppDirectoryServiceDefs.h" 1.38 +#include "nsAppRunner.h" 1.39 +#include "nsAutoRef.h" 1.40 +#include "nsDirectoryServiceDefs.h" 1.41 +#include "nsExceptionHandler.h" 1.42 +#include "nsString.h" 1.43 +#include "nsThreadUtils.h" 1.44 +#include "nsJSUtils.h" 1.45 +#include "nsWidgetsCID.h" 1.46 +#include "nsXREDirProvider.h" 1.47 + 1.48 +#include "mozilla/Omnijar.h" 1.49 +#if defined(XP_MACOSX) 1.50 +#include "nsVersionComparator.h" 1.51 +#include "chrome/common/mach_ipc_mac.h" 1.52 +#endif 1.53 +#include "nsX11ErrorHandler.h" 1.54 +#include "base/at_exit.h" 1.55 +#include "base/command_line.h" 1.56 +#include "base/message_loop.h" 1.57 +#include "base/process_util.h" 1.58 +#include "chrome/common/child_process.h" 1.59 +#include "chrome/common/notification_service.h" 1.60 + 1.61 +#include "mozilla/ipc/BrowserProcessSubThread.h" 1.62 +#include "mozilla/ipc/GeckoChildProcessHost.h" 1.63 +#include "mozilla/ipc/IOThreadChild.h" 1.64 +#include "mozilla/ipc/ProcessChild.h" 1.65 +#include "ScopedXREEmbed.h" 1.66 + 1.67 +#include "mozilla/plugins/PluginProcessChild.h" 1.68 +#include "mozilla/dom/ContentProcess.h" 1.69 +#include "mozilla/dom/ContentParent.h" 1.70 +#include "mozilla/dom/ContentChild.h" 1.71 + 1.72 +#include "mozilla/ipc/TestShellParent.h" 1.73 +#include "mozilla/ipc/XPCShellEnvironment.h" 1.74 + 1.75 +#include "GeckoProfiler.h" 1.76 + 1.77 +#ifdef MOZ_IPDL_TESTS 1.78 +#include "mozilla/_ipdltest/IPDLUnitTests.h" 1.79 +#include "mozilla/_ipdltest/IPDLUnitTestProcessChild.h" 1.80 + 1.81 +using mozilla::_ipdltest::IPDLUnitTestProcessChild; 1.82 +#endif // ifdef MOZ_IPDL_TESTS 1.83 + 1.84 +using namespace mozilla; 1.85 + 1.86 +using mozilla::ipc::BrowserProcessSubThread; 1.87 +using mozilla::ipc::GeckoChildProcessHost; 1.88 +using mozilla::ipc::IOThreadChild; 1.89 +using mozilla::ipc::ProcessChild; 1.90 +using mozilla::ipc::ScopedXREEmbed; 1.91 + 1.92 +using mozilla::plugins::PluginProcessChild; 1.93 +using mozilla::dom::ContentProcess; 1.94 +using mozilla::dom::ContentParent; 1.95 +using mozilla::dom::ContentChild; 1.96 + 1.97 +using mozilla::ipc::TestShellParent; 1.98 +using mozilla::ipc::TestShellCommandParent; 1.99 +using mozilla::ipc::XPCShellEnvironment; 1.100 + 1.101 +using mozilla::startup::sChildProcessType; 1.102 + 1.103 +static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); 1.104 + 1.105 +#ifdef XP_WIN 1.106 +static const wchar_t kShellLibraryName[] = L"shell32.dll"; 1.107 +#endif 1.108 + 1.109 +nsresult 1.110 +XRE_LockProfileDirectory(nsIFile* aDirectory, 1.111 + nsISupports* *aLockObject) 1.112 +{ 1.113 + nsCOMPtr<nsIProfileLock> lock; 1.114 + 1.115 + nsresult rv = NS_LockProfilePath(aDirectory, nullptr, nullptr, 1.116 + getter_AddRefs(lock)); 1.117 + if (NS_SUCCEEDED(rv)) 1.118 + NS_ADDREF(*aLockObject = lock); 1.119 + 1.120 + return rv; 1.121 +} 1.122 + 1.123 +static int32_t sInitCounter; 1.124 + 1.125 +nsresult 1.126 +XRE_InitEmbedding2(nsIFile *aLibXULDirectory, 1.127 + nsIFile *aAppDirectory, 1.128 + nsIDirectoryServiceProvider *aAppDirProvider) 1.129 +{ 1.130 + // Initialize some globals to make nsXREDirProvider happy 1.131 + static char* kNullCommandLine[] = { nullptr }; 1.132 + gArgv = kNullCommandLine; 1.133 + gArgc = 0; 1.134 + 1.135 + NS_ENSURE_ARG(aLibXULDirectory); 1.136 + 1.137 + if (++sInitCounter > 1) // XXXbsmedberg is this really the right solution? 1.138 + return NS_OK; 1.139 + 1.140 + if (!aAppDirectory) 1.141 + aAppDirectory = aLibXULDirectory; 1.142 + 1.143 + nsresult rv; 1.144 + 1.145 + new nsXREDirProvider; // This sets gDirServiceProvider 1.146 + if (!gDirServiceProvider) 1.147 + return NS_ERROR_OUT_OF_MEMORY; 1.148 + 1.149 + rv = gDirServiceProvider->Initialize(aAppDirectory, aLibXULDirectory, 1.150 + aAppDirProvider); 1.151 + if (NS_FAILED(rv)) 1.152 + return rv; 1.153 + 1.154 + rv = NS_InitXPCOM2(nullptr, aAppDirectory, gDirServiceProvider); 1.155 + if (NS_FAILED(rv)) 1.156 + return rv; 1.157 + 1.158 + // We do not need to autoregister components here. The CheckCompatibility() 1.159 + // bits in nsAppRunner.cpp check for an invalidation flag in 1.160 + // compatibility.ini. 1.161 + // If the app wants to autoregister every time (for instance, if it's debug), 1.162 + // it can do so after we return from this function. 1.163 + 1.164 + nsCOMPtr<nsIObserver> startupNotifier 1.165 + (do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID)); 1.166 + if (!startupNotifier) 1.167 + return NS_ERROR_FAILURE; 1.168 + 1.169 + startupNotifier->Observe(nullptr, APPSTARTUP_TOPIC, nullptr); 1.170 + 1.171 + return NS_OK; 1.172 +} 1.173 + 1.174 +void 1.175 +XRE_NotifyProfile() 1.176 +{ 1.177 + NS_ASSERTION(gDirServiceProvider, "XRE_InitEmbedding was not called!"); 1.178 + gDirServiceProvider->DoStartup(); 1.179 +} 1.180 + 1.181 +void 1.182 +XRE_TermEmbedding() 1.183 +{ 1.184 + if (--sInitCounter != 0) 1.185 + return; 1.186 + 1.187 + NS_ASSERTION(gDirServiceProvider, 1.188 + "XRE_TermEmbedding without XRE_InitEmbedding"); 1.189 + 1.190 + gDirServiceProvider->DoShutdown(); 1.191 + NS_ShutdownXPCOM(nullptr); 1.192 + delete gDirServiceProvider; 1.193 +} 1.194 + 1.195 +const char* 1.196 +XRE_ChildProcessTypeToString(GeckoProcessType aProcessType) 1.197 +{ 1.198 + return (aProcessType < GeckoProcessType_End) ? 1.199 + kGeckoProcessTypeString[aProcessType] : nullptr; 1.200 +} 1.201 + 1.202 +GeckoProcessType 1.203 +XRE_StringToChildProcessType(const char* aProcessTypeString) 1.204 +{ 1.205 + for (int i = 0; 1.206 + i < (int) ArrayLength(kGeckoProcessTypeString); 1.207 + ++i) { 1.208 + if (!strcmp(kGeckoProcessTypeString[i], aProcessTypeString)) { 1.209 + return static_cast<GeckoProcessType>(i); 1.210 + } 1.211 + } 1.212 + return GeckoProcessType_Invalid; 1.213 +} 1.214 + 1.215 +namespace mozilla { 1.216 +namespace startup { 1.217 +GeckoProcessType sChildProcessType = GeckoProcessType_Default; 1.218 +} 1.219 +} 1.220 + 1.221 +#if defined(MOZ_CRASHREPORTER) 1.222 +// FIXME/bug 539522: this out-of-place function is stuck here because 1.223 +// IPDL wants access to this crashreporter interface, and 1.224 +// crashreporter is built in such a way to make that awkward 1.225 +bool 1.226 +XRE_TakeMinidumpForChild(uint32_t aChildPid, nsIFile** aDump, 1.227 + uint32_t* aSequence) 1.228 +{ 1.229 + return CrashReporter::TakeMinidumpForChild(aChildPid, aDump, aSequence); 1.230 +} 1.231 + 1.232 +bool 1.233 +XRE_SetRemoteExceptionHandler(const char* aPipe/*= 0*/) 1.234 +{ 1.235 +#if defined(XP_WIN) || defined(XP_MACOSX) 1.236 + return CrashReporter::SetRemoteExceptionHandler(nsDependentCString(aPipe)); 1.237 +#elif defined(OS_LINUX) 1.238 + return CrashReporter::SetRemoteExceptionHandler(); 1.239 +#else 1.240 +# error "OOP crash reporter unsupported on this platform" 1.241 +#endif 1.242 +} 1.243 +#endif // if defined(MOZ_CRASHREPORTER) 1.244 + 1.245 +#if defined(XP_WIN) 1.246 +void 1.247 +SetTaskbarGroupId(const nsString& aId) 1.248 +{ 1.249 + typedef HRESULT (WINAPI * SetCurrentProcessExplicitAppUserModelIDPtr)(PCWSTR AppID); 1.250 + 1.251 + SetCurrentProcessExplicitAppUserModelIDPtr funcAppUserModelID = nullptr; 1.252 + 1.253 + HMODULE hDLL = ::LoadLibraryW(kShellLibraryName); 1.254 + 1.255 + funcAppUserModelID = (SetCurrentProcessExplicitAppUserModelIDPtr) 1.256 + GetProcAddress(hDLL, "SetCurrentProcessExplicitAppUserModelID"); 1.257 + 1.258 + if (!funcAppUserModelID) { 1.259 + ::FreeLibrary(hDLL); 1.260 + return; 1.261 + } 1.262 + 1.263 + if (FAILED(funcAppUserModelID(aId.get()))) { 1.264 + NS_WARNING("SetCurrentProcessExplicitAppUserModelID failed for child process."); 1.265 + } 1.266 + 1.267 + if (hDLL) 1.268 + ::FreeLibrary(hDLL); 1.269 +} 1.270 +#endif 1.271 + 1.272 +nsresult 1.273 +XRE_InitChildProcess(int aArgc, 1.274 + char* aArgv[], 1.275 + GeckoProcessType aProcess) 1.276 +{ 1.277 + NS_ENSURE_ARG_MIN(aArgc, 2); 1.278 + NS_ENSURE_ARG_POINTER(aArgv); 1.279 + NS_ENSURE_ARG_POINTER(aArgv[0]); 1.280 + 1.281 +#if defined(XP_WIN) 1.282 + // From the --attach-console support in nsNativeAppSupportWin.cpp, but 1.283 + // here we are a content child process, so we always attempt to attach 1.284 + // to the parent's (ie, the browser's) console. 1.285 + // Try to attach console to the parent process. 1.286 + // It will succeed when the parent process is a command line, 1.287 + // so that stdio will be displayed in it. 1.288 + if (AttachConsole(ATTACH_PARENT_PROCESS)) { 1.289 + // Change std handles to refer to new console handles. 1.290 + // Before doing so, ensure that stdout/stderr haven't been 1.291 + // redirected to a valid file 1.292 + if (_fileno(stdout) == -1 || 1.293 + _get_osfhandle(fileno(stdout)) == -1) 1.294 + freopen("CONOUT$", "w", stdout); 1.295 + // Merge stderr into CONOUT$ since there isn't any `CONERR$`. 1.296 + // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx 1.297 + if (_fileno(stderr) == -1 || 1.298 + _get_osfhandle(fileno(stderr)) == -1) 1.299 + freopen("CONOUT$", "w", stderr); 1.300 + if (_fileno(stdin) == -1 || _get_osfhandle(fileno(stdin)) == -1) 1.301 + freopen("CONIN$", "r", stdin); 1.302 + } 1.303 +#endif 1.304 + 1.305 + char aLocal; 1.306 + profiler_init(&aLocal); 1.307 + PROFILER_LABEL("Startup", "XRE_InitChildProcess"); 1.308 + 1.309 + sChildProcessType = aProcess; 1.310 + 1.311 + // Complete 'task_t' exchange for Mac OS X. This structure has the same size 1.312 + // regardless of architecture so we don't have any cross-arch issues here. 1.313 +#ifdef XP_MACOSX 1.314 + if (aArgc < 1) 1.315 + return NS_ERROR_FAILURE; 1.316 + const char* const mach_port_name = aArgv[--aArgc]; 1.317 + 1.318 + const int kTimeoutMs = 1000; 1.319 + 1.320 + MachSendMessage child_message(0); 1.321 + if (!child_message.AddDescriptor(mach_task_self())) { 1.322 + NS_WARNING("child AddDescriptor(mach_task_self()) failed."); 1.323 + return NS_ERROR_FAILURE; 1.324 + } 1.325 + 1.326 + ReceivePort child_recv_port; 1.327 + mach_port_t raw_child_recv_port = child_recv_port.GetPort(); 1.328 + if (!child_message.AddDescriptor(raw_child_recv_port)) { 1.329 + NS_WARNING("Adding descriptor to message failed"); 1.330 + return NS_ERROR_FAILURE; 1.331 + } 1.332 + 1.333 + MachPortSender child_sender(mach_port_name); 1.334 + kern_return_t err = child_sender.SendMessage(child_message, kTimeoutMs); 1.335 + if (err != KERN_SUCCESS) { 1.336 + NS_WARNING("child SendMessage() failed"); 1.337 + return NS_ERROR_FAILURE; 1.338 + } 1.339 + 1.340 + MachReceiveMessage parent_message; 1.341 + err = child_recv_port.WaitForMessage(&parent_message, kTimeoutMs); 1.342 + if (err != KERN_SUCCESS) { 1.343 + NS_WARNING("child WaitForMessage() failed"); 1.344 + return NS_ERROR_FAILURE; 1.345 + } 1.346 + 1.347 + if (parent_message.GetTranslatedPort(0) == MACH_PORT_NULL) { 1.348 + NS_WARNING("child GetTranslatedPort(0) failed"); 1.349 + return NS_ERROR_FAILURE; 1.350 + } 1.351 + err = task_set_bootstrap_port(mach_task_self(), 1.352 + parent_message.GetTranslatedPort(0)); 1.353 + if (err != KERN_SUCCESS) { 1.354 + NS_WARNING("child task_set_bootstrap_port() failed"); 1.355 + return NS_ERROR_FAILURE; 1.356 + } 1.357 +#endif 1.358 + 1.359 + SetupErrorHandling(aArgv[0]); 1.360 + 1.361 +#if defined(MOZ_CRASHREPORTER) 1.362 + if (aArgc < 1) 1.363 + return NS_ERROR_FAILURE; 1.364 + const char* const crashReporterArg = aArgv[--aArgc]; 1.365 + 1.366 +# if defined(XP_WIN) || defined(XP_MACOSX) 1.367 + // on windows and mac, |crashReporterArg| is the named pipe on which the 1.368 + // server is listening for requests, or "-" if crash reporting is 1.369 + // disabled. 1.370 + if (0 != strcmp("-", crashReporterArg) && 1.371 + !XRE_SetRemoteExceptionHandler(crashReporterArg)) { 1.372 + // Bug 684322 will add better visibility into this condition 1.373 + NS_WARNING("Could not setup crash reporting\n"); 1.374 + } 1.375 +# elif defined(OS_LINUX) 1.376 + // on POSIX, |crashReporterArg| is "true" if crash reporting is 1.377 + // enabled, false otherwise 1.378 + if (0 != strcmp("false", crashReporterArg) && 1.379 + !XRE_SetRemoteExceptionHandler(nullptr)) { 1.380 + // Bug 684322 will add better visibility into this condition 1.381 + NS_WARNING("Could not setup crash reporting\n"); 1.382 + } 1.383 +# else 1.384 +# error "OOP crash reporting unsupported on this platform" 1.385 +# endif 1.386 +#endif // if defined(MOZ_CRASHREPORTER) 1.387 + 1.388 + gArgv = aArgv; 1.389 + gArgc = aArgc; 1.390 + 1.391 +#if defined(MOZ_WIDGET_GTK) 1.392 + g_thread_init(nullptr); 1.393 +#endif 1.394 + 1.395 +#if defined(MOZ_WIDGET_QT) 1.396 + nsQAppInstance::AddRef(); 1.397 +#endif 1.398 + 1.399 + if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS")) { 1.400 +#ifdef OS_POSIX 1.401 + printf("\n\nCHILDCHILDCHILDCHILD\n debug me @ %d\n\n", getpid()); 1.402 + sleep(30); 1.403 +#elif defined(OS_WIN) 1.404 + // Windows has a decent JIT debugging story, so NS_DebugBreak does the 1.405 + // right thing. 1.406 + NS_DebugBreak(NS_DEBUG_BREAK, 1.407 + "Invoking NS_DebugBreak() to debug child process", 1.408 + nullptr, __FILE__, __LINE__); 1.409 +#endif 1.410 + } 1.411 + 1.412 + // child processes launched by GeckoChildProcessHost get this magic 1.413 + // argument appended to their command lines 1.414 + const char* const parentPIDString = aArgv[aArgc-1]; 1.415 + NS_ABORT_IF_FALSE(parentPIDString, "NULL parent PID"); 1.416 + --aArgc; 1.417 + 1.418 + char* end = 0; 1.419 + base::ProcessId parentPID = strtol(parentPIDString, &end, 10); 1.420 + NS_ABORT_IF_FALSE(!*end, "invalid parent PID"); 1.421 + 1.422 + base::ProcessHandle parentHandle; 1.423 + mozilla::DebugOnly<bool> ok = base::OpenProcessHandle(parentPID, &parentHandle); 1.424 + NS_ABORT_IF_FALSE(ok, "can't open handle to parent"); 1.425 + 1.426 +#if defined(XP_WIN) 1.427 + // On Win7+, register the application user model id passed in by 1.428 + // parent. This insures windows created by the container properly 1.429 + // group with the parent app on the Win7 taskbar. 1.430 + const char* const appModelUserId = aArgv[--aArgc]; 1.431 + if (appModelUserId) { 1.432 + // '-' implies no support 1.433 + if (*appModelUserId != '-') { 1.434 + nsString appId; 1.435 + appId.AssignWithConversion(nsDependentCString(appModelUserId)); 1.436 + // The version string is encased in quotes 1.437 + appId.Trim(NS_LITERAL_CSTRING("\"").get()); 1.438 + // Set the id 1.439 + SetTaskbarGroupId(appId); 1.440 + } 1.441 + } 1.442 +#endif 1.443 + 1.444 + base::AtExitManager exitManager; 1.445 + NotificationService notificationService; 1.446 + 1.447 + NS_LogInit(); 1.448 + 1.449 + nsresult rv = XRE_InitCommandLine(aArgc, aArgv); 1.450 + if (NS_FAILED(rv)) { 1.451 + profiler_shutdown(); 1.452 + NS_LogTerm(); 1.453 + return NS_ERROR_FAILURE; 1.454 + } 1.455 + 1.456 + MessageLoop::Type uiLoopType; 1.457 + switch (aProcess) { 1.458 + case GeckoProcessType_Content: 1.459 + // Content processes need the XPCOM/chromium frankenventloop 1.460 + uiLoopType = MessageLoop::TYPE_MOZILLA_CHILD; 1.461 + break; 1.462 + default: 1.463 + uiLoopType = MessageLoop::TYPE_UI; 1.464 + break; 1.465 + } 1.466 + 1.467 + { 1.468 + // This is a lexical scope for the MessageLoop below. We want it 1.469 + // to go out of scope before NS_LogTerm() so that we don't get 1.470 + // spurious warnings about XPCOM objects being destroyed from a 1.471 + // static context. 1.472 + 1.473 + // Associate this thread with a UI MessageLoop 1.474 + MessageLoop uiMessageLoop(uiLoopType); 1.475 + { 1.476 + nsAutoPtr<ProcessChild> process; 1.477 + 1.478 +#ifdef XP_WIN 1.479 + mozilla::ipc::windows::InitUIThread(); 1.480 +#endif 1.481 + 1.482 + switch (aProcess) { 1.483 + case GeckoProcessType_Default: 1.484 + NS_RUNTIMEABORT("This makes no sense"); 1.485 + break; 1.486 + 1.487 + case GeckoProcessType_Plugin: 1.488 + process = new PluginProcessChild(parentHandle); 1.489 + break; 1.490 + 1.491 + case GeckoProcessType_Content: { 1.492 + process = new ContentProcess(parentHandle); 1.493 + // If passed in grab the application path for xpcom init 1.494 + nsCString appDir; 1.495 + for (int idx = aArgc; idx > 0; idx--) { 1.496 + if (aArgv[idx] && !strcmp(aArgv[idx], "-appdir")) { 1.497 + appDir.Assign(nsDependentCString(aArgv[idx+1])); 1.498 + static_cast<ContentProcess*>(process.get())->SetAppDir(appDir); 1.499 + break; 1.500 + } 1.501 + } 1.502 + } 1.503 + break; 1.504 + 1.505 + case GeckoProcessType_IPDLUnitTest: 1.506 +#ifdef MOZ_IPDL_TESTS 1.507 + process = new IPDLUnitTestProcessChild(parentHandle); 1.508 +#else 1.509 + NS_RUNTIMEABORT("rebuild with --enable-ipdl-tests"); 1.510 +#endif 1.511 + break; 1.512 + 1.513 + default: 1.514 + NS_RUNTIMEABORT("Unknown main thread class"); 1.515 + } 1.516 + 1.517 + if (!process->Init()) { 1.518 + profiler_shutdown(); 1.519 + NS_LogTerm(); 1.520 + return NS_ERROR_FAILURE; 1.521 + } 1.522 + 1.523 + // Run the UI event loop on the main thread. 1.524 + uiMessageLoop.MessageLoop::Run(); 1.525 + 1.526 + // Allow ProcessChild to clean up after itself before going out of 1.527 + // scope and being deleted 1.528 + process->CleanUp(); 1.529 + mozilla::Omnijar::CleanUp(); 1.530 + } 1.531 + } 1.532 + 1.533 + profiler_shutdown(); 1.534 + NS_LogTerm(); 1.535 + return XRE_DeinitCommandLine(); 1.536 +} 1.537 + 1.538 +MessageLoop* 1.539 +XRE_GetIOMessageLoop() 1.540 +{ 1.541 + if (sChildProcessType == GeckoProcessType_Default) { 1.542 + return BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO); 1.543 + } 1.544 + return IOThreadChild::message_loop(); 1.545 +} 1.546 + 1.547 +namespace { 1.548 + 1.549 +class MainFunctionRunnable : public nsRunnable 1.550 +{ 1.551 +public: 1.552 + NS_DECL_NSIRUNNABLE 1.553 + 1.554 + MainFunctionRunnable(MainFunction aFunction, 1.555 + void* aData) 1.556 + : mFunction(aFunction), 1.557 + mData(aData) 1.558 + { 1.559 + NS_ASSERTION(aFunction, "Don't give me a null pointer!"); 1.560 + } 1.561 + 1.562 +private: 1.563 + MainFunction mFunction; 1.564 + void* mData; 1.565 +}; 1.566 + 1.567 +} /* anonymous namespace */ 1.568 + 1.569 +NS_IMETHODIMP 1.570 +MainFunctionRunnable::Run() 1.571 +{ 1.572 + mFunction(mData); 1.573 + return NS_OK; 1.574 +} 1.575 + 1.576 +nsresult 1.577 +XRE_InitParentProcess(int aArgc, 1.578 + char* aArgv[], 1.579 + MainFunction aMainFunction, 1.580 + void* aMainFunctionData) 1.581 +{ 1.582 + NS_ENSURE_ARG_MIN(aArgc, 1); 1.583 + NS_ENSURE_ARG_POINTER(aArgv); 1.584 + NS_ENSURE_ARG_POINTER(aArgv[0]); 1.585 + 1.586 + ScopedXREEmbed embed; 1.587 + 1.588 + gArgc = aArgc; 1.589 + gArgv = aArgv; 1.590 + nsresult rv = XRE_InitCommandLine(gArgc, gArgv); 1.591 + if (NS_FAILED(rv)) 1.592 + return NS_ERROR_FAILURE; 1.593 + 1.594 + { 1.595 + embed.Start(); 1.596 + 1.597 + nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID)); 1.598 + NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE); 1.599 + 1.600 + if (aMainFunction) { 1.601 + nsCOMPtr<nsIRunnable> runnable = 1.602 + new MainFunctionRunnable(aMainFunction, aMainFunctionData); 1.603 + NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY); 1.604 + 1.605 + nsresult rv = NS_DispatchToCurrentThread(runnable); 1.606 + NS_ENSURE_SUCCESS(rv, rv); 1.607 + } 1.608 + 1.609 + // Do event loop 1.610 + if (NS_FAILED(appShell->Run())) { 1.611 + NS_WARNING("Failed to run appshell"); 1.612 + return NS_ERROR_FAILURE; 1.613 + } 1.614 + } 1.615 + 1.616 + return XRE_DeinitCommandLine(); 1.617 +} 1.618 + 1.619 +#ifdef MOZ_IPDL_TESTS 1.620 +//----------------------------------------------------------------------------- 1.621 +// IPDL unit test 1.622 + 1.623 +int 1.624 +XRE_RunIPDLTest(int aArgc, char** aArgv) 1.625 +{ 1.626 + if (aArgc < 2) { 1.627 + fprintf(stderr, "TEST-UNEXPECTED-FAIL | <---> | insufficient #args, need at least 2\n"); 1.628 + return 1; 1.629 + } 1.630 + 1.631 + void* data = reinterpret_cast<void*>(aArgv[aArgc-1]); 1.632 + 1.633 + nsresult rv = 1.634 + XRE_InitParentProcess( 1.635 + --aArgc, aArgv, mozilla::_ipdltest::IPDLUnitTestMain, data); 1.636 + NS_ENSURE_SUCCESS(rv, 1); 1.637 + 1.638 + return 0; 1.639 +} 1.640 +#endif // ifdef MOZ_IPDL_TESTS 1.641 + 1.642 +nsresult 1.643 +XRE_RunAppShell() 1.644 +{ 1.645 + nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID)); 1.646 + NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE); 1.647 +#if defined(XP_MACOSX) 1.648 + { 1.649 + // In content processes that want XPCOM (and hence want 1.650 + // AppShell), we usually run our hybrid event loop through 1.651 + // MessagePump::Run(), by way of nsBaseAppShell::Run(). The 1.652 + // Cocoa nsAppShell impl, however, implements its own Run() 1.653 + // that's unaware of MessagePump. That's all rather suboptimal, 1.654 + // but oddly enough not a problem... usually. 1.655 + // 1.656 + // The problem with this setup comes during startup. 1.657 + // XPCOM-in-subprocesses depends on IPC, e.g. to init the pref 1.658 + // service, so we have to init IPC first. But, IPC also 1.659 + // indirectly kinda-depends on XPCOM, because MessagePump 1.660 + // schedules work from off-main threads (e.g. IO thread) by 1.661 + // using NS_DispatchToMainThread(). If the IO thread receives a 1.662 + // Message from the parent before nsThreadManager is 1.663 + // initialized, then DispatchToMainThread() will fail, although 1.664 + // MessagePump will remember the task. This race condition 1.665 + // isn't a problem when appShell->Run() ends up in 1.666 + // MessagePump::Run(), because MessagePump will immediate see it 1.667 + // has work to do. It *is* a problem when we end up in [NSApp 1.668 + // run], because it's not aware that MessagePump has work that 1.669 + // needs to be processed; that was supposed to be signaled by 1.670 + // nsIRunnable(s). 1.671 + // 1.672 + // So instead of hacking Cocoa nsAppShell or rewriting the 1.673 + // event-loop system, we compromise here by processing any tasks 1.674 + // that might have been enqueued on MessagePump, *before* 1.675 + // MessagePump::ScheduleWork was able to successfully 1.676 + // DispatchToMainThread(). 1.677 + MessageLoop* loop = MessageLoop::current(); 1.678 + bool couldNest = loop->NestableTasksAllowed(); 1.679 + 1.680 + loop->SetNestableTasksAllowed(true); 1.681 + loop->PostTask(FROM_HERE, new MessageLoop::QuitTask()); 1.682 + loop->Run(); 1.683 + 1.684 + loop->SetNestableTasksAllowed(couldNest); 1.685 + } 1.686 +#endif // XP_MACOSX 1.687 + return appShell->Run(); 1.688 +} 1.689 + 1.690 +template<> 1.691 +struct RunnableMethodTraits<ContentChild> 1.692 +{ 1.693 + static void RetainCallee(ContentChild* obj) { } 1.694 + static void ReleaseCallee(ContentChild* obj) { } 1.695 +}; 1.696 + 1.697 +void 1.698 +XRE_ShutdownChildProcess() 1.699 +{ 1.700 + NS_ABORT_IF_FALSE(MessageLoopForUI::current(), "Wrong thread!"); 1.701 + 1.702 + mozilla::DebugOnly<MessageLoop*> ioLoop = XRE_GetIOMessageLoop(); 1.703 + NS_ABORT_IF_FALSE(!!ioLoop, "Bad shutdown order"); 1.704 + 1.705 + // Quit() sets off the following chain of events 1.706 + // (1) UI loop starts quitting 1.707 + // (2) UI loop returns from Run() in XRE_InitChildProcess() 1.708 + // (3) ProcessChild goes out of scope and terminates the IO thread 1.709 + // (4) ProcessChild joins the IO thread 1.710 + // (5) exit() 1.711 + MessageLoop::current()->Quit(); 1.712 +#if defined(XP_MACOSX) 1.713 + nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID)); 1.714 + if (appShell) { 1.715 + // On Mac, we might be only above nsAppShell::Run(), not 1.716 + // MessagePump::Run(). See XRE_RunAppShell(). To account for 1.717 + // that case, we fire off an Exit() here. If we were indeed 1.718 + // above MessagePump::Run(), this Exit() is just superfluous. 1.719 + appShell->Exit(); 1.720 + } 1.721 +#endif // XP_MACOSX 1.722 +} 1.723 + 1.724 +namespace { 1.725 +ContentParent* gContentParent; //long-lived, manually refcounted 1.726 +TestShellParent* GetOrCreateTestShellParent() 1.727 +{ 1.728 + if (!gContentParent) { 1.729 + nsRefPtr<ContentParent> parent = ContentParent::GetNewOrUsed(); 1.730 + parent.forget(&gContentParent); 1.731 + } else if (!gContentParent->IsAlive()) { 1.732 + return nullptr; 1.733 + } 1.734 + TestShellParent* tsp = gContentParent->GetTestShellSingleton(); 1.735 + if (!tsp) { 1.736 + tsp = gContentParent->CreateTestShell(); 1.737 + } 1.738 + return tsp; 1.739 +} 1.740 +} 1.741 + 1.742 +bool 1.743 +XRE_SendTestShellCommand(JSContext* aCx, 1.744 + JSString* aCommand, 1.745 + void* aCallback) 1.746 +{ 1.747 + JS::RootedString cmd(aCx, aCommand); 1.748 + TestShellParent* tsp = GetOrCreateTestShellParent(); 1.749 + NS_ENSURE_TRUE(tsp, false); 1.750 + 1.751 + nsDependentJSString command; 1.752 + NS_ENSURE_TRUE(command.init(aCx, cmd), false); 1.753 + 1.754 + if (!aCallback) { 1.755 + return tsp->SendExecuteCommand(command); 1.756 + } 1.757 + 1.758 + TestShellCommandParent* callback = static_cast<TestShellCommandParent*>( 1.759 + tsp->SendPTestShellCommandConstructor(command)); 1.760 + NS_ENSURE_TRUE(callback, false); 1.761 + 1.762 + JS::Value callbackVal = *reinterpret_cast<JS::Value*>(aCallback); 1.763 + NS_ENSURE_TRUE(callback->SetCallback(aCx, callbackVal), false); 1.764 + 1.765 + return true; 1.766 +} 1.767 + 1.768 +bool 1.769 +XRE_ShutdownTestShell() 1.770 +{ 1.771 + if (!gContentParent) { 1.772 + return true; 1.773 + } 1.774 + bool ret = true; 1.775 + if (gContentParent->IsAlive()) { 1.776 + ret = gContentParent->DestroyTestShell( 1.777 + gContentParent->GetTestShellSingleton()); 1.778 + } 1.779 + NS_RELEASE(gContentParent); 1.780 + return ret; 1.781 +} 1.782 + 1.783 +#ifdef MOZ_X11 1.784 +void 1.785 +XRE_InstallX11ErrorHandler() 1.786 +{ 1.787 + InstallX11ErrorHandler(); 1.788 +} 1.789 +#endif 1.790 + 1.791 +#ifdef XP_WIN 1.792 +static WindowsEnvironmentType 1.793 +sWindowsEnvironmentType = WindowsEnvironmentType_Desktop; 1.794 + 1.795 +void 1.796 +SetWindowsEnvironment(WindowsEnvironmentType aEnvID) 1.797 +{ 1.798 + sWindowsEnvironmentType = aEnvID; 1.799 +} 1.800 + 1.801 +WindowsEnvironmentType 1.802 +XRE_GetWindowsEnvironment() 1.803 +{ 1.804 + return sWindowsEnvironmentType; 1.805 +} 1.806 +#endif // XP_WIN 1.807 +