dom/ipc/ContentParent.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 #include "mozilla/DebugOnly.h"
michael@0 8
michael@0 9 #include "base/basictypes.h"
michael@0 10
michael@0 11 #include "ContentParent.h"
michael@0 12
michael@0 13 #if defined(ANDROID) || defined(LINUX)
michael@0 14 # include <sys/time.h>
michael@0 15 # include <sys/resource.h>
michael@0 16 #endif
michael@0 17
michael@0 18 #ifdef MOZ_WIDGET_GONK
michael@0 19 #include <sys/types.h>
michael@0 20 #include <sys/wait.h>
michael@0 21 #endif
michael@0 22
michael@0 23 #include "chrome/common/process_watcher.h"
michael@0 24
michael@0 25 #include "AppProcessChecker.h"
michael@0 26 #include "AudioChannelService.h"
michael@0 27 #include "CrashReporterParent.h"
michael@0 28 #include "IHistory.h"
michael@0 29 #include "IDBFactory.h"
michael@0 30 #include "IndexedDBParent.h"
michael@0 31 #include "IndexedDatabaseManager.h"
michael@0 32 #include "mozIApplication.h"
michael@0 33 #include "mozilla/ClearOnShutdown.h"
michael@0 34 #include "mozilla/dom/asmjscache/AsmJSCache.h"
michael@0 35 #include "mozilla/dom/Element.h"
michael@0 36 #include "mozilla/dom/ExternalHelperAppParent.h"
michael@0 37 #include "mozilla/dom/PFileDescriptorSetParent.h"
michael@0 38 #include "mozilla/dom/PMemoryReportRequestParent.h"
michael@0 39 #include "mozilla/dom/power/PowerManagerService.h"
michael@0 40 #include "mozilla/dom/DOMStorageIPC.h"
michael@0 41 #include "mozilla/dom/bluetooth/PBluetoothParent.h"
michael@0 42 #include "mozilla/dom/PFMRadioParent.h"
michael@0 43 #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
michael@0 44 #include "mozilla/dom/FileSystemRequestParent.h"
michael@0 45 #include "mozilla/dom/GeolocationBinding.h"
michael@0 46 #include "mozilla/dom/FileDescriptorSetParent.h"
michael@0 47 #include "mozilla/dom/telephony/TelephonyParent.h"
michael@0 48 #include "mozilla/dom/time/DateCacheCleaner.h"
michael@0 49 #include "SmsParent.h"
michael@0 50 #include "mozilla/hal_sandbox/PHalParent.h"
michael@0 51 #include "mozilla/ipc/BackgroundChild.h"
michael@0 52 #include "mozilla/ipc/BackgroundParent.h"
michael@0 53 #include "mozilla/ipc/TestShellParent.h"
michael@0 54 #include "mozilla/ipc/InputStreamUtils.h"
michael@0 55 #include "mozilla/layers/CompositorParent.h"
michael@0 56 #include "mozilla/layers/ImageBridgeParent.h"
michael@0 57 #include "mozilla/net/NeckoParent.h"
michael@0 58 #include "mozilla/Preferences.h"
michael@0 59 #include "mozilla/Services.h"
michael@0 60 #include "mozilla/StaticPtr.h"
michael@0 61 #include "mozilla/unused.h"
michael@0 62 #include "nsAppRunner.h"
michael@0 63 #include "nsAutoPtr.h"
michael@0 64 #include "nsCDefaultURIFixup.h"
michael@0 65 #include "nsCExternalHandlerService.h"
michael@0 66 #include "nsCOMPtr.h"
michael@0 67 #include "nsChromeRegistryChrome.h"
michael@0 68 #include "nsConsoleMessage.h"
michael@0 69 #include "nsConsoleService.h"
michael@0 70 #include "nsDebugImpl.h"
michael@0 71 #include "nsDOMFile.h"
michael@0 72 #include "nsFrameMessageManager.h"
michael@0 73 #include "nsHashPropertyBag.h"
michael@0 74 #include "nsIAlertsService.h"
michael@0 75 #include "nsIAppsService.h"
michael@0 76 #include "nsIClipboard.h"
michael@0 77 #include "nsIDOMGeoGeolocation.h"
michael@0 78 #include "mozilla/dom/WakeLock.h"
michael@0 79 #include "nsIDOMWindow.h"
michael@0 80 #include "nsIExternalProtocolService.h"
michael@0 81 #include "nsIGfxInfo.h"
michael@0 82 #include "nsIIdleService.h"
michael@0 83 #include "nsIMemoryReporter.h"
michael@0 84 #include "nsIMozBrowserFrame.h"
michael@0 85 #include "nsIMutable.h"
michael@0 86 #include "nsIObserverService.h"
michael@0 87 #include "nsIPresShell.h"
michael@0 88 #include "nsIRemoteBlob.h"
michael@0 89 #include "nsIScriptError.h"
michael@0 90 #include "nsIStyleSheet.h"
michael@0 91 #include "nsISupportsPrimitives.h"
michael@0 92 #include "nsIURIFixup.h"
michael@0 93 #include "nsIWindowWatcher.h"
michael@0 94 #include "nsIXULRuntime.h"
michael@0 95 #include "nsMemoryReporterManager.h"
michael@0 96 #include "nsServiceManagerUtils.h"
michael@0 97 #include "nsStyleSheetService.h"
michael@0 98 #include "nsThreadUtils.h"
michael@0 99 #include "nsToolkitCompsCID.h"
michael@0 100 #include "nsWidgetsCID.h"
michael@0 101 #include "PreallocatedProcessManager.h"
michael@0 102 #include "ProcessPriorityManager.h"
michael@0 103 #include "SandboxHal.h"
michael@0 104 #include "StructuredCloneUtils.h"
michael@0 105 #include "TabParent.h"
michael@0 106 #include "URIUtils.h"
michael@0 107 #include "nsIWebBrowserChrome.h"
michael@0 108 #include "nsIDocShell.h"
michael@0 109 #include "mozilla/net/NeckoMessageUtils.h"
michael@0 110 #include "gfxPrefs.h"
michael@0 111
michael@0 112 #if defined(ANDROID) || defined(LINUX)
michael@0 113 #include "nsSystemInfo.h"
michael@0 114 #endif
michael@0 115
michael@0 116 #ifdef ANDROID
michael@0 117 # include "gfxAndroidPlatform.h"
michael@0 118 #endif
michael@0 119
michael@0 120 #ifdef MOZ_PERMISSIONS
michael@0 121 # include "nsPermissionManager.h"
michael@0 122 #endif
michael@0 123
michael@0 124 #ifdef MOZ_WIDGET_ANDROID
michael@0 125 # include "AndroidBridge.h"
michael@0 126 #endif
michael@0 127
michael@0 128 #ifdef MOZ_WIDGET_GONK
michael@0 129 #include "nsIVolume.h"
michael@0 130 #include "nsIVolumeService.h"
michael@0 131 #include "SpeakerManagerService.h"
michael@0 132 using namespace mozilla::system;
michael@0 133 #endif
michael@0 134
michael@0 135 #ifdef MOZ_B2G_BT
michael@0 136 #include "BluetoothParent.h"
michael@0 137 #include "BluetoothService.h"
michael@0 138 #endif
michael@0 139
michael@0 140 #include "JavaScriptParent.h"
michael@0 141
michael@0 142 #ifdef MOZ_B2G_FM
michael@0 143 #include "mozilla/dom/FMRadioParent.h"
michael@0 144 #endif
michael@0 145
michael@0 146 #include "Crypto.h"
michael@0 147
michael@0 148 #ifdef MOZ_WEBSPEECH
michael@0 149 #include "mozilla/dom/SpeechSynthesisParent.h"
michael@0 150 #endif
michael@0 151
michael@0 152 #ifdef ENABLE_TESTS
michael@0 153 #include "BackgroundChildImpl.h"
michael@0 154 #include "mozilla/ipc/PBackgroundChild.h"
michael@0 155 #include "nsIIPCBackgroundChildCreateCallback.h"
michael@0 156 #endif
michael@0 157
michael@0 158 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
michael@0 159 static const char* sClipboardTextFlavors[] = { kUnicodeMime };
michael@0 160
michael@0 161 using base::ChildPrivileges;
michael@0 162 using base::KillProcess;
michael@0 163 using namespace mozilla::dom::bluetooth;
michael@0 164 using namespace mozilla::dom::devicestorage;
michael@0 165 using namespace mozilla::dom::indexedDB;
michael@0 166 using namespace mozilla::dom::power;
michael@0 167 using namespace mozilla::dom::mobilemessage;
michael@0 168 using namespace mozilla::dom::telephony;
michael@0 169 using namespace mozilla::hal;
michael@0 170 using namespace mozilla::ipc;
michael@0 171 using namespace mozilla::layers;
michael@0 172 using namespace mozilla::net;
michael@0 173 using namespace mozilla::jsipc;
michael@0 174
michael@0 175 #ifdef ENABLE_TESTS
michael@0 176
michael@0 177 class BackgroundTester MOZ_FINAL : public nsIIPCBackgroundChildCreateCallback,
michael@0 178 public nsIObserver
michael@0 179 {
michael@0 180 static uint32_t sCallbackCount;
michael@0 181
michael@0 182 private:
michael@0 183 ~BackgroundTester()
michael@0 184 { }
michael@0 185
michael@0 186 virtual void
michael@0 187 ActorCreated(PBackgroundChild* aActor) MOZ_OVERRIDE
michael@0 188 {
michael@0 189 MOZ_RELEASE_ASSERT(aActor,
michael@0 190 "Failed to create a PBackgroundChild actor!");
michael@0 191
michael@0 192 NS_NAMED_LITERAL_CSTRING(testStr, "0123456789");
michael@0 193
michael@0 194 PBackgroundTestChild* testActor =
michael@0 195 aActor->SendPBackgroundTestConstructor(testStr);
michael@0 196 MOZ_RELEASE_ASSERT(testActor);
michael@0 197
michael@0 198 if (!sCallbackCount) {
michael@0 199 PBackgroundChild* existingBackgroundChild =
michael@0 200 BackgroundChild::GetForCurrentThread();
michael@0 201
michael@0 202 MOZ_RELEASE_ASSERT(existingBackgroundChild);
michael@0 203 MOZ_RELEASE_ASSERT(existingBackgroundChild == aActor);
michael@0 204
michael@0 205 bool ok =
michael@0 206 existingBackgroundChild->
michael@0 207 SendPBackgroundTestConstructor(testStr);
michael@0 208 MOZ_RELEASE_ASSERT(ok);
michael@0 209
michael@0 210 // Callback 3.
michael@0 211 ok = BackgroundChild::GetOrCreateForCurrentThread(this);
michael@0 212 MOZ_RELEASE_ASSERT(ok);
michael@0 213 }
michael@0 214
michael@0 215 sCallbackCount++;
michael@0 216 }
michael@0 217
michael@0 218 virtual void
michael@0 219 ActorFailed() MOZ_OVERRIDE
michael@0 220 {
michael@0 221 MOZ_CRASH("Failed to create a PBackgroundChild actor!");
michael@0 222 }
michael@0 223
michael@0 224 NS_IMETHOD
michael@0 225 Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
michael@0 226 MOZ_OVERRIDE
michael@0 227 {
michael@0 228 nsCOMPtr<nsIObserverService> observerService =
michael@0 229 mozilla::services::GetObserverService();
michael@0 230 MOZ_RELEASE_ASSERT(observerService);
michael@0 231
michael@0 232 nsresult rv = observerService->RemoveObserver(this, aTopic);
michael@0 233 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
michael@0 234
michael@0 235 if (!strcmp(aTopic, "profile-after-change")) {
michael@0 236 if (mozilla::Preferences::GetBool("pbackground.testing", false)) {
michael@0 237 rv = observerService->AddObserver(this, "xpcom-shutdown",
michael@0 238 false);
michael@0 239 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
michael@0 240
michael@0 241 // Callback 1.
michael@0 242 bool ok = BackgroundChild::GetOrCreateForCurrentThread(this);
michael@0 243 MOZ_RELEASE_ASSERT(ok);
michael@0 244
michael@0 245 BackgroundChildImpl::ThreadLocal* threadLocal =
michael@0 246 BackgroundChildImpl::GetThreadLocalForCurrentThread();
michael@0 247 MOZ_RELEASE_ASSERT(threadLocal);
michael@0 248
michael@0 249 // Callback 2.
michael@0 250 ok = BackgroundChild::GetOrCreateForCurrentThread(this);
michael@0 251 MOZ_RELEASE_ASSERT(ok);
michael@0 252 }
michael@0 253
michael@0 254 return NS_OK;
michael@0 255 }
michael@0 256
michael@0 257 if (!strcmp(aTopic, "xpcom-shutdown")) {
michael@0 258 MOZ_RELEASE_ASSERT(sCallbackCount == 3);
michael@0 259
michael@0 260 return NS_OK;
michael@0 261 }
michael@0 262
michael@0 263 MOZ_CRASH("Unknown observer topic!");
michael@0 264 }
michael@0 265
michael@0 266 public:
michael@0 267 NS_DECL_ISUPPORTS
michael@0 268 };
michael@0 269
michael@0 270 uint32_t BackgroundTester::sCallbackCount = 0;
michael@0 271
michael@0 272 NS_IMPL_ISUPPORTS(BackgroundTester, nsIIPCBackgroundChildCreateCallback,
michael@0 273 nsIObserver)
michael@0 274
michael@0 275 #endif // ENABLE_TESTS
michael@0 276
michael@0 277 void
michael@0 278 MaybeTestPBackground()
michael@0 279 {
michael@0 280 #ifdef ENABLE_TESTS
michael@0 281 // This test relies on running the event loop and XPCShell does not always
michael@0 282 // do so. Bail out here if we detect that we're running in XPCShell.
michael@0 283 if (PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR")) {
michael@0 284 return;
michael@0 285 }
michael@0 286
michael@0 287 // This is called too early at startup to test preferences directly. We have
michael@0 288 // to install an observer to be notified when preferences are available.
michael@0 289 nsCOMPtr<nsIObserverService> observerService =
michael@0 290 mozilla::services::GetObserverService();
michael@0 291 MOZ_RELEASE_ASSERT(observerService);
michael@0 292
michael@0 293 nsCOMPtr<nsIObserver> observer = new BackgroundTester();
michael@0 294 nsresult rv = observerService->AddObserver(observer, "profile-after-change",
michael@0 295 false);
michael@0 296 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
michael@0 297 #endif
michael@0 298 }
michael@0 299
michael@0 300 namespace mozilla {
michael@0 301 namespace dom {
michael@0 302
michael@0 303 #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
michael@0 304
michael@0 305 class MemoryReportRequestParent : public PMemoryReportRequestParent
michael@0 306 {
michael@0 307 public:
michael@0 308 MemoryReportRequestParent();
michael@0 309 virtual ~MemoryReportRequestParent();
michael@0 310
michael@0 311 virtual bool Recv__delete__(const uint32_t& generation, const InfallibleTArray<MemoryReport>& report);
michael@0 312 private:
michael@0 313 ContentParent* Owner()
michael@0 314 {
michael@0 315 return static_cast<ContentParent*>(Manager());
michael@0 316 }
michael@0 317 };
michael@0 318
michael@0 319 MemoryReportRequestParent::MemoryReportRequestParent()
michael@0 320 {
michael@0 321 MOZ_COUNT_CTOR(MemoryReportRequestParent);
michael@0 322 }
michael@0 323
michael@0 324 bool
michael@0 325 MemoryReportRequestParent::Recv__delete__(const uint32_t& generation, const InfallibleTArray<MemoryReport>& childReports)
michael@0 326 {
michael@0 327 nsRefPtr<nsMemoryReporterManager> mgr =
michael@0 328 nsMemoryReporterManager::GetOrCreate();
michael@0 329 if (mgr) {
michael@0 330 mgr->HandleChildReports(generation, childReports);
michael@0 331 }
michael@0 332 return true;
michael@0 333 }
michael@0 334
michael@0 335 MemoryReportRequestParent::~MemoryReportRequestParent()
michael@0 336 {
michael@0 337 MOZ_COUNT_DTOR(MemoryReportRequestParent);
michael@0 338 }
michael@0 339
michael@0 340 // A memory reporter for ContentParent objects themselves.
michael@0 341 class ContentParentsMemoryReporter MOZ_FINAL : public nsIMemoryReporter
michael@0 342 {
michael@0 343 public:
michael@0 344 NS_DECL_ISUPPORTS
michael@0 345 NS_DECL_NSIMEMORYREPORTER
michael@0 346 };
michael@0 347
michael@0 348 NS_IMPL_ISUPPORTS(ContentParentsMemoryReporter, nsIMemoryReporter)
michael@0 349
michael@0 350 NS_IMETHODIMP
michael@0 351 ContentParentsMemoryReporter::CollectReports(nsIMemoryReporterCallback* cb,
michael@0 352 nsISupports* aClosure)
michael@0 353 {
michael@0 354 nsAutoTArray<ContentParent*, 16> cps;
michael@0 355 ContentParent::GetAllEvenIfDead(cps);
michael@0 356
michael@0 357 for (uint32_t i = 0; i < cps.Length(); i++) {
michael@0 358 ContentParent* cp = cps[i];
michael@0 359 MessageChannel* channel = cp->GetIPCChannel();
michael@0 360
michael@0 361 nsString friendlyName;
michael@0 362 cp->FriendlyName(friendlyName);
michael@0 363
michael@0 364 cp->AddRef();
michael@0 365 nsrefcnt refcnt = cp->Release();
michael@0 366
michael@0 367 const char* channelStr = "no channel";
michael@0 368 uint32_t numQueuedMessages = 0;
michael@0 369 if (channel) {
michael@0 370 if (channel->Unsound_IsClosed()) {
michael@0 371 channelStr = "closed channel";
michael@0 372 } else {
michael@0 373 channelStr = "open channel";
michael@0 374 }
michael@0 375 numQueuedMessages = channel->Unsound_NumQueuedMessages();
michael@0 376 }
michael@0 377
michael@0 378 nsPrintfCString path("queued-ipc-messages/content-parent"
michael@0 379 "(%s, pid=%d, %s, 0x%p, refcnt=%d)",
michael@0 380 NS_ConvertUTF16toUTF8(friendlyName).get(),
michael@0 381 cp->Pid(), channelStr, cp, refcnt);
michael@0 382
michael@0 383 NS_NAMED_LITERAL_CSTRING(desc,
michael@0 384 "The number of unset IPC messages held in this ContentParent's "
michael@0 385 "channel. A large value here might indicate that we're leaking "
michael@0 386 "messages. Similarly, a ContentParent object for a process that's no "
michael@0 387 "longer running could indicate that we're leaking ContentParents.");
michael@0 388
michael@0 389 nsresult rv = cb->Callback(/* process */ EmptyCString(),
michael@0 390 path,
michael@0 391 KIND_OTHER,
michael@0 392 UNITS_COUNT,
michael@0 393 numQueuedMessages,
michael@0 394 desc,
michael@0 395 aClosure);
michael@0 396
michael@0 397 NS_ENSURE_SUCCESS(rv, rv);
michael@0 398 }
michael@0 399
michael@0 400 return NS_OK;
michael@0 401 }
michael@0 402
michael@0 403 nsDataHashtable<nsStringHashKey, ContentParent*>* ContentParent::sAppContentParents;
michael@0 404 nsTArray<ContentParent*>* ContentParent::sNonAppContentParents;
michael@0 405 nsTArray<ContentParent*>* ContentParent::sPrivateContent;
michael@0 406 StaticAutoPtr<LinkedList<ContentParent> > ContentParent::sContentParents;
michael@0 407
michael@0 408 // This is true when subprocess launching is enabled. This is the
michael@0 409 // case between StartUp() and ShutDown() or JoinAllSubprocesses().
michael@0 410 static bool sCanLaunchSubprocesses;
michael@0 411
michael@0 412 // The first content child has ID 1, so the chrome process can have ID 0.
michael@0 413 static uint64_t gContentChildID = 1;
michael@0 414
michael@0 415 // We want the prelaunched process to know that it's for apps, but not
michael@0 416 // actually for any app in particular. Use a magic manifest URL.
michael@0 417 // Can't be a static constant.
michael@0 418 #define MAGIC_PREALLOCATED_APP_MANIFEST_URL NS_LITERAL_STRING("{{template}}")
michael@0 419
michael@0 420 static const char* sObserverTopics[] = {
michael@0 421 "xpcom-shutdown",
michael@0 422 NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
michael@0 423 "child-memory-reporter-request",
michael@0 424 "memory-pressure",
michael@0 425 "child-gc-request",
michael@0 426 "child-cc-request",
michael@0 427 "child-mmu-request",
michael@0 428 "last-pb-context-exited",
michael@0 429 "file-watcher-update",
michael@0 430 #ifdef MOZ_WIDGET_GONK
michael@0 431 NS_VOLUME_STATE_CHANGED,
michael@0 432 "phone-state-changed",
michael@0 433 #endif
michael@0 434 #ifdef ACCESSIBILITY
michael@0 435 "a11y-init-or-shutdown",
michael@0 436 #endif
michael@0 437 };
michael@0 438
michael@0 439 /* static */ already_AddRefed<ContentParent>
michael@0 440 ContentParent::RunNuwaProcess()
michael@0 441 {
michael@0 442 MOZ_ASSERT(NS_IsMainThread());
michael@0 443 nsRefPtr<ContentParent> nuwaProcess =
michael@0 444 new ContentParent(/* aApp = */ nullptr,
michael@0 445 /* aIsForBrowser = */ false,
michael@0 446 /* aIsForPreallocated = */ true,
michael@0 447 PROCESS_PRIORITY_BACKGROUND,
michael@0 448 /* aIsNuwaProcess = */ true);
michael@0 449 nuwaProcess->Init();
michael@0 450 return nuwaProcess.forget();
michael@0 451 }
michael@0 452
michael@0 453 // PreallocateAppProcess is called by the PreallocatedProcessManager.
michael@0 454 // ContentParent then takes this process back within
michael@0 455 // MaybeTakePreallocatedAppProcess.
michael@0 456 /*static*/ already_AddRefed<ContentParent>
michael@0 457 ContentParent::PreallocateAppProcess()
michael@0 458 {
michael@0 459 nsRefPtr<ContentParent> process =
michael@0 460 new ContentParent(/* app = */ nullptr,
michael@0 461 /* isForBrowserElement = */ false,
michael@0 462 /* isForPreallocated = */ true,
michael@0 463 PROCESS_PRIORITY_PREALLOC);
michael@0 464 process->Init();
michael@0 465 return process.forget();
michael@0 466 }
michael@0 467
michael@0 468 /*static*/ already_AddRefed<ContentParent>
michael@0 469 ContentParent::MaybeTakePreallocatedAppProcess(const nsAString& aAppManifestURL,
michael@0 470 ProcessPriority aInitialPriority)
michael@0 471 {
michael@0 472 nsRefPtr<ContentParent> process = PreallocatedProcessManager::Take();
michael@0 473 if (!process) {
michael@0 474 return nullptr;
michael@0 475 }
michael@0 476
michael@0 477 if (!process->SetPriorityAndCheckIsAlive(aInitialPriority)) {
michael@0 478 // Kill the process just in case it's not actually dead; we don't want
michael@0 479 // to "leak" this process!
michael@0 480 process->KillHard();
michael@0 481 return nullptr;
michael@0 482 }
michael@0 483 process->TransformPreallocatedIntoApp(aAppManifestURL);
michael@0 484
michael@0 485 return process.forget();
michael@0 486 }
michael@0 487
michael@0 488 /*static*/ void
michael@0 489 ContentParent::StartUp()
michael@0 490 {
michael@0 491 if (XRE_GetProcessType() != GeckoProcessType_Default) {
michael@0 492 return;
michael@0 493 }
michael@0 494
michael@0 495 // Note: This reporter measures all ContentParents.
michael@0 496 RegisterStrongMemoryReporter(new ContentParentsMemoryReporter());
michael@0 497
michael@0 498 mozilla::dom::time::InitializeDateCacheCleaner();
michael@0 499
michael@0 500 BackgroundChild::Startup();
michael@0 501
michael@0 502 sCanLaunchSubprocesses = true;
michael@0 503
michael@0 504 // Try to preallocate a process that we can transform into an app later.
michael@0 505 PreallocatedProcessManager::AllocateAfterDelay();
michael@0 506
michael@0 507 // Test the PBackground infrastructure on ENABLE_TESTS builds when a special
michael@0 508 // testing preference is set.
michael@0 509 MaybeTestPBackground();
michael@0 510 }
michael@0 511
michael@0 512 /*static*/ void
michael@0 513 ContentParent::ShutDown()
michael@0 514 {
michael@0 515 // No-op for now. We rely on normal process shutdown and
michael@0 516 // ClearOnShutdown() to clean up our state.
michael@0 517 sCanLaunchSubprocesses = false;
michael@0 518 }
michael@0 519
michael@0 520 /*static*/ void
michael@0 521 ContentParent::JoinProcessesIOThread(const nsTArray<ContentParent*>* aProcesses,
michael@0 522 Monitor* aMonitor, bool* aDone)
michael@0 523 {
michael@0 524 const nsTArray<ContentParent*>& processes = *aProcesses;
michael@0 525 for (uint32_t i = 0; i < processes.Length(); ++i) {
michael@0 526 if (GeckoChildProcessHost* process = processes[i]->mSubprocess) {
michael@0 527 process->Join();
michael@0 528 }
michael@0 529 }
michael@0 530 {
michael@0 531 MonitorAutoLock lock(*aMonitor);
michael@0 532 *aDone = true;
michael@0 533 lock.Notify();
michael@0 534 }
michael@0 535 // Don't touch any arguments to this function from now on.
michael@0 536 }
michael@0 537
michael@0 538 /*static*/ void
michael@0 539 ContentParent::JoinAllSubprocesses()
michael@0 540 {
michael@0 541 MOZ_ASSERT(NS_IsMainThread());
michael@0 542
michael@0 543 nsAutoTArray<ContentParent*, 8> processes;
michael@0 544 GetAll(processes);
michael@0 545 if (processes.IsEmpty()) {
michael@0 546 printf_stderr("There are no live subprocesses.");
michael@0 547 return;
michael@0 548 }
michael@0 549
michael@0 550 printf_stderr("Subprocesses are still alive. Doing emergency join.\n");
michael@0 551
michael@0 552 bool done = false;
michael@0 553 Monitor monitor("mozilla.dom.ContentParent.JoinAllSubprocesses");
michael@0 554 XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
michael@0 555 NewRunnableFunction(
michael@0 556 &ContentParent::JoinProcessesIOThread,
michael@0 557 &processes, &monitor, &done));
michael@0 558 {
michael@0 559 MonitorAutoLock lock(monitor);
michael@0 560 while (!done) {
michael@0 561 lock.Wait();
michael@0 562 }
michael@0 563 }
michael@0 564
michael@0 565 sCanLaunchSubprocesses = false;
michael@0 566 }
michael@0 567
michael@0 568 /*static*/ already_AddRefed<ContentParent>
michael@0 569 ContentParent::GetNewOrUsed(bool aForBrowserElement)
michael@0 570 {
michael@0 571 if (!sNonAppContentParents)
michael@0 572 sNonAppContentParents = new nsTArray<ContentParent*>();
michael@0 573
michael@0 574 int32_t maxContentProcesses = Preferences::GetInt("dom.ipc.processCount", 1);
michael@0 575 if (maxContentProcesses < 1)
michael@0 576 maxContentProcesses = 1;
michael@0 577
michael@0 578 if (sNonAppContentParents->Length() >= uint32_t(maxContentProcesses)) {
michael@0 579 uint32_t idx = rand() % sNonAppContentParents->Length();
michael@0 580 nsRefPtr<ContentParent> p = (*sNonAppContentParents)[idx];
michael@0 581 NS_ASSERTION(p->IsAlive(), "Non-alive contentparent in sNonAppContentParents?");
michael@0 582 return p.forget();
michael@0 583 }
michael@0 584
michael@0 585 // Try to take and transform the preallocated process into browser.
michael@0 586 nsRefPtr<ContentParent> p = PreallocatedProcessManager::Take();
michael@0 587 if (p) {
michael@0 588 p->TransformPreallocatedIntoBrowser();
michael@0 589 } else {
michael@0 590 // Failed in using the preallocated process: fork from the chrome process.
michael@0 591 #ifdef MOZ_NUWA_PROCESS
michael@0 592 if (Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false)) {
michael@0 593 // Wait until the Nuwa process forks a new process.
michael@0 594 return nullptr;
michael@0 595 }
michael@0 596 #endif
michael@0 597 p = new ContentParent(/* app = */ nullptr,
michael@0 598 aForBrowserElement,
michael@0 599 /* isForPreallocated = */ false,
michael@0 600 PROCESS_PRIORITY_FOREGROUND);
michael@0 601 }
michael@0 602
michael@0 603 p->Init();
michael@0 604 sNonAppContentParents->AppendElement(p);
michael@0 605 return p.forget();
michael@0 606 }
michael@0 607
michael@0 608 /*static*/ ProcessPriority
michael@0 609 ContentParent::GetInitialProcessPriority(Element* aFrameElement)
michael@0 610 {
michael@0 611 // Frames with mozapptype == critical which are expecting a system message
michael@0 612 // get FOREGROUND_HIGH priority.
michael@0 613
michael@0 614 if (!aFrameElement) {
michael@0 615 return PROCESS_PRIORITY_FOREGROUND;
michael@0 616 }
michael@0 617
michael@0 618 if (aFrameElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::mozapptype,
michael@0 619 NS_LITERAL_STRING("keyboard"), eCaseMatters)) {
michael@0 620 return PROCESS_PRIORITY_FOREGROUND_KEYBOARD;
michael@0 621 } else if (!aFrameElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::mozapptype,
michael@0 622 NS_LITERAL_STRING("critical"), eCaseMatters)) {
michael@0 623 return PROCESS_PRIORITY_FOREGROUND;
michael@0 624 }
michael@0 625
michael@0 626 nsCOMPtr<nsIMozBrowserFrame> browserFrame =
michael@0 627 do_QueryInterface(aFrameElement);
michael@0 628 if (!browserFrame) {
michael@0 629 return PROCESS_PRIORITY_FOREGROUND;
michael@0 630 }
michael@0 631
michael@0 632 return browserFrame->GetIsExpectingSystemMessage() ?
michael@0 633 PROCESS_PRIORITY_FOREGROUND_HIGH :
michael@0 634 PROCESS_PRIORITY_FOREGROUND;
michael@0 635 }
michael@0 636
michael@0 637 bool
michael@0 638 ContentParent::PreallocatedProcessReady()
michael@0 639 {
michael@0 640 #ifdef MOZ_NUWA_PROCESS
michael@0 641 return PreallocatedProcessManager::PreallocatedProcessReady();
michael@0 642 #else
michael@0 643 return true;
michael@0 644 #endif
michael@0 645 }
michael@0 646
michael@0 647 void
michael@0 648 ContentParent::RunAfterPreallocatedProcessReady(nsIRunnable* aRequest)
michael@0 649 {
michael@0 650 #ifdef MOZ_NUWA_PROCESS
michael@0 651 PreallocatedProcessManager::RunAfterPreallocatedProcessReady(aRequest);
michael@0 652 #endif
michael@0 653 }
michael@0 654
michael@0 655 /*static*/ TabParent*
michael@0 656 ContentParent::CreateBrowserOrApp(const TabContext& aContext,
michael@0 657 Element* aFrameElement)
michael@0 658 {
michael@0 659 if (!sCanLaunchSubprocesses) {
michael@0 660 return nullptr;
michael@0 661 }
michael@0 662
michael@0 663 if (aContext.IsBrowserElement() || !aContext.HasOwnApp()) {
michael@0 664 if (nsRefPtr<ContentParent> cp = GetNewOrUsed(aContext.IsBrowserElement())) {
michael@0 665 uint32_t chromeFlags = 0;
michael@0 666
michael@0 667 // Propagate the private-browsing status of the element's parent
michael@0 668 // docshell to the remote docshell, via the chrome flags.
michael@0 669 nsCOMPtr<Element> frameElement = do_QueryInterface(aFrameElement);
michael@0 670 MOZ_ASSERT(frameElement);
michael@0 671 nsIDocShell* docShell =
michael@0 672 frameElement->OwnerDoc()->GetWindow()->GetDocShell();
michael@0 673 MOZ_ASSERT(docShell);
michael@0 674 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
michael@0 675 if (loadContext && loadContext->UsePrivateBrowsing()) {
michael@0 676 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
michael@0 677 }
michael@0 678 bool affectLifetime;
michael@0 679 docShell->GetAffectPrivateSessionLifetime(&affectLifetime);
michael@0 680 if (affectLifetime) {
michael@0 681 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME;
michael@0 682 }
michael@0 683
michael@0 684 nsRefPtr<TabParent> tp(new TabParent(cp, aContext, chromeFlags));
michael@0 685 tp->SetOwnerElement(aFrameElement);
michael@0 686
michael@0 687 PBrowserParent* browser = cp->SendPBrowserConstructor(
michael@0 688 // DeallocPBrowserParent() releases this ref.
michael@0 689 tp.forget().take(),
michael@0 690 aContext.AsIPCTabContext(),
michael@0 691 chromeFlags);
michael@0 692 return static_cast<TabParent*>(browser);
michael@0 693 }
michael@0 694 return nullptr;
michael@0 695 }
michael@0 696
michael@0 697 // If we got here, we have an app and we're not a browser element. ownApp
michael@0 698 // shouldn't be null, because we otherwise would have gone into the
michael@0 699 // !HasOwnApp() branch above.
michael@0 700 nsCOMPtr<mozIApplication> ownApp = aContext.GetOwnApp();
michael@0 701
michael@0 702 if (!sAppContentParents) {
michael@0 703 sAppContentParents =
michael@0 704 new nsDataHashtable<nsStringHashKey, ContentParent*>();
michael@0 705 }
michael@0 706
michael@0 707 // Each app gets its own ContentParent instance unless it shares it with
michael@0 708 // a parent app.
michael@0 709 nsAutoString manifestURL;
michael@0 710 if (NS_FAILED(ownApp->GetManifestURL(manifestURL))) {
michael@0 711 NS_ERROR("Failed to get manifest URL");
michael@0 712 return nullptr;
michael@0 713 }
michael@0 714
michael@0 715 ProcessPriority initialPriority = GetInitialProcessPriority(aFrameElement);
michael@0 716 nsRefPtr<ContentParent> p = sAppContentParents->Get(manifestURL);
michael@0 717
michael@0 718 if (!p && Preferences::GetBool("dom.ipc.reuse_parent_app")) {
michael@0 719 nsAutoString parentAppURL;
michael@0 720 aFrameElement->GetAttr(kNameSpaceID_None,
michael@0 721 nsGkAtoms::parentapp, parentAppURL);
michael@0 722 nsAdoptingString systemAppURL =
michael@0 723 Preferences::GetString("browser.homescreenURL");
michael@0 724 nsCOMPtr<nsIAppsService> appsService =
michael@0 725 do_GetService(APPS_SERVICE_CONTRACTID);
michael@0 726 if (!parentAppURL.IsEmpty() &&
michael@0 727 !parentAppURL.Equals(systemAppURL) &&
michael@0 728 appsService) {
michael@0 729 nsCOMPtr<mozIApplication> parentApp;
michael@0 730 nsCOMPtr<mozIApplication> app;
michael@0 731 appsService->GetAppByManifestURL(parentAppURL,
michael@0 732 getter_AddRefs(parentApp));
michael@0 733 appsService->GetAppByManifestURL(manifestURL,
michael@0 734 getter_AddRefs(app));
michael@0 735
michael@0 736 // Only let certified apps re-use the same process.
michael@0 737 unsigned short parentAppStatus = 0;
michael@0 738 unsigned short appStatus = 0;
michael@0 739 if (app &&
michael@0 740 NS_SUCCEEDED(app->GetAppStatus(&appStatus)) &&
michael@0 741 appStatus == nsIPrincipal::APP_STATUS_CERTIFIED &&
michael@0 742 parentApp &&
michael@0 743 NS_SUCCEEDED(parentApp->GetAppStatus(&parentAppStatus)) &&
michael@0 744 parentAppStatus == nsIPrincipal::APP_STATUS_CERTIFIED) {
michael@0 745 // Check if we can re-use the process of the parent app.
michael@0 746 p = sAppContentParents->Get(parentAppURL);
michael@0 747 }
michael@0 748 }
michael@0 749 }
michael@0 750
michael@0 751 if (p) {
michael@0 752 // Check that the process is still alive and set its priority.
michael@0 753 // Hopefully the process won't die after this point, if this call
michael@0 754 // succeeds.
michael@0 755 if (!p->SetPriorityAndCheckIsAlive(initialPriority)) {
michael@0 756 p = nullptr;
michael@0 757 }
michael@0 758 }
michael@0 759
michael@0 760 if (!p) {
michael@0 761 p = MaybeTakePreallocatedAppProcess(manifestURL,
michael@0 762 initialPriority);
michael@0 763 if (!p) {
michael@0 764 #ifdef MOZ_NUWA_PROCESS
michael@0 765 if (Preferences::GetBool("dom.ipc.processPrelaunch.enabled",
michael@0 766 false)) {
michael@0 767 // Returning nullptr from here so the frame loader will retry
michael@0 768 // later when we have a spare process.
michael@0 769 return nullptr;
michael@0 770 }
michael@0 771 #endif
michael@0 772 NS_WARNING("Unable to use pre-allocated app process");
michael@0 773 p = new ContentParent(ownApp,
michael@0 774 /* isForBrowserElement = */ false,
michael@0 775 /* isForPreallocated = */ false,
michael@0 776 initialPriority);
michael@0 777 p->Init();
michael@0 778 }
michael@0 779 sAppContentParents->Put(manifestURL, p);
michael@0 780 }
michael@0 781
michael@0 782 uint32_t chromeFlags = 0;
michael@0 783
michael@0 784 nsRefPtr<TabParent> tp = new TabParent(p, aContext, chromeFlags);
michael@0 785 tp->SetOwnerElement(aFrameElement);
michael@0 786 PBrowserParent* browser = p->SendPBrowserConstructor(
michael@0 787 // DeallocPBrowserParent() releases this ref.
michael@0 788 nsRefPtr<TabParent>(tp).forget().take(),
michael@0 789 aContext.AsIPCTabContext(),
michael@0 790 chromeFlags);
michael@0 791
michael@0 792 p->MaybeTakeCPUWakeLock(aFrameElement);
michael@0 793
michael@0 794 return static_cast<TabParent*>(browser);
michael@0 795 }
michael@0 796
michael@0 797 void
michael@0 798 ContentParent::GetAll(nsTArray<ContentParent*>& aArray)
michael@0 799 {
michael@0 800 aArray.Clear();
michael@0 801
michael@0 802 if (!sContentParents) {
michael@0 803 return;
michael@0 804 }
michael@0 805
michael@0 806 for (ContentParent* cp = sContentParents->getFirst(); cp;
michael@0 807 cp = cp->LinkedListElement<ContentParent>::getNext()) {
michael@0 808 if (cp->mIsAlive) {
michael@0 809 aArray.AppendElement(cp);
michael@0 810 }
michael@0 811 }
michael@0 812 }
michael@0 813
michael@0 814 void
michael@0 815 ContentParent::GetAllEvenIfDead(nsTArray<ContentParent*>& aArray)
michael@0 816 {
michael@0 817 aArray.Clear();
michael@0 818
michael@0 819 if (!sContentParents) {
michael@0 820 return;
michael@0 821 }
michael@0 822
michael@0 823 for (ContentParent* cp = sContentParents->getFirst(); cp;
michael@0 824 cp = cp->LinkedListElement<ContentParent>::getNext()) {
michael@0 825 aArray.AppendElement(cp);
michael@0 826 }
michael@0 827 }
michael@0 828
michael@0 829 void
michael@0 830 ContentParent::Init()
michael@0 831 {
michael@0 832 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
michael@0 833 if (obs) {
michael@0 834 size_t length = ArrayLength(sObserverTopics);
michael@0 835 for (size_t i = 0; i < length; ++i) {
michael@0 836 obs->AddObserver(this, sObserverTopics[i], false);
michael@0 837 }
michael@0 838 }
michael@0 839 Preferences::AddStrongObserver(this, "");
michael@0 840 if (obs) {
michael@0 841 obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created", nullptr);
michael@0 842 }
michael@0 843
michael@0 844 #ifdef ACCESSIBILITY
michael@0 845 // If accessibility is running in chrome process then start it in content
michael@0 846 // process.
michael@0 847 if (nsIPresShell::IsAccessibilityActive()) {
michael@0 848 unused << SendActivateA11y();
michael@0 849 }
michael@0 850 #endif
michael@0 851
michael@0 852 DebugOnly<FileUpdateDispatcher*> observer = FileUpdateDispatcher::GetSingleton();
michael@0 853 NS_ASSERTION(observer, "FileUpdateDispatcher is null");
michael@0 854 }
michael@0 855
michael@0 856 namespace {
michael@0 857
michael@0 858 class SystemMessageHandledListener MOZ_FINAL
michael@0 859 : public nsITimerCallback
michael@0 860 , public LinkedListElement<SystemMessageHandledListener>
michael@0 861 {
michael@0 862 public:
michael@0 863 NS_DECL_ISUPPORTS
michael@0 864
michael@0 865 SystemMessageHandledListener() {}
michael@0 866
michael@0 867 static void OnSystemMessageHandled()
michael@0 868 {
michael@0 869 if (!sListeners) {
michael@0 870 return;
michael@0 871 }
michael@0 872
michael@0 873 SystemMessageHandledListener* listener = sListeners->popFirst();
michael@0 874 if (!listener) {
michael@0 875 return;
michael@0 876 }
michael@0 877
michael@0 878 // Careful: ShutDown() may delete |this|.
michael@0 879 listener->ShutDown();
michael@0 880 }
michael@0 881
michael@0 882 void Init(WakeLock* aWakeLock)
michael@0 883 {
michael@0 884 MOZ_ASSERT(!mWakeLock);
michael@0 885 MOZ_ASSERT(!mTimer);
michael@0 886
michael@0 887 // mTimer keeps a strong reference to |this|. When this object's
michael@0 888 // destructor runs, it will remove itself from the LinkedList.
michael@0 889
michael@0 890 if (!sListeners) {
michael@0 891 sListeners = new LinkedList<SystemMessageHandledListener>();
michael@0 892 ClearOnShutdown(&sListeners);
michael@0 893 }
michael@0 894 sListeners->insertBack(this);
michael@0 895
michael@0 896 mWakeLock = aWakeLock;
michael@0 897
michael@0 898 mTimer = do_CreateInstance("@mozilla.org/timer;1");
michael@0 899
michael@0 900 uint32_t timeoutSec =
michael@0 901 Preferences::GetInt("dom.ipc.systemMessageCPULockTimeoutSec", 30);
michael@0 902 mTimer->InitWithCallback(this, timeoutSec * 1000,
michael@0 903 nsITimer::TYPE_ONE_SHOT);
michael@0 904 }
michael@0 905
michael@0 906 NS_IMETHOD Notify(nsITimer* aTimer)
michael@0 907 {
michael@0 908 // Careful: ShutDown() may delete |this|.
michael@0 909 ShutDown();
michael@0 910 return NS_OK;
michael@0 911 }
michael@0 912
michael@0 913 private:
michael@0 914 static StaticAutoPtr<LinkedList<SystemMessageHandledListener> > sListeners;
michael@0 915
michael@0 916 void ShutDown()
michael@0 917 {
michael@0 918 nsRefPtr<SystemMessageHandledListener> kungFuDeathGrip = this;
michael@0 919
michael@0 920 ErrorResult rv;
michael@0 921 mWakeLock->Unlock(rv);
michael@0 922
michael@0 923 if (mTimer) {
michael@0 924 mTimer->Cancel();
michael@0 925 mTimer = nullptr;
michael@0 926 }
michael@0 927 }
michael@0 928
michael@0 929 nsRefPtr<WakeLock> mWakeLock;
michael@0 930 nsCOMPtr<nsITimer> mTimer;
michael@0 931 };
michael@0 932
michael@0 933 StaticAutoPtr<LinkedList<SystemMessageHandledListener> >
michael@0 934 SystemMessageHandledListener::sListeners;
michael@0 935
michael@0 936 NS_IMPL_ISUPPORTS(SystemMessageHandledListener,
michael@0 937 nsITimerCallback)
michael@0 938
michael@0 939 } // anonymous namespace
michael@0 940
michael@0 941 void
michael@0 942 ContentParent::MaybeTakeCPUWakeLock(Element* aFrameElement)
michael@0 943 {
michael@0 944 // Take the CPU wake lock on behalf of this processs if it's expecting a
michael@0 945 // system message. We'll release the CPU lock once the message is
michael@0 946 // delivered, or after some period of time, which ever comes first.
michael@0 947
michael@0 948 nsCOMPtr<nsIMozBrowserFrame> browserFrame =
michael@0 949 do_QueryInterface(aFrameElement);
michael@0 950 if (!browserFrame ||
michael@0 951 !browserFrame->GetIsExpectingSystemMessage()) {
michael@0 952 return;
michael@0 953 }
michael@0 954
michael@0 955 nsRefPtr<PowerManagerService> pms = PowerManagerService::GetInstance();
michael@0 956 nsRefPtr<WakeLock> lock =
michael@0 957 pms->NewWakeLockOnBehalfOfProcess(NS_LITERAL_STRING("cpu"), this);
michael@0 958
michael@0 959 // This object's Init() function keeps it alive.
michael@0 960 nsRefPtr<SystemMessageHandledListener> listener =
michael@0 961 new SystemMessageHandledListener();
michael@0 962 listener->Init(lock);
michael@0 963 }
michael@0 964
michael@0 965 bool
michael@0 966 ContentParent::SetPriorityAndCheckIsAlive(ProcessPriority aPriority)
michael@0 967 {
michael@0 968 ProcessPriorityManager::SetProcessPriority(this, aPriority);
michael@0 969
michael@0 970 // Now that we've set this process's priority, check whether the process is
michael@0 971 // still alive. Hopefully we've set the priority to FOREGROUND*, so the
michael@0 972 // process won't unexpectedly crash after this point!
michael@0 973 //
michael@0 974 // Bug 943174: use waitid() with WNOWAIT so that, if the process
michael@0 975 // did exit, we won't consume its zombie and confuse the
michael@0 976 // GeckoChildProcessHost dtor. Also, if the process isn't a
michael@0 977 // direct child because of Nuwa this will fail with ECHILD, and we
michael@0 978 // need to assume the child is alive in that case rather than
michael@0 979 // assuming it's dead (as is otherwise a reasonable fallback).
michael@0 980 #ifdef MOZ_WIDGET_GONK
michael@0 981 siginfo_t info;
michael@0 982 info.si_pid = 0;
michael@0 983 if (waitid(P_PID, Pid(), &info, WNOWAIT | WNOHANG | WEXITED) == 0
michael@0 984 && info.si_pid != 0) {
michael@0 985 return false;
michael@0 986 }
michael@0 987 #endif
michael@0 988
michael@0 989 return true;
michael@0 990 }
michael@0 991
michael@0 992 // Helper for ContentParent::TransformPreallocatedIntoApp.
michael@0 993 static void
michael@0 994 TryGetNameFromManifestURL(const nsAString& aManifestURL,
michael@0 995 nsAString& aName)
michael@0 996 {
michael@0 997 aName.Truncate();
michael@0 998 if (aManifestURL.IsEmpty() ||
michael@0 999 aManifestURL == MAGIC_PREALLOCATED_APP_MANIFEST_URL) {
michael@0 1000 return;
michael@0 1001 }
michael@0 1002
michael@0 1003 nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
michael@0 1004 NS_ENSURE_TRUE_VOID(appsService);
michael@0 1005
michael@0 1006 nsCOMPtr<mozIApplication> app;
michael@0 1007 appsService->GetAppByManifestURL(aManifestURL, getter_AddRefs(app));
michael@0 1008
michael@0 1009 if (!app) {
michael@0 1010 return;
michael@0 1011 }
michael@0 1012
michael@0 1013 app->GetName(aName);
michael@0 1014 }
michael@0 1015
michael@0 1016 void
michael@0 1017 ContentParent::TransformPreallocatedIntoApp(const nsAString& aAppManifestURL)
michael@0 1018 {
michael@0 1019 MOZ_ASSERT(IsPreallocated());
michael@0 1020 mAppManifestURL = aAppManifestURL;
michael@0 1021 TryGetNameFromManifestURL(aAppManifestURL, mAppName);
michael@0 1022 }
michael@0 1023
michael@0 1024 void
michael@0 1025 ContentParent::TransformPreallocatedIntoBrowser()
michael@0 1026 {
michael@0 1027 // Reset mAppManifestURL, mIsForBrowser and mOSPrivileges for browser.
michael@0 1028 mAppManifestURL.Truncate();
michael@0 1029 mIsForBrowser = true;
michael@0 1030 }
michael@0 1031
michael@0 1032 void
michael@0 1033 ContentParent::ShutDownProcess(bool aCloseWithError)
michael@0 1034 {
michael@0 1035 const InfallibleTArray<PIndexedDBParent*>& idbParents =
michael@0 1036 ManagedPIndexedDBParent();
michael@0 1037 for (uint32_t i = 0; i < idbParents.Length(); ++i) {
michael@0 1038 static_cast<IndexedDBParent*>(idbParents[i])->Disconnect();
michael@0 1039 }
michael@0 1040
michael@0 1041 // If Close() fails with an error, we'll end up back in this function, but
michael@0 1042 // with aCloseWithError = true. It's important that we call
michael@0 1043 // CloseWithError() in this case; see bug 895204.
michael@0 1044
michael@0 1045 if (!aCloseWithError && !mCalledClose) {
michael@0 1046 // Close() can only be called once: It kicks off the destruction
michael@0 1047 // sequence.
michael@0 1048 mCalledClose = true;
michael@0 1049 Close();
michael@0 1050 }
michael@0 1051
michael@0 1052 if (aCloseWithError && !mCalledCloseWithError) {
michael@0 1053 MessageChannel* channel = GetIPCChannel();
michael@0 1054 if (channel) {
michael@0 1055 mCalledCloseWithError = true;
michael@0 1056 channel->CloseWithError();
michael@0 1057 }
michael@0 1058 }
michael@0 1059
michael@0 1060 // NB: must MarkAsDead() here so that this isn't accidentally
michael@0 1061 // returned from Get*() while in the midst of shutdown.
michael@0 1062 MarkAsDead();
michael@0 1063
michael@0 1064 // A ContentParent object might not get freed until after XPCOM shutdown has
michael@0 1065 // shut down the cycle collector. But by then it's too late to release any
michael@0 1066 // CC'ed objects, so we need to null them out here, while we still can. See
michael@0 1067 // bug 899761.
michael@0 1068 if (mMessageManager) {
michael@0 1069 mMessageManager->Disconnect();
michael@0 1070 mMessageManager = nullptr;
michael@0 1071 }
michael@0 1072 }
michael@0 1073
michael@0 1074 void
michael@0 1075 ContentParent::MarkAsDead()
michael@0 1076 {
michael@0 1077 if (!mAppManifestURL.IsEmpty()) {
michael@0 1078 if (sAppContentParents) {
michael@0 1079 sAppContentParents->Remove(mAppManifestURL);
michael@0 1080 if (!sAppContentParents->Count()) {
michael@0 1081 delete sAppContentParents;
michael@0 1082 sAppContentParents = nullptr;
michael@0 1083 }
michael@0 1084 }
michael@0 1085 } else if (sNonAppContentParents) {
michael@0 1086 sNonAppContentParents->RemoveElement(this);
michael@0 1087 if (!sNonAppContentParents->Length()) {
michael@0 1088 delete sNonAppContentParents;
michael@0 1089 sNonAppContentParents = nullptr;
michael@0 1090 }
michael@0 1091 }
michael@0 1092
michael@0 1093 if (sPrivateContent) {
michael@0 1094 sPrivateContent->RemoveElement(this);
michael@0 1095 if (!sPrivateContent->Length()) {
michael@0 1096 delete sPrivateContent;
michael@0 1097 sPrivateContent = nullptr;
michael@0 1098 }
michael@0 1099 }
michael@0 1100
michael@0 1101 mIsAlive = false;
michael@0 1102 }
michael@0 1103
michael@0 1104 void
michael@0 1105 ContentParent::OnChannelError()
michael@0 1106 {
michael@0 1107 nsRefPtr<ContentParent> content(this);
michael@0 1108 #ifdef MOZ_NUWA_PROCESS
michael@0 1109 // Handle app or Nuwa process exit before normal channel error handling.
michael@0 1110 PreallocatedProcessManager::MaybeForgetSpare(this);
michael@0 1111 #endif
michael@0 1112 PContentParent::OnChannelError();
michael@0 1113 }
michael@0 1114
michael@0 1115 void
michael@0 1116 ContentParent::OnChannelConnected(int32_t pid)
michael@0 1117 {
michael@0 1118 ProcessHandle handle;
michael@0 1119 if (!base::OpenPrivilegedProcessHandle(pid, &handle)) {
michael@0 1120 NS_WARNING("Can't open handle to child process.");
michael@0 1121 }
michael@0 1122 else {
michael@0 1123 // we need to close the existing handle before setting a new one.
michael@0 1124 base::CloseProcessHandle(OtherProcess());
michael@0 1125 SetOtherProcess(handle);
michael@0 1126
michael@0 1127 #if defined(ANDROID) || defined(LINUX)
michael@0 1128 // Check nice preference
michael@0 1129 int32_t nice = Preferences::GetInt("dom.ipc.content.nice", 0);
michael@0 1130
michael@0 1131 // Environment variable overrides preference
michael@0 1132 char* relativeNicenessStr = getenv("MOZ_CHILD_PROCESS_RELATIVE_NICENESS");
michael@0 1133 if (relativeNicenessStr) {
michael@0 1134 nice = atoi(relativeNicenessStr);
michael@0 1135 }
michael@0 1136
michael@0 1137 /* make the GUI thread have higher priority on single-cpu devices */
michael@0 1138 nsCOMPtr<nsIPropertyBag2> infoService = do_GetService(NS_SYSTEMINFO_CONTRACTID);
michael@0 1139 if (infoService) {
michael@0 1140 int32_t cpus;
michael@0 1141 nsresult rv = infoService->GetPropertyAsInt32(NS_LITERAL_STRING("cpucount"), &cpus);
michael@0 1142 if (NS_FAILED(rv)) {
michael@0 1143 cpus = 1;
michael@0 1144 }
michael@0 1145 if (nice != 0 && cpus == 1) {
michael@0 1146 setpriority(PRIO_PROCESS, pid, getpriority(PRIO_PROCESS, pid) + nice);
michael@0 1147 }
michael@0 1148 }
michael@0 1149 #endif
michael@0 1150 }
michael@0 1151
michael@0 1152 // Set a reply timeout. The only time the parent process will actually
michael@0 1153 // timeout is through urgent messages (which are used by CPOWs).
michael@0 1154 SetReplyTimeoutMs(Preferences::GetInt("dom.ipc.cpow.timeout", 3000));
michael@0 1155 }
michael@0 1156
michael@0 1157 void
michael@0 1158 ContentParent::ProcessingError(Result what)
michael@0 1159 {
michael@0 1160 if (MsgDropped == what) {
michael@0 1161 // Messages sent after crashes etc. are not a big deal.
michael@0 1162 return;
michael@0 1163 }
michael@0 1164 // Other errors are big deals.
michael@0 1165 KillHard();
michael@0 1166 }
michael@0 1167
michael@0 1168 namespace {
michael@0 1169
michael@0 1170 void
michael@0 1171 DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess)
michael@0 1172 {
michael@0 1173 XRE_GetIOMessageLoop()
michael@0 1174 ->PostTask(FROM_HERE,
michael@0 1175 new DeleteTask<GeckoChildProcessHost>(aSubprocess));
michael@0 1176 }
michael@0 1177
michael@0 1178 // This runnable only exists to delegate ownership of the
michael@0 1179 // ContentParent to this runnable, until it's deleted by the event
michael@0 1180 // system.
michael@0 1181 struct DelayedDeleteContentParentTask : public nsRunnable
michael@0 1182 {
michael@0 1183 DelayedDeleteContentParentTask(ContentParent* aObj) : mObj(aObj) { }
michael@0 1184
michael@0 1185 // No-op
michael@0 1186 NS_IMETHODIMP Run() { return NS_OK; }
michael@0 1187
michael@0 1188 nsRefPtr<ContentParent> mObj;
michael@0 1189 };
michael@0 1190
michael@0 1191 }
michael@0 1192
michael@0 1193 void
michael@0 1194 ContentParent::ActorDestroy(ActorDestroyReason why)
michael@0 1195 {
michael@0 1196 if (mForceKillTask) {
michael@0 1197 mForceKillTask->Cancel();
michael@0 1198 mForceKillTask = nullptr;
michael@0 1199 }
michael@0 1200
michael@0 1201 nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
michael@0 1202 if (ppm) {
michael@0 1203 ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
michael@0 1204 CHILD_PROCESS_SHUTDOWN_MESSAGE, false,
michael@0 1205 nullptr, nullptr, nullptr, nullptr);
michael@0 1206 }
michael@0 1207 nsRefPtr<ContentParent> kungFuDeathGrip(this);
michael@0 1208 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
michael@0 1209 if (obs) {
michael@0 1210 size_t length = ArrayLength(sObserverTopics);
michael@0 1211 for (size_t i = 0; i < length; ++i) {
michael@0 1212 obs->RemoveObserver(static_cast<nsIObserver*>(this),
michael@0 1213 sObserverTopics[i]);
michael@0 1214 }
michael@0 1215 }
michael@0 1216
michael@0 1217 if (ppm) {
michael@0 1218 ppm->Disconnect();
michael@0 1219 }
michael@0 1220
michael@0 1221 // Tell the memory reporter manager that this ContentParent is going away.
michael@0 1222 nsRefPtr<nsMemoryReporterManager> mgr =
michael@0 1223 nsMemoryReporterManager::GetOrCreate();
michael@0 1224 #ifdef MOZ_NUWA_PROCESS
michael@0 1225 bool isMemoryChild = !IsNuwaProcess();
michael@0 1226 #else
michael@0 1227 bool isMemoryChild = true;
michael@0 1228 #endif
michael@0 1229 if (mgr && isMemoryChild) {
michael@0 1230 mgr->DecrementNumChildProcesses();
michael@0 1231 }
michael@0 1232
michael@0 1233 // remove the global remote preferences observers
michael@0 1234 Preferences::RemoveObserver(this, "");
michael@0 1235
michael@0 1236 RecvRemoveGeolocationListener();
michael@0 1237
michael@0 1238 mConsoleService = nullptr;
michael@0 1239
michael@0 1240 MarkAsDead();
michael@0 1241
michael@0 1242 if (obs) {
michael@0 1243 nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
michael@0 1244
michael@0 1245 props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), mChildID);
michael@0 1246
michael@0 1247 if (AbnormalShutdown == why) {
michael@0 1248 props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), true);
michael@0 1249
michael@0 1250 #ifdef MOZ_CRASHREPORTER
michael@0 1251 // There's a window in which child processes can crash
michael@0 1252 // after IPC is established, but before a crash reporter
michael@0 1253 // is created.
michael@0 1254 if (ManagedPCrashReporterParent().Length() > 0) {
michael@0 1255 CrashReporterParent* crashReporter =
michael@0 1256 static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
michael@0 1257
michael@0 1258 // If we're an app process, always stomp the latest URI
michael@0 1259 // loaded in the child process with our manifest URL. We
michael@0 1260 // would rather associate the crashes with apps than
michael@0 1261 // random child windows loaded in them.
michael@0 1262 //
michael@0 1263 // XXX would be nice if we could get both ...
michael@0 1264 if (!mAppManifestURL.IsEmpty()) {
michael@0 1265 crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("URL"),
michael@0 1266 NS_ConvertUTF16toUTF8(mAppManifestURL));
michael@0 1267 }
michael@0 1268
michael@0 1269 crashReporter->GenerateCrashReport(this, nullptr);
michael@0 1270
michael@0 1271 nsAutoString dumpID(crashReporter->ChildDumpID());
michael@0 1272 props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID);
michael@0 1273 }
michael@0 1274 #endif
michael@0 1275 }
michael@0 1276 obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nullptr);
michael@0 1277 }
michael@0 1278
michael@0 1279 mIdleListeners.Clear();
michael@0 1280
michael@0 1281 // If the child process was terminated due to a SIGKIL, ShutDownProcess
michael@0 1282 // might not have been called yet. We must call it to ensure that our
michael@0 1283 // channel is closed, etc.
michael@0 1284 ShutDownProcess(/* closeWithError */ true);
michael@0 1285
michael@0 1286 MessageLoop::current()->
michael@0 1287 PostTask(FROM_HERE,
michael@0 1288 NewRunnableFunction(DelayedDeleteSubprocess, mSubprocess));
michael@0 1289 mSubprocess = nullptr;
michael@0 1290
michael@0 1291 // IPDL rules require actors to live on past ActorDestroy, but it
michael@0 1292 // may be that the kungFuDeathGrip above is the last reference to
michael@0 1293 // |this|. If so, when we go out of scope here, we're deleted and
michael@0 1294 // all hell breaks loose.
michael@0 1295 //
michael@0 1296 // This runnable ensures that a reference to |this| lives on at
michael@0 1297 // least until after the current task finishes running.
michael@0 1298 NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
michael@0 1299 }
michael@0 1300
michael@0 1301 void
michael@0 1302 ContentParent::NotifyTabDestroying(PBrowserParent* aTab)
michael@0 1303 {
michael@0 1304 // There can be more than one PBrowser for a given app process
michael@0 1305 // because of popup windows. PBrowsers can also destroy
michael@0 1306 // concurrently. When all the PBrowsers are destroying, kick off
michael@0 1307 // another task to ensure the child process *really* shuts down,
michael@0 1308 // even if the PBrowsers themselves never finish destroying.
michael@0 1309 int32_t numLiveTabs = ManagedPBrowserParent().Length();
michael@0 1310 ++mNumDestroyingTabs;
michael@0 1311 if (mNumDestroyingTabs != numLiveTabs) {
michael@0 1312 return;
michael@0 1313 }
michael@0 1314
michael@0 1315 // We're dying now, so prevent this content process from being
michael@0 1316 // recycled during its shutdown procedure.
michael@0 1317 MarkAsDead();
michael@0 1318
michael@0 1319 MOZ_ASSERT(!mForceKillTask);
michael@0 1320 int32_t timeoutSecs =
michael@0 1321 Preferences::GetInt("dom.ipc.tabs.shutdownTimeoutSecs", 5);
michael@0 1322 if (timeoutSecs > 0) {
michael@0 1323 MessageLoop::current()->PostDelayedTask(
michael@0 1324 FROM_HERE,
michael@0 1325 mForceKillTask = NewRunnableMethod(this, &ContentParent::KillHard),
michael@0 1326 timeoutSecs * 1000);
michael@0 1327 }
michael@0 1328 }
michael@0 1329
michael@0 1330 void
michael@0 1331 ContentParent::NotifyTabDestroyed(PBrowserParent* aTab,
michael@0 1332 bool aNotifiedDestroying)
michael@0 1333 {
michael@0 1334 if (aNotifiedDestroying) {
michael@0 1335 --mNumDestroyingTabs;
michael@0 1336 }
michael@0 1337
michael@0 1338 // There can be more than one PBrowser for a given app process
michael@0 1339 // because of popup windows. When the last one closes, shut
michael@0 1340 // us down.
michael@0 1341 if (ManagedPBrowserParent().Length() == 1) {
michael@0 1342 MessageLoop::current()->PostTask(
michael@0 1343 FROM_HERE,
michael@0 1344 NewRunnableMethod(this, &ContentParent::ShutDownProcess,
michael@0 1345 /* force */ false));
michael@0 1346 }
michael@0 1347 }
michael@0 1348
michael@0 1349 jsipc::JavaScriptParent*
michael@0 1350 ContentParent::GetCPOWManager()
michael@0 1351 {
michael@0 1352 if (ManagedPJavaScriptParent().Length()) {
michael@0 1353 return static_cast<JavaScriptParent*>(ManagedPJavaScriptParent()[0]);
michael@0 1354 }
michael@0 1355 JavaScriptParent* actor = static_cast<JavaScriptParent*>(SendPJavaScriptConstructor());
michael@0 1356 return actor;
michael@0 1357 }
michael@0 1358
michael@0 1359 TestShellParent*
michael@0 1360 ContentParent::CreateTestShell()
michael@0 1361 {
michael@0 1362 return static_cast<TestShellParent*>(SendPTestShellConstructor());
michael@0 1363 }
michael@0 1364
michael@0 1365 bool
michael@0 1366 ContentParent::DestroyTestShell(TestShellParent* aTestShell)
michael@0 1367 {
michael@0 1368 return PTestShellParent::Send__delete__(aTestShell);
michael@0 1369 }
michael@0 1370
michael@0 1371 TestShellParent*
michael@0 1372 ContentParent::GetTestShellSingleton()
michael@0 1373 {
michael@0 1374 if (!ManagedPTestShellParent().Length())
michael@0 1375 return nullptr;
michael@0 1376 return static_cast<TestShellParent*>(ManagedPTestShellParent()[0]);
michael@0 1377 }
michael@0 1378
michael@0 1379 void
michael@0 1380 ContentParent::InitializeMembers()
michael@0 1381 {
michael@0 1382 mSubprocess = nullptr;
michael@0 1383 mChildID = gContentChildID++;
michael@0 1384 mGeolocationWatchID = -1;
michael@0 1385 mForceKillTask = nullptr;
michael@0 1386 mNumDestroyingTabs = 0;
michael@0 1387 mIsAlive = true;
michael@0 1388 mSendPermissionUpdates = false;
michael@0 1389 mCalledClose = false;
michael@0 1390 mCalledCloseWithError = false;
michael@0 1391 mCalledKillHard = false;
michael@0 1392 }
michael@0 1393
michael@0 1394 ContentParent::ContentParent(mozIApplication* aApp,
michael@0 1395 bool aIsForBrowser,
michael@0 1396 bool aIsForPreallocated,
michael@0 1397 ProcessPriority aInitialPriority /* = PROCESS_PRIORITY_FOREGROUND */,
michael@0 1398 bool aIsNuwaProcess /* = false */)
michael@0 1399 : mIsForBrowser(aIsForBrowser)
michael@0 1400 , mIsNuwaProcess(aIsNuwaProcess)
michael@0 1401 {
michael@0 1402 InitializeMembers(); // Perform common initialization.
michael@0 1403
michael@0 1404 // No more than one of !!aApp, aIsForBrowser, aIsForPreallocated should be
michael@0 1405 // true.
michael@0 1406 MOZ_ASSERT(!!aApp + aIsForBrowser + aIsForPreallocated <= 1);
michael@0 1407
michael@0 1408 // Only the preallocated process uses Nuwa.
michael@0 1409 MOZ_ASSERT_IF(aIsNuwaProcess, aIsForPreallocated);
michael@0 1410
michael@0 1411 // Insert ourselves into the global linked list of ContentParent objects.
michael@0 1412 if (!sContentParents) {
michael@0 1413 sContentParents = new LinkedList<ContentParent>();
michael@0 1414 }
michael@0 1415 if (!aIsNuwaProcess) {
michael@0 1416 sContentParents->insertBack(this);
michael@0 1417 }
michael@0 1418
michael@0 1419 if (aApp) {
michael@0 1420 aApp->GetManifestURL(mAppManifestURL);
michael@0 1421 aApp->GetName(mAppName);
michael@0 1422 } else if (aIsForPreallocated) {
michael@0 1423 mAppManifestURL = MAGIC_PREALLOCATED_APP_MANIFEST_URL;
michael@0 1424 }
michael@0 1425
michael@0 1426 // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the
michael@0 1427 // PID along with the warning.
michael@0 1428 nsDebugImpl::SetMultiprocessMode("Parent");
michael@0 1429
michael@0 1430 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
michael@0 1431 ChildPrivileges privs = aIsNuwaProcess
michael@0 1432 ? base::PRIVILEGES_INHERIT
michael@0 1433 : base::PRIVILEGES_DEFAULT;
michael@0 1434 mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content, privs);
michael@0 1435 mSubprocess->SetSandboxEnabled(ShouldSandboxContentProcesses());
michael@0 1436
michael@0 1437 IToplevelProtocol::SetTransport(mSubprocess->GetChannel());
michael@0 1438
michael@0 1439 if (!aIsNuwaProcess) {
michael@0 1440 // Tell the memory reporter manager that this ContentParent exists.
michael@0 1441 nsRefPtr<nsMemoryReporterManager> mgr =
michael@0 1442 nsMemoryReporterManager::GetOrCreate();
michael@0 1443 if (mgr) {
michael@0 1444 mgr->IncrementNumChildProcesses();
michael@0 1445 }
michael@0 1446 }
michael@0 1447
michael@0 1448 std::vector<std::string> extraArgs;
michael@0 1449 if (aIsNuwaProcess) {
michael@0 1450 extraArgs.push_back("-nuwa");
michael@0 1451 }
michael@0 1452 mSubprocess->LaunchAndWaitForProcessHandle(extraArgs);
michael@0 1453
michael@0 1454 Open(mSubprocess->GetChannel(), mSubprocess->GetOwnedChildProcessHandle());
michael@0 1455
michael@0 1456 InitInternal(aInitialPriority,
michael@0 1457 true, /* Setup off-main thread compositing */
michael@0 1458 true /* Send registered chrome */);
michael@0 1459 }
michael@0 1460
michael@0 1461 #ifdef MOZ_NUWA_PROCESS
michael@0 1462 static const mozilla::ipc::FileDescriptor*
michael@0 1463 FindFdProtocolFdMapping(const nsTArray<ProtocolFdMapping>& aFds,
michael@0 1464 ProtocolId aProtoId)
michael@0 1465 {
michael@0 1466 for (unsigned int i = 0; i < aFds.Length(); i++) {
michael@0 1467 if (aFds[i].protocolId() == aProtoId) {
michael@0 1468 return &aFds[i].fd();
michael@0 1469 }
michael@0 1470 }
michael@0 1471 return nullptr;
michael@0 1472 }
michael@0 1473
michael@0 1474 /**
michael@0 1475 * This constructor is used for new content process cloned from a template.
michael@0 1476 *
michael@0 1477 * For Nuwa.
michael@0 1478 */
michael@0 1479 ContentParent::ContentParent(ContentParent* aTemplate,
michael@0 1480 const nsAString& aAppManifestURL,
michael@0 1481 base::ProcessHandle aPid,
michael@0 1482 const nsTArray<ProtocolFdMapping>& aFds)
michael@0 1483 : mAppManifestURL(aAppManifestURL)
michael@0 1484 , mIsForBrowser(false)
michael@0 1485 , mIsNuwaProcess(false)
michael@0 1486 {
michael@0 1487 InitializeMembers(); // Perform common initialization.
michael@0 1488
michael@0 1489 sContentParents->insertBack(this);
michael@0 1490
michael@0 1491 // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the
michael@0 1492 // PID along with the warning.
michael@0 1493 nsDebugImpl::SetMultiprocessMode("Parent");
michael@0 1494
michael@0 1495 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
michael@0 1496
michael@0 1497 const FileDescriptor* fd = FindFdProtocolFdMapping(aFds, GetProtocolId());
michael@0 1498
michael@0 1499 NS_ASSERTION(fd != nullptr, "IPC Channel for PContent is necessary!");
michael@0 1500 mSubprocess = new GeckoExistingProcessHost(GeckoProcessType_Content,
michael@0 1501 aPid,
michael@0 1502 *fd);
michael@0 1503
michael@0 1504 // Tell the memory reporter manager that this ContentParent exists.
michael@0 1505 nsRefPtr<nsMemoryReporterManager> mgr =
michael@0 1506 nsMemoryReporterManager::GetOrCreate();
michael@0 1507 if (mgr) {
michael@0 1508 mgr->IncrementNumChildProcesses();
michael@0 1509 }
michael@0 1510
michael@0 1511 mSubprocess->LaunchAndWaitForProcessHandle();
michael@0 1512
michael@0 1513 // Clone actors routed by aTemplate for this instance.
michael@0 1514 IToplevelProtocol::SetTransport(mSubprocess->GetChannel());
michael@0 1515 ProtocolCloneContext cloneContext;
michael@0 1516 cloneContext.SetContentParent(this);
michael@0 1517 CloneManagees(aTemplate, &cloneContext);
michael@0 1518 CloneOpenedToplevels(aTemplate, aFds, aPid, &cloneContext);
michael@0 1519
michael@0 1520 Open(mSubprocess->GetChannel(),
michael@0 1521 mSubprocess->GetChildProcessHandle());
michael@0 1522
michael@0 1523 // Set the subprocess's priority (bg if we're a preallocated process, fg
michael@0 1524 // otherwise). We do this first because we're likely /lowering/ its CPU and
michael@0 1525 // memory priority, which it has inherited from this process.
michael@0 1526 ProcessPriority priority;
michael@0 1527 if (IsPreallocated()) {
michael@0 1528 priority = PROCESS_PRIORITY_PREALLOC;
michael@0 1529 } else {
michael@0 1530 priority = PROCESS_PRIORITY_FOREGROUND;
michael@0 1531 }
michael@0 1532
michael@0 1533 InitInternal(priority,
michael@0 1534 false, /* Setup Off-main thread compositing */
michael@0 1535 false /* Send registered chrome */);
michael@0 1536 }
michael@0 1537 #endif // MOZ_NUWA_PROCESS
michael@0 1538
michael@0 1539 ContentParent::~ContentParent()
michael@0 1540 {
michael@0 1541 if (mForceKillTask) {
michael@0 1542 mForceKillTask->Cancel();
michael@0 1543 }
michael@0 1544
michael@0 1545 if (OtherProcess())
michael@0 1546 base::CloseProcessHandle(OtherProcess());
michael@0 1547
michael@0 1548 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
michael@0 1549
michael@0 1550 // We should be removed from all these lists in ActorDestroy.
michael@0 1551 MOZ_ASSERT(!sPrivateContent || !sPrivateContent->Contains(this));
michael@0 1552 if (mAppManifestURL.IsEmpty()) {
michael@0 1553 MOZ_ASSERT(!sNonAppContentParents ||
michael@0 1554 !sNonAppContentParents->Contains(this));
michael@0 1555 } else {
michael@0 1556 // In general, we expect sAppContentParents->Get(mAppManifestURL) to be
michael@0 1557 // nullptr. But it could be that we created another ContentParent for
michael@0 1558 // this app after we did this->ActorDestroy(), so the right check is
michael@0 1559 // that sAppContentParents->Get(mAppManifestURL) != this.
michael@0 1560 MOZ_ASSERT(!sAppContentParents ||
michael@0 1561 sAppContentParents->Get(mAppManifestURL) != this);
michael@0 1562 }
michael@0 1563 }
michael@0 1564
michael@0 1565 void
michael@0 1566 ContentParent::InitInternal(ProcessPriority aInitialPriority,
michael@0 1567 bool aSetupOffMainThreadCompositing,
michael@0 1568 bool aSendRegisteredChrome)
michael@0 1569 {
michael@0 1570 // Set the subprocess's priority. We do this early on because we're likely
michael@0 1571 // /lowering/ the process's CPU and memory priority, which it has inherited
michael@0 1572 // from this process.
michael@0 1573 //
michael@0 1574 // This call can cause us to send IPC messages to the child process, so it
michael@0 1575 // must come after the Open() call above.
michael@0 1576 ProcessPriorityManager::SetProcessPriority(this, aInitialPriority);
michael@0 1577
michael@0 1578 if (aSetupOffMainThreadCompositing) {
michael@0 1579 // NB: internally, this will send an IPC message to the child
michael@0 1580 // process to get it to create the CompositorChild. This
michael@0 1581 // message goes through the regular IPC queue for this
michael@0 1582 // channel, so delivery will happen-before any other messages
michael@0 1583 // we send. The CompositorChild must be created before any
michael@0 1584 // PBrowsers are created, because they rely on the Compositor
michael@0 1585 // already being around. (Creation is async, so can't happen
michael@0 1586 // on demand.)
michael@0 1587 bool useOffMainThreadCompositing = !!CompositorParent::CompositorLoop();
michael@0 1588 if (useOffMainThreadCompositing) {
michael@0 1589 DebugOnly<bool> opened = PCompositor::Open(this);
michael@0 1590 MOZ_ASSERT(opened);
michael@0 1591
michael@0 1592 if (gfxPrefs::AsyncVideoEnabled()) {
michael@0 1593 opened = PImageBridge::Open(this);
michael@0 1594 MOZ_ASSERT(opened);
michael@0 1595 }
michael@0 1596 }
michael@0 1597 }
michael@0 1598
michael@0 1599 if (aSendRegisteredChrome) {
michael@0 1600 nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
michael@0 1601 nsChromeRegistryChrome* chromeRegistry =
michael@0 1602 static_cast<nsChromeRegistryChrome*>(registrySvc.get());
michael@0 1603 chromeRegistry->SendRegisteredChrome(this);
michael@0 1604 }
michael@0 1605
michael@0 1606 mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this);
michael@0 1607
michael@0 1608 if (gAppData) {
michael@0 1609 nsCString version(gAppData->version);
michael@0 1610 nsCString buildID(gAppData->buildID);
michael@0 1611 nsCString name(gAppData->name);
michael@0 1612 nsCString UAName(gAppData->UAName);
michael@0 1613
michael@0 1614 // Sending all information to content process.
michael@0 1615 unused << SendAppInfo(version, buildID, name, UAName);
michael@0 1616 }
michael@0 1617
michael@0 1618 nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
michael@0 1619 if (sheetService) {
michael@0 1620 // This looks like a lot of work, but in a normal browser session we just
michael@0 1621 // send two loads.
michael@0 1622
michael@0 1623 nsCOMArray<nsIStyleSheet>& agentSheets = *sheetService->AgentStyleSheets();
michael@0 1624 for (uint32_t i = 0; i < agentSheets.Length(); i++) {
michael@0 1625 URIParams uri;
michael@0 1626 SerializeURI(agentSheets[i]->GetSheetURI(), uri);
michael@0 1627 unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AGENT_SHEET);
michael@0 1628 }
michael@0 1629
michael@0 1630 nsCOMArray<nsIStyleSheet>& userSheets = *sheetService->UserStyleSheets();
michael@0 1631 for (uint32_t i = 0; i < userSheets.Length(); i++) {
michael@0 1632 URIParams uri;
michael@0 1633 SerializeURI(userSheets[i]->GetSheetURI(), uri);
michael@0 1634 unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::USER_SHEET);
michael@0 1635 }
michael@0 1636
michael@0 1637 nsCOMArray<nsIStyleSheet>& authorSheets = *sheetService->AuthorStyleSheets();
michael@0 1638 for (uint32_t i = 0; i < authorSheets.Length(); i++) {
michael@0 1639 URIParams uri;
michael@0 1640 SerializeURI(authorSheets[i]->GetSheetURI(), uri);
michael@0 1641 unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AUTHOR_SHEET);
michael@0 1642 }
michael@0 1643 }
michael@0 1644
michael@0 1645 #ifdef MOZ_CONTENT_SANDBOX
michael@0 1646 bool shouldSandbox = true;
michael@0 1647 #ifdef MOZ_NUWA_PROCESS
michael@0 1648 if (IsNuwaProcess()) {
michael@0 1649 shouldSandbox = false;
michael@0 1650 }
michael@0 1651 #endif
michael@0 1652 if (shouldSandbox && !SendSetProcessSandbox()) {
michael@0 1653 KillHard();
michael@0 1654 }
michael@0 1655 #endif
michael@0 1656 }
michael@0 1657
michael@0 1658 bool
michael@0 1659 ContentParent::IsAlive()
michael@0 1660 {
michael@0 1661 return mIsAlive;
michael@0 1662 }
michael@0 1663
michael@0 1664 bool
michael@0 1665 ContentParent::IsForApp()
michael@0 1666 {
michael@0 1667 return !mAppManifestURL.IsEmpty();
michael@0 1668 }
michael@0 1669
michael@0 1670 #ifdef MOZ_NUWA_PROCESS
michael@0 1671 bool
michael@0 1672 ContentParent::IsNuwaProcess()
michael@0 1673 {
michael@0 1674 return mIsNuwaProcess;
michael@0 1675 }
michael@0 1676 #endif
michael@0 1677
michael@0 1678 int32_t
michael@0 1679 ContentParent::Pid()
michael@0 1680 {
michael@0 1681 if (!mSubprocess || !mSubprocess->GetChildProcessHandle()) {
michael@0 1682 return -1;
michael@0 1683 }
michael@0 1684 return base::GetProcId(mSubprocess->GetChildProcessHandle());
michael@0 1685 }
michael@0 1686
michael@0 1687 bool
michael@0 1688 ContentParent::RecvReadPrefsArray(InfallibleTArray<PrefSetting>* aPrefs)
michael@0 1689 {
michael@0 1690 Preferences::GetPreferences(aPrefs);
michael@0 1691 return true;
michael@0 1692 }
michael@0 1693
michael@0 1694 bool
michael@0 1695 ContentParent::RecvReadFontList(InfallibleTArray<FontListEntry>* retValue)
michael@0 1696 {
michael@0 1697 #ifdef ANDROID
michael@0 1698 gfxAndroidPlatform::GetPlatform()->GetFontList(retValue);
michael@0 1699 #endif
michael@0 1700 return true;
michael@0 1701 }
michael@0 1702
michael@0 1703 bool
michael@0 1704 ContentParent::RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions)
michael@0 1705 {
michael@0 1706 #ifdef MOZ_PERMISSIONS
michael@0 1707 nsCOMPtr<nsIPermissionManager> permissionManagerIface =
michael@0 1708 do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
michael@0 1709 nsPermissionManager* permissionManager =
michael@0 1710 static_cast<nsPermissionManager*>(permissionManagerIface.get());
michael@0 1711 NS_ABORT_IF_FALSE(permissionManager,
michael@0 1712 "We have no permissionManager in the Chrome process !");
michael@0 1713
michael@0 1714 nsCOMPtr<nsISimpleEnumerator> enumerator;
michael@0 1715 DebugOnly<nsresult> rv = permissionManager->GetEnumerator(getter_AddRefs(enumerator));
michael@0 1716 NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Could not get enumerator!");
michael@0 1717 while(1) {
michael@0 1718 bool hasMore;
michael@0 1719 enumerator->HasMoreElements(&hasMore);
michael@0 1720 if (!hasMore)
michael@0 1721 break;
michael@0 1722
michael@0 1723 nsCOMPtr<nsISupports> supp;
michael@0 1724 enumerator->GetNext(getter_AddRefs(supp));
michael@0 1725 nsCOMPtr<nsIPermission> perm = do_QueryInterface(supp);
michael@0 1726
michael@0 1727 nsCString host;
michael@0 1728 perm->GetHost(host);
michael@0 1729 uint32_t appId;
michael@0 1730 perm->GetAppId(&appId);
michael@0 1731 bool isInBrowserElement;
michael@0 1732 perm->GetIsInBrowserElement(&isInBrowserElement);
michael@0 1733 nsCString type;
michael@0 1734 perm->GetType(type);
michael@0 1735 uint32_t capability;
michael@0 1736 perm->GetCapability(&capability);
michael@0 1737 uint32_t expireType;
michael@0 1738 perm->GetExpireType(&expireType);
michael@0 1739 int64_t expireTime;
michael@0 1740 perm->GetExpireTime(&expireTime);
michael@0 1741
michael@0 1742 aPermissions->AppendElement(IPC::Permission(host, appId,
michael@0 1743 isInBrowserElement, type,
michael@0 1744 capability, expireType,
michael@0 1745 expireTime));
michael@0 1746 }
michael@0 1747
michael@0 1748 // Ask for future changes
michael@0 1749 mSendPermissionUpdates = true;
michael@0 1750 #endif
michael@0 1751
michael@0 1752 return true;
michael@0 1753 }
michael@0 1754
michael@0 1755 bool
michael@0 1756 ContentParent::RecvSetClipboardText(const nsString& text,
michael@0 1757 const bool& isPrivateData,
michael@0 1758 const int32_t& whichClipboard)
michael@0 1759 {
michael@0 1760 nsresult rv;
michael@0 1761 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
michael@0 1762 NS_ENSURE_SUCCESS(rv, true);
michael@0 1763
michael@0 1764 nsCOMPtr<nsISupportsString> dataWrapper =
michael@0 1765 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
michael@0 1766 NS_ENSURE_SUCCESS(rv, true);
michael@0 1767
michael@0 1768 rv = dataWrapper->SetData(text);
michael@0 1769 NS_ENSURE_SUCCESS(rv, true);
michael@0 1770
michael@0 1771 nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
michael@0 1772 NS_ENSURE_SUCCESS(rv, true);
michael@0 1773 trans->Init(nullptr);
michael@0 1774
michael@0 1775 // If our data flavor has already been added, this will fail. But we don't care
michael@0 1776 trans->AddDataFlavor(kUnicodeMime);
michael@0 1777 trans->SetIsPrivateData(isPrivateData);
michael@0 1778
michael@0 1779 nsCOMPtr<nsISupports> nsisupportsDataWrapper =
michael@0 1780 do_QueryInterface(dataWrapper);
michael@0 1781
michael@0 1782 rv = trans->SetTransferData(kUnicodeMime, nsisupportsDataWrapper,
michael@0 1783 text.Length() * sizeof(char16_t));
michael@0 1784 NS_ENSURE_SUCCESS(rv, true);
michael@0 1785
michael@0 1786 clipboard->SetData(trans, nullptr, whichClipboard);
michael@0 1787 return true;
michael@0 1788 }
michael@0 1789
michael@0 1790 bool
michael@0 1791 ContentParent::RecvGetClipboardText(const int32_t& whichClipboard, nsString* text)
michael@0 1792 {
michael@0 1793 nsresult rv;
michael@0 1794 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
michael@0 1795 NS_ENSURE_SUCCESS(rv, true);
michael@0 1796
michael@0 1797 nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
michael@0 1798 NS_ENSURE_SUCCESS(rv, true);
michael@0 1799 trans->Init(nullptr);
michael@0 1800 trans->AddDataFlavor(kUnicodeMime);
michael@0 1801
michael@0 1802 clipboard->GetData(trans, whichClipboard);
michael@0 1803 nsCOMPtr<nsISupports> tmp;
michael@0 1804 uint32_t len;
michael@0 1805 rv = trans->GetTransferData(kUnicodeMime, getter_AddRefs(tmp), &len);
michael@0 1806 if (NS_FAILED(rv))
michael@0 1807 return true;
michael@0 1808
michael@0 1809 nsCOMPtr<nsISupportsString> supportsString = do_QueryInterface(tmp);
michael@0 1810 // No support for non-text data
michael@0 1811 if (!supportsString)
michael@0 1812 return true;
michael@0 1813 supportsString->GetData(*text);
michael@0 1814 return true;
michael@0 1815 }
michael@0 1816
michael@0 1817 bool
michael@0 1818 ContentParent::RecvEmptyClipboard(const int32_t& whichClipboard)
michael@0 1819 {
michael@0 1820 nsresult rv;
michael@0 1821 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
michael@0 1822 NS_ENSURE_SUCCESS(rv, true);
michael@0 1823
michael@0 1824 clipboard->EmptyClipboard(whichClipboard);
michael@0 1825
michael@0 1826 return true;
michael@0 1827 }
michael@0 1828
michael@0 1829 bool
michael@0 1830 ContentParent::RecvClipboardHasText(const int32_t& whichClipboard, bool* hasText)
michael@0 1831 {
michael@0 1832 nsresult rv;
michael@0 1833 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
michael@0 1834 NS_ENSURE_SUCCESS(rv, true);
michael@0 1835
michael@0 1836 clipboard->HasDataMatchingFlavors(sClipboardTextFlavors, 1,
michael@0 1837 whichClipboard, hasText);
michael@0 1838 return true;
michael@0 1839 }
michael@0 1840
michael@0 1841 bool
michael@0 1842 ContentParent::RecvGetSystemColors(const uint32_t& colorsCount, InfallibleTArray<uint32_t>* colors)
michael@0 1843 {
michael@0 1844 #ifdef MOZ_WIDGET_ANDROID
michael@0 1845 NS_ASSERTION(AndroidBridge::Bridge() != nullptr, "AndroidBridge is not available");
michael@0 1846 if (AndroidBridge::Bridge() == nullptr) {
michael@0 1847 // Do not fail - the colors won't be right, but it's not critical
michael@0 1848 return true;
michael@0 1849 }
michael@0 1850
michael@0 1851 colors->AppendElements(colorsCount);
michael@0 1852
michael@0 1853 // The array elements correspond to the members of AndroidSystemColors structure,
michael@0 1854 // so just pass the pointer to the elements buffer
michael@0 1855 AndroidBridge::Bridge()->GetSystemColors((AndroidSystemColors*)colors->Elements());
michael@0 1856 #endif
michael@0 1857 return true;
michael@0 1858 }
michael@0 1859
michael@0 1860 bool
michael@0 1861 ContentParent::RecvGetIconForExtension(const nsCString& aFileExt, const uint32_t& aIconSize, InfallibleTArray<uint8_t>* bits)
michael@0 1862 {
michael@0 1863 #ifdef MOZ_WIDGET_ANDROID
michael@0 1864 NS_ASSERTION(AndroidBridge::Bridge() != nullptr, "AndroidBridge is not available");
michael@0 1865 if (AndroidBridge::Bridge() == nullptr) {
michael@0 1866 // Do not fail - just no icon will be shown
michael@0 1867 return true;
michael@0 1868 }
michael@0 1869
michael@0 1870 bits->AppendElements(aIconSize * aIconSize * 4);
michael@0 1871
michael@0 1872 AndroidBridge::Bridge()->GetIconForExtension(aFileExt, aIconSize, bits->Elements());
michael@0 1873 #endif
michael@0 1874 return true;
michael@0 1875 }
michael@0 1876
michael@0 1877 bool
michael@0 1878 ContentParent::RecvGetShowPasswordSetting(bool* showPassword)
michael@0 1879 {
michael@0 1880 // default behavior is to show the last password character
michael@0 1881 *showPassword = true;
michael@0 1882 #ifdef MOZ_WIDGET_ANDROID
michael@0 1883 NS_ASSERTION(AndroidBridge::Bridge() != nullptr, "AndroidBridge is not available");
michael@0 1884
michael@0 1885 *showPassword = mozilla::widget::android::GeckoAppShell::GetShowPasswordSetting();
michael@0 1886 #endif
michael@0 1887 return true;
michael@0 1888 }
michael@0 1889
michael@0 1890 bool
michael@0 1891 ContentParent::RecvFirstIdle()
michael@0 1892 {
michael@0 1893 // When the ContentChild goes idle, it sends us a FirstIdle message
michael@0 1894 // which we use as a good time to prelaunch another process. If we
michael@0 1895 // prelaunch any sooner than this, then we'll be competing with the
michael@0 1896 // child process and slowing it down.
michael@0 1897 PreallocatedProcessManager::AllocateAfterDelay();
michael@0 1898 return true;
michael@0 1899 }
michael@0 1900
michael@0 1901 bool
michael@0 1902 ContentParent::RecvAudioChannelGetState(const AudioChannel& aChannel,
michael@0 1903 const bool& aElementHidden,
michael@0 1904 const bool& aElementWasHidden,
michael@0 1905 AudioChannelState* aState)
michael@0 1906 {
michael@0 1907 nsRefPtr<AudioChannelService> service =
michael@0 1908 AudioChannelService::GetAudioChannelService();
michael@0 1909 *aState = AUDIO_CHANNEL_STATE_NORMAL;
michael@0 1910 if (service) {
michael@0 1911 *aState = service->GetStateInternal(aChannel, mChildID,
michael@0 1912 aElementHidden, aElementWasHidden);
michael@0 1913 }
michael@0 1914 return true;
michael@0 1915 }
michael@0 1916
michael@0 1917 bool
michael@0 1918 ContentParent::RecvAudioChannelRegisterType(const AudioChannel& aChannel,
michael@0 1919 const bool& aWithVideo)
michael@0 1920 {
michael@0 1921 nsRefPtr<AudioChannelService> service =
michael@0 1922 AudioChannelService::GetAudioChannelService();
michael@0 1923 if (service) {
michael@0 1924 service->RegisterType(aChannel, mChildID, aWithVideo);
michael@0 1925 }
michael@0 1926 return true;
michael@0 1927 }
michael@0 1928
michael@0 1929 bool
michael@0 1930 ContentParent::RecvAudioChannelUnregisterType(const AudioChannel& aChannel,
michael@0 1931 const bool& aElementHidden,
michael@0 1932 const bool& aWithVideo)
michael@0 1933 {
michael@0 1934 nsRefPtr<AudioChannelService> service =
michael@0 1935 AudioChannelService::GetAudioChannelService();
michael@0 1936 if (service) {
michael@0 1937 service->UnregisterType(aChannel, aElementHidden, mChildID, aWithVideo);
michael@0 1938 }
michael@0 1939 return true;
michael@0 1940 }
michael@0 1941
michael@0 1942 bool
michael@0 1943 ContentParent::RecvAudioChannelChangedNotification()
michael@0 1944 {
michael@0 1945 nsRefPtr<AudioChannelService> service =
michael@0 1946 AudioChannelService::GetAudioChannelService();
michael@0 1947 if (service) {
michael@0 1948 service->SendAudioChannelChangedNotification(ChildID());
michael@0 1949 }
michael@0 1950 return true;
michael@0 1951 }
michael@0 1952
michael@0 1953 bool
michael@0 1954 ContentParent::RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel,
michael@0 1955 const bool& aHidden)
michael@0 1956 {
michael@0 1957 nsRefPtr<AudioChannelService> service =
michael@0 1958 AudioChannelService::GetAudioChannelService();
michael@0 1959 if (service) {
michael@0 1960 service->SetDefaultVolumeControlChannelInternal(aChannel,
michael@0 1961 aHidden, mChildID);
michael@0 1962 }
michael@0 1963 return true;
michael@0 1964 }
michael@0 1965
michael@0 1966 bool
michael@0 1967 ContentParent::RecvBroadcastVolume(const nsString& aVolumeName)
michael@0 1968 {
michael@0 1969 #ifdef MOZ_WIDGET_GONK
michael@0 1970 nsresult rv;
michael@0 1971 nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
michael@0 1972 if (vs) {
michael@0 1973 vs->BroadcastVolume(aVolumeName);
michael@0 1974 }
michael@0 1975 return true;
michael@0 1976 #else
michael@0 1977 NS_WARNING("ContentParent::RecvBroadcastVolume shouldn't be called when MOZ_WIDGET_GONK is not defined");
michael@0 1978 return false;
michael@0 1979 #endif
michael@0 1980 }
michael@0 1981
michael@0 1982 bool
michael@0 1983 ContentParent::RecvNuwaReady()
michael@0 1984 {
michael@0 1985 #ifdef MOZ_NUWA_PROCESS
michael@0 1986 if (!IsNuwaProcess()) {
michael@0 1987 NS_ERROR(
michael@0 1988 nsPrintfCString(
michael@0 1989 "Terminating child process %d for unauthorized IPC message: NuwaReady",
michael@0 1990 Pid()).get());
michael@0 1991
michael@0 1992 KillHard();
michael@0 1993 return false;
michael@0 1994 }
michael@0 1995 PreallocatedProcessManager::OnNuwaReady();
michael@0 1996 return true;
michael@0 1997 #else
michael@0 1998 NS_ERROR("ContentParent::RecvNuwaReady() not implemented!");
michael@0 1999 return false;
michael@0 2000 #endif
michael@0 2001 }
michael@0 2002
michael@0 2003 bool
michael@0 2004 ContentParent::RecvAddNewProcess(const uint32_t& aPid,
michael@0 2005 const InfallibleTArray<ProtocolFdMapping>& aFds)
michael@0 2006 {
michael@0 2007 #ifdef MOZ_NUWA_PROCESS
michael@0 2008 if (!IsNuwaProcess()) {
michael@0 2009 NS_ERROR(
michael@0 2010 nsPrintfCString(
michael@0 2011 "Terminating child process %d for unauthorized IPC message: "
michael@0 2012 "AddNewProcess(%d)", Pid(), aPid).get());
michael@0 2013
michael@0 2014 KillHard();
michael@0 2015 return false;
michael@0 2016 }
michael@0 2017 nsRefPtr<ContentParent> content;
michael@0 2018 content = new ContentParent(this,
michael@0 2019 MAGIC_PREALLOCATED_APP_MANIFEST_URL,
michael@0 2020 aPid,
michael@0 2021 aFds);
michael@0 2022 content->Init();
michael@0 2023 PreallocatedProcessManager::PublishSpareProcess(content);
michael@0 2024 return true;
michael@0 2025 #else
michael@0 2026 NS_ERROR("ContentParent::RecvAddNewProcess() not implemented!");
michael@0 2027 return false;
michael@0 2028 #endif
michael@0 2029 }
michael@0 2030
michael@0 2031 // We want ContentParent to show up in CC logs for debugging purposes, but we
michael@0 2032 // don't actually cycle collect it.
michael@0 2033 NS_IMPL_CYCLE_COLLECTION_0(ContentParent)
michael@0 2034
michael@0 2035 NS_IMPL_CYCLE_COLLECTING_ADDREF(ContentParent)
michael@0 2036 NS_IMPL_CYCLE_COLLECTING_RELEASE(ContentParent)
michael@0 2037
michael@0 2038 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ContentParent)
michael@0 2039 NS_INTERFACE_MAP_ENTRY(nsIObserver)
michael@0 2040 NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionCallback)
michael@0 2041 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
michael@0 2042 NS_INTERFACE_MAP_END
michael@0 2043
michael@0 2044 NS_IMETHODIMP
michael@0 2045 ContentParent::Observe(nsISupports* aSubject,
michael@0 2046 const char* aTopic,
michael@0 2047 const char16_t* aData)
michael@0 2048 {
michael@0 2049 if (!strcmp(aTopic, "xpcom-shutdown") && mSubprocess) {
michael@0 2050 ShutDownProcess(/* closeWithError */ false);
michael@0 2051 NS_ASSERTION(!mSubprocess, "Close should have nulled mSubprocess");
michael@0 2052 }
michael@0 2053
michael@0 2054 if (!mIsAlive || !mSubprocess)
michael@0 2055 return NS_OK;
michael@0 2056
michael@0 2057 // listening for memory pressure event
michael@0 2058 if (!strcmp(aTopic, "memory-pressure") &&
michael@0 2059 !StringEndsWith(nsDependentString(aData),
michael@0 2060 NS_LITERAL_STRING("-no-forward"))) {
michael@0 2061 unused << SendFlushMemory(nsDependentString(aData));
michael@0 2062 }
michael@0 2063 // listening for remotePrefs...
michael@0 2064 else if (!strcmp(aTopic, "nsPref:changed")) {
michael@0 2065 // We know prefs are ASCII here.
michael@0 2066 NS_LossyConvertUTF16toASCII strData(aData);
michael@0 2067
michael@0 2068 PrefSetting pref(strData, null_t(), null_t());
michael@0 2069 Preferences::GetPreference(&pref);
michael@0 2070 if (!SendPreferenceUpdate(pref)) {
michael@0 2071 return NS_ERROR_NOT_AVAILABLE;
michael@0 2072 }
michael@0 2073 }
michael@0 2074 else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) {
michael@0 2075 NS_ConvertUTF16toUTF8 dataStr(aData);
michael@0 2076 const char *offline = dataStr.get();
michael@0 2077 if (!SendSetOffline(!strcmp(offline, "true") ? true : false))
michael@0 2078 return NS_ERROR_NOT_AVAILABLE;
michael@0 2079 }
michael@0 2080 // listening for alert notifications
michael@0 2081 else if (!strcmp(aTopic, "alertfinished") ||
michael@0 2082 !strcmp(aTopic, "alertclickcallback") ||
michael@0 2083 !strcmp(aTopic, "alertshow") ) {
michael@0 2084 if (!SendNotifyAlertsObserver(nsDependentCString(aTopic),
michael@0 2085 nsDependentString(aData)))
michael@0 2086 return NS_ERROR_NOT_AVAILABLE;
michael@0 2087 }
michael@0 2088 else if (!strcmp(aTopic, "child-memory-reporter-request")) {
michael@0 2089 bool isNuwa = false;
michael@0 2090 #ifdef MOZ_NUWA_PROCESS
michael@0 2091 isNuwa = IsNuwaProcess();
michael@0 2092 #endif
michael@0 2093 if (!isNuwa) {
michael@0 2094 unsigned generation;
michael@0 2095 int minimize, identOffset = -1;
michael@0 2096 nsDependentString msg(aData);
michael@0 2097 NS_ConvertUTF16toUTF8 cmsg(msg);
michael@0 2098
michael@0 2099 if (sscanf(cmsg.get(),
michael@0 2100 "generation=%x minimize=%d DMDident=%n",
michael@0 2101 &generation, &minimize, &identOffset) < 2
michael@0 2102 || identOffset < 0) {
michael@0 2103 return NS_ERROR_INVALID_ARG;
michael@0 2104 }
michael@0 2105 // The pre-%n part of the string should be all ASCII, so the byte
michael@0 2106 // offset in identOffset should be correct as a char offset.
michael@0 2107 MOZ_ASSERT(cmsg[identOffset - 1] == '=');
michael@0 2108 unused << SendPMemoryReportRequestConstructor(
michael@0 2109 generation, minimize, nsString(Substring(msg, identOffset)));
michael@0 2110 }
michael@0 2111 }
michael@0 2112 else if (!strcmp(aTopic, "child-gc-request")){
michael@0 2113 unused << SendGarbageCollect();
michael@0 2114 }
michael@0 2115 else if (!strcmp(aTopic, "child-cc-request")){
michael@0 2116 unused << SendCycleCollect();
michael@0 2117 }
michael@0 2118 else if (!strcmp(aTopic, "child-mmu-request")){
michael@0 2119 unused << SendMinimizeMemoryUsage();
michael@0 2120 }
michael@0 2121 else if (!strcmp(aTopic, "last-pb-context-exited")) {
michael@0 2122 unused << SendLastPrivateDocShellDestroyed();
michael@0 2123 }
michael@0 2124 else if (!strcmp(aTopic, "file-watcher-update")) {
michael@0 2125 nsCString creason;
michael@0 2126 CopyUTF16toUTF8(aData, creason);
michael@0 2127 DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject);
michael@0 2128
michael@0 2129 unused << SendFilePathUpdate(file->mStorageType, file->mStorageName, file->mPath, creason);
michael@0 2130 }
michael@0 2131 #ifdef MOZ_WIDGET_GONK
michael@0 2132 else if(!strcmp(aTopic, NS_VOLUME_STATE_CHANGED)) {
michael@0 2133 nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject);
michael@0 2134 if (!vol) {
michael@0 2135 return NS_ERROR_NOT_AVAILABLE;
michael@0 2136 }
michael@0 2137
michael@0 2138 nsString volName;
michael@0 2139 nsString mountPoint;
michael@0 2140 int32_t state;
michael@0 2141 int32_t mountGeneration;
michael@0 2142 bool isMediaPresent;
michael@0 2143 bool isSharing;
michael@0 2144 bool isFormatting;
michael@0 2145
michael@0 2146 vol->GetName(volName);
michael@0 2147 vol->GetMountPoint(mountPoint);
michael@0 2148 vol->GetState(&state);
michael@0 2149 vol->GetMountGeneration(&mountGeneration);
michael@0 2150 vol->GetIsMediaPresent(&isMediaPresent);
michael@0 2151 vol->GetIsSharing(&isSharing);
michael@0 2152 vol->GetIsFormatting(&isFormatting);
michael@0 2153
michael@0 2154 unused << SendFileSystemUpdate(volName, mountPoint, state,
michael@0 2155 mountGeneration, isMediaPresent,
michael@0 2156 isSharing, isFormatting);
michael@0 2157 } else if (!strcmp(aTopic, "phone-state-changed")) {
michael@0 2158 nsString state(aData);
michael@0 2159 unused << SendNotifyPhoneStateChange(state);
michael@0 2160 }
michael@0 2161 #endif
michael@0 2162 #ifdef ACCESSIBILITY
michael@0 2163 // Make sure accessibility is running in content process when accessibility
michael@0 2164 // gets initiated in chrome process.
michael@0 2165 else if (aData && (*aData == '1') &&
michael@0 2166 !strcmp(aTopic, "a11y-init-or-shutdown")) {
michael@0 2167 unused << SendActivateA11y();
michael@0 2168 }
michael@0 2169 #endif
michael@0 2170
michael@0 2171 return NS_OK;
michael@0 2172 }
michael@0 2173
michael@0 2174 PCompositorParent*
michael@0 2175 ContentParent::AllocPCompositorParent(mozilla::ipc::Transport* aTransport,
michael@0 2176 base::ProcessId aOtherProcess)
michael@0 2177 {
michael@0 2178 return CompositorParent::Create(aTransport, aOtherProcess);
michael@0 2179 }
michael@0 2180
michael@0 2181 PImageBridgeParent*
michael@0 2182 ContentParent::AllocPImageBridgeParent(mozilla::ipc::Transport* aTransport,
michael@0 2183 base::ProcessId aOtherProcess)
michael@0 2184 {
michael@0 2185 return ImageBridgeParent::Create(aTransport, aOtherProcess);
michael@0 2186 }
michael@0 2187
michael@0 2188 PBackgroundParent*
michael@0 2189 ContentParent::AllocPBackgroundParent(Transport* aTransport,
michael@0 2190 ProcessId aOtherProcess)
michael@0 2191 {
michael@0 2192 return BackgroundParent::Alloc(this, aTransport, aOtherProcess);
michael@0 2193 }
michael@0 2194
michael@0 2195 bool
michael@0 2196 ContentParent::RecvGetProcessAttributes(uint64_t* aId,
michael@0 2197 bool* aIsForApp, bool* aIsForBrowser)
michael@0 2198 {
michael@0 2199 *aId = mChildID;
michael@0 2200 *aIsForApp = IsForApp();
michael@0 2201 *aIsForBrowser = mIsForBrowser;
michael@0 2202
michael@0 2203 return true;
michael@0 2204 }
michael@0 2205
michael@0 2206 bool
michael@0 2207 ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline)
michael@0 2208 {
michael@0 2209 nsCOMPtr<nsIIOService> io(do_GetIOService());
michael@0 2210 NS_ASSERTION(io, "No IO service?");
michael@0 2211 DebugOnly<nsresult> rv = io->GetOffline(aIsOffline);
michael@0 2212 NS_ASSERTION(NS_SUCCEEDED(rv), "Failed getting offline?");
michael@0 2213
michael@0 2214 return true;
michael@0 2215 }
michael@0 2216
michael@0 2217 mozilla::jsipc::PJavaScriptParent *
michael@0 2218 ContentParent::AllocPJavaScriptParent()
michael@0 2219 {
michael@0 2220 mozilla::jsipc::JavaScriptParent *parent = new mozilla::jsipc::JavaScriptParent();
michael@0 2221 if (!parent->init()) {
michael@0 2222 delete parent;
michael@0 2223 return nullptr;
michael@0 2224 }
michael@0 2225 return parent;
michael@0 2226 }
michael@0 2227
michael@0 2228 bool
michael@0 2229 ContentParent::DeallocPJavaScriptParent(PJavaScriptParent *parent)
michael@0 2230 {
michael@0 2231 static_cast<mozilla::jsipc::JavaScriptParent *>(parent)->decref();
michael@0 2232 return true;
michael@0 2233 }
michael@0 2234
michael@0 2235 PBrowserParent*
michael@0 2236 ContentParent::AllocPBrowserParent(const IPCTabContext& aContext,
michael@0 2237 const uint32_t &aChromeFlags)
michael@0 2238 {
michael@0 2239 unused << aChromeFlags;
michael@0 2240
michael@0 2241 const IPCTabAppBrowserContext& appBrowser = aContext.appBrowserContext();
michael@0 2242
michael@0 2243 // We don't trust the IPCTabContext we receive from the child, so we'll bail
michael@0 2244 // if we receive an IPCTabContext that's not a PopupIPCTabContext.
michael@0 2245 // (PopupIPCTabContext lets the child process prove that it has access to
michael@0 2246 // the app it's trying to open.)
michael@0 2247 if (appBrowser.type() != IPCTabAppBrowserContext::TPopupIPCTabContext) {
michael@0 2248 NS_ERROR("Unexpected IPCTabContext type. Aborting AllocPBrowserParent.");
michael@0 2249 return nullptr;
michael@0 2250 }
michael@0 2251
michael@0 2252 const PopupIPCTabContext& popupContext = appBrowser.get_PopupIPCTabContext();
michael@0 2253 TabParent* opener = static_cast<TabParent*>(popupContext.openerParent());
michael@0 2254 if (!opener) {
michael@0 2255 NS_ERROR("Got null opener from child; aborting AllocPBrowserParent.");
michael@0 2256 return nullptr;
michael@0 2257 }
michael@0 2258
michael@0 2259 // Popup windows of isBrowser frames must be isBrowser if the parent
michael@0 2260 // isBrowser. Allocating a !isBrowser frame with same app ID would allow
michael@0 2261 // the content to access data it's not supposed to.
michael@0 2262 if (!popupContext.isBrowserElement() && opener->IsBrowserElement()) {
michael@0 2263 NS_ERROR("Child trying to escalate privileges! Aborting AllocPBrowserParent.");
michael@0 2264 return nullptr;
michael@0 2265 }
michael@0 2266
michael@0 2267 MaybeInvalidTabContext tc(aContext);
michael@0 2268 if (!tc.IsValid()) {
michael@0 2269 NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext. (%s) "
michael@0 2270 "Aborting AllocPBrowserParent.",
michael@0 2271 tc.GetInvalidReason()).get());
michael@0 2272 return nullptr;
michael@0 2273 }
michael@0 2274
michael@0 2275 TabParent* parent = new TabParent(this, tc.GetTabContext(), aChromeFlags);
michael@0 2276
michael@0 2277 // We release this ref in DeallocPBrowserParent()
michael@0 2278 NS_ADDREF(parent);
michael@0 2279 return parent;
michael@0 2280 }
michael@0 2281
michael@0 2282 bool
michael@0 2283 ContentParent::DeallocPBrowserParent(PBrowserParent* frame)
michael@0 2284 {
michael@0 2285 TabParent* parent = static_cast<TabParent*>(frame);
michael@0 2286 NS_RELEASE(parent);
michael@0 2287 return true;
michael@0 2288 }
michael@0 2289
michael@0 2290 PDeviceStorageRequestParent*
michael@0 2291 ContentParent::AllocPDeviceStorageRequestParent(const DeviceStorageParams& aParams)
michael@0 2292 {
michael@0 2293 nsRefPtr<DeviceStorageRequestParent> result = new DeviceStorageRequestParent(aParams);
michael@0 2294 if (!result->EnsureRequiredPermissions(this)) {
michael@0 2295 return nullptr;
michael@0 2296 }
michael@0 2297 result->Dispatch();
michael@0 2298 return result.forget().take();
michael@0 2299 }
michael@0 2300
michael@0 2301 bool
michael@0 2302 ContentParent::DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent* doomed)
michael@0 2303 {
michael@0 2304 DeviceStorageRequestParent *parent = static_cast<DeviceStorageRequestParent*>(doomed);
michael@0 2305 NS_RELEASE(parent);
michael@0 2306 return true;
michael@0 2307 }
michael@0 2308
michael@0 2309 PFileSystemRequestParent*
michael@0 2310 ContentParent::AllocPFileSystemRequestParent(const FileSystemParams& aParams)
michael@0 2311 {
michael@0 2312 nsRefPtr<FileSystemRequestParent> result = new FileSystemRequestParent();
michael@0 2313 if (!result->Dispatch(this, aParams)) {
michael@0 2314 return nullptr;
michael@0 2315 }
michael@0 2316 return result.forget().take();
michael@0 2317 }
michael@0 2318
michael@0 2319 bool
michael@0 2320 ContentParent::DeallocPFileSystemRequestParent(PFileSystemRequestParent* doomed)
michael@0 2321 {
michael@0 2322 FileSystemRequestParent* parent = static_cast<FileSystemRequestParent*>(doomed);
michael@0 2323 NS_RELEASE(parent);
michael@0 2324 return true;
michael@0 2325 }
michael@0 2326
michael@0 2327 PBlobParent*
michael@0 2328 ContentParent::AllocPBlobParent(const BlobConstructorParams& aParams)
michael@0 2329 {
michael@0 2330 return BlobParent::Create(this, aParams);
michael@0 2331 }
michael@0 2332
michael@0 2333 bool
michael@0 2334 ContentParent::DeallocPBlobParent(PBlobParent* aActor)
michael@0 2335 {
michael@0 2336 delete aActor;
michael@0 2337 return true;
michael@0 2338 }
michael@0 2339
michael@0 2340 BlobParent*
michael@0 2341 ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
michael@0 2342 {
michael@0 2343 MOZ_ASSERT(NS_IsMainThread());
michael@0 2344 MOZ_ASSERT(aBlob);
michael@0 2345
michael@0 2346 // If the blob represents a remote blob for this ContentParent then we can
michael@0 2347 // simply pass its actor back here.
michael@0 2348 if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob)) {
michael@0 2349 if (BlobParent* actor = static_cast<BlobParent*>(
michael@0 2350 static_cast<PBlobParent*>(remoteBlob->GetPBlob()))) {
michael@0 2351 if (static_cast<ContentParent*>(actor->Manager()) == this) {
michael@0 2352 return actor;
michael@0 2353 }
michael@0 2354 }
michael@0 2355 }
michael@0 2356
michael@0 2357 // XXX This is only safe so long as all blob implementations in our tree
michael@0 2358 // inherit nsDOMFileBase. If that ever changes then this will need to grow
michael@0 2359 // a real interface or something.
michael@0 2360 const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
michael@0 2361
michael@0 2362 // We often pass blobs that are multipart but that only contain one sub-blob
michael@0 2363 // (WebActivities does this a bunch). Unwrap to reduce the number of actors
michael@0 2364 // that we have to maintain.
michael@0 2365 const nsTArray<nsCOMPtr<nsIDOMBlob> >* subBlobs = blob->GetSubBlobs();
michael@0 2366 if (subBlobs && subBlobs->Length() == 1) {
michael@0 2367 const nsCOMPtr<nsIDOMBlob>& subBlob = subBlobs->ElementAt(0);
michael@0 2368 MOZ_ASSERT(subBlob);
michael@0 2369
michael@0 2370 // We can only take this shortcut if the multipart and the sub-blob are both
michael@0 2371 // Blob objects or both File objects.
michael@0 2372 nsCOMPtr<nsIDOMFile> multipartBlobAsFile = do_QueryInterface(aBlob);
michael@0 2373 nsCOMPtr<nsIDOMFile> subBlobAsFile = do_QueryInterface(subBlob);
michael@0 2374 if (!multipartBlobAsFile == !subBlobAsFile) {
michael@0 2375 // The wrapping might have been unnecessary, see if we can simply pass an
michael@0 2376 // existing remote blob for this ContentParent.
michael@0 2377 if (nsCOMPtr<nsIRemoteBlob> remoteSubBlob = do_QueryInterface(subBlob)) {
michael@0 2378 BlobParent* actor =
michael@0 2379 static_cast<BlobParent*>(
michael@0 2380 static_cast<PBlobParent*>(remoteSubBlob->GetPBlob()));
michael@0 2381 MOZ_ASSERT(actor);
michael@0 2382
michael@0 2383 if (static_cast<ContentParent*>(actor->Manager()) == this) {
michael@0 2384 return actor;
michael@0 2385 }
michael@0 2386 }
michael@0 2387
michael@0 2388 // No need to add a reference here since the original blob must have a
michael@0 2389 // strong reference in the caller and it must also have a strong reference
michael@0 2390 // to this sub-blob.
michael@0 2391 aBlob = subBlob;
michael@0 2392 blob = static_cast<nsDOMFileBase*>(aBlob);
michael@0 2393 subBlobs = blob->GetSubBlobs();
michael@0 2394 }
michael@0 2395 }
michael@0 2396
michael@0 2397 // All blobs shared between processes must be immutable.
michael@0 2398 nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
michael@0 2399 if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
michael@0 2400 NS_WARNING("Failed to make blob immutable!");
michael@0 2401 return nullptr;
michael@0 2402 }
michael@0 2403
michael@0 2404 ChildBlobConstructorParams params;
michael@0 2405
michael@0 2406 if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
michael@0 2407 // We don't want to call GetSize or GetLastModifiedDate
michael@0 2408 // yet since that may stat a file on the main thread
michael@0 2409 // here. Instead we'll learn the size lazily from the
michael@0 2410 // other process.
michael@0 2411 params = MysteryBlobConstructorParams();
michael@0 2412 }
michael@0 2413 else {
michael@0 2414 nsString contentType;
michael@0 2415 nsresult rv = aBlob->GetType(contentType);
michael@0 2416 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 2417
michael@0 2418 uint64_t length;
michael@0 2419 rv = aBlob->GetSize(&length);
michael@0 2420 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 2421
michael@0 2422 nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
michael@0 2423 if (file) {
michael@0 2424 FileBlobConstructorParams fileParams;
michael@0 2425
michael@0 2426 rv = file->GetMozLastModifiedDate(&fileParams.modDate());
michael@0 2427 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 2428
michael@0 2429 rv = file->GetName(fileParams.name());
michael@0 2430 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 2431
michael@0 2432 fileParams.contentType() = contentType;
michael@0 2433 fileParams.length() = length;
michael@0 2434
michael@0 2435 params = fileParams;
michael@0 2436 } else {
michael@0 2437 NormalBlobConstructorParams blobParams;
michael@0 2438 blobParams.contentType() = contentType;
michael@0 2439 blobParams.length() = length;
michael@0 2440 params = blobParams;
michael@0 2441 }
michael@0 2442 }
michael@0 2443
michael@0 2444 BlobParent* actor = BlobParent::Create(this, aBlob);
michael@0 2445 NS_ENSURE_TRUE(actor, nullptr);
michael@0 2446
michael@0 2447 return SendPBlobConstructor(actor, params) ? actor : nullptr;
michael@0 2448 }
michael@0 2449
michael@0 2450 void
michael@0 2451 ContentParent::KillHard()
michael@0 2452 {
michael@0 2453 // On Windows, calling KillHard multiple times causes problems - the
michael@0 2454 // process handle becomes invalid on the first call, causing a second call
michael@0 2455 // to crash our process - more details in bug 890840.
michael@0 2456 if (mCalledKillHard) {
michael@0 2457 return;
michael@0 2458 }
michael@0 2459 mCalledKillHard = true;
michael@0 2460 mForceKillTask = nullptr;
michael@0 2461 // This ensures the process is eventually killed, but doesn't
michael@0 2462 // immediately KILLITWITHFIRE because we want to get a minidump if
michael@0 2463 // possible. After a timeout though, the process is forceably
michael@0 2464 // killed.
michael@0 2465 if (!KillProcess(OtherProcess(), 1, false)) {
michael@0 2466 NS_WARNING("failed to kill subprocess!");
michael@0 2467 }
michael@0 2468 mSubprocess->SetAlreadyDead();
michael@0 2469 XRE_GetIOMessageLoop()->PostTask(
michael@0 2470 FROM_HERE,
michael@0 2471 NewRunnableFunction(&ProcessWatcher::EnsureProcessTerminated,
michael@0 2472 OtherProcess(), /*force=*/true));
michael@0 2473 //We do clean-up here
michael@0 2474 MessageLoop::current()->PostDelayedTask(
michael@0 2475 FROM_HERE,
michael@0 2476 NewRunnableMethod(this, &ContentParent::ShutDownProcess,
michael@0 2477 /* closeWithError */ true),
michael@0 2478 3000);
michael@0 2479 // We've now closed the OtherProcess() handle, so must set it to null to
michael@0 2480 // prevent our dtor closing it twice.
michael@0 2481 SetOtherProcess(0);
michael@0 2482 }
michael@0 2483
michael@0 2484 bool
michael@0 2485 ContentParent::IsPreallocated()
michael@0 2486 {
michael@0 2487 return mAppManifestURL == MAGIC_PREALLOCATED_APP_MANIFEST_URL;
michael@0 2488 }
michael@0 2489
michael@0 2490 void
michael@0 2491 ContentParent::FriendlyName(nsAString& aName)
michael@0 2492 {
michael@0 2493 aName.Truncate();
michael@0 2494 #ifdef MOZ_NUWA_PROCESS
michael@0 2495 if (IsNuwaProcess()) {
michael@0 2496 aName.AssignLiteral("(Nuwa)");
michael@0 2497 } else
michael@0 2498 #endif
michael@0 2499 if (IsPreallocated()) {
michael@0 2500 aName.AssignLiteral("(Preallocated)");
michael@0 2501 } else if (mIsForBrowser) {
michael@0 2502 aName.AssignLiteral("Browser");
michael@0 2503 } else if (!mAppName.IsEmpty()) {
michael@0 2504 aName = mAppName;
michael@0 2505 } else if (!mAppManifestURL.IsEmpty()) {
michael@0 2506 aName.AssignLiteral("Unknown app: ");
michael@0 2507 aName.Append(mAppManifestURL);
michael@0 2508 } else {
michael@0 2509 aName.AssignLiteral("???");
michael@0 2510 }
michael@0 2511 }
michael@0 2512
michael@0 2513 PCrashReporterParent*
michael@0 2514 ContentParent::AllocPCrashReporterParent(const NativeThreadId& tid,
michael@0 2515 const uint32_t& processType)
michael@0 2516 {
michael@0 2517 #ifdef MOZ_CRASHREPORTER
michael@0 2518 return new CrashReporterParent();
michael@0 2519 #else
michael@0 2520 return nullptr;
michael@0 2521 #endif
michael@0 2522 }
michael@0 2523
michael@0 2524 bool
michael@0 2525 ContentParent::RecvPCrashReporterConstructor(PCrashReporterParent* actor,
michael@0 2526 const NativeThreadId& tid,
michael@0 2527 const uint32_t& processType)
michael@0 2528 {
michael@0 2529 static_cast<CrashReporterParent*>(actor)->SetChildData(tid, processType);
michael@0 2530 return true;
michael@0 2531 }
michael@0 2532
michael@0 2533 bool
michael@0 2534 ContentParent::DeallocPCrashReporterParent(PCrashReporterParent* crashreporter)
michael@0 2535 {
michael@0 2536 delete crashreporter;
michael@0 2537 return true;
michael@0 2538 }
michael@0 2539
michael@0 2540 hal_sandbox::PHalParent*
michael@0 2541 ContentParent::AllocPHalParent()
michael@0 2542 {
michael@0 2543 return hal_sandbox::CreateHalParent();
michael@0 2544 }
michael@0 2545
michael@0 2546 bool
michael@0 2547 ContentParent::DeallocPHalParent(hal_sandbox::PHalParent* aHal)
michael@0 2548 {
michael@0 2549 delete aHal;
michael@0 2550 return true;
michael@0 2551 }
michael@0 2552
michael@0 2553 PIndexedDBParent*
michael@0 2554 ContentParent::AllocPIndexedDBParent()
michael@0 2555 {
michael@0 2556 return new IndexedDBParent(this);
michael@0 2557 }
michael@0 2558
michael@0 2559 bool
michael@0 2560 ContentParent::DeallocPIndexedDBParent(PIndexedDBParent* aActor)
michael@0 2561 {
michael@0 2562 delete aActor;
michael@0 2563 return true;
michael@0 2564 }
michael@0 2565
michael@0 2566 bool
michael@0 2567 ContentParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor)
michael@0 2568 {
michael@0 2569 nsRefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::GetOrCreate();
michael@0 2570 NS_ENSURE_TRUE(mgr, false);
michael@0 2571
michael@0 2572 if (!IndexedDatabaseManager::IsMainProcess()) {
michael@0 2573 NS_RUNTIMEABORT("Not supported yet!");
michael@0 2574 }
michael@0 2575
michael@0 2576 nsRefPtr<IDBFactory> factory;
michael@0 2577 nsresult rv = IDBFactory::Create(this, getter_AddRefs(factory));
michael@0 2578 NS_ENSURE_SUCCESS(rv, false);
michael@0 2579
michael@0 2580 NS_ASSERTION(factory, "This should never be null!");
michael@0 2581
michael@0 2582 IndexedDBParent* actor = static_cast<IndexedDBParent*>(aActor);
michael@0 2583 actor->mFactory = factory;
michael@0 2584 actor->mASCIIOrigin = factory->GetASCIIOrigin();
michael@0 2585
michael@0 2586 return true;
michael@0 2587 }
michael@0 2588
michael@0 2589 PMemoryReportRequestParent*
michael@0 2590 ContentParent::AllocPMemoryReportRequestParent(const uint32_t& generation,
michael@0 2591 const bool &minimizeMemoryUsage,
michael@0 2592 const nsString &aDMDDumpIdent)
michael@0 2593 {
michael@0 2594 MemoryReportRequestParent* parent = new MemoryReportRequestParent();
michael@0 2595 return parent;
michael@0 2596 }
michael@0 2597
michael@0 2598 bool
michael@0 2599 ContentParent::DeallocPMemoryReportRequestParent(PMemoryReportRequestParent* actor)
michael@0 2600 {
michael@0 2601 delete actor;
michael@0 2602 return true;
michael@0 2603 }
michael@0 2604
michael@0 2605 PTestShellParent*
michael@0 2606 ContentParent::AllocPTestShellParent()
michael@0 2607 {
michael@0 2608 return new TestShellParent();
michael@0 2609 }
michael@0 2610
michael@0 2611 bool
michael@0 2612 ContentParent::DeallocPTestShellParent(PTestShellParent* shell)
michael@0 2613 {
michael@0 2614 delete shell;
michael@0 2615 return true;
michael@0 2616 }
michael@0 2617
michael@0 2618 PNeckoParent*
michael@0 2619 ContentParent::AllocPNeckoParent()
michael@0 2620 {
michael@0 2621 return new NeckoParent();
michael@0 2622 }
michael@0 2623
michael@0 2624 bool
michael@0 2625 ContentParent::DeallocPNeckoParent(PNeckoParent* necko)
michael@0 2626 {
michael@0 2627 delete necko;
michael@0 2628 return true;
michael@0 2629 }
michael@0 2630
michael@0 2631 PExternalHelperAppParent*
michael@0 2632 ContentParent::AllocPExternalHelperAppParent(const OptionalURIParams& uri,
michael@0 2633 const nsCString& aMimeContentType,
michael@0 2634 const nsCString& aContentDisposition,
michael@0 2635 const uint32_t& aContentDispositionHint,
michael@0 2636 const nsString& aContentDispositionFilename,
michael@0 2637 const bool& aForceSave,
michael@0 2638 const int64_t& aContentLength,
michael@0 2639 const OptionalURIParams& aReferrer,
michael@0 2640 PBrowserParent* aBrowser)
michael@0 2641 {
michael@0 2642 ExternalHelperAppParent *parent = new ExternalHelperAppParent(uri, aContentLength);
michael@0 2643 parent->AddRef();
michael@0 2644 parent->Init(this,
michael@0 2645 aMimeContentType,
michael@0 2646 aContentDisposition,
michael@0 2647 aContentDispositionHint,
michael@0 2648 aContentDispositionFilename,
michael@0 2649 aForceSave,
michael@0 2650 aReferrer,
michael@0 2651 aBrowser);
michael@0 2652 return parent;
michael@0 2653 }
michael@0 2654
michael@0 2655 bool
michael@0 2656 ContentParent::DeallocPExternalHelperAppParent(PExternalHelperAppParent* aService)
michael@0 2657 {
michael@0 2658 ExternalHelperAppParent *parent = static_cast<ExternalHelperAppParent *>(aService);
michael@0 2659 parent->Release();
michael@0 2660 return true;
michael@0 2661 }
michael@0 2662
michael@0 2663 PSmsParent*
michael@0 2664 ContentParent::AllocPSmsParent()
michael@0 2665 {
michael@0 2666 if (!AssertAppProcessPermission(this, "sms")) {
michael@0 2667 return nullptr;
michael@0 2668 }
michael@0 2669
michael@0 2670 SmsParent* parent = new SmsParent();
michael@0 2671 parent->AddRef();
michael@0 2672 return parent;
michael@0 2673 }
michael@0 2674
michael@0 2675 bool
michael@0 2676 ContentParent::DeallocPSmsParent(PSmsParent* aSms)
michael@0 2677 {
michael@0 2678 static_cast<SmsParent*>(aSms)->Release();
michael@0 2679 return true;
michael@0 2680 }
michael@0 2681
michael@0 2682 PTelephonyParent*
michael@0 2683 ContentParent::AllocPTelephonyParent()
michael@0 2684 {
michael@0 2685 if (!AssertAppProcessPermission(this, "telephony")) {
michael@0 2686 return nullptr;
michael@0 2687 }
michael@0 2688
michael@0 2689 TelephonyParent* actor = new TelephonyParent();
michael@0 2690 NS_ADDREF(actor);
michael@0 2691 return actor;
michael@0 2692 }
michael@0 2693
michael@0 2694 bool
michael@0 2695 ContentParent::DeallocPTelephonyParent(PTelephonyParent* aActor)
michael@0 2696 {
michael@0 2697 static_cast<TelephonyParent*>(aActor)->Release();
michael@0 2698 return true;
michael@0 2699 }
michael@0 2700
michael@0 2701 PStorageParent*
michael@0 2702 ContentParent::AllocPStorageParent()
michael@0 2703 {
michael@0 2704 return new DOMStorageDBParent();
michael@0 2705 }
michael@0 2706
michael@0 2707 bool
michael@0 2708 ContentParent::DeallocPStorageParent(PStorageParent* aActor)
michael@0 2709 {
michael@0 2710 DOMStorageDBParent* child = static_cast<DOMStorageDBParent*>(aActor);
michael@0 2711 child->ReleaseIPDLReference();
michael@0 2712 return true;
michael@0 2713 }
michael@0 2714
michael@0 2715 PBluetoothParent*
michael@0 2716 ContentParent::AllocPBluetoothParent()
michael@0 2717 {
michael@0 2718 #ifdef MOZ_B2G_BT
michael@0 2719 if (!AssertAppProcessPermission(this, "bluetooth")) {
michael@0 2720 return nullptr;
michael@0 2721 }
michael@0 2722 return new mozilla::dom::bluetooth::BluetoothParent();
michael@0 2723 #else
michael@0 2724 MOZ_CRASH("No support for bluetooth on this platform!");
michael@0 2725 #endif
michael@0 2726 }
michael@0 2727
michael@0 2728 bool
michael@0 2729 ContentParent::DeallocPBluetoothParent(PBluetoothParent* aActor)
michael@0 2730 {
michael@0 2731 #ifdef MOZ_B2G_BT
michael@0 2732 delete aActor;
michael@0 2733 return true;
michael@0 2734 #else
michael@0 2735 MOZ_CRASH("No support for bluetooth on this platform!");
michael@0 2736 #endif
michael@0 2737 }
michael@0 2738
michael@0 2739 bool
michael@0 2740 ContentParent::RecvPBluetoothConstructor(PBluetoothParent* aActor)
michael@0 2741 {
michael@0 2742 #ifdef MOZ_B2G_BT
michael@0 2743 nsRefPtr<BluetoothService> btService = BluetoothService::Get();
michael@0 2744 NS_ENSURE_TRUE(btService, false);
michael@0 2745
michael@0 2746 return static_cast<BluetoothParent*>(aActor)->InitWithService(btService);
michael@0 2747 #else
michael@0 2748 MOZ_CRASH("No support for bluetooth on this platform!");
michael@0 2749 #endif
michael@0 2750 }
michael@0 2751
michael@0 2752 PFMRadioParent*
michael@0 2753 ContentParent::AllocPFMRadioParent()
michael@0 2754 {
michael@0 2755 #ifdef MOZ_B2G_FM
michael@0 2756 if (!AssertAppProcessPermission(this, "fmradio")) {
michael@0 2757 return nullptr;
michael@0 2758 }
michael@0 2759 return new FMRadioParent();
michael@0 2760 #else
michael@0 2761 NS_WARNING("No support for FMRadio on this platform!");
michael@0 2762 return nullptr;
michael@0 2763 #endif
michael@0 2764 }
michael@0 2765
michael@0 2766 bool
michael@0 2767 ContentParent::DeallocPFMRadioParent(PFMRadioParent* aActor)
michael@0 2768 {
michael@0 2769 #ifdef MOZ_B2G_FM
michael@0 2770 delete aActor;
michael@0 2771 return true;
michael@0 2772 #else
michael@0 2773 NS_WARNING("No support for FMRadio on this platform!");
michael@0 2774 return false;
michael@0 2775 #endif
michael@0 2776 }
michael@0 2777
michael@0 2778 asmjscache::PAsmJSCacheEntryParent*
michael@0 2779 ContentParent::AllocPAsmJSCacheEntryParent(
michael@0 2780 const asmjscache::OpenMode& aOpenMode,
michael@0 2781 const asmjscache::WriteParams& aWriteParams,
michael@0 2782 const IPC::Principal& aPrincipal)
michael@0 2783 {
michael@0 2784 return asmjscache::AllocEntryParent(aOpenMode, aWriteParams, aPrincipal);
michael@0 2785 }
michael@0 2786
michael@0 2787 bool
michael@0 2788 ContentParent::DeallocPAsmJSCacheEntryParent(PAsmJSCacheEntryParent* aActor)
michael@0 2789 {
michael@0 2790 asmjscache::DeallocEntryParent(aActor);
michael@0 2791 return true;
michael@0 2792 }
michael@0 2793
michael@0 2794 PSpeechSynthesisParent*
michael@0 2795 ContentParent::AllocPSpeechSynthesisParent()
michael@0 2796 {
michael@0 2797 #ifdef MOZ_WEBSPEECH
michael@0 2798 return new mozilla::dom::SpeechSynthesisParent();
michael@0 2799 #else
michael@0 2800 return nullptr;
michael@0 2801 #endif
michael@0 2802 }
michael@0 2803
michael@0 2804 bool
michael@0 2805 ContentParent::DeallocPSpeechSynthesisParent(PSpeechSynthesisParent* aActor)
michael@0 2806 {
michael@0 2807 #ifdef MOZ_WEBSPEECH
michael@0 2808 delete aActor;
michael@0 2809 return true;
michael@0 2810 #else
michael@0 2811 return false;
michael@0 2812 #endif
michael@0 2813 }
michael@0 2814
michael@0 2815 bool
michael@0 2816 ContentParent::RecvPSpeechSynthesisConstructor(PSpeechSynthesisParent* aActor)
michael@0 2817 {
michael@0 2818 #ifdef MOZ_WEBSPEECH
michael@0 2819 return true;
michael@0 2820 #else
michael@0 2821 return false;
michael@0 2822 #endif
michael@0 2823 }
michael@0 2824
michael@0 2825 bool
michael@0 2826 ContentParent::RecvSpeakerManagerGetSpeakerStatus(bool* aValue)
michael@0 2827 {
michael@0 2828 #ifdef MOZ_WIDGET_GONK
michael@0 2829 *aValue = false;
michael@0 2830 nsRefPtr<SpeakerManagerService> service =
michael@0 2831 SpeakerManagerService::GetSpeakerManagerService();
michael@0 2832 if (service) {
michael@0 2833 *aValue = service->GetSpeakerStatus();
michael@0 2834 }
michael@0 2835 return true;
michael@0 2836 #endif
michael@0 2837 return false;
michael@0 2838 }
michael@0 2839
michael@0 2840 bool
michael@0 2841 ContentParent::RecvSpeakerManagerForceSpeaker(const bool& aEnable)
michael@0 2842 {
michael@0 2843 #ifdef MOZ_WIDGET_GONK
michael@0 2844 nsRefPtr<SpeakerManagerService> service =
michael@0 2845 SpeakerManagerService::GetSpeakerManagerService();
michael@0 2846 if (service) {
michael@0 2847 service->ForceSpeaker(aEnable, mChildID);
michael@0 2848 }
michael@0 2849 return true;
michael@0 2850 #endif
michael@0 2851 return false;
michael@0 2852 }
michael@0 2853
michael@0 2854 bool
michael@0 2855 ContentParent::RecvStartVisitedQuery(const URIParams& aURI)
michael@0 2856 {
michael@0 2857 nsCOMPtr<nsIURI> newURI = DeserializeURI(aURI);
michael@0 2858 if (!newURI) {
michael@0 2859 return false;
michael@0 2860 }
michael@0 2861 nsCOMPtr<IHistory> history = services::GetHistoryService();
michael@0 2862 if (history) {
michael@0 2863 history->RegisterVisitedCallback(newURI, nullptr);
michael@0 2864 }
michael@0 2865 return true;
michael@0 2866 }
michael@0 2867
michael@0 2868
michael@0 2869 bool
michael@0 2870 ContentParent::RecvVisitURI(const URIParams& uri,
michael@0 2871 const OptionalURIParams& referrer,
michael@0 2872 const uint32_t& flags)
michael@0 2873 {
michael@0 2874 nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri);
michael@0 2875 if (!ourURI) {
michael@0 2876 return false;
michael@0 2877 }
michael@0 2878 nsCOMPtr<nsIURI> ourReferrer = DeserializeURI(referrer);
michael@0 2879 nsCOMPtr<IHistory> history = services::GetHistoryService();
michael@0 2880 if (history) {
michael@0 2881 history->VisitURI(ourURI, ourReferrer, flags);
michael@0 2882 }
michael@0 2883 return true;
michael@0 2884 }
michael@0 2885
michael@0 2886
michael@0 2887 bool
michael@0 2888 ContentParent::RecvSetURITitle(const URIParams& uri,
michael@0 2889 const nsString& title)
michael@0 2890 {
michael@0 2891 nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri);
michael@0 2892 if (!ourURI) {
michael@0 2893 return false;
michael@0 2894 }
michael@0 2895 nsCOMPtr<IHistory> history = services::GetHistoryService();
michael@0 2896 if (history) {
michael@0 2897 history->SetURITitle(ourURI, title);
michael@0 2898 }
michael@0 2899 return true;
michael@0 2900 }
michael@0 2901
michael@0 2902 bool
michael@0 2903 ContentParent::RecvGetRandomValues(const uint32_t& length,
michael@0 2904 InfallibleTArray<uint8_t>* randomValues)
michael@0 2905 {
michael@0 2906 uint8_t* buf = Crypto::GetRandomValues(length);
michael@0 2907 if (!buf) {
michael@0 2908 return true;
michael@0 2909 }
michael@0 2910
michael@0 2911 randomValues->SetCapacity(length);
michael@0 2912 randomValues->SetLength(length);
michael@0 2913
michael@0 2914 memcpy(randomValues->Elements(), buf, length);
michael@0 2915
michael@0 2916 NS_Free(buf);
michael@0 2917
michael@0 2918 return true;
michael@0 2919 }
michael@0 2920
michael@0 2921 bool
michael@0 2922 ContentParent::RecvLoadURIExternal(const URIParams& uri)
michael@0 2923 {
michael@0 2924 nsCOMPtr<nsIExternalProtocolService> extProtService(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
michael@0 2925 if (!extProtService) {
michael@0 2926 return true;
michael@0 2927 }
michael@0 2928 nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri);
michael@0 2929 if (!ourURI) {
michael@0 2930 return false;
michael@0 2931 }
michael@0 2932 extProtService->LoadURI(ourURI, nullptr);
michael@0 2933 return true;
michael@0 2934 }
michael@0 2935
michael@0 2936 bool
michael@0 2937 ContentParent::RecvShowAlertNotification(const nsString& aImageUrl, const nsString& aTitle,
michael@0 2938 const nsString& aText, const bool& aTextClickable,
michael@0 2939 const nsString& aCookie, const nsString& aName,
michael@0 2940 const nsString& aBidi, const nsString& aLang,
michael@0 2941 const IPC::Principal& aPrincipal)
michael@0 2942 {
michael@0 2943 #ifdef MOZ_CHILD_PERMISSIONS
michael@0 2944 uint32_t permission = mozilla::CheckPermission(this, aPrincipal,
michael@0 2945 "desktop-notification");
michael@0 2946 if (permission != nsIPermissionManager::ALLOW_ACTION) {
michael@0 2947 return true;
michael@0 2948 }
michael@0 2949 #endif /* MOZ_CHILD_PERMISSIONS */
michael@0 2950
michael@0 2951 nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_ALERTSERVICE_CONTRACTID));
michael@0 2952 if (sysAlerts) {
michael@0 2953 sysAlerts->ShowAlertNotification(aImageUrl, aTitle, aText, aTextClickable,
michael@0 2954 aCookie, this, aName, aBidi, aLang, aPrincipal);
michael@0 2955 }
michael@0 2956 return true;
michael@0 2957 }
michael@0 2958
michael@0 2959 bool
michael@0 2960 ContentParent::RecvCloseAlert(const nsString& aName,
michael@0 2961 const IPC::Principal& aPrincipal)
michael@0 2962 {
michael@0 2963 #ifdef MOZ_CHILD_PERMISSIONS
michael@0 2964 uint32_t permission = mozilla::CheckPermission(this, aPrincipal,
michael@0 2965 "desktop-notification");
michael@0 2966 if (permission != nsIPermissionManager::ALLOW_ACTION) {
michael@0 2967 return true;
michael@0 2968 }
michael@0 2969 #endif
michael@0 2970
michael@0 2971 nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_ALERTSERVICE_CONTRACTID));
michael@0 2972 if (sysAlerts) {
michael@0 2973 sysAlerts->CloseAlert(aName, aPrincipal);
michael@0 2974 }
michael@0 2975
michael@0 2976 return true;
michael@0 2977 }
michael@0 2978
michael@0 2979 bool
michael@0 2980 ContentParent::RecvSyncMessage(const nsString& aMsg,
michael@0 2981 const ClonedMessageData& aData,
michael@0 2982 const InfallibleTArray<CpowEntry>& aCpows,
michael@0 2983 const IPC::Principal& aPrincipal,
michael@0 2984 InfallibleTArray<nsString>* aRetvals)
michael@0 2985 {
michael@0 2986 nsIPrincipal* principal = aPrincipal;
michael@0 2987 if (!Preferences::GetBool("dom.testing.ignore_ipc_principal", false) &&
michael@0 2988 principal && !AssertAppPrincipal(this, principal)) {
michael@0 2989 return false;
michael@0 2990 }
michael@0 2991
michael@0 2992 nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
michael@0 2993 if (ppm) {
michael@0 2994 StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
michael@0 2995 CpowIdHolder cpows(GetCPOWManager(), aCpows);
michael@0 2996
michael@0 2997 ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
michael@0 2998 aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals);
michael@0 2999 }
michael@0 3000 return true;
michael@0 3001 }
michael@0 3002
michael@0 3003 bool
michael@0 3004 ContentParent::AnswerRpcMessage(const nsString& aMsg,
michael@0 3005 const ClonedMessageData& aData,
michael@0 3006 const InfallibleTArray<CpowEntry>& aCpows,
michael@0 3007 const IPC::Principal& aPrincipal,
michael@0 3008 InfallibleTArray<nsString>* aRetvals)
michael@0 3009 {
michael@0 3010 nsIPrincipal* principal = aPrincipal;
michael@0 3011 if (!Preferences::GetBool("dom.testing.ignore_ipc_principal", false) &&
michael@0 3012 principal && !AssertAppPrincipal(this, principal)) {
michael@0 3013 return false;
michael@0 3014 }
michael@0 3015
michael@0 3016 nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
michael@0 3017 if (ppm) {
michael@0 3018 StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
michael@0 3019 CpowIdHolder cpows(GetCPOWManager(), aCpows);
michael@0 3020 ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
michael@0 3021 aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals);
michael@0 3022 }
michael@0 3023 return true;
michael@0 3024 }
michael@0 3025
michael@0 3026 bool
michael@0 3027 ContentParent::RecvAsyncMessage(const nsString& aMsg,
michael@0 3028 const ClonedMessageData& aData,
michael@0 3029 const InfallibleTArray<CpowEntry>& aCpows,
michael@0 3030 const IPC::Principal& aPrincipal)
michael@0 3031 {
michael@0 3032 nsIPrincipal* principal = aPrincipal;
michael@0 3033 if (!Preferences::GetBool("dom.testing.ignore_ipc_principal", false) &&
michael@0 3034 principal && !AssertAppPrincipal(this, principal)) {
michael@0 3035 return false;
michael@0 3036 }
michael@0 3037
michael@0 3038 nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
michael@0 3039 if (ppm) {
michael@0 3040 StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
michael@0 3041 CpowIdHolder cpows(GetCPOWManager(), aCpows);
michael@0 3042 ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
michael@0 3043 aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
michael@0 3044 }
michael@0 3045 return true;
michael@0 3046 }
michael@0 3047
michael@0 3048 bool
michael@0 3049 ContentParent::RecvFilePathUpdateNotify(const nsString& aType,
michael@0 3050 const nsString& aStorageName,
michael@0 3051 const nsString& aFilePath,
michael@0 3052 const nsCString& aReason)
michael@0 3053 {
michael@0 3054 nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(aType,
michael@0 3055 aStorageName,
michael@0 3056 aFilePath);
michael@0 3057
michael@0 3058 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
michael@0 3059 if (!obs) {
michael@0 3060 return false;
michael@0 3061 }
michael@0 3062 obs->NotifyObservers(dsf, "file-watcher-update",
michael@0 3063 NS_ConvertASCIItoUTF16(aReason).get());
michael@0 3064 return true;
michael@0 3065 }
michael@0 3066
michael@0 3067 static int32_t
michael@0 3068 AddGeolocationListener(nsIDOMGeoPositionCallback* watcher, bool highAccuracy)
michael@0 3069 {
michael@0 3070 nsCOMPtr<nsIDOMGeoGeolocation> geo = do_GetService("@mozilla.org/geolocation;1");
michael@0 3071 if (!geo) {
michael@0 3072 return -1;
michael@0 3073 }
michael@0 3074
michael@0 3075 PositionOptions* options = new PositionOptions();
michael@0 3076 options->mTimeout = 0;
michael@0 3077 options->mMaximumAge = 0;
michael@0 3078 options->mEnableHighAccuracy = highAccuracy;
michael@0 3079 int32_t retval = 1;
michael@0 3080 geo->WatchPosition(watcher, nullptr, options, &retval);
michael@0 3081 return retval;
michael@0 3082 }
michael@0 3083
michael@0 3084 bool
michael@0 3085 ContentParent::RecvAddGeolocationListener(const IPC::Principal& aPrincipal,
michael@0 3086 const bool& aHighAccuracy)
michael@0 3087 {
michael@0 3088 #ifdef MOZ_CHILD_PERMISSIONS
michael@0 3089 if (!Preferences::GetBool("dom.testing.ignore_ipc_principal", false)) {
michael@0 3090 uint32_t permission = mozilla::CheckPermission(this, aPrincipal,
michael@0 3091 "geolocation");
michael@0 3092 if (permission != nsIPermissionManager::ALLOW_ACTION) {
michael@0 3093 return true;
michael@0 3094 }
michael@0 3095 }
michael@0 3096 #endif /* MOZ_CHILD_PERMISSIONS */
michael@0 3097
michael@0 3098 // To ensure no geolocation updates are skipped, we always force the
michael@0 3099 // creation of a new listener.
michael@0 3100 RecvRemoveGeolocationListener();
michael@0 3101 mGeolocationWatchID = AddGeolocationListener(this, aHighAccuracy);
michael@0 3102 return true;
michael@0 3103 }
michael@0 3104
michael@0 3105 bool
michael@0 3106 ContentParent::RecvRemoveGeolocationListener()
michael@0 3107 {
michael@0 3108 if (mGeolocationWatchID != -1) {
michael@0 3109 nsCOMPtr<nsIDOMGeoGeolocation> geo = do_GetService("@mozilla.org/geolocation;1");
michael@0 3110 if (!geo) {
michael@0 3111 return true;
michael@0 3112 }
michael@0 3113 geo->ClearWatch(mGeolocationWatchID);
michael@0 3114 mGeolocationWatchID = -1;
michael@0 3115 }
michael@0 3116 return true;
michael@0 3117 }
michael@0 3118
michael@0 3119 bool
michael@0 3120 ContentParent::RecvSetGeolocationHigherAccuracy(const bool& aEnable)
michael@0 3121 {
michael@0 3122 // This should never be called without a listener already present,
michael@0 3123 // so this check allows us to forgo securing privileges.
michael@0 3124 if (mGeolocationWatchID != -1) {
michael@0 3125 RecvRemoveGeolocationListener();
michael@0 3126 mGeolocationWatchID = AddGeolocationListener(this, aEnable);
michael@0 3127 }
michael@0 3128 return true;
michael@0 3129 }
michael@0 3130
michael@0 3131 NS_IMETHODIMP
michael@0 3132 ContentParent::HandleEvent(nsIDOMGeoPosition* postion)
michael@0 3133 {
michael@0 3134 unused << SendGeolocationUpdate(GeoPosition(postion));
michael@0 3135 return NS_OK;
michael@0 3136 }
michael@0 3137
michael@0 3138 nsConsoleService *
michael@0 3139 ContentParent::GetConsoleService()
michael@0 3140 {
michael@0 3141 if (mConsoleService) {
michael@0 3142 return mConsoleService.get();
michael@0 3143 }
michael@0 3144
michael@0 3145 // Get the ConsoleService by CID rather than ContractID, so that we
michael@0 3146 // can cast the returned pointer to an nsConsoleService (rather than
michael@0 3147 // just an nsIConsoleService). This allows us to call the non-idl function
michael@0 3148 // nsConsoleService::LogMessageWithMode.
michael@0 3149 NS_DEFINE_CID(consoleServiceCID, NS_CONSOLESERVICE_CID);
michael@0 3150 nsCOMPtr<nsConsoleService> consoleService(do_GetService(consoleServiceCID));
michael@0 3151 mConsoleService = consoleService;
michael@0 3152 return mConsoleService.get();
michael@0 3153 }
michael@0 3154
michael@0 3155 bool
michael@0 3156 ContentParent::RecvConsoleMessage(const nsString& aMessage)
michael@0 3157 {
michael@0 3158 nsRefPtr<nsConsoleService> consoleService = GetConsoleService();
michael@0 3159 if (!consoleService) {
michael@0 3160 return true;
michael@0 3161 }
michael@0 3162
michael@0 3163 nsRefPtr<nsConsoleMessage> msg(new nsConsoleMessage(aMessage.get()));
michael@0 3164 consoleService->LogMessageWithMode(msg, nsConsoleService::SuppressLog);
michael@0 3165 return true;
michael@0 3166 }
michael@0 3167
michael@0 3168 bool
michael@0 3169 ContentParent::RecvScriptError(const nsString& aMessage,
michael@0 3170 const nsString& aSourceName,
michael@0 3171 const nsString& aSourceLine,
michael@0 3172 const uint32_t& aLineNumber,
michael@0 3173 const uint32_t& aColNumber,
michael@0 3174 const uint32_t& aFlags,
michael@0 3175 const nsCString& aCategory)
michael@0 3176 {
michael@0 3177 nsRefPtr<nsConsoleService> consoleService = GetConsoleService();
michael@0 3178 if (!consoleService) {
michael@0 3179 return true;
michael@0 3180 }
michael@0 3181
michael@0 3182 nsCOMPtr<nsIScriptError> msg(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
michael@0 3183 nsresult rv = msg->Init(aMessage, aSourceName, aSourceLine,
michael@0 3184 aLineNumber, aColNumber, aFlags, aCategory.get());
michael@0 3185 if (NS_FAILED(rv))
michael@0 3186 return true;
michael@0 3187
michael@0 3188 consoleService->LogMessageWithMode(msg, nsConsoleService::SuppressLog);
michael@0 3189 return true;
michael@0 3190 }
michael@0 3191
michael@0 3192 bool
michael@0 3193 ContentParent::RecvPrivateDocShellsExist(const bool& aExist)
michael@0 3194 {
michael@0 3195 if (!sPrivateContent)
michael@0 3196 sPrivateContent = new nsTArray<ContentParent*>();
michael@0 3197 if (aExist) {
michael@0 3198 sPrivateContent->AppendElement(this);
michael@0 3199 } else {
michael@0 3200 sPrivateContent->RemoveElement(this);
michael@0 3201 if (!sPrivateContent->Length()) {
michael@0 3202 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
michael@0 3203 obs->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
michael@0 3204 delete sPrivateContent;
michael@0 3205 sPrivateContent = nullptr;
michael@0 3206 }
michael@0 3207 }
michael@0 3208 return true;
michael@0 3209 }
michael@0 3210
michael@0 3211 bool
michael@0 3212 ContentParent::DoSendAsyncMessage(JSContext* aCx,
michael@0 3213 const nsAString& aMessage,
michael@0 3214 const mozilla::dom::StructuredCloneData& aData,
michael@0 3215 JS::Handle<JSObject *> aCpows,
michael@0 3216 nsIPrincipal* aPrincipal)
michael@0 3217 {
michael@0 3218 ClonedMessageData data;
michael@0 3219 if (!BuildClonedMessageDataForParent(this, aData, data)) {
michael@0 3220 return false;
michael@0 3221 }
michael@0 3222 InfallibleTArray<CpowEntry> cpows;
michael@0 3223 if (!GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
michael@0 3224 return false;
michael@0 3225 }
michael@0 3226 return SendAsyncMessage(nsString(aMessage), data, cpows, aPrincipal);
michael@0 3227 }
michael@0 3228
michael@0 3229 bool
michael@0 3230 ContentParent::CheckPermission(const nsAString& aPermission)
michael@0 3231 {
michael@0 3232 return AssertAppProcessPermission(this, NS_ConvertUTF16toUTF8(aPermission).get());
michael@0 3233 }
michael@0 3234
michael@0 3235 bool
michael@0 3236 ContentParent::CheckManifestURL(const nsAString& aManifestURL)
michael@0 3237 {
michael@0 3238 return AssertAppProcessManifestURL(this, NS_ConvertUTF16toUTF8(aManifestURL).get());
michael@0 3239 }
michael@0 3240
michael@0 3241 bool
michael@0 3242 ContentParent::CheckAppHasPermission(const nsAString& aPermission)
michael@0 3243 {
michael@0 3244 return AssertAppHasPermission(this, NS_ConvertUTF16toUTF8(aPermission).get());
michael@0 3245 }
michael@0 3246
michael@0 3247 bool
michael@0 3248 ContentParent::CheckAppHasStatus(unsigned short aStatus)
michael@0 3249 {
michael@0 3250 return AssertAppHasStatus(this, aStatus);
michael@0 3251 }
michael@0 3252
michael@0 3253 bool
michael@0 3254 ContentParent::RecvSystemMessageHandled()
michael@0 3255 {
michael@0 3256 SystemMessageHandledListener::OnSystemMessageHandled();
michael@0 3257 return true;
michael@0 3258 }
michael@0 3259
michael@0 3260 bool
michael@0 3261 ContentParent::RecvCreateFakeVolume(const nsString& fsName, const nsString& mountPoint)
michael@0 3262 {
michael@0 3263 #ifdef MOZ_WIDGET_GONK
michael@0 3264 nsresult rv;
michael@0 3265 nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
michael@0 3266 if (vs) {
michael@0 3267 vs->CreateFakeVolume(fsName, mountPoint);
michael@0 3268 }
michael@0 3269 return true;
michael@0 3270 #else
michael@0 3271 NS_WARNING("ContentParent::RecvCreateFakeVolume shouldn't be called when MOZ_WIDGET_GONK is not defined");
michael@0 3272 return false;
michael@0 3273 #endif
michael@0 3274 }
michael@0 3275
michael@0 3276 bool
michael@0 3277 ContentParent::RecvSetFakeVolumeState(const nsString& fsName, const int32_t& fsState)
michael@0 3278 {
michael@0 3279 #ifdef MOZ_WIDGET_GONK
michael@0 3280 nsresult rv;
michael@0 3281 nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
michael@0 3282 if (vs) {
michael@0 3283 vs->SetFakeVolumeState(fsName, fsState);
michael@0 3284 }
michael@0 3285 return true;
michael@0 3286 #else
michael@0 3287 NS_WARNING("ContentParent::RecvSetFakeVolumeState shouldn't be called when MOZ_WIDGET_GONK is not defined");
michael@0 3288 return false;
michael@0 3289 #endif
michael@0 3290 }
michael@0 3291
michael@0 3292 bool
michael@0 3293 ContentParent::RecvKeywordToURI(const nsCString& aKeyword, OptionalInputStreamParams* aPostData,
michael@0 3294 OptionalURIParams* aURI)
michael@0 3295 {
michael@0 3296 nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID);
michael@0 3297 if (!fixup) {
michael@0 3298 return true;
michael@0 3299 }
michael@0 3300
michael@0 3301 nsCOMPtr<nsIInputStream> postData;
michael@0 3302 nsCOMPtr<nsIURI> uri;
michael@0 3303 if (NS_FAILED(fixup->KeywordToURI(aKeyword, getter_AddRefs(postData),
michael@0 3304 getter_AddRefs(uri)))) {
michael@0 3305 return true;
michael@0 3306 }
michael@0 3307
michael@0 3308 nsTArray<mozilla::ipc::FileDescriptor> fds;
michael@0 3309 SerializeInputStream(postData, *aPostData, fds);
michael@0 3310 MOZ_ASSERT(fds.IsEmpty());
michael@0 3311
michael@0 3312 SerializeURI(uri, *aURI);
michael@0 3313 return true;
michael@0 3314 }
michael@0 3315
michael@0 3316 bool
michael@0 3317 ContentParent::ShouldContinueFromReplyTimeout()
michael@0 3318 {
michael@0 3319 // The only time ContentParent sends blocking messages is for CPOWs, so
michael@0 3320 // timeouts should only ever occur in electrolysis-enabled sessions.
michael@0 3321 MOZ_ASSERT(BrowserTabsRemote());
michael@0 3322 return false;
michael@0 3323 }
michael@0 3324
michael@0 3325 bool
michael@0 3326 ContentParent::ShouldSandboxContentProcesses()
michael@0 3327 {
michael@0 3328 #ifdef MOZ_CONTENT_SANDBOX
michael@0 3329 return !PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX");
michael@0 3330 #else
michael@0 3331 return true;
michael@0 3332 #endif
michael@0 3333 }
michael@0 3334
michael@0 3335 bool
michael@0 3336 ContentParent::RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
michael@0 3337 const nsString& aPageURL,
michael@0 3338 const bool& aIsAudio,
michael@0 3339 const bool& aIsVideo)
michael@0 3340 {
michael@0 3341 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
michael@0 3342 if (obs) {
michael@0 3343 // recording-device-ipc-events needs to gather more information from content process
michael@0 3344 nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
michael@0 3345 props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), ChildID());
michael@0 3346 props->SetPropertyAsBool(NS_LITERAL_STRING("isApp"), IsForApp());
michael@0 3347 props->SetPropertyAsBool(NS_LITERAL_STRING("isAudio"), aIsAudio);
michael@0 3348 props->SetPropertyAsBool(NS_LITERAL_STRING("isVideo"), aIsVideo);
michael@0 3349
michael@0 3350 nsString requestURL = IsForApp() ? AppManifestURL() : aPageURL;
michael@0 3351 props->SetPropertyAsAString(NS_LITERAL_STRING("requestURL"), requestURL);
michael@0 3352
michael@0 3353 obs->NotifyObservers((nsIPropertyBag2*) props,
michael@0 3354 "recording-device-ipc-events",
michael@0 3355 aRecordingStatus.get());
michael@0 3356 } else {
michael@0 3357 NS_WARNING("Could not get the Observer service for ContentParent::RecvRecordingDeviceEvents.");
michael@0 3358 }
michael@0 3359 return true;
michael@0 3360 }
michael@0 3361
michael@0 3362 bool
michael@0 3363 ContentParent::RecvGetGraphicsFeatureStatus(const int32_t& aFeature,
michael@0 3364 int32_t* aStatus,
michael@0 3365 bool* aSuccess)
michael@0 3366 {
michael@0 3367 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
michael@0 3368 if (!gfxInfo) {
michael@0 3369 *aSuccess = false;
michael@0 3370 return true;
michael@0 3371 }
michael@0 3372
michael@0 3373 *aSuccess = NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, aStatus));
michael@0 3374 return true;
michael@0 3375 }
michael@0 3376
michael@0 3377 bool
michael@0 3378 ContentParent::RecvAddIdleObserver(const uint64_t& aObserver, const uint32_t& aIdleTimeInS)
michael@0 3379 {
michael@0 3380 nsresult rv;
michael@0 3381 nsCOMPtr<nsIIdleService> idleService =
michael@0 3382 do_GetService("@mozilla.org/widget/idleservice;1", &rv);
michael@0 3383 NS_ENSURE_SUCCESS(rv, false);
michael@0 3384
michael@0 3385 nsRefPtr<ParentIdleListener> listener = new ParentIdleListener(this, aObserver);
michael@0 3386 mIdleListeners.Put(aObserver, listener);
michael@0 3387 idleService->AddIdleObserver(listener, aIdleTimeInS);
michael@0 3388 return true;
michael@0 3389 }
michael@0 3390
michael@0 3391 bool
michael@0 3392 ContentParent::RecvRemoveIdleObserver(const uint64_t& aObserver, const uint32_t& aIdleTimeInS)
michael@0 3393 {
michael@0 3394 nsresult rv;
michael@0 3395 nsCOMPtr<nsIIdleService> idleService =
michael@0 3396 do_GetService("@mozilla.org/widget/idleservice;1", &rv);
michael@0 3397 NS_ENSURE_SUCCESS(rv, false);
michael@0 3398
michael@0 3399 nsRefPtr<ParentIdleListener> listener;
michael@0 3400 bool found = mIdleListeners.Get(aObserver, &listener);
michael@0 3401 if (found) {
michael@0 3402 mIdleListeners.Remove(aObserver);
michael@0 3403 idleService->RemoveIdleObserver(listener, aIdleTimeInS);
michael@0 3404 }
michael@0 3405
michael@0 3406 return true;
michael@0 3407 }
michael@0 3408
michael@0 3409 bool
michael@0 3410 ContentParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd)
michael@0 3411 {
michael@0 3412 #ifndef MOZ_X11
michael@0 3413 NS_RUNTIMEABORT("This message only makes sense on X11 platforms");
michael@0 3414 #else
michael@0 3415 NS_ABORT_IF_FALSE(0 > mChildXSocketFdDup.get(),
michael@0 3416 "Already backed up X resources??");
michael@0 3417 mChildXSocketFdDup.forget();
michael@0 3418 if (aXSocketFd.IsValid()) {
michael@0 3419 mChildXSocketFdDup.reset(aXSocketFd.PlatformHandle());
michael@0 3420 }
michael@0 3421 #endif
michael@0 3422 return true;
michael@0 3423 }
michael@0 3424
michael@0 3425 PFileDescriptorSetParent*
michael@0 3426 ContentParent::AllocPFileDescriptorSetParent(const FileDescriptor& aFD)
michael@0 3427 {
michael@0 3428 return new FileDescriptorSetParent(aFD);
michael@0 3429 }
michael@0 3430
michael@0 3431 bool
michael@0 3432 ContentParent::DeallocPFileDescriptorSetParent(PFileDescriptorSetParent* aActor)
michael@0 3433 {
michael@0 3434 delete static_cast<FileDescriptorSetParent*>(aActor);
michael@0 3435 return true;
michael@0 3436 }
michael@0 3437
michael@0 3438 } // namespace dom
michael@0 3439 } // namespace mozilla
michael@0 3440
michael@0 3441 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
michael@0 3442
michael@0 3443 NS_IMETHODIMP
michael@0 3444 ParentIdleListener::Observe(nsISupports*, const char* aTopic, const char16_t* aData) {
michael@0 3445 mozilla::unused << mParent->SendNotifyIdleObserver(mObserver,
michael@0 3446 nsDependentCString(aTopic),
michael@0 3447 nsDependentString(aData));
michael@0 3448 return NS_OK;
michael@0 3449 }

mercurial