toolkit/xre/nsEmbedFunctions.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:d815e2e4a646
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/. */
4
5 #include "mozilla/DebugOnly.h"
6
7 #if defined(MOZ_WIDGET_QT)
8 #include "nsQAppInstance.h"
9 #endif
10
11 #include "base/basictypes.h"
12
13 #include "nsXULAppAPI.h"
14
15 #include <stdlib.h>
16 #if defined(MOZ_WIDGET_GTK)
17 #include <glib.h>
18 #endif
19
20 #include "prenv.h"
21
22 #include "nsIAppShell.h"
23 #include "nsIAppStartupNotifier.h"
24 #include "nsIDirectoryService.h"
25 #include "nsIFile.h"
26 #include "nsIToolkitChromeRegistry.h"
27 #include "nsIToolkitProfile.h"
28
29 #ifdef XP_WIN
30 #include <process.h>
31 #include "mozilla/ipc/WindowsMessageLoop.h"
32 #endif
33
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"
44
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"
57
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"
63
64 #include "mozilla/plugins/PluginProcessChild.h"
65 #include "mozilla/dom/ContentProcess.h"
66 #include "mozilla/dom/ContentParent.h"
67 #include "mozilla/dom/ContentChild.h"
68
69 #include "mozilla/ipc/TestShellParent.h"
70 #include "mozilla/ipc/XPCShellEnvironment.h"
71
72 #include "GeckoProfiler.h"
73
74 #ifdef MOZ_IPDL_TESTS
75 #include "mozilla/_ipdltest/IPDLUnitTests.h"
76 #include "mozilla/_ipdltest/IPDLUnitTestProcessChild.h"
77
78 using mozilla::_ipdltest::IPDLUnitTestProcessChild;
79 #endif // ifdef MOZ_IPDL_TESTS
80
81 using namespace mozilla;
82
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;
88
89 using mozilla::plugins::PluginProcessChild;
90 using mozilla::dom::ContentProcess;
91 using mozilla::dom::ContentParent;
92 using mozilla::dom::ContentChild;
93
94 using mozilla::ipc::TestShellParent;
95 using mozilla::ipc::TestShellCommandParent;
96 using mozilla::ipc::XPCShellEnvironment;
97
98 using mozilla::startup::sChildProcessType;
99
100 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
101
102 #ifdef XP_WIN
103 static const wchar_t kShellLibraryName[] = L"shell32.dll";
104 #endif
105
106 nsresult
107 XRE_LockProfileDirectory(nsIFile* aDirectory,
108 nsISupports* *aLockObject)
109 {
110 nsCOMPtr<nsIProfileLock> lock;
111
112 nsresult rv = NS_LockProfilePath(aDirectory, nullptr, nullptr,
113 getter_AddRefs(lock));
114 if (NS_SUCCEEDED(rv))
115 NS_ADDREF(*aLockObject = lock);
116
117 return rv;
118 }
119
120 static int32_t sInitCounter;
121
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;
131
132 NS_ENSURE_ARG(aLibXULDirectory);
133
134 if (++sInitCounter > 1) // XXXbsmedberg is this really the right solution?
135 return NS_OK;
136
137 if (!aAppDirectory)
138 aAppDirectory = aLibXULDirectory;
139
140 nsresult rv;
141
142 new nsXREDirProvider; // This sets gDirServiceProvider
143 if (!gDirServiceProvider)
144 return NS_ERROR_OUT_OF_MEMORY;
145
146 rv = gDirServiceProvider->Initialize(aAppDirectory, aLibXULDirectory,
147 aAppDirProvider);
148 if (NS_FAILED(rv))
149 return rv;
150
151 rv = NS_InitXPCOM2(nullptr, aAppDirectory, gDirServiceProvider);
152 if (NS_FAILED(rv))
153 return rv;
154
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.
160
161 nsCOMPtr<nsIObserver> startupNotifier
162 (do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID));
163 if (!startupNotifier)
164 return NS_ERROR_FAILURE;
165
166 startupNotifier->Observe(nullptr, APPSTARTUP_TOPIC, nullptr);
167
168 return NS_OK;
169 }
170
171 void
172 XRE_NotifyProfile()
173 {
174 NS_ASSERTION(gDirServiceProvider, "XRE_InitEmbedding was not called!");
175 gDirServiceProvider->DoStartup();
176 }
177
178 void
179 XRE_TermEmbedding()
180 {
181 if (--sInitCounter != 0)
182 return;
183
184 NS_ASSERTION(gDirServiceProvider,
185 "XRE_TermEmbedding without XRE_InitEmbedding");
186
187 gDirServiceProvider->DoShutdown();
188 NS_ShutdownXPCOM(nullptr);
189 delete gDirServiceProvider;
190 }
191
192 const char*
193 XRE_ChildProcessTypeToString(GeckoProcessType aProcessType)
194 {
195 return (aProcessType < GeckoProcessType_End) ?
196 kGeckoProcessTypeString[aProcessType] : nullptr;
197 }
198
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 }
211
212 namespace mozilla {
213 namespace startup {
214 GeckoProcessType sChildProcessType = GeckoProcessType_Default;
215 }
216 }
217
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 }
228
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)
241
242 #if defined(XP_WIN)
243 void
244 SetTaskbarGroupId(const nsString& aId)
245 {
246 typedef HRESULT (WINAPI * SetCurrentProcessExplicitAppUserModelIDPtr)(PCWSTR AppID);
247
248 SetCurrentProcessExplicitAppUserModelIDPtr funcAppUserModelID = nullptr;
249
250 HMODULE hDLL = ::LoadLibraryW(kShellLibraryName);
251
252 funcAppUserModelID = (SetCurrentProcessExplicitAppUserModelIDPtr)
253 GetProcAddress(hDLL, "SetCurrentProcessExplicitAppUserModelID");
254
255 if (!funcAppUserModelID) {
256 ::FreeLibrary(hDLL);
257 return;
258 }
259
260 if (FAILED(funcAppUserModelID(aId.get()))) {
261 NS_WARNING("SetCurrentProcessExplicitAppUserModelID failed for child process.");
262 }
263
264 if (hDLL)
265 ::FreeLibrary(hDLL);
266 }
267 #endif
268
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]);
277
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
301
302 char aLocal;
303 profiler_init(&aLocal);
304 PROFILER_LABEL("Startup", "XRE_InitChildProcess");
305
306 sChildProcessType = aProcess;
307
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];
314
315 const int kTimeoutMs = 1000;
316
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 }
322
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 }
329
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 }
336
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 }
343
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
355
356 SetupErrorHandling(aArgv[0]);
357
358 #if defined(MOZ_CRASHREPORTER)
359 if (aArgc < 1)
360 return NS_ERROR_FAILURE;
361 const char* const crashReporterArg = aArgv[--aArgc];
362
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)
384
385 gArgv = aArgv;
386 gArgc = aArgc;
387
388 #if defined(MOZ_WIDGET_GTK)
389 g_thread_init(nullptr);
390 #endif
391
392 #if defined(MOZ_WIDGET_QT)
393 nsQAppInstance::AddRef();
394 #endif
395
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 }
408
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;
414
415 char* end = 0;
416 base::ProcessId parentPID = strtol(parentPIDString, &end, 10);
417 NS_ABORT_IF_FALSE(!*end, "invalid parent PID");
418
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");
422
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
440
441 base::AtExitManager exitManager;
442 NotificationService notificationService;
443
444 NS_LogInit();
445
446 nsresult rv = XRE_InitCommandLine(aArgc, aArgv);
447 if (NS_FAILED(rv)) {
448 profiler_shutdown();
449 NS_LogTerm();
450 return NS_ERROR_FAILURE;
451 }
452
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 }
463
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.
469
470 // Associate this thread with a UI MessageLoop
471 MessageLoop uiMessageLoop(uiLoopType);
472 {
473 nsAutoPtr<ProcessChild> process;
474
475 #ifdef XP_WIN
476 mozilla::ipc::windows::InitUIThread();
477 #endif
478
479 switch (aProcess) {
480 case GeckoProcessType_Default:
481 NS_RUNTIMEABORT("This makes no sense");
482 break;
483
484 case GeckoProcessType_Plugin:
485 process = new PluginProcessChild(parentHandle);
486 break;
487
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;
501
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;
509
510 default:
511 NS_RUNTIMEABORT("Unknown main thread class");
512 }
513
514 if (!process->Init()) {
515 profiler_shutdown();
516 NS_LogTerm();
517 return NS_ERROR_FAILURE;
518 }
519
520 // Run the UI event loop on the main thread.
521 uiMessageLoop.MessageLoop::Run();
522
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 }
529
530 profiler_shutdown();
531 NS_LogTerm();
532 return XRE_DeinitCommandLine();
533 }
534
535 MessageLoop*
536 XRE_GetIOMessageLoop()
537 {
538 if (sChildProcessType == GeckoProcessType_Default) {
539 return BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO);
540 }
541 return IOThreadChild::message_loop();
542 }
543
544 namespace {
545
546 class MainFunctionRunnable : public nsRunnable
547 {
548 public:
549 NS_DECL_NSIRUNNABLE
550
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 }
558
559 private:
560 MainFunction mFunction;
561 void* mData;
562 };
563
564 } /* anonymous namespace */
565
566 NS_IMETHODIMP
567 MainFunctionRunnable::Run()
568 {
569 mFunction(mData);
570 return NS_OK;
571 }
572
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]);
582
583 ScopedXREEmbed embed;
584
585 gArgc = aArgc;
586 gArgv = aArgv;
587 nsresult rv = XRE_InitCommandLine(gArgc, gArgv);
588 if (NS_FAILED(rv))
589 return NS_ERROR_FAILURE;
590
591 {
592 embed.Start();
593
594 nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
595 NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
596
597 if (aMainFunction) {
598 nsCOMPtr<nsIRunnable> runnable =
599 new MainFunctionRunnable(aMainFunction, aMainFunctionData);
600 NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
601
602 nsresult rv = NS_DispatchToCurrentThread(runnable);
603 NS_ENSURE_SUCCESS(rv, rv);
604 }
605
606 // Do event loop
607 if (NS_FAILED(appShell->Run())) {
608 NS_WARNING("Failed to run appshell");
609 return NS_ERROR_FAILURE;
610 }
611 }
612
613 return XRE_DeinitCommandLine();
614 }
615
616 #ifdef MOZ_IPDL_TESTS
617 //-----------------------------------------------------------------------------
618 // IPDL unit test
619
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 }
627
628 void* data = reinterpret_cast<void*>(aArgv[aArgc-1]);
629
630 nsresult rv =
631 XRE_InitParentProcess(
632 --aArgc, aArgv, mozilla::_ipdltest::IPDLUnitTestMain, data);
633 NS_ENSURE_SUCCESS(rv, 1);
634
635 return 0;
636 }
637 #endif // ifdef MOZ_IPDL_TESTS
638
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();
676
677 loop->SetNestableTasksAllowed(true);
678 loop->PostTask(FROM_HERE, new MessageLoop::QuitTask());
679 loop->Run();
680
681 loop->SetNestableTasksAllowed(couldNest);
682 }
683 #endif // XP_MACOSX
684 return appShell->Run();
685 }
686
687 template<>
688 struct RunnableMethodTraits<ContentChild>
689 {
690 static void RetainCallee(ContentChild* obj) { }
691 static void ReleaseCallee(ContentChild* obj) { }
692 };
693
694 void
695 XRE_ShutdownChildProcess()
696 {
697 NS_ABORT_IF_FALSE(MessageLoopForUI::current(), "Wrong thread!");
698
699 mozilla::DebugOnly<MessageLoop*> ioLoop = XRE_GetIOMessageLoop();
700 NS_ABORT_IF_FALSE(!!ioLoop, "Bad shutdown order");
701
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 }
720
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 }
738
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);
747
748 nsDependentJSString command;
749 NS_ENSURE_TRUE(command.init(aCx, cmd), false);
750
751 if (!aCallback) {
752 return tsp->SendExecuteCommand(command);
753 }
754
755 TestShellCommandParent* callback = static_cast<TestShellCommandParent*>(
756 tsp->SendPTestShellCommandConstructor(command));
757 NS_ENSURE_TRUE(callback, false);
758
759 JS::Value callbackVal = *reinterpret_cast<JS::Value*>(aCallback);
760 NS_ENSURE_TRUE(callback->SetCallback(aCx, callbackVal), false);
761
762 return true;
763 }
764
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 }
779
780 #ifdef MOZ_X11
781 void
782 XRE_InstallX11ErrorHandler()
783 {
784 InstallX11ErrorHandler();
785 }
786 #endif
787
788 #ifdef XP_WIN
789 static WindowsEnvironmentType
790 sWindowsEnvironmentType = WindowsEnvironmentType_Desktop;
791
792 void
793 SetWindowsEnvironment(WindowsEnvironmentType aEnvID)
794 {
795 sWindowsEnvironmentType = aEnvID;
796 }
797
798 WindowsEnvironmentType
799 XRE_GetWindowsEnvironment()
800 {
801 return sWindowsEnvironmentType;
802 }
803 #endif // XP_WIN
804

mercurial