|
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 } |