dom/ipc/ContentChild.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* vim: set sw=4 ts=8 et tw=80 : */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifdef MOZ_WIDGET_GTK
michael@0 8 #include <gtk/gtk.h>
michael@0 9 #endif
michael@0 10
michael@0 11 #ifdef MOZ_WIDGET_QT
michael@0 12 #include "nsQAppInstance.h"
michael@0 13 #endif
michael@0 14
michael@0 15 #include "ContentChild.h"
michael@0 16 #include "CrashReporterChild.h"
michael@0 17 #include "FileDescriptorSetChild.h"
michael@0 18 #include "TabChild.h"
michael@0 19
michael@0 20 #include "mozilla/Attributes.h"
michael@0 21 #include "mozilla/dom/asmjscache/AsmJSCache.h"
michael@0 22 #include "mozilla/dom/asmjscache/PAsmJSCacheEntryChild.h"
michael@0 23 #include "mozilla/dom/ExternalHelperAppChild.h"
michael@0 24 #include "mozilla/dom/PCrashReporterChild.h"
michael@0 25 #include "mozilla/dom/DOMStorageIPC.h"
michael@0 26 #include "mozilla/hal_sandbox/PHalChild.h"
michael@0 27 #include "mozilla/ipc/BackgroundChild.h"
michael@0 28 #include "mozilla/ipc/GeckoChildProcessHost.h"
michael@0 29 #include "mozilla/ipc/TestShellChild.h"
michael@0 30 #include "mozilla/layers/CompositorChild.h"
michael@0 31 #include "mozilla/layers/ImageBridgeChild.h"
michael@0 32 #include "mozilla/layers/PCompositorChild.h"
michael@0 33 #include "mozilla/net/NeckoChild.h"
michael@0 34 #include "mozilla/Preferences.h"
michael@0 35
michael@0 36 #if defined(MOZ_CONTENT_SANDBOX)
michael@0 37 #if defined(XP_WIN)
michael@0 38 #define TARGET_SANDBOX_EXPORTS
michael@0 39 #include "mozilla/sandboxTarget.h"
michael@0 40 #elif defined(XP_LINUX)
michael@0 41 #include "mozilla/Sandbox.h"
michael@0 42 #endif
michael@0 43 #endif
michael@0 44
michael@0 45 #include "mozilla/unused.h"
michael@0 46
michael@0 47 #include "nsIConsoleListener.h"
michael@0 48 #include "nsIIPCBackgroundChildCreateCallback.h"
michael@0 49 #include "nsIInterfaceRequestorUtils.h"
michael@0 50 #include "nsIMemoryReporter.h"
michael@0 51 #include "nsIMemoryInfoDumper.h"
michael@0 52 #include "nsIMutable.h"
michael@0 53 #include "nsIObserverService.h"
michael@0 54 #include "nsIScriptSecurityManager.h"
michael@0 55 #include "nsServiceManagerUtils.h"
michael@0 56 #include "nsStyleSheetService.h"
michael@0 57 #include "nsXULAppAPI.h"
michael@0 58 #include "nsIScriptError.h"
michael@0 59 #include "nsIConsoleService.h"
michael@0 60 #include "nsJSEnvironment.h"
michael@0 61 #include "SandboxHal.h"
michael@0 62 #include "nsDebugImpl.h"
michael@0 63 #include "nsHashPropertyBag.h"
michael@0 64 #include "nsLayoutStylesheetCache.h"
michael@0 65 #include "nsIJSRuntimeService.h"
michael@0 66 #include "nsThreadManager.h"
michael@0 67
michael@0 68 #include "IHistory.h"
michael@0 69 #include "nsNetUtil.h"
michael@0 70
michael@0 71 #include "base/message_loop.h"
michael@0 72 #include "base/process_util.h"
michael@0 73 #include "base/task.h"
michael@0 74
michael@0 75 #include "nsChromeRegistryContent.h"
michael@0 76 #include "nsFrameMessageManager.h"
michael@0 77
michael@0 78 #include "nsIGeolocationProvider.h"
michael@0 79 #include "mozilla/dom/PMemoryReportRequestChild.h"
michael@0 80
michael@0 81 #ifdef MOZ_PERMISSIONS
michael@0 82 #include "nsIScriptSecurityManager.h"
michael@0 83 #include "nsPermission.h"
michael@0 84 #include "nsPermissionManager.h"
michael@0 85 #endif
michael@0 86
michael@0 87 #include "PermissionMessageUtils.h"
michael@0 88
michael@0 89 #if defined(MOZ_WIDGET_ANDROID)
michael@0 90 #include "APKOpen.h"
michael@0 91 #endif
michael@0 92
michael@0 93 #if defined(MOZ_WIDGET_GONK)
michael@0 94 #include "nsVolume.h"
michael@0 95 #include "nsVolumeService.h"
michael@0 96 #include "SpeakerManagerService.h"
michael@0 97 #endif
michael@0 98
michael@0 99 #ifdef XP_WIN
michael@0 100 #include <process.h>
michael@0 101 #define getpid _getpid
michael@0 102 #endif
michael@0 103
michael@0 104 #ifdef MOZ_X11
michael@0 105 #include "mozilla/X11Util.h"
michael@0 106 #endif
michael@0 107
michael@0 108 #ifdef ACCESSIBILITY
michael@0 109 #include "nsIAccessibilityService.h"
michael@0 110 #endif
michael@0 111
michael@0 112 #ifdef MOZ_NUWA_PROCESS
michael@0 113 #include <setjmp.h>
michael@0 114 #include "ipc/Nuwa.h"
michael@0 115 #endif
michael@0 116
michael@0 117 #include "mozilla/dom/indexedDB/PIndexedDBChild.h"
michael@0 118 #include "mozilla/dom/mobilemessage/SmsChild.h"
michael@0 119 #include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
michael@0 120 #include "mozilla/dom/PFileSystemRequestChild.h"
michael@0 121 #include "mozilla/dom/FileSystemTaskBase.h"
michael@0 122 #include "mozilla/dom/bluetooth/PBluetoothChild.h"
michael@0 123 #include "mozilla/dom/PFMRadioChild.h"
michael@0 124 #include "mozilla/ipc/InputStreamUtils.h"
michael@0 125
michael@0 126 #ifdef MOZ_WEBSPEECH
michael@0 127 #include "mozilla/dom/PSpeechSynthesisChild.h"
michael@0 128 #endif
michael@0 129
michael@0 130 #include "nsDOMFile.h"
michael@0 131 #include "nsIRemoteBlob.h"
michael@0 132 #include "ProcessUtils.h"
michael@0 133 #include "StructuredCloneUtils.h"
michael@0 134 #include "URIUtils.h"
michael@0 135 #include "nsContentUtils.h"
michael@0 136 #include "nsIPrincipal.h"
michael@0 137 #include "nsDeviceStorage.h"
michael@0 138 #include "AudioChannelService.h"
michael@0 139 #include "JavaScriptChild.h"
michael@0 140 #include "mozilla/dom/telephony/PTelephonyChild.h"
michael@0 141 #include "mozilla/dom/time/DateCacheCleaner.h"
michael@0 142 #include "mozilla/net/NeckoMessageUtils.h"
michael@0 143
michael@0 144 using namespace base;
michael@0 145 using namespace mozilla;
michael@0 146 using namespace mozilla::docshell;
michael@0 147 using namespace mozilla::dom::bluetooth;
michael@0 148 using namespace mozilla::dom::devicestorage;
michael@0 149 using namespace mozilla::dom::ipc;
michael@0 150 using namespace mozilla::dom::mobilemessage;
michael@0 151 using namespace mozilla::dom::indexedDB;
michael@0 152 using namespace mozilla::dom::telephony;
michael@0 153 using namespace mozilla::hal_sandbox;
michael@0 154 using namespace mozilla::ipc;
michael@0 155 using namespace mozilla::layers;
michael@0 156 using namespace mozilla::net;
michael@0 157 using namespace mozilla::jsipc;
michael@0 158 #if defined(MOZ_WIDGET_GONK)
michael@0 159 using namespace mozilla::system;
michael@0 160 #endif
michael@0 161
michael@0 162 #ifdef MOZ_NUWA_PROCESS
michael@0 163 static bool sNuwaForking = false;
michael@0 164
michael@0 165 // The size of the reserved stack (in unsigned ints). It's used to reserve space
michael@0 166 // to push sigsetjmp() in NuwaCheckpointCurrentThread() to higher in the stack
michael@0 167 // so that after it returns and do other work we don't garble the stack we want
michael@0 168 // to preserve in NuwaCheckpointCurrentThread().
michael@0 169 #define RESERVED_INT_STACK 128
michael@0 170
michael@0 171 // A sentinel value for checking whether RESERVED_INT_STACK is large enough.
michael@0 172 #define STACK_SENTINEL_VALUE 0xdeadbeef
michael@0 173 #endif
michael@0 174
michael@0 175 namespace mozilla {
michael@0 176 namespace dom {
michael@0 177
michael@0 178 class MemoryReportRequestChild : public PMemoryReportRequestChild,
michael@0 179 public nsIRunnable
michael@0 180 {
michael@0 181 public:
michael@0 182 NS_DECL_ISUPPORTS
michael@0 183
michael@0 184 MemoryReportRequestChild(uint32_t aGeneration, const nsAString& aDMDDumpIdent);
michael@0 185 virtual ~MemoryReportRequestChild();
michael@0 186 NS_IMETHOD Run();
michael@0 187 private:
michael@0 188 uint32_t mGeneration;
michael@0 189 nsString mDMDDumpIdent;
michael@0 190 };
michael@0 191
michael@0 192 NS_IMPL_ISUPPORTS(MemoryReportRequestChild, nsIRunnable)
michael@0 193
michael@0 194 MemoryReportRequestChild::MemoryReportRequestChild(uint32_t aGeneration, const nsAString& aDMDDumpIdent)
michael@0 195 : mGeneration(aGeneration), mDMDDumpIdent(aDMDDumpIdent)
michael@0 196 {
michael@0 197 MOZ_COUNT_CTOR(MemoryReportRequestChild);
michael@0 198 }
michael@0 199
michael@0 200 MemoryReportRequestChild::~MemoryReportRequestChild()
michael@0 201 {
michael@0 202 MOZ_COUNT_DTOR(MemoryReportRequestChild);
michael@0 203 }
michael@0 204
michael@0 205 class AlertObserver
michael@0 206 {
michael@0 207 public:
michael@0 208
michael@0 209 AlertObserver(nsIObserver *aObserver, const nsString& aData)
michael@0 210 : mObserver(aObserver)
michael@0 211 , mData(aData)
michael@0 212 {
michael@0 213 }
michael@0 214
michael@0 215 ~AlertObserver() {}
michael@0 216
michael@0 217 bool ShouldRemoveFrom(nsIObserver* aObserver,
michael@0 218 const nsString& aData) const
michael@0 219 {
michael@0 220 return (mObserver == aObserver &&
michael@0 221 mData == aData);
michael@0 222 }
michael@0 223
michael@0 224 bool Observes(const nsString& aData) const
michael@0 225 {
michael@0 226 return mData.Equals(aData);
michael@0 227 }
michael@0 228
michael@0 229 bool Notify(const nsCString& aType) const
michael@0 230 {
michael@0 231 mObserver->Observe(nullptr, aType.get(), mData.get());
michael@0 232 return true;
michael@0 233 }
michael@0 234
michael@0 235 private:
michael@0 236 nsCOMPtr<nsIObserver> mObserver;
michael@0 237 nsString mData;
michael@0 238 };
michael@0 239
michael@0 240 class ConsoleListener MOZ_FINAL : public nsIConsoleListener
michael@0 241 {
michael@0 242 public:
michael@0 243 ConsoleListener(ContentChild* aChild)
michael@0 244 : mChild(aChild) {}
michael@0 245
michael@0 246 NS_DECL_ISUPPORTS
michael@0 247 NS_DECL_NSICONSOLELISTENER
michael@0 248
michael@0 249 private:
michael@0 250 ContentChild* mChild;
michael@0 251 friend class ContentChild;
michael@0 252 };
michael@0 253
michael@0 254 NS_IMPL_ISUPPORTS(ConsoleListener, nsIConsoleListener)
michael@0 255
michael@0 256 NS_IMETHODIMP
michael@0 257 ConsoleListener::Observe(nsIConsoleMessage* aMessage)
michael@0 258 {
michael@0 259 if (!mChild)
michael@0 260 return NS_OK;
michael@0 261
michael@0 262 nsCOMPtr<nsIScriptError> scriptError = do_QueryInterface(aMessage);
michael@0 263 if (scriptError) {
michael@0 264 nsString msg, sourceName, sourceLine;
michael@0 265 nsXPIDLCString category;
michael@0 266 uint32_t lineNum, colNum, flags;
michael@0 267
michael@0 268 nsresult rv = scriptError->GetErrorMessage(msg);
michael@0 269 NS_ENSURE_SUCCESS(rv, rv);
michael@0 270 rv = scriptError->GetSourceName(sourceName);
michael@0 271 NS_ENSURE_SUCCESS(rv, rv);
michael@0 272 rv = scriptError->GetSourceLine(sourceLine);
michael@0 273 NS_ENSURE_SUCCESS(rv, rv);
michael@0 274
michael@0 275 // Before we send the error to the parent process (which
michael@0 276 // involves copying the memory), truncate any long lines. CSS
michael@0 277 // errors in particular share the memory for long lines with
michael@0 278 // repeated errors, but the IPC communication we're about to do
michael@0 279 // will break that sharing, so we better truncate now.
michael@0 280 if (sourceLine.Length() > 1000) {
michael@0 281 sourceLine.Truncate(1000);
michael@0 282 }
michael@0 283
michael@0 284 rv = scriptError->GetCategory(getter_Copies(category));
michael@0 285 NS_ENSURE_SUCCESS(rv, rv);
michael@0 286 rv = scriptError->GetLineNumber(&lineNum);
michael@0 287 NS_ENSURE_SUCCESS(rv, rv);
michael@0 288 rv = scriptError->GetColumnNumber(&colNum);
michael@0 289 NS_ENSURE_SUCCESS(rv, rv);
michael@0 290 rv = scriptError->GetFlags(&flags);
michael@0 291 NS_ENSURE_SUCCESS(rv, rv);
michael@0 292 mChild->SendScriptError(msg, sourceName, sourceLine,
michael@0 293 lineNum, colNum, flags, category);
michael@0 294 return NS_OK;
michael@0 295 }
michael@0 296
michael@0 297 nsXPIDLString msg;
michael@0 298 nsresult rv = aMessage->GetMessageMoz(getter_Copies(msg));
michael@0 299 NS_ENSURE_SUCCESS(rv, rv);
michael@0 300 mChild->SendConsoleMessage(msg);
michael@0 301 return NS_OK;
michael@0 302 }
michael@0 303
michael@0 304 class SystemMessageHandledObserver MOZ_FINAL : public nsIObserver
michael@0 305 {
michael@0 306 public:
michael@0 307 NS_DECL_ISUPPORTS
michael@0 308 NS_DECL_NSIOBSERVER
michael@0 309
michael@0 310 void Init();
michael@0 311 };
michael@0 312
michael@0 313 void SystemMessageHandledObserver::Init()
michael@0 314 {
michael@0 315 nsCOMPtr<nsIObserverService> os =
michael@0 316 mozilla::services::GetObserverService();
michael@0 317
michael@0 318 if (os) {
michael@0 319 os->AddObserver(this, "handle-system-messages-done",
michael@0 320 /* ownsWeak */ false);
michael@0 321 }
michael@0 322 }
michael@0 323
michael@0 324 NS_IMETHODIMP
michael@0 325 SystemMessageHandledObserver::Observe(nsISupports* aSubject,
michael@0 326 const char* aTopic,
michael@0 327 const char16_t* aData)
michael@0 328 {
michael@0 329 if (ContentChild::GetSingleton()) {
michael@0 330 ContentChild::GetSingleton()->SendSystemMessageHandled();
michael@0 331 }
michael@0 332 return NS_OK;
michael@0 333 }
michael@0 334
michael@0 335 NS_IMPL_ISUPPORTS(SystemMessageHandledObserver, nsIObserver)
michael@0 336
michael@0 337 class BackgroundChildPrimer MOZ_FINAL :
michael@0 338 public nsIIPCBackgroundChildCreateCallback
michael@0 339 {
michael@0 340 public:
michael@0 341 BackgroundChildPrimer()
michael@0 342 { }
michael@0 343
michael@0 344 NS_DECL_ISUPPORTS
michael@0 345
michael@0 346 private:
michael@0 347 ~BackgroundChildPrimer()
michael@0 348 { }
michael@0 349
michael@0 350 virtual void
michael@0 351 ActorCreated(PBackgroundChild* aActor) MOZ_OVERRIDE
michael@0 352 {
michael@0 353 MOZ_ASSERT(aActor, "Failed to create a PBackgroundChild actor!");
michael@0 354 }
michael@0 355
michael@0 356 virtual void
michael@0 357 ActorFailed() MOZ_OVERRIDE
michael@0 358 {
michael@0 359 MOZ_CRASH("Failed to create a PBackgroundChild actor!");
michael@0 360 }
michael@0 361 };
michael@0 362
michael@0 363 NS_IMPL_ISUPPORTS(BackgroundChildPrimer, nsIIPCBackgroundChildCreateCallback)
michael@0 364
michael@0 365 ContentChild* ContentChild::sSingleton;
michael@0 366
michael@0 367 // Performs initialization that is not fork-safe, i.e. that must be done after
michael@0 368 // forking from the Nuwa process.
michael@0 369 static void
michael@0 370 InitOnContentProcessCreated()
michael@0 371 {
michael@0 372 // This will register cross-process observer.
michael@0 373 mozilla::dom::time::InitializeDateCacheCleaner();
michael@0 374 }
michael@0 375
michael@0 376 ContentChild::ContentChild()
michael@0 377 : mID(uint64_t(-1))
michael@0 378 #ifdef ANDROID
michael@0 379 ,mScreenSize(0, 0)
michael@0 380 #endif
michael@0 381 , mCanOverrideProcessName(true)
michael@0 382 {
michael@0 383 // This process is a content process, so it's clearly running in
michael@0 384 // multiprocess mode!
michael@0 385 nsDebugImpl::SetMultiprocessMode("Child");
michael@0 386 }
michael@0 387
michael@0 388 ContentChild::~ContentChild()
michael@0 389 {
michael@0 390 }
michael@0 391
michael@0 392 bool
michael@0 393 ContentChild::Init(MessageLoop* aIOLoop,
michael@0 394 base::ProcessHandle aParentHandle,
michael@0 395 IPC::Channel* aChannel)
michael@0 396 {
michael@0 397 #ifdef MOZ_WIDGET_GTK
michael@0 398 // sigh
michael@0 399 gtk_init(nullptr, nullptr);
michael@0 400 #endif
michael@0 401
michael@0 402 #ifdef MOZ_WIDGET_QT
michael@0 403 // sigh, seriously
michael@0 404 nsQAppInstance::AddRef();
michael@0 405 #endif
michael@0 406
michael@0 407 #ifdef MOZ_X11
michael@0 408 // Do this after initializing GDK, or GDK will install its own handler.
michael@0 409 XRE_InstallX11ErrorHandler();
michael@0 410 #endif
michael@0 411
michael@0 412 #ifdef MOZ_NUWA_PROCESS
michael@0 413 SetTransport(aChannel);
michael@0 414 #endif
michael@0 415
michael@0 416 NS_ASSERTION(!sSingleton, "only one ContentChild per child");
michael@0 417
michael@0 418 // Once we start sending IPC messages, we need the thread manager to be
michael@0 419 // initialized so we can deal with the responses. Do that here before we
michael@0 420 // try to construct the crash reporter.
michael@0 421 nsresult rv = nsThreadManager::get()->Init();
michael@0 422 if (NS_WARN_IF(NS_FAILED(rv))) {
michael@0 423 return false;
michael@0 424 }
michael@0 425
michael@0 426 Open(aChannel, aParentHandle, aIOLoop);
michael@0 427 sSingleton = this;
michael@0 428
michael@0 429 #ifdef MOZ_X11
michael@0 430 // Send the parent our X socket to act as a proxy reference for our X
michael@0 431 // resources.
michael@0 432 int xSocketFd = ConnectionNumber(DefaultXDisplay());
michael@0 433 SendBackUpXResources(FileDescriptor(xSocketFd));
michael@0 434 #endif
michael@0 435
michael@0 436 #ifdef MOZ_CRASHREPORTER
michael@0 437 SendPCrashReporterConstructor(CrashReporter::CurrentThreadId(),
michael@0 438 XRE_GetProcessType());
michael@0 439 #endif
michael@0 440
michael@0 441 GetCPOWManager();
michael@0 442
michael@0 443 InitProcessAttributes();
michael@0 444
michael@0 445 return true;
michael@0 446 }
michael@0 447
michael@0 448 void
michael@0 449 ContentChild::InitProcessAttributes()
michael@0 450 {
michael@0 451 SendGetProcessAttributes(&mID, &mIsForApp, &mIsForBrowser);
michael@0 452
michael@0 453 #ifdef MOZ_NUWA_PROCESS
michael@0 454 if (IsNuwaProcess()) {
michael@0 455 SetProcessName(NS_LITERAL_STRING("(Nuwa)"), false);
michael@0 456 return;
michael@0 457 }
michael@0 458 #endif
michael@0 459 if (mIsForApp && !mIsForBrowser) {
michael@0 460 SetProcessName(NS_LITERAL_STRING("(Preallocated app)"), false);
michael@0 461 } else {
michael@0 462 SetProcessName(NS_LITERAL_STRING("Browser"), false);
michael@0 463 }
michael@0 464
michael@0 465 }
michael@0 466
michael@0 467 void
michael@0 468 ContentChild::SetProcessName(const nsAString& aName, bool aDontOverride)
michael@0 469 {
michael@0 470 if (!mCanOverrideProcessName) {
michael@0 471 return;
michael@0 472 }
michael@0 473
michael@0 474 char* name;
michael@0 475 if ((name = PR_GetEnv("MOZ_DEBUG_APP_PROCESS")) &&
michael@0 476 aName.EqualsASCII(name)) {
michael@0 477 #ifdef OS_POSIX
michael@0 478 printf_stderr("\n\nCHILDCHILDCHILDCHILD\n [%s] debug me @%d\n\n", name, getpid());
michael@0 479 sleep(30);
michael@0 480 #elif defined(OS_WIN)
michael@0 481 // Windows has a decent JIT debugging story, so NS_DebugBreak does the
michael@0 482 // right thing.
michael@0 483 NS_DebugBreak(NS_DEBUG_BREAK,
michael@0 484 "Invoking NS_DebugBreak() to debug child process",
michael@0 485 nullptr, __FILE__, __LINE__);
michael@0 486 #endif
michael@0 487 }
michael@0 488
michael@0 489 mProcessName = aName;
michael@0 490 mozilla::ipc::SetThisProcessName(NS_LossyConvertUTF16toASCII(aName).get());
michael@0 491
michael@0 492 if (aDontOverride) {
michael@0 493 mCanOverrideProcessName = false;
michael@0 494 }
michael@0 495 }
michael@0 496
michael@0 497 void
michael@0 498 ContentChild::GetProcessName(nsAString& aName)
michael@0 499 {
michael@0 500 aName.Assign(mProcessName);
michael@0 501 }
michael@0 502
michael@0 503 void
michael@0 504 ContentChild::GetProcessName(nsACString& aName)
michael@0 505 {
michael@0 506 aName.Assign(NS_ConvertUTF16toUTF8(mProcessName));
michael@0 507 }
michael@0 508
michael@0 509 /* static */ void
michael@0 510 ContentChild::AppendProcessId(nsACString& aName)
michael@0 511 {
michael@0 512 if (!aName.IsEmpty()) {
michael@0 513 aName.AppendLiteral(" ");
michael@0 514 }
michael@0 515 unsigned pid = getpid();
michael@0 516 aName.Append(nsPrintfCString("(pid %u)", pid));
michael@0 517 }
michael@0 518
michael@0 519 void
michael@0 520 ContentChild::InitXPCOM()
michael@0 521 {
michael@0 522 // Do this as early as possible to get the parent process to initialize the
michael@0 523 // background thread since we'll likely need database information very soon.
michael@0 524 BackgroundChild::Startup();
michael@0 525
michael@0 526 nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
michael@0 527 new BackgroundChildPrimer();
michael@0 528 if (!BackgroundChild::GetOrCreateForCurrentThread(callback)) {
michael@0 529 MOZ_CRASH("Failed to create PBackgroundChild!");
michael@0 530 }
michael@0 531
michael@0 532 nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
michael@0 533 if (!svc) {
michael@0 534 NS_WARNING("Couldn't acquire console service");
michael@0 535 return;
michael@0 536 }
michael@0 537
michael@0 538 mConsoleListener = new ConsoleListener(this);
michael@0 539 if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
michael@0 540 NS_WARNING("Couldn't register console listener for child process");
michael@0 541
michael@0 542 bool isOffline;
michael@0 543 SendGetXPCOMProcessAttributes(&isOffline);
michael@0 544 RecvSetOffline(isOffline);
michael@0 545
michael@0 546 DebugOnly<FileUpdateDispatcher*> observer = FileUpdateDispatcher::GetSingleton();
michael@0 547 NS_ASSERTION(observer, "FileUpdateDispatcher is null");
michael@0 548
michael@0 549 // This object is held alive by the observer service.
michael@0 550 nsRefPtr<SystemMessageHandledObserver> sysMsgObserver =
michael@0 551 new SystemMessageHandledObserver();
michael@0 552 sysMsgObserver->Init();
michael@0 553
michael@0 554 #ifndef MOZ_NUWA_PROCESS
michael@0 555 InitOnContentProcessCreated();
michael@0 556 #endif
michael@0 557 }
michael@0 558
michael@0 559 PMemoryReportRequestChild*
michael@0 560 ContentChild::AllocPMemoryReportRequestChild(const uint32_t& generation,
michael@0 561 const bool &minimizeMemoryUsage,
michael@0 562 const nsString& aDMDDumpIdent)
michael@0 563 {
michael@0 564 MemoryReportRequestChild *actor = new MemoryReportRequestChild(generation, aDMDDumpIdent);
michael@0 565 actor->AddRef();
michael@0 566 return actor;
michael@0 567 }
michael@0 568
michael@0 569 // This is just a wrapper for InfallibleTArray<MemoryReport> that implements
michael@0 570 // nsISupports, so it can be passed to nsIMemoryReporter::CollectReports.
michael@0 571 class MemoryReportsWrapper MOZ_FINAL : public nsISupports {
michael@0 572 public:
michael@0 573 NS_DECL_ISUPPORTS
michael@0 574 MemoryReportsWrapper(InfallibleTArray<MemoryReport> *r) : mReports(r) { }
michael@0 575 InfallibleTArray<MemoryReport> *mReports;
michael@0 576 };
michael@0 577 NS_IMPL_ISUPPORTS0(MemoryReportsWrapper)
michael@0 578
michael@0 579 class MemoryReportCallback MOZ_FINAL : public nsIMemoryReporterCallback
michael@0 580 {
michael@0 581 public:
michael@0 582 NS_DECL_ISUPPORTS
michael@0 583
michael@0 584 MemoryReportCallback(const nsACString &aProcess)
michael@0 585 : mProcess(aProcess)
michael@0 586 {
michael@0 587 }
michael@0 588
michael@0 589 NS_IMETHOD Callback(const nsACString &aProcess, const nsACString &aPath,
michael@0 590 int32_t aKind, int32_t aUnits, int64_t aAmount,
michael@0 591 const nsACString &aDescription,
michael@0 592 nsISupports *aiWrappedReports)
michael@0 593 {
michael@0 594 MemoryReportsWrapper *wrappedReports =
michael@0 595 static_cast<MemoryReportsWrapper *>(aiWrappedReports);
michael@0 596
michael@0 597 MemoryReport memreport(mProcess, nsCString(aPath), aKind, aUnits,
michael@0 598 aAmount, nsCString(aDescription));
michael@0 599 wrappedReports->mReports->AppendElement(memreport);
michael@0 600 return NS_OK;
michael@0 601 }
michael@0 602 private:
michael@0 603 const nsCString mProcess;
michael@0 604 };
michael@0 605 NS_IMPL_ISUPPORTS(
michael@0 606 MemoryReportCallback
michael@0 607 , nsIMemoryReporterCallback
michael@0 608 )
michael@0 609
michael@0 610 bool
michael@0 611 ContentChild::RecvPMemoryReportRequestConstructor(
michael@0 612 PMemoryReportRequestChild* child,
michael@0 613 const uint32_t& generation,
michael@0 614 const bool& minimizeMemoryUsage,
michael@0 615 const nsString& aDMDDumpIdent)
michael@0 616 {
michael@0 617 MemoryReportRequestChild *actor = static_cast<MemoryReportRequestChild*>(child);
michael@0 618 nsresult rv;
michael@0 619
michael@0 620 if (minimizeMemoryUsage) {
michael@0 621 nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
michael@0 622 rv = mgr->MinimizeMemoryUsage(actor);
michael@0 623 // mgr will eventually call actor->Run()
michael@0 624 } else {
michael@0 625 rv = actor->Run();
michael@0 626 }
michael@0 627
michael@0 628 return !NS_WARN_IF(NS_FAILED(rv));
michael@0 629 }
michael@0 630
michael@0 631 NS_IMETHODIMP MemoryReportRequestChild::Run()
michael@0 632 {
michael@0 633 ContentChild *child = static_cast<ContentChild*>(Manager());
michael@0 634 nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
michael@0 635
michael@0 636 InfallibleTArray<MemoryReport> reports;
michael@0 637
michael@0 638 nsCString process;
michael@0 639 child->GetProcessName(process);
michael@0 640 child->AppendProcessId(process);
michael@0 641
michael@0 642 // Run the reporters. The callback will turn each measurement into a
michael@0 643 // MemoryReport.
michael@0 644 nsRefPtr<MemoryReportsWrapper> wrappedReports =
michael@0 645 new MemoryReportsWrapper(&reports);
michael@0 646 nsRefPtr<MemoryReportCallback> cb = new MemoryReportCallback(process);
michael@0 647 mgr->GetReportsForThisProcessExtended(cb, wrappedReports, mDMDDumpIdent);
michael@0 648
michael@0 649 bool sent = Send__delete__(this, mGeneration, reports);
michael@0 650 return sent ? NS_OK : NS_ERROR_FAILURE;
michael@0 651 }
michael@0 652
michael@0 653 bool
michael@0 654 ContentChild::RecvAudioChannelNotify()
michael@0 655 {
michael@0 656 nsRefPtr<AudioChannelService> service =
michael@0 657 AudioChannelService::GetAudioChannelService();
michael@0 658 if (service) {
michael@0 659 service->Notify();
michael@0 660 }
michael@0 661 return true;
michael@0 662 }
michael@0 663
michael@0 664 bool
michael@0 665 ContentChild::DeallocPMemoryReportRequestChild(PMemoryReportRequestChild* actor)
michael@0 666 {
michael@0 667 static_cast<MemoryReportRequestChild*>(actor)->Release();
michael@0 668 return true;
michael@0 669 }
michael@0 670
michael@0 671 bool
michael@0 672 ContentChild::RecvDumpGCAndCCLogsToFile(const nsString& aIdentifier,
michael@0 673 const bool& aDumpAllTraces,
michael@0 674 const bool& aDumpChildProcesses)
michael@0 675 {
michael@0 676 nsCOMPtr<nsIMemoryInfoDumper> dumper = do_GetService("@mozilla.org/memory-info-dumper;1");
michael@0 677
michael@0 678 nsString gcLogPath, ccLogPath;
michael@0 679 dumper->DumpGCAndCCLogsToFile(aIdentifier, aDumpAllTraces,
michael@0 680 aDumpChildProcesses, gcLogPath, ccLogPath);
michael@0 681 return true;
michael@0 682 }
michael@0 683
michael@0 684 PCompositorChild*
michael@0 685 ContentChild::AllocPCompositorChild(mozilla::ipc::Transport* aTransport,
michael@0 686 base::ProcessId aOtherProcess)
michael@0 687 {
michael@0 688 return CompositorChild::Create(aTransport, aOtherProcess);
michael@0 689 }
michael@0 690
michael@0 691 PImageBridgeChild*
michael@0 692 ContentChild::AllocPImageBridgeChild(mozilla::ipc::Transport* aTransport,
michael@0 693 base::ProcessId aOtherProcess)
michael@0 694 {
michael@0 695 return ImageBridgeChild::StartUpInChildProcess(aTransport, aOtherProcess);
michael@0 696 }
michael@0 697
michael@0 698 PBackgroundChild*
michael@0 699 ContentChild::AllocPBackgroundChild(Transport* aTransport,
michael@0 700 ProcessId aOtherProcess)
michael@0 701 {
michael@0 702 return BackgroundChild::Alloc(aTransport, aOtherProcess);
michael@0 703 }
michael@0 704
michael@0 705 bool
michael@0 706 ContentChild::RecvSetProcessSandbox()
michael@0 707 {
michael@0 708 // We may want to move the sandbox initialization somewhere else
michael@0 709 // at some point; see bug 880808.
michael@0 710 #if defined(MOZ_CONTENT_SANDBOX)
michael@0 711 #if defined(XP_LINUX)
michael@0 712 SetCurrentProcessSandbox();
michael@0 713 #elif defined(XP_WIN)
michael@0 714 mozilla::SandboxTarget::Instance()->StartSandbox();
michael@0 715 #endif
michael@0 716 #endif
michael@0 717 return true;
michael@0 718 }
michael@0 719
michael@0 720 bool
michael@0 721 ContentChild::RecvSpeakerManagerNotify()
michael@0 722 {
michael@0 723 #ifdef MOZ_WIDGET_GONK
michael@0 724 nsRefPtr<SpeakerManagerService> service =
michael@0 725 SpeakerManagerService::GetSpeakerManagerService();
michael@0 726 if (service) {
michael@0 727 service->Notify();
michael@0 728 }
michael@0 729 return true;
michael@0 730 #endif
michael@0 731 return false;
michael@0 732 }
michael@0 733
michael@0 734 static CancelableTask* sFirstIdleTask;
michael@0 735
michael@0 736 static void FirstIdle(void)
michael@0 737 {
michael@0 738 MOZ_ASSERT(sFirstIdleTask);
michael@0 739 sFirstIdleTask = nullptr;
michael@0 740 ContentChild::GetSingleton()->SendFirstIdle();
michael@0 741 }
michael@0 742
michael@0 743 mozilla::jsipc::PJavaScriptChild *
michael@0 744 ContentChild::AllocPJavaScriptChild()
michael@0 745 {
michael@0 746 nsCOMPtr<nsIJSRuntimeService> svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
michael@0 747 NS_ENSURE_TRUE(svc, nullptr);
michael@0 748
michael@0 749 JSRuntime *rt;
michael@0 750 svc->GetRuntime(&rt);
michael@0 751 NS_ENSURE_TRUE(svc, nullptr);
michael@0 752
michael@0 753 mozilla::jsipc::JavaScriptChild *child = new mozilla::jsipc::JavaScriptChild(rt);
michael@0 754 if (!child->init()) {
michael@0 755 delete child;
michael@0 756 return nullptr;
michael@0 757 }
michael@0 758 return child;
michael@0 759 }
michael@0 760
michael@0 761 bool
michael@0 762 ContentChild::DeallocPJavaScriptChild(PJavaScriptChild *child)
michael@0 763 {
michael@0 764 delete child;
michael@0 765 return true;
michael@0 766 }
michael@0 767
michael@0 768 PBrowserChild*
michael@0 769 ContentChild::AllocPBrowserChild(const IPCTabContext& aContext,
michael@0 770 const uint32_t& aChromeFlags)
michael@0 771 {
michael@0 772 // We'll happily accept any kind of IPCTabContext here; we don't need to
michael@0 773 // check that it's of a certain type for security purposes, because we
michael@0 774 // believe whatever the parent process tells us.
michael@0 775
michael@0 776 MaybeInvalidTabContext tc(aContext);
michael@0 777 if (!tc.IsValid()) {
michael@0 778 NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
michael@0 779 "the parent process. (%s) Crashing...",
michael@0 780 tc.GetInvalidReason()).get());
michael@0 781 MOZ_CRASH("Invalid TabContext received from the parent process.");
michael@0 782 }
michael@0 783
michael@0 784 nsRefPtr<TabChild> child = TabChild::Create(this, tc.GetTabContext(), aChromeFlags);
michael@0 785
michael@0 786 // The ref here is released in DeallocPBrowserChild.
michael@0 787 return child.forget().take();
michael@0 788 }
michael@0 789
michael@0 790 bool
michael@0 791 ContentChild::RecvPBrowserConstructor(PBrowserChild* actor,
michael@0 792 const IPCTabContext& context,
michael@0 793 const uint32_t& chromeFlags)
michael@0 794 {
michael@0 795 // This runs after AllocPBrowserChild() returns and the IPC machinery for this
michael@0 796 // PBrowserChild has been set up.
michael@0 797
michael@0 798 nsCOMPtr<nsIObserverService> os = services::GetObserverService();
michael@0 799 if (os) {
michael@0 800 nsITabChild* tc =
michael@0 801 static_cast<nsITabChild*>(static_cast<TabChild*>(actor));
michael@0 802 os->NotifyObservers(tc, "tab-child-created", nullptr);
michael@0 803 }
michael@0 804
michael@0 805 static bool hasRunOnce = false;
michael@0 806 if (!hasRunOnce) {
michael@0 807 hasRunOnce = true;
michael@0 808
michael@0 809 MOZ_ASSERT(!sFirstIdleTask);
michael@0 810 sFirstIdleTask = NewRunnableFunction(FirstIdle);
michael@0 811 MessageLoop::current()->PostIdleTask(FROM_HERE, sFirstIdleTask);
michael@0 812
michael@0 813 // Redo InitProcessAttributes() when the app or browser is really
michael@0 814 // launching so the attributes will be correct.
michael@0 815 InitProcessAttributes();
michael@0 816 }
michael@0 817
michael@0 818 return true;
michael@0 819 }
michael@0 820
michael@0 821 PFileDescriptorSetChild*
michael@0 822 ContentChild::AllocPFileDescriptorSetChild(const FileDescriptor& aFD)
michael@0 823 {
michael@0 824 return new FileDescriptorSetChild(aFD);
michael@0 825 }
michael@0 826
michael@0 827 bool
michael@0 828 ContentChild::DeallocPFileDescriptorSetChild(PFileDescriptorSetChild* aActor)
michael@0 829 {
michael@0 830 delete static_cast<FileDescriptorSetChild*>(aActor);
michael@0 831 return true;
michael@0 832 }
michael@0 833
michael@0 834 bool
michael@0 835 ContentChild::DeallocPBrowserChild(PBrowserChild* iframe)
michael@0 836 {
michael@0 837 TabChild* child = static_cast<TabChild*>(iframe);
michael@0 838 NS_RELEASE(child);
michael@0 839 return true;
michael@0 840 }
michael@0 841
michael@0 842 PBlobChild*
michael@0 843 ContentChild::AllocPBlobChild(const BlobConstructorParams& aParams)
michael@0 844 {
michael@0 845 return BlobChild::Create(this, aParams);
michael@0 846 }
michael@0 847
michael@0 848 bool
michael@0 849 ContentChild::DeallocPBlobChild(PBlobChild* aActor)
michael@0 850 {
michael@0 851 delete aActor;
michael@0 852 return true;
michael@0 853 }
michael@0 854
michael@0 855 BlobChild*
michael@0 856 ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
michael@0 857 {
michael@0 858 MOZ_ASSERT(NS_IsMainThread());
michael@0 859 MOZ_ASSERT(aBlob);
michael@0 860
michael@0 861 // If the blob represents a remote blob then we can simply pass its actor back
michael@0 862 // here.
michael@0 863 if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob)) {
michael@0 864 BlobChild* actor =
michael@0 865 static_cast<BlobChild*>(
michael@0 866 static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
michael@0 867 MOZ_ASSERT(actor);
michael@0 868 return actor;
michael@0 869 }
michael@0 870
michael@0 871 // XXX This is only safe so long as all blob implementations in our tree
michael@0 872 // inherit nsDOMFileBase. If that ever changes then this will need to grow
michael@0 873 // a real interface or something.
michael@0 874 const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
michael@0 875
michael@0 876 // We often pass blobs that are multipart but that only contain one sub-blob
michael@0 877 // (WebActivities does this a bunch). Unwrap to reduce the number of actors
michael@0 878 // that we have to maintain.
michael@0 879 const nsTArray<nsCOMPtr<nsIDOMBlob> >* subBlobs = blob->GetSubBlobs();
michael@0 880 if (subBlobs && subBlobs->Length() == 1) {
michael@0 881 const nsCOMPtr<nsIDOMBlob>& subBlob = subBlobs->ElementAt(0);
michael@0 882 MOZ_ASSERT(subBlob);
michael@0 883
michael@0 884 // We can only take this shortcut if the multipart and the sub-blob are both
michael@0 885 // Blob objects or both File objects.
michael@0 886 nsCOMPtr<nsIDOMFile> multipartBlobAsFile = do_QueryInterface(aBlob);
michael@0 887 nsCOMPtr<nsIDOMFile> subBlobAsFile = do_QueryInterface(subBlob);
michael@0 888 if (!multipartBlobAsFile == !subBlobAsFile) {
michael@0 889 // The wrapping was unnecessary, see if we can simply pass an existing
michael@0 890 // remote blob.
michael@0 891 if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(subBlob)) {
michael@0 892 BlobChild* actor =
michael@0 893 static_cast<BlobChild*>(
michael@0 894 static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
michael@0 895 MOZ_ASSERT(actor);
michael@0 896 return actor;
michael@0 897 }
michael@0 898
michael@0 899 // No need to add a reference here since the original blob must have a
michael@0 900 // strong reference in the caller and it must also have a strong reference
michael@0 901 // to this sub-blob.
michael@0 902 aBlob = subBlob;
michael@0 903 blob = static_cast<nsDOMFileBase*>(aBlob);
michael@0 904 subBlobs = blob->GetSubBlobs();
michael@0 905 }
michael@0 906 }
michael@0 907
michael@0 908 // All blobs shared between processes must be immutable.
michael@0 909 nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
michael@0 910 if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
michael@0 911 NS_WARNING("Failed to make blob immutable!");
michael@0 912 return nullptr;
michael@0 913 }
michael@0 914
michael@0 915 ParentBlobConstructorParams params;
michael@0 916
michael@0 917 if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
michael@0 918 // We don't want to call GetSize or GetLastModifiedDate
michael@0 919 // yet since that may stat a file on the main thread
michael@0 920 // here. Instead we'll learn the size lazily from the
michael@0 921 // other process.
michael@0 922 params.blobParams() = MysteryBlobConstructorParams();
michael@0 923 params.optionalInputStreamParams() = void_t();
michael@0 924 }
michael@0 925 else {
michael@0 926 nsString contentType;
michael@0 927 nsresult rv = aBlob->GetType(contentType);
michael@0 928 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 929
michael@0 930 uint64_t length;
michael@0 931 rv = aBlob->GetSize(&length);
michael@0 932 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 933
michael@0 934 nsCOMPtr<nsIInputStream> stream;
michael@0 935 rv = aBlob->GetInternalStream(getter_AddRefs(stream));
michael@0 936 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 937
michael@0 938 InputStreamParams inputStreamParams;
michael@0 939 nsTArray<mozilla::ipc::FileDescriptor> fds;
michael@0 940 SerializeInputStream(stream, inputStreamParams, fds);
michael@0 941 MOZ_ASSERT(fds.IsEmpty());
michael@0 942
michael@0 943 params.optionalInputStreamParams() = inputStreamParams;
michael@0 944
michael@0 945 nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
michael@0 946 if (file) {
michael@0 947 FileBlobConstructorParams fileParams;
michael@0 948
michael@0 949 rv = file->GetName(fileParams.name());
michael@0 950 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 951
michael@0 952 rv = file->GetMozLastModifiedDate(&fileParams.modDate());
michael@0 953 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 954
michael@0 955 fileParams.contentType() = contentType;
michael@0 956 fileParams.length() = length;
michael@0 957
michael@0 958 params.blobParams() = fileParams;
michael@0 959 } else {
michael@0 960 NormalBlobConstructorParams blobParams;
michael@0 961 blobParams.contentType() = contentType;
michael@0 962 blobParams.length() = length;
michael@0 963 params.blobParams() = blobParams;
michael@0 964 }
michael@0 965 }
michael@0 966
michael@0 967 BlobChild* actor = BlobChild::Create(this, aBlob);
michael@0 968 NS_ENSURE_TRUE(actor, nullptr);
michael@0 969
michael@0 970 return SendPBlobConstructor(actor, params) ? actor : nullptr;
michael@0 971 }
michael@0 972
michael@0 973 PCrashReporterChild*
michael@0 974 ContentChild::AllocPCrashReporterChild(const mozilla::dom::NativeThreadId& id,
michael@0 975 const uint32_t& processType)
michael@0 976 {
michael@0 977 #ifdef MOZ_CRASHREPORTER
michael@0 978 return new CrashReporterChild();
michael@0 979 #else
michael@0 980 return nullptr;
michael@0 981 #endif
michael@0 982 }
michael@0 983
michael@0 984 bool
michael@0 985 ContentChild::DeallocPCrashReporterChild(PCrashReporterChild* crashreporter)
michael@0 986 {
michael@0 987 delete crashreporter;
michael@0 988 return true;
michael@0 989 }
michael@0 990
michael@0 991 PHalChild*
michael@0 992 ContentChild::AllocPHalChild()
michael@0 993 {
michael@0 994 return CreateHalChild();
michael@0 995 }
michael@0 996
michael@0 997 bool
michael@0 998 ContentChild::DeallocPHalChild(PHalChild* aHal)
michael@0 999 {
michael@0 1000 delete aHal;
michael@0 1001 return true;
michael@0 1002 }
michael@0 1003
michael@0 1004 PIndexedDBChild*
michael@0 1005 ContentChild::AllocPIndexedDBChild()
michael@0 1006 {
michael@0 1007 NS_NOTREACHED("Should never get here!");
michael@0 1008 return nullptr;
michael@0 1009 }
michael@0 1010
michael@0 1011 bool
michael@0 1012 ContentChild::DeallocPIndexedDBChild(PIndexedDBChild* aActor)
michael@0 1013 {
michael@0 1014 delete aActor;
michael@0 1015 return true;
michael@0 1016 }
michael@0 1017
michael@0 1018 asmjscache::PAsmJSCacheEntryChild*
michael@0 1019 ContentChild::AllocPAsmJSCacheEntryChild(
michael@0 1020 const asmjscache::OpenMode& aOpenMode,
michael@0 1021 const asmjscache::WriteParams& aWriteParams,
michael@0 1022 const IPC::Principal& aPrincipal)
michael@0 1023 {
michael@0 1024 NS_NOTREACHED("Should never get here!");
michael@0 1025 return nullptr;
michael@0 1026 }
michael@0 1027
michael@0 1028 bool
michael@0 1029 ContentChild::DeallocPAsmJSCacheEntryChild(PAsmJSCacheEntryChild* aActor)
michael@0 1030 {
michael@0 1031 asmjscache::DeallocEntryChild(aActor);
michael@0 1032 return true;
michael@0 1033 }
michael@0 1034
michael@0 1035 PTestShellChild*
michael@0 1036 ContentChild::AllocPTestShellChild()
michael@0 1037 {
michael@0 1038 return new TestShellChild();
michael@0 1039 }
michael@0 1040
michael@0 1041 bool
michael@0 1042 ContentChild::DeallocPTestShellChild(PTestShellChild* shell)
michael@0 1043 {
michael@0 1044 delete shell;
michael@0 1045 return true;
michael@0 1046 }
michael@0 1047
michael@0 1048 jsipc::JavaScriptChild *
michael@0 1049 ContentChild::GetCPOWManager()
michael@0 1050 {
michael@0 1051 if (ManagedPJavaScriptChild().Length()) {
michael@0 1052 return static_cast<JavaScriptChild*>(ManagedPJavaScriptChild()[0]);
michael@0 1053 }
michael@0 1054 JavaScriptChild* actor = static_cast<JavaScriptChild*>(SendPJavaScriptConstructor());
michael@0 1055 return actor;
michael@0 1056 }
michael@0 1057
michael@0 1058 bool
michael@0 1059 ContentChild::RecvPTestShellConstructor(PTestShellChild* actor)
michael@0 1060 {
michael@0 1061 return true;
michael@0 1062 }
michael@0 1063
michael@0 1064 PDeviceStorageRequestChild*
michael@0 1065 ContentChild::AllocPDeviceStorageRequestChild(const DeviceStorageParams& aParams)
michael@0 1066 {
michael@0 1067 return new DeviceStorageRequestChild();
michael@0 1068 }
michael@0 1069
michael@0 1070 bool
michael@0 1071 ContentChild::DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild* aDeviceStorage)
michael@0 1072 {
michael@0 1073 delete aDeviceStorage;
michael@0 1074 return true;
michael@0 1075 }
michael@0 1076
michael@0 1077 PFileSystemRequestChild*
michael@0 1078 ContentChild::AllocPFileSystemRequestChild(const FileSystemParams& aParams)
michael@0 1079 {
michael@0 1080 NS_NOTREACHED("Should never get here!");
michael@0 1081 return nullptr;
michael@0 1082 }
michael@0 1083
michael@0 1084 bool
michael@0 1085 ContentChild::DeallocPFileSystemRequestChild(PFileSystemRequestChild* aFileSystem)
michael@0 1086 {
michael@0 1087 mozilla::dom::FileSystemTaskBase* child =
michael@0 1088 static_cast<mozilla::dom::FileSystemTaskBase*>(aFileSystem);
michael@0 1089 // The reference is increased in FileSystemTaskBase::Start of
michael@0 1090 // FileSystemTaskBase.cpp. We should decrease it after IPC.
michael@0 1091 NS_RELEASE(child);
michael@0 1092 return true;
michael@0 1093 }
michael@0 1094
michael@0 1095 PNeckoChild*
michael@0 1096 ContentChild::AllocPNeckoChild()
michael@0 1097 {
michael@0 1098 return new NeckoChild();
michael@0 1099 }
michael@0 1100
michael@0 1101 bool
michael@0 1102 ContentChild::DeallocPNeckoChild(PNeckoChild* necko)
michael@0 1103 {
michael@0 1104 delete necko;
michael@0 1105 return true;
michael@0 1106 }
michael@0 1107
michael@0 1108 PExternalHelperAppChild*
michael@0 1109 ContentChild::AllocPExternalHelperAppChild(const OptionalURIParams& uri,
michael@0 1110 const nsCString& aMimeContentType,
michael@0 1111 const nsCString& aContentDisposition,
michael@0 1112 const uint32_t& aContentDispositionHint,
michael@0 1113 const nsString& aContentDispositionFilename,
michael@0 1114 const bool& aForceSave,
michael@0 1115 const int64_t& aContentLength,
michael@0 1116 const OptionalURIParams& aReferrer,
michael@0 1117 PBrowserChild* aBrowser)
michael@0 1118 {
michael@0 1119 ExternalHelperAppChild *child = new ExternalHelperAppChild();
michael@0 1120 child->AddRef();
michael@0 1121 return child;
michael@0 1122 }
michael@0 1123
michael@0 1124 bool
michael@0 1125 ContentChild::DeallocPExternalHelperAppChild(PExternalHelperAppChild* aService)
michael@0 1126 {
michael@0 1127 ExternalHelperAppChild *child = static_cast<ExternalHelperAppChild*>(aService);
michael@0 1128 child->Release();
michael@0 1129 return true;
michael@0 1130 }
michael@0 1131
michael@0 1132 PSmsChild*
michael@0 1133 ContentChild::AllocPSmsChild()
michael@0 1134 {
michael@0 1135 return new SmsChild();
michael@0 1136 }
michael@0 1137
michael@0 1138 bool
michael@0 1139 ContentChild::DeallocPSmsChild(PSmsChild* aSms)
michael@0 1140 {
michael@0 1141 delete aSms;
michael@0 1142 return true;
michael@0 1143 }
michael@0 1144
michael@0 1145 PTelephonyChild*
michael@0 1146 ContentChild::AllocPTelephonyChild()
michael@0 1147 {
michael@0 1148 MOZ_CRASH("No one should be allocating PTelephonyChild actors");
michael@0 1149 }
michael@0 1150
michael@0 1151 bool
michael@0 1152 ContentChild::DeallocPTelephonyChild(PTelephonyChild* aActor)
michael@0 1153 {
michael@0 1154 delete aActor;
michael@0 1155 return true;
michael@0 1156 }
michael@0 1157
michael@0 1158 PStorageChild*
michael@0 1159 ContentChild::AllocPStorageChild()
michael@0 1160 {
michael@0 1161 NS_NOTREACHED("We should never be manually allocating PStorageChild actors");
michael@0 1162 return nullptr;
michael@0 1163 }
michael@0 1164
michael@0 1165 bool
michael@0 1166 ContentChild::DeallocPStorageChild(PStorageChild* aActor)
michael@0 1167 {
michael@0 1168 DOMStorageDBChild* child = static_cast<DOMStorageDBChild*>(aActor);
michael@0 1169 child->ReleaseIPDLReference();
michael@0 1170 return true;
michael@0 1171 }
michael@0 1172
michael@0 1173 PBluetoothChild*
michael@0 1174 ContentChild::AllocPBluetoothChild()
michael@0 1175 {
michael@0 1176 #ifdef MOZ_B2G_BT
michael@0 1177 MOZ_CRASH("No one should be allocating PBluetoothChild actors");
michael@0 1178 #else
michael@0 1179 MOZ_CRASH("No support for bluetooth on this platform!");
michael@0 1180 #endif
michael@0 1181 }
michael@0 1182
michael@0 1183 bool
michael@0 1184 ContentChild::DeallocPBluetoothChild(PBluetoothChild* aActor)
michael@0 1185 {
michael@0 1186 #ifdef MOZ_B2G_BT
michael@0 1187 delete aActor;
michael@0 1188 return true;
michael@0 1189 #else
michael@0 1190 MOZ_CRASH("No support for bluetooth on this platform!");
michael@0 1191 #endif
michael@0 1192 }
michael@0 1193
michael@0 1194 PFMRadioChild*
michael@0 1195 ContentChild::AllocPFMRadioChild()
michael@0 1196 {
michael@0 1197 #ifdef MOZ_B2G_FM
michael@0 1198 NS_RUNTIMEABORT("No one should be allocating PFMRadioChild actors");
michael@0 1199 return nullptr;
michael@0 1200 #else
michael@0 1201 NS_RUNTIMEABORT("No support for FMRadio on this platform!");
michael@0 1202 return nullptr;
michael@0 1203 #endif
michael@0 1204 }
michael@0 1205
michael@0 1206 bool
michael@0 1207 ContentChild::DeallocPFMRadioChild(PFMRadioChild* aActor)
michael@0 1208 {
michael@0 1209 #ifdef MOZ_B2G_FM
michael@0 1210 delete aActor;
michael@0 1211 return true;
michael@0 1212 #else
michael@0 1213 NS_RUNTIMEABORT("No support for FMRadio on this platform!");
michael@0 1214 return false;
michael@0 1215 #endif
michael@0 1216 }
michael@0 1217
michael@0 1218 PSpeechSynthesisChild*
michael@0 1219 ContentChild::AllocPSpeechSynthesisChild()
michael@0 1220 {
michael@0 1221 #ifdef MOZ_WEBSPEECH
michael@0 1222 MOZ_CRASH("No one should be allocating PSpeechSynthesisChild actors");
michael@0 1223 #else
michael@0 1224 return nullptr;
michael@0 1225 #endif
michael@0 1226 }
michael@0 1227
michael@0 1228 bool
michael@0 1229 ContentChild::DeallocPSpeechSynthesisChild(PSpeechSynthesisChild* aActor)
michael@0 1230 {
michael@0 1231 #ifdef MOZ_WEBSPEECH
michael@0 1232 delete aActor;
michael@0 1233 return true;
michael@0 1234 #else
michael@0 1235 return false;
michael@0 1236 #endif
michael@0 1237 }
michael@0 1238
michael@0 1239 bool
michael@0 1240 ContentChild::RecvRegisterChrome(const InfallibleTArray<ChromePackage>& packages,
michael@0 1241 const InfallibleTArray<ResourceMapping>& resources,
michael@0 1242 const InfallibleTArray<OverrideMapping>& overrides,
michael@0 1243 const nsCString& locale)
michael@0 1244 {
michael@0 1245 nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
michael@0 1246 nsChromeRegistryContent* chromeRegistry =
michael@0 1247 static_cast<nsChromeRegistryContent*>(registrySvc.get());
michael@0 1248 chromeRegistry->RegisterRemoteChrome(packages, resources, overrides, locale);
michael@0 1249 return true;
michael@0 1250 }
michael@0 1251
michael@0 1252 bool
michael@0 1253 ContentChild::RecvSetOffline(const bool& offline)
michael@0 1254 {
michael@0 1255 nsCOMPtr<nsIIOService> io (do_GetIOService());
michael@0 1256 NS_ASSERTION(io, "IO Service can not be null");
michael@0 1257
michael@0 1258 io->SetOffline(offline);
michael@0 1259
michael@0 1260 return true;
michael@0 1261 }
michael@0 1262
michael@0 1263 void
michael@0 1264 ContentChild::ActorDestroy(ActorDestroyReason why)
michael@0 1265 {
michael@0 1266 if (AbnormalShutdown == why) {
michael@0 1267 NS_WARNING("shutting down early because of crash!");
michael@0 1268 QuickExit();
michael@0 1269 }
michael@0 1270
michael@0 1271 #ifndef DEBUG
michael@0 1272 // In release builds, there's no point in the content process
michael@0 1273 // going through the full XPCOM shutdown path, because it doesn't
michael@0 1274 // keep persistent state.
michael@0 1275 QuickExit();
michael@0 1276 #endif
michael@0 1277
michael@0 1278 if (sFirstIdleTask) {
michael@0 1279 sFirstIdleTask->Cancel();
michael@0 1280 }
michael@0 1281
michael@0 1282 mAlertObservers.Clear();
michael@0 1283
michael@0 1284 mIdleObservers.Clear();
michael@0 1285
michael@0 1286 nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
michael@0 1287 if (svc) {
michael@0 1288 svc->UnregisterListener(mConsoleListener);
michael@0 1289 mConsoleListener->mChild = nullptr;
michael@0 1290 }
michael@0 1291
michael@0 1292 XRE_ShutdownChildProcess();
michael@0 1293 }
michael@0 1294
michael@0 1295 void
michael@0 1296 ContentChild::ProcessingError(Result what)
michael@0 1297 {
michael@0 1298 switch (what) {
michael@0 1299 case MsgDropped:
michael@0 1300 QuickExit();
michael@0 1301
michael@0 1302 case MsgNotKnown:
michael@0 1303 NS_RUNTIMEABORT("aborting because of MsgNotKnown");
michael@0 1304 case MsgNotAllowed:
michael@0 1305 NS_RUNTIMEABORT("aborting because of MsgNotAllowed");
michael@0 1306 case MsgPayloadError:
michael@0 1307 NS_RUNTIMEABORT("aborting because of MsgPayloadError");
michael@0 1308 case MsgProcessingError:
michael@0 1309 NS_RUNTIMEABORT("aborting because of MsgProcessingError");
michael@0 1310 case MsgRouteError:
michael@0 1311 NS_RUNTIMEABORT("aborting because of MsgRouteError");
michael@0 1312 case MsgValueError:
michael@0 1313 NS_RUNTIMEABORT("aborting because of MsgValueError");
michael@0 1314
michael@0 1315 default:
michael@0 1316 NS_RUNTIMEABORT("not reached");
michael@0 1317 }
michael@0 1318 }
michael@0 1319
michael@0 1320 void
michael@0 1321 ContentChild::QuickExit()
michael@0 1322 {
michael@0 1323 NS_WARNING("content process _exit()ing");
michael@0 1324 _exit(0);
michael@0 1325 }
michael@0 1326
michael@0 1327 nsresult
michael@0 1328 ContentChild::AddRemoteAlertObserver(const nsString& aData,
michael@0 1329 nsIObserver* aObserver)
michael@0 1330 {
michael@0 1331 NS_ASSERTION(aObserver, "Adding a null observer?");
michael@0 1332 mAlertObservers.AppendElement(new AlertObserver(aObserver, aData));
michael@0 1333 return NS_OK;
michael@0 1334 }
michael@0 1335
michael@0 1336 bool
michael@0 1337 ContentChild::RecvPreferenceUpdate(const PrefSetting& aPref)
michael@0 1338 {
michael@0 1339 Preferences::SetPreference(aPref);
michael@0 1340 return true;
michael@0 1341 }
michael@0 1342
michael@0 1343 bool
michael@0 1344 ContentChild::RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData)
michael@0 1345 {
michael@0 1346 for (uint32_t i = 0; i < mAlertObservers.Length();
michael@0 1347 /*we mutate the array during the loop; ++i iff no mutation*/) {
michael@0 1348 AlertObserver* observer = mAlertObservers[i];
michael@0 1349 if (observer->Observes(aData) && observer->Notify(aType)) {
michael@0 1350 // if aType == alertfinished, this alert is done. we can
michael@0 1351 // remove the observer.
michael@0 1352 if (aType.Equals(nsDependentCString("alertfinished"))) {
michael@0 1353 mAlertObservers.RemoveElementAt(i);
michael@0 1354 continue;
michael@0 1355 }
michael@0 1356 }
michael@0 1357 ++i;
michael@0 1358 }
michael@0 1359 return true;
michael@0 1360 }
michael@0 1361
michael@0 1362 bool
michael@0 1363 ContentChild::RecvNotifyVisited(const URIParams& aURI)
michael@0 1364 {
michael@0 1365 nsCOMPtr<nsIURI> newURI = DeserializeURI(aURI);
michael@0 1366 if (!newURI) {
michael@0 1367 return false;
michael@0 1368 }
michael@0 1369 nsCOMPtr<IHistory> history = services::GetHistoryService();
michael@0 1370 if (history) {
michael@0 1371 history->NotifyVisited(newURI);
michael@0 1372 }
michael@0 1373 return true;
michael@0 1374 }
michael@0 1375
michael@0 1376 bool
michael@0 1377 ContentChild::RecvAsyncMessage(const nsString& aMsg,
michael@0 1378 const ClonedMessageData& aData,
michael@0 1379 const InfallibleTArray<CpowEntry>& aCpows,
michael@0 1380 const IPC::Principal& aPrincipal)
michael@0 1381 {
michael@0 1382 nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
michael@0 1383 if (cpm) {
michael@0 1384 StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData);
michael@0 1385 CpowIdHolder cpows(GetCPOWManager(), aCpows);
michael@0 1386 cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
michael@0 1387 aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
michael@0 1388 }
michael@0 1389 return true;
michael@0 1390 }
michael@0 1391
michael@0 1392 bool
michael@0 1393 ContentChild::RecvGeolocationUpdate(const GeoPosition& somewhere)
michael@0 1394 {
michael@0 1395 nsCOMPtr<nsIGeolocationUpdate> gs = do_GetService("@mozilla.org/geolocation/service;1");
michael@0 1396 if (!gs) {
michael@0 1397 return true;
michael@0 1398 }
michael@0 1399 nsCOMPtr<nsIDOMGeoPosition> position = somewhere;
michael@0 1400 gs->Update(position);
michael@0 1401 return true;
michael@0 1402 }
michael@0 1403
michael@0 1404 bool
michael@0 1405 ContentChild::RecvAddPermission(const IPC::Permission& permission)
michael@0 1406 {
michael@0 1407 #if MOZ_PERMISSIONS
michael@0 1408 nsCOMPtr<nsIPermissionManager> permissionManagerIface =
michael@0 1409 do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
michael@0 1410 nsPermissionManager* permissionManager =
michael@0 1411 static_cast<nsPermissionManager*>(permissionManagerIface.get());
michael@0 1412 NS_ABORT_IF_FALSE(permissionManager,
michael@0 1413 "We have no permissionManager in the Content process !");
michael@0 1414
michael@0 1415 nsCOMPtr<nsIURI> uri;
michael@0 1416 NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + nsCString(permission.host));
michael@0 1417 NS_ENSURE_TRUE(uri, true);
michael@0 1418
michael@0 1419 nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
michael@0 1420 MOZ_ASSERT(secMan);
michael@0 1421
michael@0 1422 nsCOMPtr<nsIPrincipal> principal;
michael@0 1423 nsresult rv = secMan->GetAppCodebasePrincipal(uri, permission.appId,
michael@0 1424 permission.isInBrowserElement,
michael@0 1425 getter_AddRefs(principal));
michael@0 1426 NS_ENSURE_SUCCESS(rv, true);
michael@0 1427
michael@0 1428 permissionManager->AddInternal(principal,
michael@0 1429 nsCString(permission.type),
michael@0 1430 permission.capability,
michael@0 1431 0,
michael@0 1432 permission.expireType,
michael@0 1433 permission.expireTime,
michael@0 1434 nsPermissionManager::eNotify,
michael@0 1435 nsPermissionManager::eNoDBOperation);
michael@0 1436 #endif
michael@0 1437
michael@0 1438 return true;
michael@0 1439 }
michael@0 1440
michael@0 1441 bool
michael@0 1442 ContentChild::RecvScreenSizeChanged(const gfxIntSize& size)
michael@0 1443 {
michael@0 1444 #ifdef ANDROID
michael@0 1445 mScreenSize = size;
michael@0 1446 #else
michael@0 1447 NS_RUNTIMEABORT("Message currently only expected on android");
michael@0 1448 #endif
michael@0 1449 return true;
michael@0 1450 }
michael@0 1451
michael@0 1452 bool
michael@0 1453 ContentChild::RecvFlushMemory(const nsString& reason)
michael@0 1454 {
michael@0 1455 #ifdef MOZ_NUWA_PROCESS
michael@0 1456 if (IsNuwaProcess()) {
michael@0 1457 // Don't flush memory in the nuwa process: the GC thread could be frozen.
michael@0 1458 return true;
michael@0 1459 }
michael@0 1460 #endif
michael@0 1461 nsCOMPtr<nsIObserverService> os =
michael@0 1462 mozilla::services::GetObserverService();
michael@0 1463 if (os)
michael@0 1464 os->NotifyObservers(nullptr, "memory-pressure", reason.get());
michael@0 1465 return true;
michael@0 1466 }
michael@0 1467
michael@0 1468 bool
michael@0 1469 ContentChild::RecvActivateA11y()
michael@0 1470 {
michael@0 1471 #ifdef ACCESSIBILITY
michael@0 1472 // Start accessibility in content process if it's running in chrome
michael@0 1473 // process.
michael@0 1474 nsCOMPtr<nsIAccessibilityService> accService =
michael@0 1475 do_GetService("@mozilla.org/accessibilityService;1");
michael@0 1476 #endif
michael@0 1477 return true;
michael@0 1478 }
michael@0 1479
michael@0 1480 bool
michael@0 1481 ContentChild::RecvGarbageCollect()
michael@0 1482 {
michael@0 1483 // Rebroadcast the "child-gc-request" so that workers will GC.
michael@0 1484 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
michael@0 1485 if (obs) {
michael@0 1486 obs->NotifyObservers(nullptr, "child-gc-request", nullptr);
michael@0 1487 }
michael@0 1488 nsJSContext::GarbageCollectNow(JS::gcreason::DOM_IPC);
michael@0 1489 return true;
michael@0 1490 }
michael@0 1491
michael@0 1492 bool
michael@0 1493 ContentChild::RecvCycleCollect()
michael@0 1494 {
michael@0 1495 // Rebroadcast the "child-cc-request" so that workers will CC.
michael@0 1496 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
michael@0 1497 if (obs) {
michael@0 1498 obs->NotifyObservers(nullptr, "child-cc-request", nullptr);
michael@0 1499 }
michael@0 1500 nsJSContext::CycleCollectNow();
michael@0 1501 return true;
michael@0 1502 }
michael@0 1503
michael@0 1504 #ifdef MOZ_NUWA_PROCESS
michael@0 1505 static void
michael@0 1506 OnFinishNuwaPreparation ()
michael@0 1507 {
michael@0 1508 MakeNuwaProcess();
michael@0 1509 }
michael@0 1510 #endif
michael@0 1511
michael@0 1512 static void
michael@0 1513 PreloadSlowThings()
michael@0 1514 {
michael@0 1515 // This fetches and creates all the built-in stylesheets.
michael@0 1516 nsLayoutStylesheetCache::UserContentSheet();
michael@0 1517
michael@0 1518 TabChild::PreloadSlowThings();
michael@0 1519
michael@0 1520 }
michael@0 1521
michael@0 1522 bool
michael@0 1523 ContentChild::RecvAppInfo(const nsCString& version, const nsCString& buildID,
michael@0 1524 const nsCString& name, const nsCString& UAName)
michael@0 1525 {
michael@0 1526 mAppInfo.version.Assign(version);
michael@0 1527 mAppInfo.buildID.Assign(buildID);
michael@0 1528 mAppInfo.name.Assign(name);
michael@0 1529 mAppInfo.UAName.Assign(UAName);
michael@0 1530
michael@0 1531 if (!Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false)) {
michael@0 1532 return true;
michael@0 1533 }
michael@0 1534
michael@0 1535 // If we're part of the mozbrowser machinery, go ahead and start
michael@0 1536 // preloading things. We can only do this for mozbrowser because
michael@0 1537 // PreloadSlowThings() may set the docshell of the first TabChild
michael@0 1538 // inactive, and we can only safely restore it to active from
michael@0 1539 // BrowserElementChild.js.
michael@0 1540 if ((mIsForApp || mIsForBrowser)
michael@0 1541 #ifdef MOZ_NUWA_PROCESS
michael@0 1542 && !IsNuwaProcess()
michael@0 1543 #endif
michael@0 1544 ) {
michael@0 1545 PreloadSlowThings();
michael@0 1546 }
michael@0 1547
michael@0 1548 #ifdef MOZ_NUWA_PROCESS
michael@0 1549 if (IsNuwaProcess()) {
michael@0 1550 ContentChild::GetSingleton()->RecvGarbageCollect();
michael@0 1551 MessageLoop::current()->PostTask(
michael@0 1552 FROM_HERE, NewRunnableFunction(OnFinishNuwaPreparation));
michael@0 1553 }
michael@0 1554 #endif
michael@0 1555
michael@0 1556 return true;
michael@0 1557 }
michael@0 1558
michael@0 1559 bool
michael@0 1560 ContentChild::RecvLastPrivateDocShellDestroyed()
michael@0 1561 {
michael@0 1562 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
michael@0 1563 obs->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
michael@0 1564 return true;
michael@0 1565 }
michael@0 1566
michael@0 1567 bool
michael@0 1568 ContentChild::RecvFilePathUpdate(const nsString& aStorageType,
michael@0 1569 const nsString& aStorageName,
michael@0 1570 const nsString& aPath,
michael@0 1571 const nsCString& aReason)
michael@0 1572 {
michael@0 1573 nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(aStorageType, aStorageName, aPath);
michael@0 1574
michael@0 1575 nsString reason;
michael@0 1576 CopyASCIItoUTF16(aReason, reason);
michael@0 1577 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
michael@0 1578 obs->NotifyObservers(dsf, "file-watcher-update", reason.get());
michael@0 1579 return true;
michael@0 1580 }
michael@0 1581
michael@0 1582 bool
michael@0 1583 ContentChild::RecvFileSystemUpdate(const nsString& aFsName,
michael@0 1584 const nsString& aVolumeName,
michael@0 1585 const int32_t& aState,
michael@0 1586 const int32_t& aMountGeneration,
michael@0 1587 const bool& aIsMediaPresent,
michael@0 1588 const bool& aIsSharing,
michael@0 1589 const bool& aIsFormatting)
michael@0 1590 {
michael@0 1591 #ifdef MOZ_WIDGET_GONK
michael@0 1592 nsRefPtr<nsVolume> volume = new nsVolume(aFsName, aVolumeName, aState,
michael@0 1593 aMountGeneration, aIsMediaPresent,
michael@0 1594 aIsSharing, aIsFormatting);
michael@0 1595
michael@0 1596 nsRefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
michael@0 1597 if (vs) {
michael@0 1598 vs->UpdateVolume(volume);
michael@0 1599 }
michael@0 1600 #else
michael@0 1601 // Remove warnings about unused arguments
michael@0 1602 unused << aFsName;
michael@0 1603 unused << aVolumeName;
michael@0 1604 unused << aState;
michael@0 1605 unused << aMountGeneration;
michael@0 1606 unused << aIsMediaPresent;
michael@0 1607 unused << aIsSharing;
michael@0 1608 unused << aIsFormatting;
michael@0 1609 #endif
michael@0 1610 return true;
michael@0 1611 }
michael@0 1612
michael@0 1613 bool
michael@0 1614 ContentChild::RecvNotifyProcessPriorityChanged(
michael@0 1615 const hal::ProcessPriority& aPriority)
michael@0 1616 {
michael@0 1617 nsCOMPtr<nsIObserverService> os = services::GetObserverService();
michael@0 1618 NS_ENSURE_TRUE(os, true);
michael@0 1619
michael@0 1620 nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
michael@0 1621 props->SetPropertyAsInt32(NS_LITERAL_STRING("priority"),
michael@0 1622 static_cast<int32_t>(aPriority));
michael@0 1623
michael@0 1624 os->NotifyObservers(static_cast<nsIPropertyBag2*>(props),
michael@0 1625 "ipc:process-priority-changed", nullptr);
michael@0 1626 return true;
michael@0 1627 }
michael@0 1628
michael@0 1629 bool
michael@0 1630 ContentChild::RecvMinimizeMemoryUsage()
michael@0 1631 {
michael@0 1632 #ifdef MOZ_NUWA_PROCESS
michael@0 1633 if (IsNuwaProcess()) {
michael@0 1634 // Don't minimize memory in the nuwa process: it will perform GC, but the
michael@0 1635 // GC thread could be frozen.
michael@0 1636 return true;
michael@0 1637 }
michael@0 1638 #endif
michael@0 1639 nsCOMPtr<nsIMemoryReporterManager> mgr =
michael@0 1640 do_GetService("@mozilla.org/memory-reporter-manager;1");
michael@0 1641 NS_ENSURE_TRUE(mgr, true);
michael@0 1642
michael@0 1643 mgr->MinimizeMemoryUsage(/* callback = */ nullptr);
michael@0 1644 return true;
michael@0 1645 }
michael@0 1646
michael@0 1647 bool
michael@0 1648 ContentChild::RecvNotifyPhoneStateChange(const nsString& aState)
michael@0 1649 {
michael@0 1650 nsCOMPtr<nsIObserverService> os = services::GetObserverService();
michael@0 1651 if (os) {
michael@0 1652 os->NotifyObservers(nullptr, "phone-state-changed", aState.get());
michael@0 1653 }
michael@0 1654 return true;
michael@0 1655 }
michael@0 1656
michael@0 1657 void
michael@0 1658 ContentChild::AddIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS)
michael@0 1659 {
michael@0 1660 MOZ_ASSERT(aObserver, "null idle observer");
michael@0 1661 // Make sure aObserver isn't released while we wait for the parent
michael@0 1662 aObserver->AddRef();
michael@0 1663 SendAddIdleObserver(reinterpret_cast<uint64_t>(aObserver), aIdleTimeInS);
michael@0 1664 mIdleObservers.PutEntry(aObserver);
michael@0 1665 }
michael@0 1666
michael@0 1667 void
michael@0 1668 ContentChild::RemoveIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS)
michael@0 1669 {
michael@0 1670 MOZ_ASSERT(aObserver, "null idle observer");
michael@0 1671 SendRemoveIdleObserver(reinterpret_cast<uint64_t>(aObserver), aIdleTimeInS);
michael@0 1672 aObserver->Release();
michael@0 1673 mIdleObservers.RemoveEntry(aObserver);
michael@0 1674 }
michael@0 1675
michael@0 1676 bool
michael@0 1677 ContentChild::RecvNotifyIdleObserver(const uint64_t& aObserver,
michael@0 1678 const nsCString& aTopic,
michael@0 1679 const nsString& aTimeStr)
michael@0 1680 {
michael@0 1681 nsIObserver* observer = reinterpret_cast<nsIObserver*>(aObserver);
michael@0 1682 if (mIdleObservers.Contains(observer)) {
michael@0 1683 observer->Observe(nullptr, aTopic.get(), aTimeStr.get());
michael@0 1684 } else {
michael@0 1685 NS_WARNING("Received notification for an idle observer that was removed.");
michael@0 1686 }
michael@0 1687 return true;
michael@0 1688 }
michael@0 1689
michael@0 1690 bool
michael@0 1691 ContentChild::RecvLoadAndRegisterSheet(const URIParams& aURI, const uint32_t& aType)
michael@0 1692 {
michael@0 1693 nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
michael@0 1694 if (!uri) {
michael@0 1695 return true;
michael@0 1696 }
michael@0 1697
michael@0 1698 nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
michael@0 1699 if (sheetService) {
michael@0 1700 sheetService->LoadAndRegisterSheet(uri, aType);
michael@0 1701 }
michael@0 1702
michael@0 1703 return true;
michael@0 1704 }
michael@0 1705
michael@0 1706 bool
michael@0 1707 ContentChild::RecvUnregisterSheet(const URIParams& aURI, const uint32_t& aType)
michael@0 1708 {
michael@0 1709 nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
michael@0 1710 if (!uri) {
michael@0 1711 return true;
michael@0 1712 }
michael@0 1713
michael@0 1714 nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
michael@0 1715 if (sheetService) {
michael@0 1716 sheetService->UnregisterSheet(uri, aType);
michael@0 1717 }
michael@0 1718
michael@0 1719 return true;
michael@0 1720 }
michael@0 1721
michael@0 1722 #ifdef MOZ_NUWA_PROCESS
michael@0 1723 class CallNuwaSpawn : public nsRunnable
michael@0 1724 {
michael@0 1725 public:
michael@0 1726 NS_IMETHOD Run()
michael@0 1727 {
michael@0 1728 NuwaSpawn();
michael@0 1729 if (IsNuwaProcess()) {
michael@0 1730 return NS_OK;
michael@0 1731 }
michael@0 1732
michael@0 1733 // In the new process.
michael@0 1734 ContentChild* child = ContentChild::GetSingleton();
michael@0 1735 child->SetProcessName(NS_LITERAL_STRING("(Preallocated app)"), false);
michael@0 1736 mozilla::ipc::Transport* transport = child->GetTransport();
michael@0 1737 int fd = transport->GetFileDescriptor();
michael@0 1738 transport->ResetFileDescriptor(fd);
michael@0 1739
michael@0 1740 IToplevelProtocol* toplevel = child->GetFirstOpenedActors();
michael@0 1741 while (toplevel != nullptr) {
michael@0 1742 transport = toplevel->GetTransport();
michael@0 1743 fd = transport->GetFileDescriptor();
michael@0 1744 transport->ResetFileDescriptor(fd);
michael@0 1745
michael@0 1746 toplevel = toplevel->getNext();
michael@0 1747 }
michael@0 1748
michael@0 1749 // Perform other after-fork initializations.
michael@0 1750 InitOnContentProcessCreated();
michael@0 1751
michael@0 1752 return NS_OK;
michael@0 1753 }
michael@0 1754 };
michael@0 1755
michael@0 1756 static void
michael@0 1757 DoNuwaFork()
michael@0 1758 {
michael@0 1759 NS_ASSERTION(NuwaSpawnPrepare != nullptr,
michael@0 1760 "NuwaSpawnPrepare() is not available!");
michael@0 1761 NuwaSpawnPrepare(); // NuwaSpawn will be blocked.
michael@0 1762
michael@0 1763 {
michael@0 1764 nsCOMPtr<nsIRunnable> callSpawn(new CallNuwaSpawn());
michael@0 1765 NS_DispatchToMainThread(callSpawn);
michael@0 1766 }
michael@0 1767
michael@0 1768 // IOThread should be blocked here for waiting NuwaSpawn().
michael@0 1769 NS_ASSERTION(NuwaSpawnWait != nullptr,
michael@0 1770 "NuwaSpawnWait() is not available!");
michael@0 1771 NuwaSpawnWait(); // Now! NuwaSpawn can go.
michael@0 1772 // Here, we can make sure the spawning was finished.
michael@0 1773 }
michael@0 1774
michael@0 1775 /**
michael@0 1776 * This function should keep IO thread in a stable state and freeze it
michael@0 1777 * until the spawning is finished.
michael@0 1778 */
michael@0 1779 static void
michael@0 1780 RunNuwaFork()
michael@0 1781 {
michael@0 1782 if (NuwaCheckpointCurrentThread()) {
michael@0 1783 DoNuwaFork();
michael@0 1784 }
michael@0 1785 }
michael@0 1786 #endif
michael@0 1787
michael@0 1788 bool
michael@0 1789 ContentChild::RecvNuwaFork()
michael@0 1790 {
michael@0 1791 #ifdef MOZ_NUWA_PROCESS
michael@0 1792 if (sNuwaForking) { // No reentry.
michael@0 1793 return true;
michael@0 1794 }
michael@0 1795 sNuwaForking = true;
michael@0 1796
michael@0 1797 // We want to ensure that the PBackground actor gets cloned in the Nuwa
michael@0 1798 // process before we freeze. Also, we have to do this to avoid deadlock.
michael@0 1799 // Protocols that are "opened" (e.g. PBackground, PCompositor) block the
michael@0 1800 // main thread to wait for the IPC thread during the open operation.
michael@0 1801 // NuwaSpawnWait() blocks the IPC thread to wait for the main thread when
michael@0 1802 // the Nuwa process is forked. Unless we ensure that the two cannot happen
michael@0 1803 // at the same time then we risk deadlock. Spinning the event loop here
michael@0 1804 // guarantees the ordering is safe for PBackground.
michael@0 1805 while (!BackgroundChild::GetForCurrentThread()) {
michael@0 1806 if (NS_WARN_IF(!NS_ProcessNextEvent())) {
michael@0 1807 return false;
michael@0 1808 }
michael@0 1809 }
michael@0 1810
michael@0 1811 MessageLoop* ioloop = XRE_GetIOMessageLoop();
michael@0 1812 ioloop->PostTask(FROM_HERE, NewRunnableFunction(RunNuwaFork));
michael@0 1813 return true;
michael@0 1814 #else
michael@0 1815 return false; // Makes the underlying IPC channel abort.
michael@0 1816 #endif
michael@0 1817 }
michael@0 1818
michael@0 1819 } // namespace dom
michael@0 1820 } // namespace mozilla
michael@0 1821
michael@0 1822 extern "C" {
michael@0 1823
michael@0 1824 #if defined(MOZ_NUWA_PROCESS)
michael@0 1825 NS_EXPORT void
michael@0 1826 GetProtoFdInfos(NuwaProtoFdInfo* aInfoList,
michael@0 1827 size_t aInfoListSize,
michael@0 1828 size_t* aInfoSize)
michael@0 1829 {
michael@0 1830 size_t i = 0;
michael@0 1831
michael@0 1832 mozilla::dom::ContentChild* content =
michael@0 1833 mozilla::dom::ContentChild::GetSingleton();
michael@0 1834 aInfoList[i].protoId = content->GetProtocolId();
michael@0 1835 aInfoList[i].originFd =
michael@0 1836 content->GetTransport()->GetFileDescriptor();
michael@0 1837 i++;
michael@0 1838
michael@0 1839 for (IToplevelProtocol* actor = content->GetFirstOpenedActors();
michael@0 1840 actor != nullptr;
michael@0 1841 actor = actor->getNext()) {
michael@0 1842 if (i >= aInfoListSize) {
michael@0 1843 NS_RUNTIMEABORT("Too many top level protocols!");
michael@0 1844 }
michael@0 1845
michael@0 1846 aInfoList[i].protoId = actor->GetProtocolId();
michael@0 1847 aInfoList[i].originFd =
michael@0 1848 actor->GetTransport()->GetFileDescriptor();
michael@0 1849 i++;
michael@0 1850 }
michael@0 1851
michael@0 1852 if (i > NUWA_TOPLEVEL_MAX) {
michael@0 1853 NS_RUNTIMEABORT("Too many top level protocols!");
michael@0 1854 }
michael@0 1855 *aInfoSize = i;
michael@0 1856 }
michael@0 1857
michael@0 1858 class RunAddNewIPCProcess : public nsRunnable
michael@0 1859 {
michael@0 1860 public:
michael@0 1861 RunAddNewIPCProcess(pid_t aPid,
michael@0 1862 nsTArray<mozilla::ipc::ProtocolFdMapping>& aMaps)
michael@0 1863 : mPid(aPid)
michael@0 1864 {
michael@0 1865 mMaps.SwapElements(aMaps);
michael@0 1866 }
michael@0 1867
michael@0 1868 NS_IMETHOD Run()
michael@0 1869 {
michael@0 1870 mozilla::dom::ContentChild::GetSingleton()->
michael@0 1871 SendAddNewProcess(mPid, mMaps);
michael@0 1872
michael@0 1873 MOZ_ASSERT(sNuwaForking);
michael@0 1874 sNuwaForking = false;
michael@0 1875
michael@0 1876 return NS_OK;
michael@0 1877 }
michael@0 1878
michael@0 1879 private:
michael@0 1880 pid_t mPid;
michael@0 1881 nsTArray<mozilla::ipc::ProtocolFdMapping> mMaps;
michael@0 1882 };
michael@0 1883
michael@0 1884 /**
michael@0 1885 * AddNewIPCProcess() is called by Nuwa process to tell the parent
michael@0 1886 * process that a new process is created.
michael@0 1887 *
michael@0 1888 * In the newly created process, ResetContentChildTransport() is called to
michael@0 1889 * reset fd for the IPC Channel and the session.
michael@0 1890 */
michael@0 1891 NS_EXPORT void
michael@0 1892 AddNewIPCProcess(pid_t aPid, NuwaProtoFdInfo* aInfoList, size_t aInfoListSize)
michael@0 1893 {
michael@0 1894 nsTArray<mozilla::ipc::ProtocolFdMapping> maps;
michael@0 1895
michael@0 1896 for (size_t i = 0; i < aInfoListSize; i++) {
michael@0 1897 int _fd = aInfoList[i].newFds[NUWA_NEWFD_PARENT];
michael@0 1898 mozilla::ipc::FileDescriptor fd(_fd);
michael@0 1899 mozilla::ipc::ProtocolFdMapping map(aInfoList[i].protoId, fd);
michael@0 1900 maps.AppendElement(map);
michael@0 1901 }
michael@0 1902
michael@0 1903 nsRefPtr<RunAddNewIPCProcess> runner = new RunAddNewIPCProcess(aPid, maps);
michael@0 1904 NS_DispatchToMainThread(runner);
michael@0 1905 }
michael@0 1906
michael@0 1907 NS_EXPORT void
michael@0 1908 OnNuwaProcessReady()
michael@0 1909 {
michael@0 1910 mozilla::dom::ContentChild* content =
michael@0 1911 mozilla::dom::ContentChild::GetSingleton();
michael@0 1912 content->SendNuwaReady();
michael@0 1913 }
michael@0 1914
michael@0 1915 NS_EXPORT void
michael@0 1916 AfterNuwaFork()
michael@0 1917 {
michael@0 1918 SetCurrentProcessPrivileges(base::PRIVILEGES_DEFAULT);
michael@0 1919 }
michael@0 1920
michael@0 1921 #endif // MOZ_NUWA_PROCESS
michael@0 1922
michael@0 1923 }

mercurial