1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is Mozilla libXUL embedding.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Benjamin Smedberg <benjamin@smedbergs.us>
18 : *
19 : * Portions created by the Initial Developer are Copyright (C) 2005
20 : * the Mozilla Foundation. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #if defined(MOZ_WIDGET_QT)
39 : #include "nsQAppInstance.h"
40 : #endif
41 :
42 : #include "base/basictypes.h"
43 :
44 : #include "nsXULAppAPI.h"
45 :
46 : #include <stdlib.h>
47 : #if defined(MOZ_WIDGET_GTK2)
48 : #include <glib.h>
49 : #endif
50 :
51 : #include "prenv.h"
52 :
53 : #include "nsIAppShell.h"
54 : #include "nsIAppStartupNotifier.h"
55 : #include "nsIDirectoryService.h"
56 : #include "nsILocalFile.h"
57 : #include "nsIToolkitChromeRegistry.h"
58 : #include "nsIToolkitProfile.h"
59 :
60 : #if defined(OS_LINUX)
61 : # define XP_LINUX
62 : #endif
63 :
64 : #ifdef XP_WIN
65 : #include <process.h>
66 : #endif
67 :
68 : #include "nsAppDirectoryServiceDefs.h"
69 : #include "nsAppRunner.h"
70 : #include "nsAutoRef.h"
71 : #include "nsDirectoryServiceDefs.h"
72 : #include "nsExceptionHandler.h"
73 : #include "nsString.h"
74 : #include "nsThreadUtils.h"
75 : #include "nsJSUtils.h"
76 : #include "nsWidgetsCID.h"
77 : #include "nsXREDirProvider.h"
78 :
79 : #include "mozilla/Omnijar.h"
80 : #if defined(XP_MACOSX)
81 : #include "nsVersionComparator.h"
82 : #include "chrome/common/mach_ipc_mac.h"
83 : #endif
84 : #include "nsX11ErrorHandler.h"
85 : #include "base/at_exit.h"
86 : #include "base/command_line.h"
87 : #include "base/message_loop.h"
88 : #include "base/process_util.h"
89 : #include "chrome/common/child_process.h"
90 : #include "chrome/common/notification_service.h"
91 :
92 : #include "mozilla/ipc/BrowserProcessSubThread.h"
93 : #include "mozilla/ipc/GeckoChildProcessHost.h"
94 : #include "mozilla/ipc/IOThreadChild.h"
95 : #include "mozilla/ipc/ProcessChild.h"
96 : #include "ScopedXREEmbed.h"
97 :
98 : #include "mozilla/plugins/PluginProcessChild.h"
99 : #include "mozilla/dom/ContentProcess.h"
100 : #include "mozilla/dom/ContentParent.h"
101 : #include "mozilla/dom/ContentChild.h"
102 :
103 : #include "mozilla/jsipc/ContextWrapperParent.h"
104 :
105 : #include "mozilla/ipc/TestShellParent.h"
106 : #include "mozilla/ipc/XPCShellEnvironment.h"
107 :
108 : #include "mozilla/Util.h" // for DebugOnly
109 :
110 : #ifdef MOZ_IPDL_TESTS
111 : #include "mozilla/_ipdltest/IPDLUnitTests.h"
112 : #include "mozilla/_ipdltest/IPDLUnitTestProcessChild.h"
113 :
114 : using mozilla::_ipdltest::IPDLUnitTestProcessChild;
115 : #endif // ifdef MOZ_IPDL_TESTS
116 :
117 : using namespace mozilla;
118 :
119 : using mozilla::ipc::BrowserProcessSubThread;
120 : using mozilla::ipc::GeckoChildProcessHost;
121 : using mozilla::ipc::IOThreadChild;
122 : using mozilla::ipc::ProcessChild;
123 : using mozilla::ipc::ScopedXREEmbed;
124 :
125 : using mozilla::plugins::PluginProcessChild;
126 : using mozilla::dom::ContentProcess;
127 : using mozilla::dom::ContentParent;
128 : using mozilla::dom::ContentChild;
129 :
130 : using mozilla::jsipc::PContextWrapperParent;
131 : using mozilla::jsipc::ContextWrapperParent;
132 :
133 : using mozilla::ipc::TestShellParent;
134 : using mozilla::ipc::TestShellCommandParent;
135 : using mozilla::ipc::XPCShellEnvironment;
136 :
137 : using mozilla::startup::sChildProcessType;
138 :
139 : static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
140 :
141 : #ifdef XP_WIN
142 : static const PRUnichar kShellLibraryName[] = L"shell32.dll";
143 : #endif
144 :
145 : nsresult
146 0 : XRE_LockProfileDirectory(nsILocalFile* aDirectory,
147 : nsISupports* *aLockObject)
148 : {
149 0 : nsCOMPtr<nsIProfileLock> lock;
150 :
151 : nsresult rv = NS_LockProfilePath(aDirectory, nsnull, nsnull,
152 0 : getter_AddRefs(lock));
153 0 : if (NS_SUCCEEDED(rv))
154 0 : NS_ADDREF(*aLockObject = lock);
155 :
156 0 : return rv;
157 : }
158 :
159 : static PRInt32 sInitCounter;
160 :
161 : nsresult
162 0 : XRE_InitEmbedding2(nsILocalFile *aLibXULDirectory,
163 : nsILocalFile *aAppDirectory,
164 : nsIDirectoryServiceProvider *aAppDirProvider)
165 : {
166 : // Initialize some globals to make nsXREDirProvider happy
167 : static char* kNullCommandLine[] = { nsnull };
168 0 : gArgv = kNullCommandLine;
169 0 : gArgc = 0;
170 :
171 0 : NS_ENSURE_ARG(aLibXULDirectory);
172 :
173 0 : if (++sInitCounter > 1) // XXXbsmedberg is this really the right solution?
174 0 : return NS_OK;
175 :
176 0 : if (!aAppDirectory)
177 0 : aAppDirectory = aLibXULDirectory;
178 :
179 : nsresult rv;
180 :
181 0 : new nsXREDirProvider; // This sets gDirServiceProvider
182 0 : if (!gDirServiceProvider)
183 0 : return NS_ERROR_OUT_OF_MEMORY;
184 :
185 : rv = gDirServiceProvider->Initialize(aAppDirectory, aLibXULDirectory,
186 0 : aAppDirProvider);
187 0 : if (NS_FAILED(rv))
188 0 : return rv;
189 :
190 0 : rv = NS_InitXPCOM2(nsnull, aAppDirectory, gDirServiceProvider);
191 0 : if (NS_FAILED(rv))
192 0 : return rv;
193 :
194 : // We do not need to autoregister components here. The CheckCompatibility()
195 : // bits in nsAppRunner.cpp check for an invalidation flag in
196 : // compatibility.ini.
197 : // If the app wants to autoregister every time (for instance, if it's debug),
198 : // it can do so after we return from this function.
199 :
200 : nsCOMPtr<nsIObserver> startupNotifier
201 0 : (do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID));
202 0 : if (!startupNotifier)
203 0 : return NS_ERROR_FAILURE;
204 :
205 0 : startupNotifier->Observe(nsnull, APPSTARTUP_TOPIC, nsnull);
206 :
207 0 : return NS_OK;
208 : }
209 :
210 : void
211 0 : XRE_NotifyProfile()
212 : {
213 0 : NS_ASSERTION(gDirServiceProvider, "XRE_InitEmbedding was not called!");
214 0 : gDirServiceProvider->DoStartup();
215 0 : }
216 :
217 : void
218 0 : XRE_TermEmbedding()
219 : {
220 0 : if (--sInitCounter != 0)
221 0 : return;
222 :
223 0 : NS_ASSERTION(gDirServiceProvider,
224 : "XRE_TermEmbedding without XRE_InitEmbedding");
225 :
226 0 : gDirServiceProvider->DoShutdown();
227 0 : NS_ShutdownXPCOM(nsnull);
228 0 : delete gDirServiceProvider;
229 : }
230 :
231 : const char*
232 1409 : XRE_ChildProcessTypeToString(GeckoProcessType aProcessType)
233 : {
234 : return (aProcessType < GeckoProcessType_End) ?
235 1409 : kGeckoProcessTypeString[aProcessType] : nsnull;
236 : }
237 :
238 : GeckoProcessType
239 1 : XRE_StringToChildProcessType(const char* aProcessTypeString)
240 : {
241 6 : for (int i = 0;
242 3 : i < (int) ArrayLength(kGeckoProcessTypeString);
243 : ++i) {
244 3 : if (!strcmp(kGeckoProcessTypeString[i], aProcessTypeString)) {
245 1 : return static_cast<GeckoProcessType>(i);
246 : }
247 : }
248 0 : return GeckoProcessType_Invalid;
249 : }
250 :
251 : namespace mozilla {
252 : namespace startup {
253 : GeckoProcessType sChildProcessType = GeckoProcessType_Default;
254 : }
255 : }
256 :
257 : #if defined(MOZ_CRASHREPORTER)
258 : // FIXME/bug 539522: this out-of-place function is stuck here because
259 : // IPDL wants access to this crashreporter interface, and
260 : // crashreporter is built in such a way to make that awkward
261 : bool
262 0 : XRE_TakeMinidumpForChild(PRUint32 aChildPid, nsILocalFile** aDump)
263 : {
264 0 : return CrashReporter::TakeMinidumpForChild(aChildPid, aDump);
265 : }
266 :
267 : bool
268 1 : XRE_SetRemoteExceptionHandler(const char* aPipe/*= 0*/)
269 : {
270 : #if defined(XP_WIN) || defined(XP_MACOSX)
271 : return CrashReporter::SetRemoteExceptionHandler(nsDependentCString(aPipe));
272 : #elif defined(OS_LINUX)
273 1 : return CrashReporter::SetRemoteExceptionHandler();
274 : #else
275 : # error "OOP crash reporter unsupported on this platform"
276 : #endif
277 : }
278 : #endif // if defined(MOZ_CRASHREPORTER)
279 :
280 : #if defined(XP_WIN)
281 : void
282 : SetTaskbarGroupId(const nsString& aId)
283 : {
284 : typedef HRESULT (WINAPI * SetCurrentProcessExplicitAppUserModelIDPtr)(PCWSTR AppID);
285 :
286 : SetCurrentProcessExplicitAppUserModelIDPtr funcAppUserModelID = nsnull;
287 :
288 : HMODULE hDLL = ::LoadLibraryW(kShellLibraryName);
289 :
290 : funcAppUserModelID = (SetCurrentProcessExplicitAppUserModelIDPtr)
291 : GetProcAddress(hDLL, "SetCurrentProcessExplicitAppUserModelID");
292 :
293 : if (!funcAppUserModelID) {
294 : ::FreeLibrary(hDLL);
295 : return;
296 : }
297 :
298 : if (FAILED(funcAppUserModelID(aId.get()))) {
299 : NS_WARNING("SetCurrentProcessExplicitAppUserModelID failed for child process.");
300 : }
301 :
302 : if (hDLL)
303 : ::FreeLibrary(hDLL);
304 : }
305 : #endif
306 :
307 : nsresult
308 1 : XRE_InitChildProcess(int aArgc,
309 : char* aArgv[],
310 : GeckoProcessType aProcess)
311 : {
312 1 : NS_ENSURE_ARG_MIN(aArgc, 2);
313 1 : NS_ENSURE_ARG_POINTER(aArgv);
314 1 : NS_ENSURE_ARG_POINTER(aArgv[0]);
315 :
316 1 : sChildProcessType = aProcess;
317 :
318 : // Complete 'task_t' exchange for Mac OS X. This structure has the same size
319 : // regardless of architecture so we don't have any cross-arch issues here.
320 : #ifdef XP_MACOSX
321 : if (aArgc < 1)
322 : return 1;
323 : const char* const mach_port_name = aArgv[--aArgc];
324 :
325 : const int kTimeoutMs = 1000;
326 :
327 : MachSendMessage child_message(0);
328 : if (!child_message.AddDescriptor(mach_task_self())) {
329 : NS_WARNING("child AddDescriptor(mach_task_self()) failed.");
330 : return 1;
331 : }
332 :
333 : ReceivePort child_recv_port;
334 : mach_port_t raw_child_recv_port = child_recv_port.GetPort();
335 : if (!child_message.AddDescriptor(raw_child_recv_port)) {
336 : NS_WARNING("Adding descriptor to message failed");
337 : return 1;
338 : }
339 :
340 : MachPortSender child_sender(mach_port_name);
341 : kern_return_t err = child_sender.SendMessage(child_message, kTimeoutMs);
342 : if (err != KERN_SUCCESS) {
343 : NS_WARNING("child SendMessage() failed");
344 : return 1;
345 : }
346 :
347 : MachReceiveMessage parent_message;
348 : err = child_recv_port.WaitForMessage(&parent_message, kTimeoutMs);
349 : if (err != KERN_SUCCESS) {
350 : NS_WARNING("child WaitForMessage() failed");
351 : return 1;
352 : }
353 :
354 : if (parent_message.GetTranslatedPort(0) == MACH_PORT_NULL) {
355 : NS_WARNING("child GetTranslatedPort(0) failed");
356 : return 1;
357 : }
358 : err = task_set_bootstrap_port(mach_task_self(),
359 : parent_message.GetTranslatedPort(0));
360 : if (err != KERN_SUCCESS) {
361 : NS_WARNING("child task_set_bootstrap_port() failed");
362 : return 1;
363 : }
364 : #endif
365 :
366 1 : SetupErrorHandling(aArgv[0]);
367 :
368 : #if defined(MOZ_CRASHREPORTER)
369 1 : if (aArgc < 1)
370 0 : return 1;
371 1 : const char* const crashReporterArg = aArgv[--aArgc];
372 :
373 : # if defined(XP_WIN) || defined(XP_MACOSX)
374 : // on windows and mac, |crashReporterArg| is the named pipe on which the
375 : // server is listening for requests, or "-" if crash reporting is
376 : // disabled.
377 : if (0 != strcmp("-", crashReporterArg) &&
378 : !XRE_SetRemoteExceptionHandler(crashReporterArg)) {
379 : // Bug 684322 will add better visibility into this condition
380 : NS_WARNING("Could not setup crash reporting\n");
381 : }
382 : # elif defined(OS_LINUX)
383 : // on POSIX, |crashReporterArg| is "true" if crash reporting is
384 : // enabled, false otherwise
385 2 : if (0 != strcmp("false", crashReporterArg) &&
386 1 : !XRE_SetRemoteExceptionHandler(NULL)) {
387 : // Bug 684322 will add better visibility into this condition
388 0 : NS_WARNING("Could not setup crash reporting\n");
389 : }
390 : # else
391 : # error "OOP crash reporting unsupported on this platform"
392 : # endif
393 : #endif // if defined(MOZ_CRASHREPORTER)
394 :
395 1 : gArgv = aArgv;
396 1 : gArgc = aArgc;
397 :
398 : #if defined(MOZ_WIDGET_GTK2)
399 1 : g_thread_init(NULL);
400 : #endif
401 :
402 : #if defined(MOZ_WIDGET_QT)
403 : nsQAppInstance::AddRef();
404 : #endif
405 :
406 1 : if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS")) {
407 : #ifdef OS_POSIX
408 0 : printf("\n\nCHILDCHILDCHILDCHILD\n debug me @%d\n\n", getpid());
409 0 : sleep(30);
410 : #elif defined(OS_WIN)
411 : printf("\n\nCHILDCHILDCHILDCHILD\n debug me @%d\n\n", _getpid());
412 : Sleep(30000);
413 : #endif
414 : }
415 :
416 : // child processes launched by GeckoChildProcessHost get this magic
417 : // argument appended to their command lines
418 1 : const char* const parentPIDString = aArgv[aArgc-1];
419 1 : NS_ABORT_IF_FALSE(parentPIDString, "NULL parent PID");
420 1 : --aArgc;
421 :
422 1 : char* end = 0;
423 1 : base::ProcessId parentPID = strtol(parentPIDString, &end, 10);
424 1 : NS_ABORT_IF_FALSE(!*end, "invalid parent PID");
425 :
426 : base::ProcessHandle parentHandle;
427 1 : mozilla::DebugOnly<bool> ok = base::OpenProcessHandle(parentPID, &parentHandle);
428 1 : NS_ABORT_IF_FALSE(ok, "can't open handle to parent");
429 :
430 : #if defined(XP_WIN)
431 : // On Win7+, register the application user model id passed in by
432 : // parent. This insures windows created by the container properly
433 : // group with the parent app on the Win7 taskbar.
434 : const char* const appModelUserId = aArgv[aArgc-1];
435 : --aArgc;
436 : if (appModelUserId) {
437 : // '-' implies no support
438 : if (*appModelUserId != '-') {
439 : nsString appId;
440 : appId.AssignWithConversion(nsDependentCString(appModelUserId));
441 : // The version string is encased in quotes
442 : appId.Trim(NS_LITERAL_CSTRING("\"").get());
443 : // Set the id
444 : SetTaskbarGroupId(appId);
445 : }
446 : }
447 : #endif
448 :
449 1 : base::AtExitManager exitManager;
450 1 : NotificationService notificationService;
451 :
452 1 : NS_LogInit();
453 :
454 1 : int rv = XRE_InitCommandLine(aArgc, aArgv);
455 1 : if (NS_FAILED(rv)) {
456 0 : NS_LogTerm();
457 0 : return NS_ERROR_FAILURE;
458 : }
459 :
460 : MessageLoop::Type uiLoopType;
461 1 : switch (aProcess) {
462 : case GeckoProcessType_Content:
463 : // Content processes need the XPCOM/chromium frankenventloop
464 1 : uiLoopType = MessageLoop::TYPE_MOZILLA_CHILD;
465 1 : break;
466 : default:
467 0 : uiLoopType = MessageLoop::TYPE_UI;
468 0 : break;
469 : }
470 :
471 : {
472 : // This is a lexical scope for the MessageLoop below. We want it
473 : // to go out of scope before NS_LogTerm() so that we don't get
474 : // spurious warnings about XPCOM objects being destroyed from a
475 : // static context.
476 :
477 : // Associate this thread with a UI MessageLoop
478 1 : MessageLoop uiMessageLoop(uiLoopType);
479 : {
480 1 : nsAutoPtr<ProcessChild> process;
481 :
482 1 : switch (aProcess) {
483 : case GeckoProcessType_Default:
484 0 : NS_RUNTIMEABORT("This makes no sense");
485 0 : break;
486 :
487 : case GeckoProcessType_Plugin:
488 0 : process = new PluginProcessChild(parentHandle);
489 0 : break;
490 :
491 : case GeckoProcessType_Content:
492 1 : process = new ContentProcess(parentHandle);
493 1 : break;
494 :
495 : case GeckoProcessType_IPDLUnitTest:
496 : #ifdef MOZ_IPDL_TESTS
497 : process = new IPDLUnitTestProcessChild(parentHandle);
498 : #else
499 0 : NS_RUNTIMEABORT("rebuild with --enable-ipdl-tests");
500 : #endif
501 0 : break;
502 :
503 : default:
504 0 : NS_RUNTIMEABORT("Unknown main thread class");
505 : }
506 :
507 1 : if (!process->Init()) {
508 0 : NS_LogTerm();
509 0 : return NS_ERROR_FAILURE;
510 : }
511 :
512 : // Run the UI event loop on the main thread.
513 0 : uiMessageLoop.MessageLoop::Run();
514 :
515 : // Allow ProcessChild to clean up after itself before going out of
516 : // scope and being deleted
517 0 : process->CleanUp();
518 0 : mozilla::Omnijar::CleanUp();
519 : }
520 : }
521 :
522 0 : NS_LogTerm();
523 0 : return XRE_DeinitCommandLine();
524 : }
525 :
526 : MessageLoop*
527 0 : XRE_GetIOMessageLoop()
528 : {
529 0 : if (sChildProcessType == GeckoProcessType_Default) {
530 0 : return BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO);
531 : }
532 0 : return IOThreadChild::message_loop();
533 : }
534 :
535 : namespace {
536 :
537 : class MainFunctionRunnable : public nsRunnable
538 0 : {
539 : public:
540 : NS_DECL_NSIRUNNABLE
541 :
542 0 : MainFunctionRunnable(MainFunction aFunction,
543 : void* aData)
544 : : mFunction(aFunction),
545 0 : mData(aData)
546 : {
547 0 : NS_ASSERTION(aFunction, "Don't give me a null pointer!");
548 0 : }
549 :
550 : private:
551 : MainFunction mFunction;
552 : void* mData;
553 : };
554 :
555 : } /* anonymous namespace */
556 :
557 : NS_IMETHODIMP
558 0 : MainFunctionRunnable::Run()
559 : {
560 0 : mFunction(mData);
561 0 : return NS_OK;
562 : }
563 :
564 : nsresult
565 0 : XRE_InitParentProcess(int aArgc,
566 : char* aArgv[],
567 : MainFunction aMainFunction,
568 : void* aMainFunctionData)
569 : {
570 0 : NS_ENSURE_ARG_MIN(aArgc, 1);
571 0 : NS_ENSURE_ARG_POINTER(aArgv);
572 0 : NS_ENSURE_ARG_POINTER(aArgv[0]);
573 :
574 0 : ScopedXREEmbed embed;
575 :
576 0 : gArgc = aArgc;
577 0 : gArgv = aArgv;
578 0 : int rv = XRE_InitCommandLine(gArgc, gArgv);
579 0 : if (NS_FAILED(rv))
580 0 : return NS_ERROR_FAILURE;
581 :
582 : {
583 0 : embed.Start();
584 :
585 0 : nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
586 0 : NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
587 :
588 0 : if (aMainFunction) {
589 : nsCOMPtr<nsIRunnable> runnable =
590 0 : new MainFunctionRunnable(aMainFunction, aMainFunctionData);
591 0 : NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
592 :
593 0 : nsresult rv = NS_DispatchToCurrentThread(runnable);
594 0 : NS_ENSURE_SUCCESS(rv, rv);
595 : }
596 :
597 : // Do event loop
598 0 : if (NS_FAILED(appShell->Run())) {
599 0 : NS_WARNING("Failed to run appshell");
600 0 : return NS_ERROR_FAILURE;
601 : }
602 : }
603 :
604 0 : return XRE_DeinitCommandLine();
605 : }
606 :
607 : #ifdef MOZ_IPDL_TESTS
608 : //-----------------------------------------------------------------------------
609 : // IPDL unit test
610 :
611 : int
612 : XRE_RunIPDLTest(int aArgc, char** aArgv)
613 : {
614 : if (aArgc < 2) {
615 : fprintf(stderr, "TEST-UNEXPECTED-FAIL | <---> | insufficient #args, need at least 2\n");
616 : return 1;
617 : }
618 :
619 : void* data = reinterpret_cast<void*>(aArgv[aArgc-1]);
620 :
621 : nsresult rv =
622 : XRE_InitParentProcess(
623 : --aArgc, aArgv, mozilla::_ipdltest::IPDLUnitTestMain, data);
624 : NS_ENSURE_SUCCESS(rv, 1);
625 :
626 : return 0;
627 : }
628 : #endif // ifdef MOZ_IPDL_TESTS
629 :
630 : nsresult
631 0 : XRE_RunAppShell()
632 : {
633 0 : nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
634 : #if defined(XP_MACOSX)
635 : {
636 : // In content processes that want XPCOM (and hence want
637 : // AppShell), we usually run our hybrid event loop through
638 : // MessagePump::Run(), by way of nsBaseAppShell::Run(). The
639 : // Cocoa nsAppShell impl, however, implements its own Run()
640 : // that's unaware of MessagePump. That's all rather suboptimal,
641 : // but oddly enough not a problem... usually.
642 : //
643 : // The problem with this setup comes during startup.
644 : // XPCOM-in-subprocesses depends on IPC, e.g. to init the pref
645 : // service, so we have to init IPC first. But, IPC also
646 : // indirectly kinda-depends on XPCOM, because MessagePump
647 : // schedules work from off-main threads (e.g. IO thread) by
648 : // using NS_DispatchToMainThread(). If the IO thread receives a
649 : // Message from the parent before nsThreadManager is
650 : // initialized, then DispatchToMainThread() will fail, although
651 : // MessagePump will remember the task. This race condition
652 : // isn't a problem when appShell->Run() ends up in
653 : // MessagePump::Run(), because MessagePump will immediate see it
654 : // has work to do. It *is* a problem when we end up in [NSApp
655 : // run], because it's not aware that MessagePump has work that
656 : // needs to be processed; that was supposed to be signaled by
657 : // nsIRunnable(s).
658 : //
659 : // So instead of hacking Cocoa nsAppShell or rewriting the
660 : // event-loop system, we compromise here by processing any tasks
661 : // that might have been enqueued on MessagePump, *before*
662 : // MessagePump::ScheduleWork was able to successfully
663 : // DispatchToMainThread().
664 : MessageLoop* loop = MessageLoop::current();
665 : bool couldNest = loop->NestableTasksAllowed();
666 :
667 : loop->SetNestableTasksAllowed(true);
668 : loop->PostTask(FROM_HERE, new MessageLoop::QuitTask());
669 : loop->Run();
670 :
671 : loop->SetNestableTasksAllowed(couldNest);
672 : }
673 : #endif // XP_MACOSX
674 0 : return appShell->Run();
675 : }
676 :
677 : template<>
678 : struct RunnableMethodTraits<ContentChild>
679 : {
680 : static void RetainCallee(ContentChild* obj) { }
681 : static void ReleaseCallee(ContentChild* obj) { }
682 : };
683 :
684 : void
685 0 : XRE_ShutdownChildProcess()
686 : {
687 0 : NS_ABORT_IF_FALSE(MessageLoopForUI::current(), "Wrong thread!");
688 :
689 0 : mozilla::DebugOnly<MessageLoop*> ioLoop = XRE_GetIOMessageLoop();
690 0 : NS_ABORT_IF_FALSE(!!ioLoop, "Bad shutdown order");
691 :
692 : // Quit() sets off the following chain of events
693 : // (1) UI loop starts quitting
694 : // (2) UI loop returns from Run() in XRE_InitChildProcess()
695 : // (3) ProcessChild goes out of scope and terminates the IO thread
696 : // (4) ProcessChild joins the IO thread
697 : // (5) exit()
698 0 : MessageLoop::current()->Quit();
699 : #if defined(XP_MACOSX)
700 : nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
701 : if (appShell) {
702 : // On Mac, we might be only above nsAppShell::Run(), not
703 : // MessagePump::Run(). See XRE_RunAppShell(). To account for
704 : // that case, we fire off an Exit() here. If we were indeed
705 : // above MessagePump::Run(), this Exit() is just superfluous.
706 : appShell->Exit();
707 : }
708 : #endif // XP_MACOSX
709 0 : }
710 :
711 : namespace {
712 : ContentParent* gContentParent; //long-lived, manually refcounted
713 0 : TestShellParent* GetOrCreateTestShellParent()
714 : {
715 0 : if (!gContentParent) {
716 0 : NS_ADDREF(gContentParent = ContentParent::GetNewOrUsed());
717 0 : } else if (!gContentParent->IsAlive()) {
718 0 : return nsnull;
719 : }
720 0 : TestShellParent* tsp = gContentParent->GetTestShellSingleton();
721 0 : if (!tsp) {
722 0 : tsp = gContentParent->CreateTestShell();
723 : }
724 0 : return tsp;
725 : }
726 : }
727 :
728 : bool
729 0 : XRE_SendTestShellCommand(JSContext* aCx,
730 : JSString* aCommand,
731 : void* aCallback)
732 : {
733 0 : TestShellParent* tsp = GetOrCreateTestShellParent();
734 0 : NS_ENSURE_TRUE(tsp, false);
735 :
736 0 : nsDependentJSString command;
737 0 : NS_ENSURE_TRUE(command.init(aCx, aCommand), false);
738 :
739 0 : if (!aCallback) {
740 0 : return tsp->SendExecuteCommand(command);
741 : }
742 :
743 : TestShellCommandParent* callback = static_cast<TestShellCommandParent*>(
744 0 : tsp->SendPTestShellCommandConstructor(command));
745 0 : NS_ENSURE_TRUE(callback, false);
746 :
747 0 : jsval callbackVal = *reinterpret_cast<jsval*>(aCallback);
748 0 : NS_ENSURE_TRUE(callback->SetCallback(aCx, callbackVal), false);
749 :
750 0 : return true;
751 : }
752 :
753 : bool
754 0 : XRE_GetChildGlobalObject(JSContext* aCx, JSObject** aGlobalP)
755 : {
756 0 : TestShellParent* tsp = GetOrCreateTestShellParent();
757 0 : return tsp && tsp->GetGlobalJSObject(aCx, aGlobalP);
758 : }
759 :
760 : bool
761 1387 : XRE_ShutdownTestShell()
762 : {
763 1387 : if (!gContentParent) {
764 1387 : return true;
765 : }
766 0 : bool ret = true;
767 0 : if (gContentParent->IsAlive()) {
768 : ret = gContentParent->DestroyTestShell(
769 0 : gContentParent->GetTestShellSingleton());
770 : }
771 0 : NS_RELEASE(gContentParent);
772 0 : return ret;
773 : }
774 :
775 : #ifdef MOZ_X11
776 : void
777 0 : XRE_InstallX11ErrorHandler()
778 : {
779 0 : InstallX11ErrorHandler();
780 0 : }
781 : #endif
|