toolkit/xre/nsEmbedFunctions.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial