dom/ipc/ContentChild.cpp

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

mercurial