dom/ipc/ContentParent.cpp

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

mercurial