toolkit/xre/nsEmbedFunctions.cpp

changeset 0
6474c204b198
     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 +

mercurial