/src/mozilla-central/dom/ipc/ContentParent.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 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 | | #include "base/shared_memory.h" |
11 | | |
12 | | #include "ContentParent.h" |
13 | | #include "TabParent.h" |
14 | | |
15 | | #if defined(ANDROID) || defined(LINUX) |
16 | | # include <sys/time.h> |
17 | | # include <sys/resource.h> |
18 | | #endif |
19 | | |
20 | | #include "chrome/common/process_watcher.h" |
21 | | |
22 | | #include "mozilla/a11y/PDocAccessible.h" |
23 | | #include "GeckoProfiler.h" |
24 | | #include "GMPServiceParent.h" |
25 | | #include "HandlerServiceParent.h" |
26 | | #include "IHistory.h" |
27 | | #include "imgIContainer.h" |
28 | | #if defined(XP_WIN) && defined(ACCESSIBILITY) |
29 | | #include "mozilla/a11y/AccessibleWrap.h" |
30 | | #include "mozilla/a11y/Compatibility.h" |
31 | | #endif |
32 | | #include "mozilla/AntiTrackingCommon.h" |
33 | | #include "mozilla/BasePrincipal.h" |
34 | | #include "mozilla/ClearOnShutdown.h" |
35 | | #include "mozilla/StyleSheetInlines.h" |
36 | | #include "mozilla/DataStorage.h" |
37 | | #include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h" |
38 | | #include "mozilla/docshell/OfflineCacheUpdateParent.h" |
39 | | #include "mozilla/dom/BrowsingContext.h" |
40 | | #include "mozilla/dom/ChromeBrowsingContext.h" |
41 | | #include "mozilla/dom/ClientManager.h" |
42 | | #include "mozilla/dom/ClientOpenWindowOpActors.h" |
43 | | #include "mozilla/dom/DataTransfer.h" |
44 | | #include "mozilla/dom/Element.h" |
45 | | #include "mozilla/dom/File.h" |
46 | | #include "mozilla/dom/FileCreatorHelper.h" |
47 | | #include "mozilla/dom/FileSystemSecurity.h" |
48 | | #include "mozilla/dom/IPCBlobUtils.h" |
49 | | #include "mozilla/dom/ExternalHelperAppParent.h" |
50 | | #include "mozilla/dom/GetFilesHelper.h" |
51 | | #include "mozilla/dom/GeolocationBinding.h" |
52 | | #include "mozilla/dom/MemoryReportRequest.h" |
53 | | #include "mozilla/dom/Notification.h" |
54 | | #include "mozilla/dom/PContentBridgeParent.h" |
55 | | #include "mozilla/dom/PContentPermissionRequestParent.h" |
56 | | #include "mozilla/dom/PCycleCollectWithLogsParent.h" |
57 | | #include "mozilla/dom/PositionError.h" |
58 | | #include "mozilla/dom/ServiceWorkerRegistrar.h" |
59 | | #include "mozilla/dom/power/PowerManagerService.h" |
60 | | #include "mozilla/dom/Permissions.h" |
61 | | #include "mozilla/dom/PresentationParent.h" |
62 | | #include "mozilla/dom/PPresentationParent.h" |
63 | | #include "mozilla/dom/PushNotifier.h" |
64 | | #include "mozilla/dom/quota/QuotaManagerService.h" |
65 | | #include "mozilla/dom/ServiceWorkerUtils.h" |
66 | | #include "mozilla/dom/URLClassifierParent.h" |
67 | | #include "mozilla/dom/ipc/SharedMap.h" |
68 | | #include "mozilla/embedding/printingui/PrintingParent.h" |
69 | | #include "mozilla/extensions/StreamFilterParent.h" |
70 | | #include "mozilla/gfx/gfxVars.h" |
71 | | #include "mozilla/gfx/GPUProcessManager.h" |
72 | | #include "mozilla/hal_sandbox/PHalParent.h" |
73 | | #include "mozilla/ipc/BackgroundChild.h" |
74 | | #include "mozilla/ipc/BackgroundParent.h" |
75 | | #include "mozilla/ipc/CrashReporterHost.h" |
76 | | #include "mozilla/ipc/FileDescriptorUtils.h" |
77 | | #include "mozilla/ipc/PChildToParentStreamParent.h" |
78 | | #include "mozilla/ipc/TestShellParent.h" |
79 | | #include "mozilla/ipc/IPCStreamUtils.h" |
80 | | #include "mozilla/intl/LocaleService.h" |
81 | | #include "mozilla/jsipc/CrossProcessObjectWrappers.h" |
82 | | #include "mozilla/layers/PAPZParent.h" |
83 | | #include "mozilla/layers/CompositorThread.h" |
84 | | #include "mozilla/layers/ImageBridgeParent.h" |
85 | | #include "mozilla/layers/LayerTreeOwnerTracker.h" |
86 | | #include "mozilla/layout/RenderFrameParent.h" |
87 | | #include "mozilla/loader/ScriptCacheActors.h" |
88 | | #include "mozilla/LoginReputationIPC.h" |
89 | | #include "mozilla/LookAndFeel.h" |
90 | | #include "mozilla/media/MediaParent.h" |
91 | | #include "mozilla/Move.h" |
92 | | #include "mozilla/net/NeckoParent.h" |
93 | | #include "mozilla/net/CookieServiceParent.h" |
94 | | #include "mozilla/net/PCookieServiceParent.h" |
95 | | #include "mozilla/plugins/PluginBridge.h" |
96 | | #include "mozilla/Preferences.h" |
97 | | #include "mozilla/ProcessHangMonitor.h" |
98 | | #include "mozilla/ProcessHangMonitorIPC.h" |
99 | | #include "mozilla/recordreplay/ParentIPC.h" |
100 | | #include "mozilla/Scheduler.h" |
101 | | #include "mozilla/ScopeExit.h" |
102 | | #include "mozilla/ScriptPreloader.h" |
103 | | #include "mozilla/Services.h" |
104 | | #include "mozilla/StaticPtr.h" |
105 | | #include "mozilla/StaticPrefs.h" |
106 | | #include "mozilla/Telemetry.h" |
107 | | #include "mozilla/TelemetryIPC.h" |
108 | | #include "mozilla/WebBrowserPersistDocumentParent.h" |
109 | | #include "mozilla/widget/ScreenManager.h" |
110 | | #include "mozilla/Unused.h" |
111 | | #include "mozilla/HangDetails.h" |
112 | | #include "nsAnonymousTemporaryFile.h" |
113 | | #include "nsAppRunner.h" |
114 | | #include "nsCDefaultURIFixup.h" |
115 | | #include "nsCExternalHandlerService.h" |
116 | | #include "nsCOMPtr.h" |
117 | | #include "nsChromeRegistryChrome.h" |
118 | | #include "nsConsoleMessage.h" |
119 | | #include "nsConsoleService.h" |
120 | | #include "nsContentUtils.h" |
121 | | #include "nsDebugImpl.h" |
122 | | #include "nsDirectoryServiceDefs.h" |
123 | | #include "nsEmbedCID.h" |
124 | | #include "nsFrameLoader.h" |
125 | | #include "nsFrameMessageManager.h" |
126 | | #include "nsHashPropertyBag.h" |
127 | | #include "nsIAlertsService.h" |
128 | | #include "nsIClipboard.h" |
129 | | #include "nsICookie.h" |
130 | | #include "nsContentPermissionHelper.h" |
131 | | #include "nsIContentProcess.h" |
132 | | #include "nsICycleCollectorListener.h" |
133 | | #include "nsIDocShellTreeOwner.h" |
134 | | #include "nsIDocument.h" |
135 | | #include "nsGeolocation.h" |
136 | | #include "nsIDragService.h" |
137 | | #include "mozilla/dom/WakeLock.h" |
138 | | #include "nsIDOMWindow.h" |
139 | | #include "nsIExternalProtocolService.h" |
140 | | #include "nsIFormProcessor.h" |
141 | | #include "nsIGfxInfo.h" |
142 | | #include "nsIIdleService.h" |
143 | | #include "nsIInterfaceRequestorUtils.h" |
144 | | #include "nsIMemoryInfoDumper.h" |
145 | | #include "nsIMemoryReporter.h" |
146 | | #include "nsIMozBrowserFrame.h" |
147 | | #include "nsIMutable.h" |
148 | | #include "nsIObserverService.h" |
149 | | #include "nsIParentChannel.h" |
150 | | #include "nsIPresShell.h" |
151 | | #include "nsIRemoteWindowContext.h" |
152 | | #include "nsIScriptError.h" |
153 | | #include "nsIScriptSecurityManager.h" |
154 | | #include "nsISiteSecurityService.h" |
155 | | #include "nsISound.h" |
156 | | #include "mozilla/mozSpellChecker.h" |
157 | | #include "nsIStringBundle.h" |
158 | | #include "nsISupportsPrimitives.h" |
159 | | #include "nsITimer.h" |
160 | | #include "nsIURIFixup.h" |
161 | | #include "nsIURL.h" |
162 | | #include "nsIDocShellTreeOwner.h" |
163 | | #include "nsIXULWindow.h" |
164 | | #include "nsIDOMChromeWindow.h" |
165 | | #include "nsIWindowWatcher.h" |
166 | | #include "nsPIWindowWatcher.h" |
167 | | #include "nsThread.h" |
168 | | #include "nsWindowWatcher.h" |
169 | | #include "nsIXULRuntime.h" |
170 | | #include "mozilla/dom/ParentProcessMessageManager.h" |
171 | | #include "mozilla/dom/ProcessMessageManager.h" |
172 | | #include "mozilla/dom/nsMixedContentBlocker.h" |
173 | | #include "nsMemoryInfoDumper.h" |
174 | | #include "nsMemoryReporterManager.h" |
175 | | #include "nsScriptError.h" |
176 | | #include "nsServiceManagerUtils.h" |
177 | | #include "nsStyleSheetService.h" |
178 | | #include "nsThreadUtils.h" |
179 | | #include "nsToolkitCompsCID.h" |
180 | | #include "nsWidgetsCID.h" |
181 | | #include "PreallocatedProcessManager.h" |
182 | | #include "ProcessPriorityManager.h" |
183 | | #include "SandboxHal.h" |
184 | | #include "SourceSurfaceRawData.h" |
185 | | #include "TabParent.h" |
186 | | #include "URIUtils.h" |
187 | | #include "nsIWebBrowserChrome.h" |
188 | | #include "nsIDocShell.h" |
189 | | #include "nsDocShell.h" |
190 | | #include "nsOpenURIInFrameParams.h" |
191 | | #include "mozilla/net/NeckoMessageUtils.h" |
192 | | #include "gfxPlatform.h" |
193 | | #include "gfxPrefs.h" |
194 | | #include "prio.h" |
195 | | #include "private/pprio.h" |
196 | | #include "ContentProcessManager.h" |
197 | | #include "mozilla/dom/BlobURLProtocolHandler.h" |
198 | | #include "mozilla/dom/ipc/StructuredCloneData.h" |
199 | | #include "mozilla/PerformanceMetricsCollector.h" |
200 | | #include "mozilla/psm/PSMContentListener.h" |
201 | | #include "nsPluginHost.h" |
202 | | #include "nsPluginTags.h" |
203 | | #include "nsIBlocklistService.h" |
204 | | #include "mozilla/StyleSheet.h" |
205 | | #include "mozilla/StyleSheetInlines.h" |
206 | | #include "nsICaptivePortalService.h" |
207 | | #include "nsIObjectLoadingContent.h" |
208 | | #include "nsIBidiKeyboard.h" |
209 | | #include "nsLayoutStylesheetCache.h" |
210 | | |
211 | | #include "mozilla/Sprintf.h" |
212 | | |
213 | | #ifdef MOZ_WEBRTC |
214 | | #include "signaling/src/peerconnection/WebrtcGlobalParent.h" |
215 | | #endif |
216 | | |
217 | | #if defined(ANDROID) || defined(LINUX) |
218 | | #include "nsSystemInfo.h" |
219 | | #endif |
220 | | |
221 | | #if defined(XP_LINUX) |
222 | | #include "mozilla/Hal.h" |
223 | | #endif |
224 | | |
225 | | #ifdef ANDROID |
226 | | # include "gfxAndroidPlatform.h" |
227 | | #endif |
228 | | |
229 | | # include "nsPermissionManager.h" |
230 | | |
231 | | #ifdef MOZ_WIDGET_ANDROID |
232 | | # include "AndroidBridge.h" |
233 | | #endif |
234 | | |
235 | | #ifdef MOZ_WIDGET_GTK |
236 | | #include <gdk/gdk.h> |
237 | | #endif |
238 | | |
239 | | #include "mozilla/RemoteSpellCheckEngineParent.h" |
240 | | |
241 | | #include "Crypto.h" |
242 | | |
243 | | #ifdef MOZ_WEBSPEECH |
244 | | #include "mozilla/dom/SpeechSynthesisParent.h" |
245 | | #endif |
246 | | |
247 | | #if defined(MOZ_CONTENT_SANDBOX) |
248 | | #include "mozilla/SandboxSettings.h" |
249 | | #if defined(XP_LINUX) |
250 | | #include "mozilla/SandboxInfo.h" |
251 | | #include "mozilla/SandboxBroker.h" |
252 | | #include "mozilla/SandboxBrokerPolicyFactory.h" |
253 | | #endif |
254 | | #endif |
255 | | |
256 | | #ifdef MOZ_TOOLKIT_SEARCH |
257 | | #include "nsIBrowserSearchService.h" |
258 | | #endif |
259 | | |
260 | | #ifdef XP_WIN |
261 | | #include "mozilla/audio/AudioNotificationSender.h" |
262 | | #include "mozilla/widget/AudioSession.h" |
263 | | #endif |
264 | | |
265 | | #ifdef ACCESSIBILITY |
266 | | #include "nsAccessibilityService.h" |
267 | | #endif |
268 | | |
269 | | #ifdef MOZ_GECKO_PROFILER |
270 | | #include "nsIProfiler.h" |
271 | | #include "ProfilerParent.h" |
272 | | #endif |
273 | | |
274 | | #ifdef MOZ_CODE_COVERAGE |
275 | | #include "mozilla/CodeCoverageHandler.h" |
276 | | #endif |
277 | | |
278 | | // For VP9Benchmark::sBenchmarkFpsPref |
279 | | #include "Benchmark.h" |
280 | | |
281 | | static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); |
282 | | |
283 | | using base::KillProcess; |
284 | | |
285 | | using namespace CrashReporter; |
286 | | using namespace mozilla::dom::power; |
287 | | using namespace mozilla::media; |
288 | | using namespace mozilla::embedding; |
289 | | using namespace mozilla::gfx; |
290 | | using namespace mozilla::gmp; |
291 | | using namespace mozilla::hal; |
292 | | using namespace mozilla::ipc; |
293 | | using namespace mozilla::intl; |
294 | | using namespace mozilla::layers; |
295 | | using namespace mozilla::layout; |
296 | | using namespace mozilla::net; |
297 | | using namespace mozilla::jsipc; |
298 | | using namespace mozilla::psm; |
299 | | using namespace mozilla::widget; |
300 | | using mozilla::loader::PScriptCacheParent; |
301 | | using mozilla::Telemetry::ProcessID; |
302 | | |
303 | | // XXX Workaround for bug 986973 to maintain the existing broken semantics |
304 | | template<> |
305 | | struct nsIConsoleService::COMTypeInfo<nsConsoleService, void> { |
306 | | static const nsIID kIID; |
307 | | }; |
308 | | const nsIID nsIConsoleService::COMTypeInfo<nsConsoleService, void>::kIID = NS_ICONSOLESERVICE_IID; |
309 | | |
310 | | namespace mozilla { |
311 | | namespace CubebUtils { |
312 | | extern FileDescriptor CreateAudioIPCConnection(); |
313 | | } |
314 | | |
315 | | namespace dom { |
316 | | |
317 | 0 | #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline" |
318 | 0 | #define NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC "ipc:network:set-connectivity" |
319 | | |
320 | | // IPC receiver for remote GC/CC logging. |
321 | | class CycleCollectWithLogsParent final : public PCycleCollectWithLogsParent |
322 | | { |
323 | | public: |
324 | | ~CycleCollectWithLogsParent() |
325 | 0 | { |
326 | 0 | MOZ_COUNT_DTOR(CycleCollectWithLogsParent); |
327 | 0 | } |
328 | | |
329 | | static bool AllocAndSendConstructor(ContentParent* aManager, |
330 | | bool aDumpAllTraces, |
331 | | nsICycleCollectorLogSink* aSink, |
332 | | nsIDumpGCAndCCLogsCallback* aCallback) |
333 | 0 | { |
334 | 0 | CycleCollectWithLogsParent *actor; |
335 | 0 | FILE* gcLog; |
336 | 0 | FILE* ccLog; |
337 | 0 | nsresult rv; |
338 | 0 |
|
339 | 0 | actor = new CycleCollectWithLogsParent(aSink, aCallback); |
340 | 0 | rv = actor->mSink->Open(&gcLog, &ccLog); |
341 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
342 | 0 | delete actor; |
343 | 0 | return false; |
344 | 0 | } |
345 | 0 | |
346 | 0 | return aManager-> |
347 | 0 | SendPCycleCollectWithLogsConstructor(actor, |
348 | 0 | aDumpAllTraces, |
349 | 0 | FILEToFileDescriptor(gcLog), |
350 | 0 | FILEToFileDescriptor(ccLog)); |
351 | 0 | } |
352 | | |
353 | | private: |
354 | | virtual mozilla::ipc::IPCResult RecvCloseGCLog() override |
355 | 0 | { |
356 | 0 | Unused << mSink->CloseGCLog(); |
357 | 0 | return IPC_OK(); |
358 | 0 | } |
359 | | |
360 | | virtual mozilla::ipc::IPCResult RecvCloseCCLog() override |
361 | 0 | { |
362 | 0 | Unused << mSink->CloseCCLog(); |
363 | 0 | return IPC_OK(); |
364 | 0 | } |
365 | | |
366 | | virtual mozilla::ipc::IPCResult Recv__delete__() override |
367 | 0 | { |
368 | 0 | // Report completion to mCallback only on successful |
369 | 0 | // completion of the protocol. |
370 | 0 | nsCOMPtr<nsIFile> gcLog, ccLog; |
371 | 0 | mSink->GetGcLog(getter_AddRefs(gcLog)); |
372 | 0 | mSink->GetCcLog(getter_AddRefs(ccLog)); |
373 | 0 | Unused << mCallback->OnDump(gcLog, ccLog, /* parent = */ false); |
374 | 0 | return IPC_OK(); |
375 | 0 | } |
376 | | |
377 | | virtual void ActorDestroy(ActorDestroyReason aReason) override |
378 | 0 | { |
379 | 0 | // If the actor is unexpectedly destroyed, we deliberately |
380 | 0 | // don't call Close[GC]CLog on the sink, because the logs may |
381 | 0 | // be incomplete. See also the nsCycleCollectorLogSinkToFile |
382 | 0 | // implementaiton of those methods, and its destructor. |
383 | 0 | } |
384 | | |
385 | | CycleCollectWithLogsParent(nsICycleCollectorLogSink *aSink, |
386 | | nsIDumpGCAndCCLogsCallback *aCallback) |
387 | | : mSink(aSink), mCallback(aCallback) |
388 | 0 | { |
389 | 0 | MOZ_COUNT_CTOR(CycleCollectWithLogsParent); |
390 | 0 | } |
391 | | |
392 | | nsCOMPtr<nsICycleCollectorLogSink> mSink; |
393 | | nsCOMPtr<nsIDumpGCAndCCLogsCallback> mCallback; |
394 | | }; |
395 | | |
396 | | // A memory reporter for ContentParent objects themselves. |
397 | | class ContentParentsMemoryReporter final : public nsIMemoryReporter |
398 | | { |
399 | 0 | ~ContentParentsMemoryReporter() {} |
400 | | public: |
401 | | NS_DECL_ISUPPORTS |
402 | | NS_DECL_NSIMEMORYREPORTER |
403 | | }; |
404 | | |
405 | | NS_IMPL_ISUPPORTS(ContentParentsMemoryReporter, nsIMemoryReporter) |
406 | | |
407 | | NS_IMETHODIMP |
408 | | ContentParentsMemoryReporter::CollectReports( |
409 | | nsIHandleReportCallback* aHandleReport, |
410 | | nsISupports* aData, |
411 | | bool aAnonymize) |
412 | 0 | { |
413 | 0 | AutoTArray<ContentParent*, 16> cps; |
414 | 0 | ContentParent::GetAllEvenIfDead(cps); |
415 | 0 |
|
416 | 0 | for (uint32_t i = 0; i < cps.Length(); i++) { |
417 | 0 | ContentParent* cp = cps[i]; |
418 | 0 | MessageChannel* channel = cp->GetIPCChannel(); |
419 | 0 |
|
420 | 0 | nsString friendlyName; |
421 | 0 | cp->FriendlyName(friendlyName, aAnonymize); |
422 | 0 |
|
423 | 0 | cp->AddRef(); |
424 | 0 | nsrefcnt refcnt = cp->Release(); |
425 | 0 |
|
426 | 0 | const char* channelStr = "no channel"; |
427 | 0 | uint32_t numQueuedMessages = 0; |
428 | 0 | if (channel) { |
429 | 0 | if (channel->Unsound_IsClosed()) { |
430 | 0 | channelStr = "closed channel"; |
431 | 0 | } else { |
432 | 0 | channelStr = "open channel"; |
433 | 0 | } |
434 | 0 | numQueuedMessages = channel->Unsound_NumQueuedMessages(); |
435 | 0 | } |
436 | 0 |
|
437 | 0 | nsPrintfCString path("queued-ipc-messages/content-parent" |
438 | 0 | "(%s, pid=%d, %s, 0x%p, refcnt=%" PRIuPTR ")", |
439 | 0 | NS_ConvertUTF16toUTF8(friendlyName).get(), |
440 | 0 | cp->Pid(), channelStr, |
441 | 0 | static_cast<nsIContentParent*>(cp), refcnt); |
442 | 0 |
|
443 | 0 | NS_NAMED_LITERAL_CSTRING(desc, |
444 | 0 | "The number of unset IPC messages held in this ContentParent's " |
445 | 0 | "channel. A large value here might indicate that we're leaking " |
446 | 0 | "messages. Similarly, a ContentParent object for a process that's no " |
447 | 0 | "longer running could indicate that we're leaking ContentParents."); |
448 | 0 |
|
449 | 0 | aHandleReport->Callback(/* process */ EmptyCString(), path, |
450 | 0 | KIND_OTHER, UNITS_COUNT, |
451 | 0 | numQueuedMessages, desc, aData); |
452 | 0 | } |
453 | 0 |
|
454 | 0 | return NS_OK; |
455 | 0 | } |
456 | | |
457 | | nsClassHashtable<nsStringHashKey, nsTArray<ContentParent*>>* ContentParent::sBrowserContentParents; |
458 | | |
459 | | namespace { |
460 | | |
461 | | class ScriptableCPInfo final : public nsIContentProcessInfo |
462 | | { |
463 | | public: |
464 | | explicit ScriptableCPInfo(ContentParent* aParent) |
465 | | : mContentParent(aParent) |
466 | 0 | { |
467 | 0 | MOZ_ASSERT(mContentParent); |
468 | 0 | } |
469 | | |
470 | | NS_DECL_ISUPPORTS |
471 | | NS_DECL_NSICONTENTPROCESSINFO |
472 | | |
473 | | void ProcessDied() |
474 | 0 | { |
475 | 0 | mContentParent = nullptr; |
476 | 0 | } |
477 | | |
478 | | private: |
479 | | ~ScriptableCPInfo() |
480 | 0 | { |
481 | 0 | MOZ_ASSERT(!mContentParent, "must call ProcessDied"); |
482 | 0 | } |
483 | | |
484 | | ContentParent* mContentParent; |
485 | | }; |
486 | | |
487 | | NS_IMPL_ISUPPORTS(ScriptableCPInfo, nsIContentProcessInfo) |
488 | | |
489 | | NS_IMETHODIMP |
490 | | ScriptableCPInfo::GetIsAlive(bool* aIsAlive) |
491 | 0 | { |
492 | 0 | *aIsAlive = mContentParent != nullptr; |
493 | 0 | return NS_OK; |
494 | 0 | } |
495 | | |
496 | | NS_IMETHODIMP |
497 | | ScriptableCPInfo::GetProcessId(int32_t* aPID) |
498 | 0 | { |
499 | 0 | if (!mContentParent) { |
500 | 0 | *aPID = -1; |
501 | 0 | return NS_ERROR_NOT_INITIALIZED; |
502 | 0 | } |
503 | 0 | |
504 | 0 | *aPID = mContentParent->Pid(); |
505 | 0 | if (*aPID == -1) { |
506 | 0 | return NS_ERROR_FAILURE; |
507 | 0 | } |
508 | 0 | |
509 | 0 | return NS_OK; |
510 | 0 | } |
511 | | |
512 | | NS_IMETHODIMP |
513 | | ScriptableCPInfo::GetOpener(nsIContentProcessInfo** aInfo) |
514 | 0 | { |
515 | 0 | *aInfo = nullptr; |
516 | 0 | if (!mContentParent) { |
517 | 0 | return NS_ERROR_NOT_INITIALIZED; |
518 | 0 | } |
519 | 0 | |
520 | 0 | if (ContentParent* opener = mContentParent->Opener()) { |
521 | 0 | nsCOMPtr<nsIContentProcessInfo> info = opener->ScriptableHelper(); |
522 | 0 | info.forget(aInfo); |
523 | 0 | } |
524 | 0 | return NS_OK; |
525 | 0 | } |
526 | | |
527 | | NS_IMETHODIMP |
528 | | ScriptableCPInfo::GetTabCount(int32_t* aTabCount) |
529 | 0 | { |
530 | 0 | if (!mContentParent) { |
531 | 0 | return NS_ERROR_NOT_INITIALIZED; |
532 | 0 | } |
533 | 0 | |
534 | 0 | ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); |
535 | 0 | *aTabCount = cpm->GetTabParentCountByProcessId(mContentParent->ChildID()); |
536 | 0 |
|
537 | 0 | return NS_OK; |
538 | 0 | } |
539 | | |
540 | | NS_IMETHODIMP |
541 | | ScriptableCPInfo::GetMessageManager(nsISupports** aMessenger) |
542 | 0 | { |
543 | 0 | *aMessenger = nullptr; |
544 | 0 | if (!mContentParent) { |
545 | 0 | return NS_ERROR_NOT_INITIALIZED; |
546 | 0 | } |
547 | 0 | |
548 | 0 | RefPtr<ProcessMessageManager> manager = mContentParent->GetMessageManager(); |
549 | 0 | manager.forget(aMessenger); |
550 | 0 | return NS_OK; |
551 | 0 | } |
552 | | |
553 | | ProcessID |
554 | | GetTelemetryProcessID(const nsAString& remoteType) |
555 | 0 | { |
556 | 0 | // OOP WebExtensions run in a content process. |
557 | 0 | // For Telemetry though we want to break out collected data from the WebExtensions process into |
558 | 0 | // a separate bucket, to make sure we can analyze it separately and avoid skewing normal content |
559 | 0 | // process metrics. |
560 | 0 | return remoteType.EqualsLiteral(EXTENSION_REMOTE_TYPE) ? ProcessID::Extension : ProcessID::Content; |
561 | 0 | } |
562 | | |
563 | | } // anonymous namespace |
564 | | |
565 | | nsDataHashtable<nsUint32HashKey, ContentParent*>* ContentParent::sJSPluginContentParents; |
566 | | nsTArray<ContentParent*>* ContentParent::sPrivateContent; |
567 | | StaticAutoPtr<LinkedList<ContentParent> > ContentParent::sContentParents; |
568 | | #if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX) |
569 | | UniquePtr<SandboxBrokerPolicyFactory> ContentParent::sSandboxBrokerPolicyFactory; |
570 | | #endif |
571 | | uint64_t ContentParent::sNextTabParentId = 0; |
572 | | nsDataHashtable<nsUint64HashKey, TabParent*> ContentParent::sNextTabParents; |
573 | | |
574 | | // Whether a private docshell has been seen before. |
575 | | static bool sHasSeenPrivateDocShell = false; |
576 | | |
577 | | // This is true when subprocess launching is enabled. This is the |
578 | | // case between StartUp() and ShutDown(). |
579 | | static bool sCanLaunchSubprocesses; |
580 | | |
581 | | // Set to true if the DISABLE_UNSAFE_CPOW_WARNINGS environment variable is |
582 | | // set. |
583 | | static bool sDisableUnsafeCPOWWarnings = false; |
584 | | |
585 | | // The first content child has ID 1, so the chrome process can have ID 0. |
586 | | static uint64_t gContentChildID = 1; |
587 | | |
588 | | static const char* sObserverTopics[] = { |
589 | | "xpcom-shutdown", |
590 | | "profile-before-change", |
591 | | NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, |
592 | | NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC, |
593 | | NS_IPC_CAPTIVE_PORTAL_SET_STATE, |
594 | | "memory-pressure", |
595 | | "child-gc-request", |
596 | | "child-cc-request", |
597 | | "child-mmu-request", |
598 | | "child-ghost-request", |
599 | | "last-pb-context-exited", |
600 | | "file-watcher-update", |
601 | | #ifdef ACCESSIBILITY |
602 | | "a11y-init-or-shutdown", |
603 | | #endif |
604 | | "cacheservice:empty-cache", |
605 | | "intl:app-locales-changed", |
606 | | "intl:requested-locales-changed", |
607 | | "cookie-changed", |
608 | | "private-cookie-changed", |
609 | | "clear-site-data-reload-needed", |
610 | | }; |
611 | | |
612 | | // PreallocateProcess is called by the PreallocatedProcessManager. |
613 | | // ContentParent then takes this process back within GetNewOrUsedBrowserProcess. |
614 | | /*static*/ already_AddRefed<ContentParent> |
615 | | ContentParent::PreallocateProcess() |
616 | 0 | { |
617 | 0 | RefPtr<ContentParent> process = |
618 | 0 | new ContentParent(/* aOpener = */ nullptr, |
619 | 0 | NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE), |
620 | 0 | eNotRecordingOrReplaying, |
621 | 0 | /* aRecordingFile = */ EmptyString()); |
622 | 0 |
|
623 | 0 | PreallocatedProcessManager::AddBlocker(process); |
624 | 0 |
|
625 | 0 | if (!process->LaunchSubprocess(PROCESS_PRIORITY_PREALLOC)) { |
626 | 0 | return nullptr; |
627 | 0 | } |
628 | 0 | |
629 | 0 | return process.forget(); |
630 | 0 | } |
631 | | |
632 | | /*static*/ void |
633 | | ContentParent::StartUp() |
634 | 3 | { |
635 | 3 | // We could launch sub processes from content process |
636 | 3 | // FIXME Bug 1023701 - Stop using ContentParent static methods in |
637 | 3 | // child process |
638 | 3 | sCanLaunchSubprocesses = true; |
639 | 3 | |
640 | 3 | if (!XRE_IsParentProcess()) { |
641 | 0 | return; |
642 | 0 | } |
643 | 3 | |
644 | 3 | // Note: This reporter measures all ContentParents. |
645 | 3 | RegisterStrongMemoryReporter(new ContentParentsMemoryReporter()); |
646 | 3 | |
647 | 3 | BackgroundChild::Startup(); |
648 | 3 | ClientManager::Startup(); |
649 | 3 | |
650 | 3 | sDisableUnsafeCPOWWarnings = PR_GetEnv("DISABLE_UNSAFE_CPOW_WARNINGS"); |
651 | 3 | |
652 | 3 | #if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX) |
653 | 3 | sSandboxBrokerPolicyFactory = MakeUnique<SandboxBrokerPolicyFactory>(); |
654 | 3 | #endif |
655 | 3 | } |
656 | | |
657 | | /*static*/ void |
658 | | ContentParent::ShutDown() |
659 | 0 | { |
660 | 0 | // No-op for now. We rely on normal process shutdown and |
661 | 0 | // ClearOnShutdown() to clean up our state. |
662 | 0 | sCanLaunchSubprocesses = false; |
663 | 0 |
|
664 | 0 | #if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX) |
665 | 0 | sSandboxBrokerPolicyFactory = nullptr; |
666 | 0 | #endif |
667 | 0 | } |
668 | | |
669 | | /*static*/ uint32_t |
670 | | ContentParent::GetPoolSize(const nsAString& aContentProcessType) |
671 | 0 | { |
672 | 0 | if (!sBrowserContentParents) { |
673 | 0 | return 0; |
674 | 0 | } |
675 | 0 | |
676 | 0 | nsTArray<ContentParent*>* parents = |
677 | 0 | sBrowserContentParents->Get(aContentProcessType); |
678 | 0 |
|
679 | 0 | return parents ? parents->Length() : 0; |
680 | 0 | } |
681 | | |
682 | | |
683 | | /*static*/ nsTArray<ContentParent*>& |
684 | | ContentParent::GetOrCreatePool(const nsAString& aContentProcessType) |
685 | 0 | { |
686 | 0 | if (!sBrowserContentParents) { |
687 | 0 | sBrowserContentParents = |
688 | 0 | new nsClassHashtable<nsStringHashKey, nsTArray<ContentParent*>>; |
689 | 0 | } |
690 | 0 |
|
691 | 0 | return *sBrowserContentParents->LookupOrAdd(aContentProcessType); |
692 | 0 | } |
693 | | |
694 | | /*static*/ uint32_t |
695 | | ContentParent::GetMaxProcessCount(const nsAString& aContentProcessType) |
696 | 0 | { |
697 | 0 | if (aContentProcessType.EqualsLiteral("web")) { |
698 | 0 | return GetMaxWebProcessCount(); |
699 | 0 | } |
700 | 0 | |
701 | 0 | nsAutoCString processCountPref("dom.ipc.processCount."); |
702 | 0 | processCountPref.Append(NS_ConvertUTF16toUTF8(aContentProcessType)); |
703 | 0 |
|
704 | 0 | int32_t maxContentParents; |
705 | 0 | if (NS_FAILED(Preferences::GetInt(processCountPref.get(), &maxContentParents))) { |
706 | 0 | maxContentParents = Preferences::GetInt("dom.ipc.processCount", 1); |
707 | 0 | } |
708 | 0 |
|
709 | 0 | if (maxContentParents < 1) { |
710 | 0 | maxContentParents = 1; |
711 | 0 | } |
712 | 0 |
|
713 | 0 | return static_cast<uint32_t>(maxContentParents); |
714 | 0 | } |
715 | | |
716 | | /*static*/ bool |
717 | | ContentParent::IsMaxProcessCountReached(const nsAString& aContentProcessType) |
718 | 0 | { |
719 | 0 | return GetPoolSize(aContentProcessType) >= GetMaxProcessCount(aContentProcessType); |
720 | 0 | } |
721 | | |
722 | | /*static*/ void |
723 | | ContentParent::ReleaseCachedProcesses() |
724 | 0 | { |
725 | 0 | if (!GetPoolSize(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE))) { |
726 | 0 | return; |
727 | 0 | } |
728 | 0 | |
729 | 0 | // We might want to extend this for other process types as well in the future... |
730 | 0 | nsTArray<ContentParent*>& contentParents = GetOrCreatePool(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE)); |
731 | 0 | ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); |
732 | 0 | nsTArray<ContentParent*> toRelease; |
733 | 0 |
|
734 | 0 | // Shuting down these processes will change the array so let's use another array for the removal. |
735 | 0 | for (auto* cp : contentParents) { |
736 | 0 | nsTArray<TabId> tabIds = cpm->GetTabParentsByProcessId(cp->mChildID); |
737 | 0 | if (!tabIds.Length()) { |
738 | 0 | toRelease.AppendElement(cp); |
739 | 0 | } |
740 | 0 | } |
741 | 0 |
|
742 | 0 | for (auto* cp : toRelease) { |
743 | 0 | // Start a soft shutdown. |
744 | 0 | cp->ShutDownProcess(SEND_SHUTDOWN_MESSAGE); |
745 | 0 | // Make sure we don't select this process for new tabs. |
746 | 0 | cp->MarkAsDead(); |
747 | 0 | // Make sure that this process is no longer accessible from JS by its message manager. |
748 | 0 | cp->ShutDownMessageManager(); |
749 | 0 | } |
750 | 0 | } |
751 | | |
752 | | /*static*/ already_AddRefed<ContentParent> |
753 | | ContentParent::MinTabSelect(const nsTArray<ContentParent*>& aContentParents, |
754 | | ContentParent* aOpener, int32_t aMaxContentParents) |
755 | 0 | { |
756 | 0 | uint32_t maxSelectable = std::min(static_cast<uint32_t>(aContentParents.Length()), |
757 | 0 | static_cast<uint32_t>(aMaxContentParents)); |
758 | 0 | uint32_t min = INT_MAX; |
759 | 0 | RefPtr<ContentParent> candidate; |
760 | 0 | ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); |
761 | 0 |
|
762 | 0 | for (uint32_t i = 0; i < maxSelectable; i++) { |
763 | 0 | ContentParent* p = aContentParents[i]; |
764 | 0 | NS_ASSERTION(p->IsAlive(), "Non-alive contentparent in sBrowserContentParents?"); |
765 | 0 | if (p->mOpener == aOpener) { |
766 | 0 | uint32_t tabCount = cpm->GetTabParentCountByProcessId(p->ChildID()); |
767 | 0 | if (tabCount < min) { |
768 | 0 | candidate = p; |
769 | 0 | min = tabCount; |
770 | 0 | } |
771 | 0 | } |
772 | 0 | } |
773 | 0 |
|
774 | 0 | return candidate.forget(); |
775 | 0 | } |
776 | | |
777 | | static bool |
778 | | CreateTemporaryRecordingFile(nsAString& aResult) |
779 | 0 | { |
780 | 0 | static int sNumTemporaryRecordings; |
781 | 0 | nsCOMPtr<nsIFile> file; |
782 | 0 | return !NS_FAILED(NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(file))) |
783 | 0 | && !NS_FAILED(file->AppendNative(nsPrintfCString("TempRecording.%d.%d", |
784 | 0 | base::GetCurrentProcId(), |
785 | 0 | ++sNumTemporaryRecordings))) |
786 | 0 | && !NS_FAILED(file->GetPath(aResult)); |
787 | 0 | } |
788 | | |
789 | | /*static*/ already_AddRefed<ContentParent> |
790 | | ContentParent::GetNewOrUsedBrowserProcess(Element* aFrameElement, |
791 | | const nsAString& aRemoteType, |
792 | | ProcessPriority aPriority, |
793 | | ContentParent* aOpener, |
794 | | bool aPreferUsed) |
795 | 0 | { |
796 | 0 | // Figure out if this process will be recording or replaying, and which file |
797 | 0 | // to use for the recording. |
798 | 0 | RecordReplayState recordReplayState = eNotRecordingOrReplaying; |
799 | 0 | nsAutoString recordingFile; |
800 | 0 | if (aFrameElement) { |
801 | 0 | aFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::ReplayExecution, recordingFile); |
802 | 0 | if (!recordingFile.IsEmpty()) { |
803 | 0 | recordReplayState = eReplaying; |
804 | 0 | } else { |
805 | 0 | aFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::RecordExecution, recordingFile); |
806 | 0 | if (recordingFile.IsEmpty() && recordreplay::parent::SaveAllRecordingsDirectory()) { |
807 | 0 | recordingFile.AssignLiteral("*"); |
808 | 0 | } |
809 | 0 | if (!recordingFile.IsEmpty()) { |
810 | 0 | if (recordingFile.EqualsLiteral("*") && !CreateTemporaryRecordingFile(recordingFile)) { |
811 | 0 | return nullptr; |
812 | 0 | } |
813 | 0 | recordReplayState = eRecording; |
814 | 0 | } |
815 | 0 | } |
816 | 0 | } |
817 | 0 |
|
818 | 0 | nsTArray<ContentParent*>& contentParents = GetOrCreatePool(aRemoteType); |
819 | 0 | uint32_t maxContentParents = GetMaxProcessCount(aRemoteType); |
820 | 0 | if (recordReplayState != eNotRecordingOrReplaying) { |
821 | 0 | // Fall through and always create a new process when recording or replaying. |
822 | 0 | } else if (aRemoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) { |
823 | 0 | // We never want to re-use Large-Allocation processes. |
824 | 0 | if (contentParents.Length() >= maxContentParents) { |
825 | 0 | return GetNewOrUsedBrowserProcess(aFrameElement, |
826 | 0 | NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE), |
827 | 0 | aPriority, |
828 | 0 | aOpener); |
829 | 0 | } |
830 | 0 | } else { |
831 | 0 | uint32_t numberOfParents = contentParents.Length(); |
832 | 0 | nsTArray<nsIContentProcessInfo*> infos(numberOfParents); |
833 | 0 | for (auto* cp : contentParents) { |
834 | 0 | infos.AppendElement(cp->mScriptableHelper); |
835 | 0 | } |
836 | 0 |
|
837 | 0 | if (aPreferUsed && numberOfParents) { |
838 | 0 | // For the preloaded browser we don't want to create a new process but reuse an |
839 | 0 | // existing one. |
840 | 0 | maxContentParents = numberOfParents; |
841 | 0 | } |
842 | 0 |
|
843 | 0 | nsCOMPtr<nsIContentProcessProvider> cpp = |
844 | 0 | do_GetService("@mozilla.org/ipc/processselector;1"); |
845 | 0 | nsIContentProcessInfo* openerInfo = aOpener ? aOpener->mScriptableHelper.get() : nullptr; |
846 | 0 | int32_t index; |
847 | 0 | if (cpp && |
848 | 0 | NS_SUCCEEDED(cpp->ProvideProcess(aRemoteType, openerInfo, |
849 | 0 | infos.Elements(), infos.Length(), |
850 | 0 | maxContentParents, &index))) { |
851 | 0 | // If the provider returned an existing ContentParent, use that one. |
852 | 0 | if (0 <= index && static_cast<uint32_t>(index) <= maxContentParents) { |
853 | 0 | RefPtr<ContentParent> retval = contentParents[index]; |
854 | 0 | return retval.forget(); |
855 | 0 | } |
856 | 0 | } else { |
857 | 0 | // If there was a problem with the JS chooser, fall back to a random |
858 | 0 | // selection. |
859 | 0 | NS_WARNING("nsIContentProcessProvider failed to return a process"); |
860 | 0 | RefPtr<ContentParent> random; |
861 | 0 | if (contentParents.Length() >= maxContentParents && |
862 | 0 | (random = MinTabSelect(contentParents, aOpener, maxContentParents))) { |
863 | 0 | return random.forget(); |
864 | 0 | } |
865 | 0 | } |
866 | 0 | |
867 | 0 | // Try to take the preallocated process only for the default process type. |
868 | 0 | // The preallocated process manager might not had the chance yet to release the process |
869 | 0 | // after a very recent ShutDownProcess, let's make sure we don't try to reuse a process |
870 | 0 | // that is being shut down. |
871 | 0 | RefPtr<ContentParent> p; |
872 | 0 | if (aRemoteType.EqualsLiteral(DEFAULT_REMOTE_TYPE) && |
873 | 0 | (p = PreallocatedProcessManager::Take()) && |
874 | 0 | !p->mShutdownPending) { |
875 | 0 | // For pre-allocated process we have not set the opener yet. |
876 | 0 | p->mOpener = aOpener; |
877 | 0 | contentParents.AppendElement(p); |
878 | 0 | p->mActivateTS = TimeStamp::Now(); |
879 | 0 | return p.forget(); |
880 | 0 | } |
881 | 0 | } |
882 | 0 | |
883 | 0 | // Create a new process from scratch. |
884 | 0 | RefPtr<ContentParent> p = new ContentParent(aOpener, aRemoteType, recordReplayState, recordingFile); |
885 | 0 |
|
886 | 0 | // Until the new process is ready let's not allow to start up any preallocated processes. |
887 | 0 | PreallocatedProcessManager::AddBlocker(p); |
888 | 0 |
|
889 | 0 | if (!p->LaunchSubprocess(aPriority)) { |
890 | 0 | return nullptr; |
891 | 0 | } |
892 | 0 | |
893 | 0 | if (recordReplayState == eNotRecordingOrReplaying) { |
894 | 0 | contentParents.AppendElement(p); |
895 | 0 | } |
896 | 0 |
|
897 | 0 | p->mActivateTS = TimeStamp::Now(); |
898 | 0 | return p.forget(); |
899 | 0 | } |
900 | | |
901 | | /*static*/ already_AddRefed<ContentParent> |
902 | | ContentParent::GetNewOrUsedJSPluginProcess(uint32_t aPluginID, |
903 | | const hal::ProcessPriority& aPriority) |
904 | 0 | { |
905 | 0 | RefPtr<ContentParent> p; |
906 | 0 | if (sJSPluginContentParents) { |
907 | 0 | p = sJSPluginContentParents->Get(aPluginID); |
908 | 0 | } else { |
909 | 0 | sJSPluginContentParents = |
910 | 0 | new nsDataHashtable<nsUint32HashKey, ContentParent*>(); |
911 | 0 | } |
912 | 0 |
|
913 | 0 | if (p) { |
914 | 0 | return p.forget(); |
915 | 0 | } |
916 | 0 | |
917 | 0 | p = new ContentParent(aPluginID); |
918 | 0 |
|
919 | 0 | if (!p->LaunchSubprocess(aPriority)) { |
920 | 0 | return nullptr; |
921 | 0 | } |
922 | 0 | |
923 | 0 | sJSPluginContentParents->Put(aPluginID, p); |
924 | 0 |
|
925 | 0 | return p.forget(); |
926 | 0 | } |
927 | | |
928 | | /*static*/ ProcessPriority |
929 | | ContentParent::GetInitialProcessPriority(Element* aFrameElement) |
930 | 0 | { |
931 | 0 | // Frames with mozapptype == critical which are expecting a system message |
932 | 0 | // get FOREGROUND_HIGH priority. |
933 | 0 |
|
934 | 0 | if (!aFrameElement) { |
935 | 0 | return PROCESS_PRIORITY_FOREGROUND; |
936 | 0 | } |
937 | 0 | |
938 | 0 | nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(aFrameElement); |
939 | 0 | if (!browserFrame) { |
940 | 0 | return PROCESS_PRIORITY_FOREGROUND; |
941 | 0 | } |
942 | 0 | |
943 | 0 | return PROCESS_PRIORITY_FOREGROUND; |
944 | 0 | } |
945 | | |
946 | | #if defined(XP_WIN) |
947 | | extern const wchar_t* kPluginWidgetContentParentProperty; |
948 | | |
949 | | /*static*/ void |
950 | | ContentParent::SendAsyncUpdate(nsIWidget* aWidget) |
951 | | { |
952 | | if (!aWidget || aWidget->Destroyed()) { |
953 | | return; |
954 | | } |
955 | | // Fire off an async request to the plugin to paint its window |
956 | | HWND hwnd = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW); |
957 | | NS_ASSERTION(hwnd, "Expected valid hwnd value."); |
958 | | ContentParent* cp = reinterpret_cast<ContentParent*>( |
959 | | ::GetPropW(hwnd, kPluginWidgetContentParentProperty)); |
960 | | if (cp && !cp->IsDestroyed()) { |
961 | | Unused << cp->SendUpdateWindow((uintptr_t)hwnd); |
962 | | } |
963 | | } |
964 | | #endif // defined(XP_WIN) |
965 | | |
966 | | mozilla::ipc::IPCResult |
967 | | ContentParent::RecvCreateChildProcess(const IPCTabContext& aContext, |
968 | | const hal::ProcessPriority& aPriority, |
969 | | const TabId& aOpenerTabId, |
970 | | const TabId& aTabId, |
971 | | ContentParentId* aCpId, |
972 | | bool* aIsForBrowser) |
973 | 0 | { |
974 | | #if 0 |
975 | | if (!CanOpenBrowser(aContext)) { |
976 | | return false; |
977 | | } |
978 | | #endif |
979 | | RefPtr<ContentParent> cp; |
980 | 0 | MaybeInvalidTabContext tc(aContext); |
981 | 0 | if (!tc.IsValid()) { |
982 | 0 | NS_ERROR(nsPrintfCString("Received an invalid TabContext from " |
983 | 0 | "the child process. (%s)", |
984 | 0 | tc.GetInvalidReason()).get()); |
985 | 0 | return IPC_FAIL_NO_REASON(this); |
986 | 0 | } |
987 | 0 |
|
988 | 0 | if (tc.GetTabContext().IsJSPlugin()) { |
989 | 0 | cp = GetNewOrUsedJSPluginProcess(tc.GetTabContext().JSPluginId(), |
990 | 0 | aPriority); |
991 | 0 | } |
992 | 0 | else { |
993 | 0 | cp = GetNewOrUsedBrowserProcess(nullptr, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE), |
994 | 0 | aPriority, this); |
995 | 0 | } |
996 | 0 |
|
997 | 0 | if (!cp) { |
998 | 0 | *aCpId = 0; |
999 | 0 | *aIsForBrowser = false; |
1000 | 0 | return IPC_OK(); |
1001 | 0 | } |
1002 | 0 |
|
1003 | 0 | *aCpId = cp->ChildID(); |
1004 | 0 | *aIsForBrowser = cp->IsForBrowser(); |
1005 | 0 |
|
1006 | 0 | ContentProcessManager *cpm = ContentProcessManager::GetSingleton(); |
1007 | 0 | if (cp->IsForJSPlugin()) { |
1008 | 0 | // We group all the iframes for a specific JS plugin into one process, regardless of |
1009 | 0 | // origin. As a consequence that process can't be a child of the content process that |
1010 | 0 | // contains the document with the element loading the plugin. All content processes |
1011 | 0 | // need to be able to communicate with the process for the JS plugin. |
1012 | 0 | cpm->RegisterRemoteFrame(aTabId, ChildID(), aOpenerTabId, aContext, cp->ChildID()); |
1013 | 0 | return IPC_OK(); |
1014 | 0 | } |
1015 | 0 |
|
1016 | 0 | // cp was already added to the ContentProcessManager, this just sets the parent ID. |
1017 | 0 | cpm->AddContentProcess(cp, this->ChildID()); |
1018 | 0 |
|
1019 | 0 | if (cpm->AddGrandchildProcess(this->ChildID(), cp->ChildID()) && |
1020 | 0 | cpm->RegisterRemoteFrame(aTabId, ChildID(), aOpenerTabId, aContext, cp->ChildID())) { |
1021 | 0 | return IPC_OK(); |
1022 | 0 | } |
1023 | 0 |
|
1024 | 0 | return IPC_FAIL_NO_REASON(this); |
1025 | 0 | } |
1026 | | |
1027 | | mozilla::ipc::IPCResult |
1028 | | ContentParent::RecvBridgeToChildProcess(const ContentParentId& aCpId, |
1029 | | Endpoint<PContentBridgeParent>* aEndpoint) |
1030 | 0 | { |
1031 | 0 | ContentProcessManager *cpm = ContentProcessManager::GetSingleton(); |
1032 | 0 | ContentParent* cp = cpm->GetContentProcessById(aCpId); |
1033 | 0 |
|
1034 | 0 | if (cp && cp->CanCommunicateWith(ChildID())) { |
1035 | 0 | Endpoint<PContentBridgeParent> parent; |
1036 | 0 | Endpoint<PContentBridgeChild> child; |
1037 | 0 |
|
1038 | 0 | if (NS_FAILED(PContentBridge::CreateEndpoints(OtherPid(), cp->OtherPid(), |
1039 | 0 | &parent, &child))) { |
1040 | 0 | return IPC_FAIL(this, "CreateEndpoints failed"); |
1041 | 0 | } |
1042 | 0 |
|
1043 | 0 | *aEndpoint = std::move(parent); |
1044 | 0 |
|
1045 | 0 | if (!cp->SendInitContentBridgeChild(std::move(child))) { |
1046 | 0 | return IPC_FAIL(this, "SendInitContentBridgeChild failed"); |
1047 | 0 | } |
1048 | 0 |
|
1049 | 0 | return IPC_OK(); |
1050 | 0 | } |
1051 | 0 |
|
1052 | 0 | // You can't bridge to a process you didn't open! |
1053 | 0 | KillHard("BridgeToChildProcess"); |
1054 | 0 | return IPC_FAIL_NO_REASON(this); |
1055 | 0 | } |
1056 | | |
1057 | | static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement) |
1058 | 0 | { |
1059 | 0 | // Propagate the private-browsing status of the element's parent |
1060 | 0 | // docshell to the remote docshell, via the chrome flags. |
1061 | 0 | MOZ_ASSERT(aFrameElement); |
1062 | 0 | nsPIDOMWindowOuter* win = aFrameElement->OwnerDoc()->GetWindow(); |
1063 | 0 | if (!win) { |
1064 | 0 | NS_WARNING("Remote frame has no window"); |
1065 | 0 | return nullptr; |
1066 | 0 | } |
1067 | 0 | nsIDocShell* docShell = win->GetDocShell(); |
1068 | 0 | if (!docShell) { |
1069 | 0 | NS_WARNING("Remote frame has no docshell"); |
1070 | 0 | return nullptr; |
1071 | 0 | } |
1072 | 0 |
|
1073 | 0 | return docShell; |
1074 | 0 | } |
1075 | | |
1076 | | mozilla::ipc::IPCResult |
1077 | | ContentParent::RecvCreateGMPService() |
1078 | 0 | { |
1079 | 0 | Endpoint<PGMPServiceParent> parent; |
1080 | 0 | Endpoint<PGMPServiceChild> child; |
1081 | 0 |
|
1082 | 0 | nsresult rv; |
1083 | 0 | rv = PGMPService::CreateEndpoints(base::GetCurrentProcId(), |
1084 | 0 | OtherPid(), |
1085 | 0 | &parent, &child); |
1086 | 0 | if (NS_FAILED(rv)) { |
1087 | 0 | MOZ_ASSERT(false, "CreateEndpoints failed"); |
1088 | 0 | return IPC_FAIL_NO_REASON(this); |
1089 | 0 | } |
1090 | 0 |
|
1091 | 0 | if (!GMPServiceParent::Create(std::move(parent))) { |
1092 | 0 | MOZ_ASSERT(false, "GMPServiceParent::Create failed"); |
1093 | 0 | return IPC_FAIL_NO_REASON(this); |
1094 | 0 | } |
1095 | 0 |
|
1096 | 0 | if (!SendInitGMPService(std::move(child))) { |
1097 | 0 | MOZ_ASSERT(false, "SendInitGMPService failed"); |
1098 | 0 | return IPC_FAIL_NO_REASON(this); |
1099 | 0 | } |
1100 | 0 |
|
1101 | 0 | return IPC_OK(); |
1102 | 0 | } |
1103 | | |
1104 | | mozilla::ipc::IPCResult |
1105 | | ContentParent::RecvLoadPlugin(const uint32_t& aPluginId, |
1106 | | nsresult* aRv, |
1107 | | uint32_t* aRunID, |
1108 | | Endpoint<PPluginModuleParent>* aEndpoint) |
1109 | 0 | { |
1110 | 0 | *aRv = NS_OK; |
1111 | 0 | if (!mozilla::plugins::SetupBridge(aPluginId, this, aRv, aRunID, aEndpoint)) { |
1112 | 0 | return IPC_FAIL_NO_REASON(this); |
1113 | 0 | } |
1114 | 0 | return IPC_OK(); |
1115 | 0 | } |
1116 | | |
1117 | | mozilla::ipc::IPCResult |
1118 | | ContentParent::RecvUngrabPointer(const uint32_t& aTime) |
1119 | 0 | { |
1120 | | #if !defined(MOZ_WIDGET_GTK) |
1121 | | MOZ_CRASH("This message only makes sense on GTK platforms"); |
1122 | | #else |
1123 | | gdk_pointer_ungrab(aTime); |
1124 | 0 | return IPC_OK(); |
1125 | 0 | #endif |
1126 | 0 | } |
1127 | | |
1128 | | mozilla::ipc::IPCResult |
1129 | | ContentParent::RecvRemovePermission(const IPC::Principal& aPrincipal, |
1130 | | const nsCString& aPermissionType, |
1131 | 0 | nsresult* aRv) { |
1132 | 0 | *aRv = Permissions::RemovePermission(aPrincipal, aPermissionType.get()); |
1133 | 0 | return IPC_OK(); |
1134 | 0 | } |
1135 | | |
1136 | | mozilla::ipc::IPCResult |
1137 | | ContentParent::RecvConnectPluginBridge(const uint32_t& aPluginId, |
1138 | | nsresult* aRv, |
1139 | | Endpoint<PPluginModuleParent>* aEndpoint) |
1140 | 0 | { |
1141 | 0 | *aRv = NS_OK; |
1142 | 0 | // We don't need to get the run ID for the plugin, since we already got it |
1143 | 0 | // in the first call to SetupBridge in RecvLoadPlugin, so we pass in a dummy |
1144 | 0 | // pointer and just throw it away. |
1145 | 0 | uint32_t dummy = 0; |
1146 | 0 | if (!mozilla::plugins::SetupBridge(aPluginId, this, aRv, &dummy, aEndpoint)) { |
1147 | 0 | return IPC_FAIL(this, "SetupBridge failed"); |
1148 | 0 | } |
1149 | 0 | return IPC_OK(); |
1150 | 0 | } |
1151 | | |
1152 | | /*static*/ TabParent* |
1153 | | ContentParent::CreateBrowser(const TabContext& aContext, |
1154 | | Element* aFrameElement, |
1155 | | ContentParent* aOpenerContentParent, |
1156 | | TabParent* aSameTabGroupAs, |
1157 | | uint64_t aNextTabParentId) |
1158 | 0 | { |
1159 | 0 | AUTO_PROFILER_LABEL("ContentParent::CreateBrowser", OTHER); |
1160 | 0 |
|
1161 | 0 | if (!sCanLaunchSubprocesses) { |
1162 | 0 | return nullptr; |
1163 | 0 | } |
1164 | 0 | |
1165 | 0 | nsAutoString remoteType; |
1166 | 0 | if (!aFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType, |
1167 | 0 | remoteType)) { |
1168 | 0 | remoteType.AssignLiteral(DEFAULT_REMOTE_TYPE); |
1169 | 0 | } |
1170 | 0 |
|
1171 | 0 | if (aNextTabParentId) { |
1172 | 0 | if (TabParent* parent = |
1173 | 0 | sNextTabParents.GetAndRemove(aNextTabParentId).valueOr(nullptr)) { |
1174 | 0 | MOZ_ASSERT(!parent->GetOwnerElement(), |
1175 | 0 | "Shouldn't have an owner elemnt before"); |
1176 | 0 | parent->SetOwnerElement(aFrameElement); |
1177 | 0 | return parent; |
1178 | 0 | } |
1179 | 0 | } |
1180 | 0 |
|
1181 | 0 | ProcessPriority initialPriority = GetInitialProcessPriority(aFrameElement); |
1182 | 0 | bool isInContentProcess = !XRE_IsParentProcess(); |
1183 | 0 | TabId tabId(nsContentUtils::GenerateTabId()); |
1184 | 0 |
|
1185 | 0 | nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement); |
1186 | 0 | TabId openerTabId; |
1187 | 0 | if (docShell) { |
1188 | 0 | openerTabId = TabParent::GetTabIdFrom(docShell); |
1189 | 0 | } |
1190 | 0 |
|
1191 | 0 | bool isPreloadBrowser = false; |
1192 | 0 | nsAutoString isPreloadBrowserStr; |
1193 | 0 | if (aFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::preloadedState, |
1194 | 0 | isPreloadBrowserStr)) { |
1195 | 0 | isPreloadBrowser = isPreloadBrowserStr.EqualsLiteral("preloaded"); |
1196 | 0 | } |
1197 | 0 |
|
1198 | 0 | RefPtr<nsIContentParent> constructorSender; |
1199 | 0 | if (isInContentProcess) { |
1200 | 0 | MOZ_ASSERT(aContext.IsMozBrowserElement() || aContext.IsJSPlugin()); |
1201 | 0 | constructorSender = CreateContentBridgeParent(aContext, initialPriority, |
1202 | 0 | openerTabId, tabId); |
1203 | 0 | } else { |
1204 | 0 | if (aOpenerContentParent) { |
1205 | 0 | constructorSender = aOpenerContentParent; |
1206 | 0 | } else { |
1207 | 0 | if (aContext.IsJSPlugin()) { |
1208 | 0 | constructorSender = |
1209 | 0 | GetNewOrUsedJSPluginProcess(aContext.JSPluginId(), |
1210 | 0 | initialPriority); |
1211 | 0 | } else { |
1212 | 0 | constructorSender = |
1213 | 0 | GetNewOrUsedBrowserProcess(aFrameElement, remoteType, initialPriority, |
1214 | 0 | nullptr, isPreloadBrowser); |
1215 | 0 | } |
1216 | 0 | if (!constructorSender) { |
1217 | 0 | return nullptr; |
1218 | 0 | } |
1219 | 0 | } |
1220 | 0 | ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); |
1221 | 0 | cpm->RegisterRemoteFrame(tabId, |
1222 | 0 | ContentParentId(0), |
1223 | 0 | openerTabId, |
1224 | 0 | aContext.AsIPCTabContext(), |
1225 | 0 | constructorSender->ChildID()); |
1226 | 0 | } |
1227 | 0 | if (constructorSender) { |
1228 | 0 | nsCOMPtr<nsIDocShellTreeOwner> treeOwner; |
1229 | 0 | docShell->GetTreeOwner(getter_AddRefs(treeOwner)); |
1230 | 0 | if (!treeOwner) { |
1231 | 0 | return nullptr; |
1232 | 0 | } |
1233 | 0 | |
1234 | 0 | nsCOMPtr<nsIWebBrowserChrome> wbc = do_GetInterface(treeOwner); |
1235 | 0 | if (!wbc) { |
1236 | 0 | return nullptr; |
1237 | 0 | } |
1238 | 0 | uint32_t chromeFlags = 0; |
1239 | 0 | wbc->GetChromeFlags(&chromeFlags); |
1240 | 0 |
|
1241 | 0 | nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell); |
1242 | 0 | if (loadContext && loadContext->UsePrivateBrowsing()) { |
1243 | 0 | chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW; |
1244 | 0 | } |
1245 | 0 | if (docShell->GetAffectPrivateSessionLifetime()) { |
1246 | 0 | chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME; |
1247 | 0 | } |
1248 | 0 |
|
1249 | 0 | if (tabId == 0) { |
1250 | 0 | return nullptr; |
1251 | 0 | } |
1252 | 0 | RefPtr<TabParent> tp(new TabParent(constructorSender, tabId, |
1253 | 0 | aContext, chromeFlags)); |
1254 | 0 | tp->SetInitedByParent(); |
1255 | 0 |
|
1256 | 0 | PBrowserParent* browser = |
1257 | 0 | constructorSender->SendPBrowserConstructor( |
1258 | 0 | // DeallocPBrowserParent() releases this ref. |
1259 | 0 | tp.forget().take(), tabId, |
1260 | 0 | aSameTabGroupAs ? aSameTabGroupAs->GetTabId() : TabId(0), |
1261 | 0 | aContext.AsIPCTabContext(), |
1262 | 0 | chromeFlags, |
1263 | 0 | constructorSender->ChildID(), |
1264 | 0 | constructorSender->IsForBrowser()); |
1265 | 0 |
|
1266 | 0 | if (remoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) { |
1267 | 0 | // Tell the TabChild object that it was created due to a Large-Allocation |
1268 | 0 | // request. |
1269 | 0 | Unused << browser->SendAwaitLargeAlloc(); |
1270 | 0 | } |
1271 | 0 |
|
1272 | 0 | if (browser) { |
1273 | 0 | RefPtr<TabParent> constructedTabParent = TabParent::GetFrom(browser); |
1274 | 0 | constructedTabParent->SetOwnerElement(aFrameElement); |
1275 | 0 | return constructedTabParent; |
1276 | 0 | } |
1277 | 0 | } |
1278 | 0 | return nullptr; |
1279 | 0 | } |
1280 | | |
1281 | | /*static*/ ContentBridgeParent* |
1282 | | ContentParent::CreateContentBridgeParent(const TabContext& aContext, |
1283 | | const hal::ProcessPriority& aPriority, |
1284 | | const TabId& aOpenerTabId, |
1285 | | const TabId& aTabId) |
1286 | 0 | { |
1287 | 0 | MOZ_ASSERT(aTabId); |
1288 | 0 |
|
1289 | 0 | ContentChild* child = ContentChild::GetSingleton(); |
1290 | 0 | ContentParentId cpId; |
1291 | 0 | bool isForBrowser; |
1292 | 0 | if (!child->SendCreateChildProcess(aContext.AsIPCTabContext(), |
1293 | 0 | aPriority, |
1294 | 0 | aOpenerTabId, |
1295 | 0 | aTabId, |
1296 | 0 | &cpId, |
1297 | 0 | &isForBrowser)) { |
1298 | 0 | return nullptr; |
1299 | 0 | } |
1300 | 0 | if (cpId == 0) { |
1301 | 0 | return nullptr; |
1302 | 0 | } |
1303 | 0 | Endpoint<PContentBridgeParent> endpoint; |
1304 | 0 | if (!child->SendBridgeToChildProcess(cpId, &endpoint)) { |
1305 | 0 | return nullptr; |
1306 | 0 | } |
1307 | 0 | ContentBridgeParent* parent = ContentBridgeParent::Create(std::move(endpoint)); |
1308 | 0 | parent->SetChildID(cpId); |
1309 | 0 | parent->SetIsForBrowser(isForBrowser); |
1310 | 0 | parent->SetIsForJSPlugin(aContext.IsJSPlugin()); |
1311 | 0 | return parent; |
1312 | 0 | } |
1313 | | |
1314 | | void |
1315 | | ContentParent::GetAll(nsTArray<ContentParent*>& aArray) |
1316 | 129 | { |
1317 | 129 | aArray.Clear(); |
1318 | 129 | |
1319 | 129 | for (auto* cp : AllProcesses(eLive)) { |
1320 | 0 | aArray.AppendElement(cp); |
1321 | 0 | } |
1322 | 129 | } |
1323 | | |
1324 | | void |
1325 | | ContentParent::GetAllEvenIfDead(nsTArray<ContentParent*>& aArray) |
1326 | 0 | { |
1327 | 0 | aArray.Clear(); |
1328 | 0 |
|
1329 | 0 | for (auto* cp : AllProcesses(eAll)) { |
1330 | 0 | aArray.AppendElement(cp); |
1331 | 0 | } |
1332 | 0 | } |
1333 | | |
1334 | | void |
1335 | | ContentParent::BroadcastStringBundle(const StringBundleDescriptor& aBundle) |
1336 | 0 | { |
1337 | 0 | AutoTArray<StringBundleDescriptor, 1> array; |
1338 | 0 | array.AppendElement(aBundle); |
1339 | 0 |
|
1340 | 0 | for (auto* cp : AllProcesses(eLive)) { |
1341 | 0 | Unused << cp->SendRegisterStringBundles(array); |
1342 | 0 | } |
1343 | 0 | } |
1344 | | |
1345 | | const nsAString& |
1346 | | ContentParent::GetRemoteType() const |
1347 | 0 | { |
1348 | 0 | return mRemoteType; |
1349 | 0 | } |
1350 | | |
1351 | | void |
1352 | | ContentParent::Init() |
1353 | 0 | { |
1354 | 0 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
1355 | 0 | if (obs) { |
1356 | 0 | size_t length = ArrayLength(sObserverTopics); |
1357 | 0 | for (size_t i = 0; i < length; ++i) { |
1358 | 0 | obs->AddObserver(this, sObserverTopics[i], false); |
1359 | 0 | } |
1360 | 0 | } |
1361 | 0 |
|
1362 | 0 | // Register ContentParent as an observer for changes to any pref whose prefix |
1363 | 0 | // matches the empty string, i.e. all of them. |
1364 | 0 | Preferences::AddStrongObserver(this, ""); |
1365 | 0 |
|
1366 | 0 | if (obs) { |
1367 | 0 | nsAutoString cpId; |
1368 | 0 | cpId.AppendInt(static_cast<uint64_t>(this->ChildID())); |
1369 | 0 | obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created", cpId.get()); |
1370 | 0 | } |
1371 | 0 |
|
1372 | 0 | #ifdef ACCESSIBILITY |
1373 | 0 | // If accessibility is running in chrome process then start it in content |
1374 | 0 | // process. |
1375 | 0 | if (nsIPresShell::IsAccessibilityActive()) { |
1376 | | #if defined(XP_WIN) |
1377 | | // Don't init content a11y if we detect an incompat version of JAWS in use. |
1378 | | if (!mozilla::a11y::Compatibility::IsOldJAWS()) { |
1379 | | Unused << SendActivateA11y(::GetCurrentThreadId(), |
1380 | | a11y::AccessibleWrap::GetContentProcessIdFor(ChildID())); |
1381 | | } |
1382 | | #else |
1383 | | Unused << SendActivateA11y(0, 0); |
1384 | 0 | #endif |
1385 | 0 | } |
1386 | 0 | #endif |
1387 | 0 |
|
1388 | 0 | #ifdef MOZ_GECKO_PROFILER |
1389 | 0 | Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid())); |
1390 | 0 | #endif |
1391 | 0 |
|
1392 | 0 | // Ensure that the default set of permissions are avaliable in the content |
1393 | 0 | // process before we try to load any URIs in it. |
1394 | 0 | EnsurePermissionsByKey(EmptyCString()); |
1395 | 0 |
|
1396 | 0 | RefPtr<GeckoMediaPluginServiceParent> gmps(GeckoMediaPluginServiceParent::GetSingleton()); |
1397 | 0 | gmps->UpdateContentProcessGMPCapabilities(); |
1398 | 0 |
|
1399 | 0 | mScriptableHelper = new ScriptableCPInfo(this); |
1400 | 0 | } |
1401 | | |
1402 | | namespace { |
1403 | | |
1404 | | class RemoteWindowContext final : public nsIRemoteWindowContext |
1405 | | , public nsIInterfaceRequestor |
1406 | | { |
1407 | | public: |
1408 | | explicit RemoteWindowContext(TabParent* aTabParent) |
1409 | | : mTabParent(aTabParent) |
1410 | 0 | { |
1411 | 0 | } |
1412 | | |
1413 | | NS_DECL_ISUPPORTS |
1414 | | NS_DECL_NSIINTERFACEREQUESTOR |
1415 | | NS_DECL_NSIREMOTEWINDOWCONTEXT |
1416 | | |
1417 | | private: |
1418 | | ~RemoteWindowContext(); |
1419 | | RefPtr<TabParent> mTabParent; |
1420 | | }; |
1421 | | |
1422 | | NS_IMPL_ISUPPORTS(RemoteWindowContext, nsIRemoteWindowContext, nsIInterfaceRequestor) |
1423 | | |
1424 | | RemoteWindowContext::~RemoteWindowContext() |
1425 | 0 | { |
1426 | 0 | } |
1427 | | |
1428 | | NS_IMETHODIMP |
1429 | | RemoteWindowContext::GetInterface(const nsIID& aIID, void** aSink) |
1430 | 0 | { |
1431 | 0 | return QueryInterface(aIID, aSink); |
1432 | 0 | } |
1433 | | |
1434 | | NS_IMETHODIMP |
1435 | | RemoteWindowContext::OpenURI(nsIURI* aURI) |
1436 | 0 | { |
1437 | 0 | mTabParent->LoadURL(aURI); |
1438 | 0 | return NS_OK; |
1439 | 0 | } |
1440 | | |
1441 | | } // namespace |
1442 | | |
1443 | | void |
1444 | | ContentParent::ShutDownProcess(ShutDownMethod aMethod) |
1445 | 0 | { |
1446 | 0 | if (mScriptableHelper) { |
1447 | 0 | static_cast<ScriptableCPInfo*>(mScriptableHelper.get())->ProcessDied(); |
1448 | 0 | mScriptableHelper = nullptr; |
1449 | 0 | } |
1450 | 0 |
|
1451 | 0 | // Shutting down by sending a shutdown message works differently than the |
1452 | 0 | // other methods. We first call Shutdown() in the child. After the child is |
1453 | 0 | // ready, it calls FinishShutdown() on us. Then we close the channel. |
1454 | 0 | if (aMethod == SEND_SHUTDOWN_MESSAGE) { |
1455 | 0 | if (const char* directory = recordreplay::parent::SaveAllRecordingsDirectory()) { |
1456 | 0 | // Save a recording for the child process before it shuts down. |
1457 | 0 | static int sNumSavedRecordings; |
1458 | 0 | nsCOMPtr<nsIFile> file; |
1459 | 0 | if (!NS_FAILED(NS_NewNativeLocalFile(nsDependentCString(directory), false, |
1460 | 0 | getter_AddRefs(file))) && |
1461 | 0 | !NS_FAILED(file->AppendNative(nsPrintfCString("Recording.%d.%d", |
1462 | 0 | base::GetCurrentProcId(), |
1463 | 0 | ++sNumSavedRecordings)))) { |
1464 | 0 | bool unused; |
1465 | 0 | SaveRecording(file, &unused); |
1466 | 0 | } |
1467 | 0 | } |
1468 | 0 |
|
1469 | 0 | if (mIPCOpen && !mShutdownPending) { |
1470 | 0 | // Stop sending input events with input priority when shutting down. |
1471 | 0 | SetInputPriorityEventEnabled(false); |
1472 | 0 | if (SendShutdown()) { |
1473 | 0 | mShutdownPending = true; |
1474 | 0 | // Start the force-kill timer if we haven't already. |
1475 | 0 | StartForceKillTimer(); |
1476 | 0 | } |
1477 | 0 | } |
1478 | 0 | // If call was not successful, the channel must have been broken |
1479 | 0 | // somehow, and we will clean up the error in ActorDestroy. |
1480 | 0 | return; |
1481 | 0 | } |
1482 | 0 |
|
1483 | 0 | using mozilla::dom::quota::QuotaManagerService; |
1484 | 0 |
|
1485 | 0 | if (QuotaManagerService* quotaManagerService = QuotaManagerService::Get()) { |
1486 | 0 | quotaManagerService->AbortOperationsForProcess(mChildID); |
1487 | 0 | } |
1488 | 0 |
|
1489 | 0 | // If Close() fails with an error, we'll end up back in this function, but |
1490 | 0 | // with aMethod = CLOSE_CHANNEL_WITH_ERROR. |
1491 | 0 |
|
1492 | 0 | if (aMethod == CLOSE_CHANNEL && !mCalledClose) { |
1493 | 0 | // Close() can only be called once: It kicks off the destruction |
1494 | 0 | // sequence. |
1495 | 0 | mCalledClose = true; |
1496 | 0 | Close(); |
1497 | 0 | } |
1498 | 0 |
|
1499 | 0 | const ManagedContainer<POfflineCacheUpdateParent>& ocuParents = |
1500 | 0 | ManagedPOfflineCacheUpdateParent(); |
1501 | 0 | for (auto iter = ocuParents.ConstIter(); !iter.Done(); iter.Next()) { |
1502 | 0 | RefPtr<mozilla::docshell::OfflineCacheUpdateParent> ocuParent = |
1503 | 0 | static_cast<mozilla::docshell::OfflineCacheUpdateParent*>(iter.Get()->GetKey()); |
1504 | 0 | ocuParent->StopSendingMessagesToChild(); |
1505 | 0 | } |
1506 | 0 |
|
1507 | 0 | // NB: must MarkAsDead() here so that this isn't accidentally |
1508 | 0 | // returned from Get*() while in the midst of shutdown. |
1509 | 0 | MarkAsDead(); |
1510 | 0 |
|
1511 | 0 | // A ContentParent object might not get freed until after XPCOM shutdown has |
1512 | 0 | // shut down the cycle collector. But by then it's too late to release any |
1513 | 0 | // CC'ed objects, so we need to null them out here, while we still can. See |
1514 | 0 | // bug 899761. |
1515 | 0 | ShutDownMessageManager(); |
1516 | 0 | } |
1517 | | |
1518 | | mozilla::ipc::IPCResult |
1519 | | ContentParent::RecvFinishShutdown() |
1520 | 0 | { |
1521 | 0 | // At this point, we already called ShutDownProcess once with |
1522 | 0 | // SEND_SHUTDOWN_MESSAGE. To actually close the channel, we call |
1523 | 0 | // ShutDownProcess again with CLOSE_CHANNEL. |
1524 | 0 | MOZ_ASSERT(mShutdownPending); |
1525 | 0 | ShutDownProcess(CLOSE_CHANNEL); |
1526 | 0 | return IPC_OK(); |
1527 | 0 | } |
1528 | | |
1529 | | void |
1530 | | ContentParent::ShutDownMessageManager() |
1531 | 0 | { |
1532 | 0 | if (!mMessageManager) { |
1533 | 0 | return; |
1534 | 0 | } |
1535 | 0 | |
1536 | 0 | mMessageManager->ReceiveMessage(mMessageManager, nullptr, |
1537 | 0 | CHILD_PROCESS_SHUTDOWN_MESSAGE, false, |
1538 | 0 | nullptr, nullptr, nullptr, nullptr, IgnoreErrors()); |
1539 | 0 |
|
1540 | 0 | mMessageManager->Disconnect(); |
1541 | 0 | mMessageManager = nullptr; |
1542 | 0 | } |
1543 | | |
1544 | | void |
1545 | | ContentParent::RemoveFromList() |
1546 | 0 | { |
1547 | 0 | if (IsForJSPlugin()) { |
1548 | 0 | if (sJSPluginContentParents) { |
1549 | 0 | sJSPluginContentParents->Remove(mJSPluginID); |
1550 | 0 | if (!sJSPluginContentParents->Count()) { |
1551 | 0 | delete sJSPluginContentParents; |
1552 | 0 | sJSPluginContentParents = nullptr; |
1553 | 0 | } |
1554 | 0 | } |
1555 | 0 | } else if (sBrowserContentParents) { |
1556 | 0 | if (auto entry = sBrowserContentParents->Lookup(mRemoteType)) { |
1557 | 0 | nsTArray<ContentParent*>* contentParents = entry.Data(); |
1558 | 0 | contentParents->RemoveElement(this); |
1559 | 0 | if (contentParents->IsEmpty()) { |
1560 | 0 | entry.Remove(); |
1561 | 0 | } |
1562 | 0 | } |
1563 | 0 | if (sBrowserContentParents->IsEmpty()) { |
1564 | 0 | delete sBrowserContentParents; |
1565 | 0 | sBrowserContentParents = nullptr; |
1566 | 0 | } |
1567 | 0 | } |
1568 | 0 |
|
1569 | 0 | if (sPrivateContent) { |
1570 | 0 | sPrivateContent->RemoveElement(this); |
1571 | 0 | if (!sPrivateContent->Length()) { |
1572 | 0 | delete sPrivateContent; |
1573 | 0 | sPrivateContent = nullptr; |
1574 | 0 | } |
1575 | 0 | } |
1576 | 0 | } |
1577 | | |
1578 | | void |
1579 | | ContentParent::MarkAsTroubled() |
1580 | 0 | { |
1581 | 0 | RemoveFromList(); |
1582 | 0 | mIsAvailable = false; |
1583 | 0 | } |
1584 | | |
1585 | | void |
1586 | | ContentParent::MarkAsDead() |
1587 | 0 | { |
1588 | 0 | MarkAsTroubled(); |
1589 | 0 | mIsAlive = false; |
1590 | 0 | } |
1591 | | |
1592 | | void |
1593 | | ContentParent::OnChannelError() |
1594 | 0 | { |
1595 | 0 | RefPtr<ContentParent> content(this); |
1596 | 0 | PContentParent::OnChannelError(); |
1597 | 0 | } |
1598 | | |
1599 | | void |
1600 | | ContentParent::OnChannelConnected(int32_t pid) |
1601 | 0 | { |
1602 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1603 | 0 |
|
1604 | 0 | #ifndef ASYNC_CONTENTPROC_LAUNCH |
1605 | 0 | SetOtherProcessId(pid); |
1606 | 0 | #endif |
1607 | 0 |
|
1608 | 0 | #if defined(ANDROID) || defined(LINUX) |
1609 | 0 | // Check nice preference |
1610 | 0 | int32_t nice = Preferences::GetInt("dom.ipc.content.nice", 0); |
1611 | 0 |
|
1612 | 0 | // Environment variable overrides preference |
1613 | 0 | char* relativeNicenessStr = getenv("MOZ_CHILD_PROCESS_RELATIVE_NICENESS"); |
1614 | 0 | if (relativeNicenessStr) { |
1615 | 0 | nice = atoi(relativeNicenessStr); |
1616 | 0 | } |
1617 | 0 |
|
1618 | 0 | /* make the GUI thread have higher priority on single-cpu devices */ |
1619 | 0 | nsCOMPtr<nsIPropertyBag2> infoService = do_GetService(NS_SYSTEMINFO_CONTRACTID); |
1620 | 0 | if (infoService) { |
1621 | 0 | int32_t cpus; |
1622 | 0 | nsresult rv = infoService->GetPropertyAsInt32(NS_LITERAL_STRING("cpucount"), &cpus); |
1623 | 0 | if (NS_FAILED(rv)) { |
1624 | 0 | cpus = 1; |
1625 | 0 | } |
1626 | 0 | if (nice != 0 && cpus == 1) { |
1627 | 0 | setpriority(PRIO_PROCESS, pid, getpriority(PRIO_PROCESS, pid) + nice); |
1628 | 0 | } |
1629 | 0 | } |
1630 | 0 | #endif |
1631 | 0 |
|
1632 | | #if defined(MOZ_CODE_COVERAGE) && defined(ASYNC_CONTENTPROC_LAUNCH) |
1633 | | Unused << SendShareCodeCoverageMutex( |
1634 | | CodeCoverageHandler::Get()->GetMutexHandle(pid)); |
1635 | | #endif |
1636 | | } |
1637 | | |
1638 | | void |
1639 | | ContentParent::ProcessingError(Result aCode, const char* aReason) |
1640 | 0 | { |
1641 | 0 | if (MsgDropped == aCode) { |
1642 | 0 | return; |
1643 | 0 | } |
1644 | | #ifndef FUZZING |
1645 | | // Other errors are big deals. |
1646 | | KillHard(aReason); |
1647 | | #endif |
1648 | | } |
1649 | | |
1650 | | /* static */ |
1651 | | bool |
1652 | | ContentParent::AllocateLayerTreeId(TabParent* aTabParent, layers::LayersId* aId) |
1653 | 0 | { |
1654 | 0 | return AllocateLayerTreeId(aTabParent->Manager()->AsContentParent(), |
1655 | 0 | aTabParent, aTabParent->GetTabId(), aId); |
1656 | 0 | } |
1657 | | |
1658 | | /* static */ |
1659 | | bool |
1660 | | ContentParent::AllocateLayerTreeId(ContentParent* aContent, |
1661 | | TabParent* aTopLevel, const TabId& aTabId, |
1662 | | layers::LayersId* aId) |
1663 | 0 | { |
1664 | 0 | GPUProcessManager* gpu = GPUProcessManager::Get(); |
1665 | 0 |
|
1666 | 0 | *aId = gpu->AllocateLayerTreeId(); |
1667 | 0 |
|
1668 | 0 | if (!aContent || !aTopLevel) { |
1669 | 0 | return false; |
1670 | 0 | } |
1671 | 0 | |
1672 | 0 | gpu->MapLayerTreeId(*aId, aContent->OtherPid()); |
1673 | 0 |
|
1674 | 0 | return true; |
1675 | 0 | } |
1676 | | |
1677 | | mozilla::ipc::IPCResult |
1678 | | ContentParent::RecvAllocateLayerTreeId(const ContentParentId& aCpId, |
1679 | | const TabId& aTabId, layers::LayersId* aId) |
1680 | 0 | { |
1681 | 0 | // Protect against spoofing by a compromised child. aCpId must either |
1682 | 0 | // correspond to the process that this ContentParent represents or be a |
1683 | 0 | // child of it. |
1684 | 0 | ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); |
1685 | 0 | RefPtr<ContentParent> contentParent = cpm->GetContentProcessById(aCpId); |
1686 | 0 | if (!contentParent || |
1687 | 0 | (ChildID() != aCpId && !contentParent->CanCommunicateWith(ChildID()))) { |
1688 | 0 | return IPC_FAIL_NO_REASON(this); |
1689 | 0 | } |
1690 | 0 |
|
1691 | 0 | // GetTopLevelTabParentByProcessAndTabId will make sure that aTabId |
1692 | 0 | // lives in the process for aCpId. |
1693 | 0 | RefPtr<TabParent> browserParent = |
1694 | 0 | cpm->GetTopLevelTabParentByProcessAndTabId(aCpId, aTabId); |
1695 | 0 | MOZ_ASSERT(contentParent && browserParent); |
1696 | 0 |
|
1697 | 0 | if (!AllocateLayerTreeId(contentParent, browserParent, aTabId, aId)) { |
1698 | 0 | return IPC_FAIL_NO_REASON(this); |
1699 | 0 | } |
1700 | 0 | return IPC_OK(); |
1701 | 0 | } |
1702 | | |
1703 | | mozilla::ipc::IPCResult |
1704 | | ContentParent::RecvDeallocateLayerTreeId(const ContentParentId& aCpId, |
1705 | | const layers::LayersId& aId) |
1706 | 0 | { |
1707 | 0 | GPUProcessManager* gpu = GPUProcessManager::Get(); |
1708 | 0 |
|
1709 | 0 | ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); |
1710 | 0 | RefPtr<ContentParent> contentParent = cpm->GetContentProcessById(aCpId); |
1711 | 0 | if (!contentParent || !contentParent->CanCommunicateWith(ChildID())) { |
1712 | 0 | return IPC_FAIL(this, "Spoofed DeallocateLayerTreeId call"); |
1713 | 0 | } |
1714 | 0 |
|
1715 | 0 | if (!gpu->IsLayerTreeIdMapped(aId, contentParent->OtherPid())) { |
1716 | 0 | // You can't deallocate layer tree ids that you didn't allocate |
1717 | 0 | KillHard("DeallocateLayerTreeId"); |
1718 | 0 | } |
1719 | 0 |
|
1720 | 0 | gpu->UnmapLayerTreeId(aId, contentParent->OtherPid()); |
1721 | 0 |
|
1722 | 0 | return IPC_OK(); |
1723 | 0 | } |
1724 | | |
1725 | | namespace { |
1726 | | |
1727 | | void |
1728 | | DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess) |
1729 | 0 | { |
1730 | 0 | RefPtr<DeleteTask<GeckoChildProcessHost>> task = new DeleteTask<GeckoChildProcessHost>(aSubprocess); |
1731 | 0 | XRE_GetIOMessageLoop()->PostTask(task.forget()); |
1732 | 0 | } |
1733 | | |
1734 | | // This runnable only exists to delegate ownership of the |
1735 | | // ContentParent to this runnable, until it's deleted by the event |
1736 | | // system. |
1737 | | struct DelayedDeleteContentParentTask : public Runnable |
1738 | | { |
1739 | | explicit DelayedDeleteContentParentTask(ContentParent* aObj) |
1740 | | : Runnable("dom::DelayedDeleteContentParentTask") |
1741 | | , mObj(aObj) |
1742 | 0 | { |
1743 | 0 | } |
1744 | | |
1745 | | // No-op |
1746 | 0 | NS_IMETHOD Run() override { return NS_OK; } |
1747 | | |
1748 | | RefPtr<ContentParent> mObj; |
1749 | | }; |
1750 | | |
1751 | | } // namespace |
1752 | | |
1753 | | void |
1754 | | ContentParent::ActorDestroy(ActorDestroyReason why) |
1755 | 0 | { |
1756 | 0 | if (mForceKillTimer) { |
1757 | 0 | mForceKillTimer->Cancel(); |
1758 | 0 | mForceKillTimer = nullptr; |
1759 | 0 | } |
1760 | 0 |
|
1761 | 0 | // Signal shutdown completion regardless of error state, so we can |
1762 | 0 | // finish waiting in the xpcom-shutdown/profile-before-change observer. |
1763 | 0 | mIPCOpen = false; |
1764 | 0 |
|
1765 | 0 | if (mHangMonitorActor) { |
1766 | 0 | ProcessHangMonitor::RemoveProcess(mHangMonitorActor); |
1767 | 0 | mHangMonitorActor = nullptr; |
1768 | 0 | } |
1769 | 0 |
|
1770 | 0 | RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get(); |
1771 | 0 | if (fss) { |
1772 | 0 | fss->Forget(ChildID()); |
1773 | 0 | } |
1774 | 0 |
|
1775 | 0 | if (why == NormalShutdown && !mCalledClose) { |
1776 | 0 | // If we shut down normally but haven't called Close, assume somebody |
1777 | 0 | // else called Close on us. In that case, we still need to call |
1778 | 0 | // ShutDownProcess below to perform other necessary clean up. |
1779 | 0 | mCalledClose = true; |
1780 | 0 | } |
1781 | 0 |
|
1782 | 0 | // Make sure we always clean up. |
1783 | 0 | ShutDownProcess(why == NormalShutdown ? CLOSE_CHANNEL |
1784 | 0 | : CLOSE_CHANNEL_WITH_ERROR); |
1785 | 0 |
|
1786 | 0 | RefPtr<ContentParent> kungFuDeathGrip(this); |
1787 | 0 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
1788 | 0 | if (obs) { |
1789 | 0 | size_t length = ArrayLength(sObserverTopics); |
1790 | 0 | for (size_t i = 0; i < length; ++i) { |
1791 | 0 | obs->RemoveObserver(static_cast<nsIObserver*>(this), |
1792 | 0 | sObserverTopics[i]); |
1793 | 0 | } |
1794 | 0 | } |
1795 | 0 |
|
1796 | 0 | // remove the global remote preferences observers |
1797 | 0 | Preferences::RemoveObserver(this, ""); |
1798 | 0 | gfxVars::RemoveReceiver(this); |
1799 | 0 |
|
1800 | 0 | if (GPUProcessManager* gpu = GPUProcessManager::Get()) { |
1801 | 0 | // Note: the manager could have shutdown already. |
1802 | 0 | gpu->RemoveListener(this); |
1803 | 0 | } |
1804 | 0 |
|
1805 | 0 | RecvRemoveGeolocationListener(); |
1806 | 0 |
|
1807 | 0 | mConsoleService = nullptr; |
1808 | 0 |
|
1809 | 0 | if (obs) { |
1810 | 0 | RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag(); |
1811 | 0 |
|
1812 | 0 | props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), mChildID); |
1813 | 0 |
|
1814 | 0 | if (AbnormalShutdown == why) { |
1815 | 0 | Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT, |
1816 | 0 | NS_LITERAL_CSTRING("content"), 1); |
1817 | 0 |
|
1818 | 0 | props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), true); |
1819 | 0 |
|
1820 | 0 | // There's a window in which child processes can crash |
1821 | 0 | // after IPC is established, but before a crash reporter |
1822 | 0 | // is created. |
1823 | 0 | if (mCrashReporter) { |
1824 | 0 | // if mCreatedPairedMinidumps is true, we've already generated |
1825 | 0 | // parent/child dumps for desktop crashes. |
1826 | 0 | if (!mCreatedPairedMinidumps) { |
1827 | 0 | mCrashReporter->GenerateCrashReport(OtherPid()); |
1828 | 0 | } |
1829 | 0 |
|
1830 | 0 | nsAutoString dumpID; |
1831 | 0 | if (mCrashReporter->HasMinidump()) { |
1832 | 0 | dumpID = mCrashReporter->MinidumpID(); |
1833 | 0 | } |
1834 | 0 | props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID); |
1835 | 0 | } |
1836 | 0 | } |
1837 | 0 | nsAutoString cpId; |
1838 | 0 | cpId.AppendInt(static_cast<uint64_t>(this->ChildID())); |
1839 | 0 | obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", cpId.get()); |
1840 | 0 | } |
1841 | 0 |
|
1842 | 0 | // Remove any and all idle listeners. |
1843 | 0 | nsCOMPtr<nsIIdleService> idleService = |
1844 | 0 | do_GetService("@mozilla.org/widget/idleservice;1"); |
1845 | 0 | MOZ_ASSERT(idleService); |
1846 | 0 | RefPtr<ParentIdleListener> listener; |
1847 | 0 | for (int32_t i = mIdleListeners.Length() - 1; i >= 0; --i) { |
1848 | 0 | listener = static_cast<ParentIdleListener*>(mIdleListeners[i].get()); |
1849 | 0 | idleService->RemoveIdleObserver(listener, listener->mTime); |
1850 | 0 | } |
1851 | 0 | mIdleListeners.Clear(); |
1852 | 0 |
|
1853 | 0 | MessageLoop::current()-> |
1854 | 0 | PostTask(NewRunnableFunction("DelayedDeleteSubprocessRunnable", |
1855 | 0 | DelayedDeleteSubprocess, mSubprocess)); |
1856 | 0 | mSubprocess = nullptr; |
1857 | 0 |
|
1858 | 0 | // Delete any remaining replaying children. |
1859 | 0 | for (auto& replayingProcess : mReplayingChildren) { |
1860 | 0 | if (replayingProcess) { |
1861 | 0 | DelayedDeleteSubprocess(replayingProcess); |
1862 | 0 | replayingProcess = nullptr; |
1863 | 0 | } |
1864 | 0 | } |
1865 | 0 |
|
1866 | 0 | // IPDL rules require actors to live on past ActorDestroy, but it |
1867 | 0 | // may be that the kungFuDeathGrip above is the last reference to |
1868 | 0 | // |this|. If so, when we go out of scope here, we're deleted and |
1869 | 0 | // all hell breaks loose. |
1870 | 0 | // |
1871 | 0 | // This runnable ensures that a reference to |this| lives on at |
1872 | 0 | // least until after the current task finishes running. |
1873 | 0 | NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this)); |
1874 | 0 |
|
1875 | 0 | ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); |
1876 | 0 | nsTArray<ContentParentId> childIDArray = |
1877 | 0 | cpm->GetAllChildProcessById(this->ChildID()); |
1878 | 0 |
|
1879 | 0 | // Destroy any processes created by this ContentParent |
1880 | 0 | for(uint32_t i = 0; i < childIDArray.Length(); i++) { |
1881 | 0 | ContentParent* cp = cpm->GetContentProcessById(childIDArray[i]); |
1882 | 0 | MessageLoop::current()->PostTask( |
1883 | 0 | NewRunnableMethod<ShutDownMethod>("dom::ContentParent::ShutDownProcess", |
1884 | 0 | cp, |
1885 | 0 | &ContentParent::ShutDownProcess, |
1886 | 0 | SEND_SHUTDOWN_MESSAGE)); |
1887 | 0 | } |
1888 | 0 | cpm->RemoveContentProcess(this->ChildID()); |
1889 | 0 |
|
1890 | 0 | if (mDriverCrashGuard) { |
1891 | 0 | mDriverCrashGuard->NotifyCrashed(); |
1892 | 0 | } |
1893 | 0 |
|
1894 | 0 | // Unregister all the BlobURLs registered by the ContentChild. |
1895 | 0 | for (uint32_t i = 0; i < mBlobURLs.Length(); ++i) { |
1896 | 0 | BlobURLProtocolHandler::RemoveDataEntry(mBlobURLs[i]); |
1897 | 0 | } |
1898 | 0 |
|
1899 | 0 | mBlobURLs.Clear(); |
1900 | 0 |
|
1901 | | #if defined(XP_WIN32) && defined(ACCESSIBILITY) |
1902 | | a11y::AccessibleWrap::ReleaseContentProcessIdFor(ChildID()); |
1903 | | #endif |
1904 | |
|
1905 | 0 | ChromeBrowsingContext::CleanupContexts(ChildID()); |
1906 | 0 | } |
1907 | | |
1908 | | bool |
1909 | | ContentParent::TryToRecycle() |
1910 | 0 | { |
1911 | 0 | // This life time check should be replaced by a memory health check (memory usage + fragmentation). |
1912 | 0 | const double kMaxLifeSpan = 5; |
1913 | 0 | if (mShutdownPending || |
1914 | 0 | mCalledKillHard || |
1915 | 0 | !IsAvailable() || |
1916 | 0 | !mRemoteType.EqualsLiteral(DEFAULT_REMOTE_TYPE) || |
1917 | 0 | (TimeStamp::Now() - mActivateTS).ToSeconds() > kMaxLifeSpan || |
1918 | 0 | !PreallocatedProcessManager::Provide(this)) { |
1919 | 0 | return false; |
1920 | 0 | } |
1921 | 0 | |
1922 | 0 | // The PreallocatedProcessManager took over the ownership let's not keep a reference to it, |
1923 | 0 | // until we don't take it back. |
1924 | 0 | RemoveFromList(); |
1925 | 0 | return true; |
1926 | 0 | } |
1927 | | |
1928 | | bool |
1929 | | ContentParent::ShouldKeepProcessAlive() const |
1930 | 0 | { |
1931 | 0 | if (IsForJSPlugin()) { |
1932 | 0 | return true; |
1933 | 0 | } |
1934 | 0 | |
1935 | 0 | if (!sBrowserContentParents) { |
1936 | 0 | return false; |
1937 | 0 | } |
1938 | 0 | |
1939 | 0 | // If we have already been marked as troubled/dead, don't prevent shutdown. |
1940 | 0 | if (!IsAvailable()) { |
1941 | 0 | return false; |
1942 | 0 | } |
1943 | 0 | |
1944 | 0 | // Recording/replaying content parents cannot be reused and should not be |
1945 | 0 | // kept alive. |
1946 | 0 | if (this->IsRecordingOrReplaying()) { |
1947 | 0 | return false; |
1948 | 0 | } |
1949 | 0 | |
1950 | 0 | auto contentParents = sBrowserContentParents->Get(mRemoteType); |
1951 | 0 | if (!contentParents) { |
1952 | 0 | return false; |
1953 | 0 | } |
1954 | 0 | |
1955 | 0 | // We might want to keep some content processes alive for performance reasons. |
1956 | 0 | // e.g. test runs and privileged content process for some about: pages. |
1957 | 0 | // We don't want to alter behavior if the pref is not set, so default to 0. |
1958 | 0 | int32_t processesToKeepAlive = 0; |
1959 | 0 |
|
1960 | 0 | nsAutoCString keepAlivePref("dom.ipc.keepProcessesAlive."); |
1961 | 0 | keepAlivePref.Append(NS_ConvertUTF16toUTF8(mRemoteType)); |
1962 | 0 | if (NS_FAILED(Preferences::GetInt(keepAlivePref.get(), &processesToKeepAlive))) { |
1963 | 0 | return false; |
1964 | 0 | } |
1965 | 0 | |
1966 | 0 | int32_t numberOfAliveProcesses = contentParents->Length(); |
1967 | 0 |
|
1968 | 0 | return numberOfAliveProcesses <= processesToKeepAlive; |
1969 | 0 | } |
1970 | | |
1971 | | void |
1972 | | ContentParent::NotifyTabDestroying(const TabId& aTabId, |
1973 | | const ContentParentId& aCpId) |
1974 | 0 | { |
1975 | 0 | if (XRE_IsParentProcess()) { |
1976 | 0 | // There can be more than one PBrowser for a given app process |
1977 | 0 | // because of popup windows. PBrowsers can also destroy |
1978 | 0 | // concurrently. When all the PBrowsers are destroying, kick off |
1979 | 0 | // another task to ensure the child process *really* shuts down, |
1980 | 0 | // even if the PBrowsers themselves never finish destroying. |
1981 | 0 | ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); |
1982 | 0 | ContentParent* cp = cpm->GetContentProcessById(aCpId); |
1983 | 0 | if (!cp) { |
1984 | 0 | return; |
1985 | 0 | } |
1986 | 0 | ++cp->mNumDestroyingTabs; |
1987 | 0 | nsTArray<TabId> tabIds = cpm->GetTabParentsByProcessId(aCpId); |
1988 | 0 | if (static_cast<size_t>(cp->mNumDestroyingTabs) != tabIds.Length()) { |
1989 | 0 | return; |
1990 | 0 | } |
1991 | 0 | |
1992 | 0 | if (cp->ShouldKeepProcessAlive()) { |
1993 | 0 | return; |
1994 | 0 | } |
1995 | 0 | |
1996 | 0 | if (cp->TryToRecycle()) { |
1997 | 0 | return; |
1998 | 0 | } |
1999 | 0 | |
2000 | 0 | // We're dying now, so prevent this content process from being |
2001 | 0 | // recycled during its shutdown procedure. |
2002 | 0 | cp->MarkAsDead(); |
2003 | 0 | cp->StartForceKillTimer(); |
2004 | 0 | } else { |
2005 | 0 | ContentChild::GetSingleton()->SendNotifyTabDestroying(aTabId, aCpId); |
2006 | 0 | } |
2007 | 0 | } |
2008 | | |
2009 | | void |
2010 | | ContentParent::StartForceKillTimer() |
2011 | 0 | { |
2012 | 0 | if (mForceKillTimer || !mIPCOpen) { |
2013 | 0 | return; |
2014 | 0 | } |
2015 | 0 | |
2016 | 0 | int32_t timeoutSecs = Preferences::GetInt("dom.ipc.tabs.shutdownTimeoutSecs", 5); |
2017 | 0 | if (timeoutSecs > 0) { |
2018 | 0 | NS_NewTimerWithFuncCallback(getter_AddRefs(mForceKillTimer), |
2019 | 0 | ContentParent::ForceKillTimerCallback, |
2020 | 0 | this, |
2021 | 0 | timeoutSecs * 1000, |
2022 | 0 | nsITimer::TYPE_ONE_SHOT, |
2023 | 0 | "dom::ContentParent::StartForceKillTimer"); |
2024 | 0 | MOZ_ASSERT(mForceKillTimer); |
2025 | 0 | } |
2026 | 0 | } |
2027 | | |
2028 | | void |
2029 | | ContentParent::NotifyTabDestroyed(const TabId& aTabId, |
2030 | | bool aNotifiedDestroying) |
2031 | 0 | { |
2032 | 0 | if (aNotifiedDestroying) { |
2033 | 0 | --mNumDestroyingTabs; |
2034 | 0 | } |
2035 | 0 |
|
2036 | 0 | nsTArray<PContentPermissionRequestParent*> parentArray = |
2037 | 0 | nsContentPermissionUtils::GetContentPermissionRequestParentById(aTabId); |
2038 | 0 |
|
2039 | 0 | // Need to close undeleted ContentPermissionRequestParents before tab is closed. |
2040 | 0 | for (auto& permissionRequestParent : parentArray) { |
2041 | 0 | Unused << PContentPermissionRequestParent::Send__delete__(permissionRequestParent); |
2042 | 0 | } |
2043 | 0 |
|
2044 | 0 | // There can be more than one PBrowser for a given app process |
2045 | 0 | // because of popup windows. When the last one closes, shut |
2046 | 0 | // us down. |
2047 | 0 | ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); |
2048 | 0 | nsTArray<TabId> tabIds = cpm->GetTabParentsByProcessId(this->ChildID()); |
2049 | 0 |
|
2050 | 0 | if (tabIds.Length() == 1 && !ShouldKeepProcessAlive() && !TryToRecycle()) { |
2051 | 0 | // In the case of normal shutdown, send a shutdown message to child to |
2052 | 0 | // allow it to perform shutdown tasks. |
2053 | 0 | MessageLoop::current()->PostTask( |
2054 | 0 | NewRunnableMethod<ShutDownMethod>("dom::ContentParent::ShutDownProcess", |
2055 | 0 | this, |
2056 | 0 | &ContentParent::ShutDownProcess, |
2057 | 0 | SEND_SHUTDOWN_MESSAGE)); |
2058 | 0 | } |
2059 | 0 | } |
2060 | | |
2061 | | mozilla::ipc::IPCResult |
2062 | | ContentParent::RecvOpenRecordReplayChannel(const uint32_t& aChannelId, |
2063 | | FileDescriptor* aConnection) |
2064 | 0 | { |
2065 | 0 | // We should only get this message from the child if it is recording or replaying. |
2066 | 0 | if (!this->IsRecordingOrReplaying()) { |
2067 | 0 | return IPC_FAIL_NO_REASON(this); |
2068 | 0 | } |
2069 | 0 |
|
2070 | 0 | recordreplay::parent::OpenChannel(Pid(), aChannelId, aConnection); |
2071 | 0 | return IPC_OK(); |
2072 | 0 | } |
2073 | | |
2074 | | mozilla::ipc::IPCResult |
2075 | | ContentParent::RecvCreateReplayingProcess(const uint32_t& aChannelId) |
2076 | 0 | { |
2077 | 0 | // We should only get this message from the child if it is recording or replaying. |
2078 | 0 | if (!this->IsRecordingOrReplaying()) { |
2079 | 0 | return IPC_FAIL_NO_REASON(this); |
2080 | 0 | } |
2081 | 0 |
|
2082 | 0 | while (aChannelId >= mReplayingChildren.length()) { |
2083 | 0 | if (!mReplayingChildren.append(nullptr)) { |
2084 | 0 | return IPC_FAIL_NO_REASON(this); |
2085 | 0 | } |
2086 | 0 | } |
2087 | 0 | if (mReplayingChildren[aChannelId]) { |
2088 | 0 | return IPC_FAIL_NO_REASON(this); |
2089 | 0 | } |
2090 | 0 |
|
2091 | 0 | std::vector<std::string> extraArgs; |
2092 | 0 | recordreplay::parent::GetArgumentsForChildProcess(Pid(), aChannelId, |
2093 | 0 | NS_ConvertUTF16toUTF8(mRecordingFile).get(), |
2094 | 0 | /* aRecording = */ false, |
2095 | 0 | extraArgs); |
2096 | 0 |
|
2097 | 0 | mReplayingChildren[aChannelId] = new GeckoChildProcessHost(GeckoProcessType_Content); |
2098 | 0 | if (!mReplayingChildren[aChannelId]->LaunchAndWaitForProcessHandle(extraArgs)) { |
2099 | 0 | return IPC_FAIL_NO_REASON(this); |
2100 | 0 | } |
2101 | 0 |
|
2102 | 0 | return IPC_OK(); |
2103 | 0 | } |
2104 | | |
2105 | | mozilla::ipc::IPCResult |
2106 | | ContentParent::RecvTerminateReplayingProcess(const uint32_t& aChannelId) |
2107 | 0 | { |
2108 | 0 | // We should only get this message from the child if it is recording or replaying. |
2109 | 0 | if (!this->IsRecordingOrReplaying()) { |
2110 | 0 | return IPC_FAIL_NO_REASON(this); |
2111 | 0 | } |
2112 | 0 |
|
2113 | 0 | if (aChannelId < mReplayingChildren.length() && mReplayingChildren[aChannelId]) { |
2114 | 0 | DelayedDeleteSubprocess(mReplayingChildren[aChannelId]); |
2115 | 0 | mReplayingChildren[aChannelId] = nullptr; |
2116 | 0 | } |
2117 | 0 | return IPC_OK(); |
2118 | 0 | } |
2119 | | |
2120 | | jsipc::CPOWManager* |
2121 | | ContentParent::GetCPOWManager() |
2122 | 0 | { |
2123 | 0 | if (PJavaScriptParent* p = LoneManagedOrNullAsserts(ManagedPJavaScriptParent())) { |
2124 | 0 | return CPOWManagerFor(p); |
2125 | 0 | } |
2126 | 0 | return nullptr; |
2127 | 0 | } |
2128 | | |
2129 | | TestShellParent* |
2130 | | ContentParent::CreateTestShell() |
2131 | 0 | { |
2132 | 0 | return static_cast<TestShellParent*>(SendPTestShellConstructor()); |
2133 | 0 | } |
2134 | | |
2135 | | bool |
2136 | | ContentParent::DestroyTestShell(TestShellParent* aTestShell) |
2137 | 0 | { |
2138 | 0 | return PTestShellParent::Send__delete__(aTestShell); |
2139 | 0 | } |
2140 | | |
2141 | | TestShellParent* |
2142 | | ContentParent::GetTestShellSingleton() |
2143 | 0 | { |
2144 | 0 | PTestShellParent* p = LoneManagedOrNullAsserts(ManagedPTestShellParent()); |
2145 | 0 | return static_cast<TestShellParent*>(p); |
2146 | 0 | } |
2147 | | |
2148 | | bool |
2149 | | ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PRIORITY_FOREGROUND */) |
2150 | 0 | { |
2151 | 0 | AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess", OTHER); |
2152 | 0 |
|
2153 | 0 | if (!ContentProcessManager::GetSingleton()) { |
2154 | 0 | // Shutdown has begun, we shouldn't spawn any more child processes. |
2155 | 0 | return false; |
2156 | 0 | } |
2157 | 0 | |
2158 | 0 | std::vector<std::string> extraArgs; |
2159 | 0 | extraArgs.push_back("-childID"); |
2160 | 0 | char idStr[21]; |
2161 | 0 | SprintfLiteral(idStr, "%" PRId64, static_cast<uint64_t>(mChildID)); |
2162 | 0 | extraArgs.push_back(idStr); |
2163 | 0 | extraArgs.push_back(IsForBrowser() ? "-isForBrowser" : "-notForBrowser"); |
2164 | 0 |
|
2165 | 0 | // Prefs information is passed via anonymous shared memory to avoid bloating |
2166 | 0 | // the command line. |
2167 | 0 |
|
2168 | 0 | size_t prefMapSize; |
2169 | 0 | auto prefMapHandle = Preferences::EnsureSnapshot(&prefMapSize).ClonePlatformHandle(); |
2170 | 0 |
|
2171 | 0 | // Serialize the early prefs. |
2172 | 0 | nsAutoCStringN<1024> prefs; |
2173 | 0 | Preferences::SerializePreferences(prefs); |
2174 | 0 |
|
2175 | 0 | // Set up the shared memory. |
2176 | 0 | base::SharedMemory shm; |
2177 | 0 | if (!shm.Create(prefs.Length())) { |
2178 | 0 | NS_ERROR("failed to create shared memory in the parent"); |
2179 | 0 | MarkAsDead(); |
2180 | 0 | return false; |
2181 | 0 | } |
2182 | 0 | if (!shm.Map(prefs.Length())) { |
2183 | 0 | NS_ERROR("failed to map shared memory in the parent"); |
2184 | 0 | MarkAsDead(); |
2185 | 0 | return false; |
2186 | 0 | } |
2187 | 0 |
|
2188 | 0 | // Copy the serialized prefs into the shared memory. |
2189 | 0 | memcpy(static_cast<char*>(shm.memory()), prefs.get(), prefs.Length()); |
2190 | 0 |
|
2191 | 0 | // Formats a pointer or pointer-sized-integer as a string suitable for passing |
2192 | 0 | // in an arguments list. |
2193 | 0 | auto formatPtrArg = [] (auto arg) { |
2194 | 0 | return nsPrintfCString("%zu", uintptr_t(arg)); |
2195 | 0 | }; Unexecuted instantiation: Unified_cpp_dom_ipc0.cpp:_ZZN7mozilla3dom13ContentParent16LaunchSubprocessENS_3hal15ProcessPriorityEENK3$_0clIjEEDaT_ Unexecuted instantiation: Unified_cpp_dom_ipc0.cpp:_ZZN7mozilla3dom13ContentParent16LaunchSubprocessENS_3hal15ProcessPriorityEENK3$_0clImEEDaT_ |
2196 | 0 |
|
2197 | | #if defined(XP_WIN) |
2198 | | // Record the handle as to-be-shared, and pass it via a command flag. This |
2199 | | // works because Windows handles are system-wide. |
2200 | | HANDLE prefsHandle = shm.handle(); |
2201 | | mSubprocess->AddHandleToShare(prefsHandle); |
2202 | | mSubprocess->AddHandleToShare(prefMapHandle.get()); |
2203 | | extraArgs.push_back("-prefsHandle"); |
2204 | | extraArgs.push_back(formatPtrArg(prefsHandle).get()); |
2205 | | extraArgs.push_back("-prefMapHandle"); |
2206 | | extraArgs.push_back(formatPtrArg(prefMapHandle.get()).get()); |
2207 | | #else |
2208 | | // In contrast, Unix fds are per-process. So remap the fd to a fixed one that |
2209 | 0 | // will be used in the child. |
2210 | 0 | // XXX: bug 1440207 is about improving how fixed fds are used. |
2211 | 0 | // |
2212 | 0 | // Note: on Android, AddFdToRemap() sets up the fd to be passed via a Parcel, |
2213 | 0 | // and the fixed fd isn't used. However, we still need to mark it for |
2214 | 0 | // remapping so it doesn't get closed in the child. |
2215 | 0 | mSubprocess->AddFdToRemap(shm.handle().fd, kPrefsFileDescriptor); |
2216 | 0 | mSubprocess->AddFdToRemap(prefMapHandle.get(), kPrefMapFileDescriptor); |
2217 | 0 | #endif |
2218 | 0 |
|
2219 | 0 | // Pass the lengths via command line flags. |
2220 | 0 | extraArgs.push_back("-prefsLen"); |
2221 | 0 | extraArgs.push_back(formatPtrArg(prefs.Length()).get()); |
2222 | 0 |
|
2223 | 0 | extraArgs.push_back("-prefMapSize"); |
2224 | 0 | extraArgs.push_back(formatPtrArg(prefMapSize).get()); |
2225 | 0 |
|
2226 | 0 | // Scheduler prefs need to be handled differently because the scheduler needs |
2227 | 0 | // to start up in the content process before the normal preferences service. |
2228 | 0 | nsPrintfCString schedulerPrefs = Scheduler::GetPrefs(); |
2229 | 0 | extraArgs.push_back("-schedulerPrefs"); |
2230 | 0 | extraArgs.push_back(schedulerPrefs.get()); |
2231 | 0 |
|
2232 | 0 | if (gSafeMode) { |
2233 | 0 | extraArgs.push_back("-safeMode"); |
2234 | 0 | } |
2235 | 0 |
|
2236 | 0 | nsCString parentBuildID(mozilla::PlatformBuildID()); |
2237 | 0 | extraArgs.push_back("-parentBuildID"); |
2238 | 0 | extraArgs.push_back(parentBuildID.get()); |
2239 | 0 |
|
2240 | 0 | // Specify whether the process is recording or replaying an execution. |
2241 | 0 | if (mRecordReplayState != eNotRecordingOrReplaying) { |
2242 | 0 | nsPrintfCString buf("%d", mRecordReplayState == eRecording |
2243 | 0 | ? (int) recordreplay::ProcessKind::MiddlemanRecording |
2244 | 0 | : (int) recordreplay::ProcessKind::MiddlemanReplaying); |
2245 | 0 | extraArgs.push_back(recordreplay::gProcessKindOption); |
2246 | 0 | extraArgs.push_back(buf.get()); |
2247 | 0 |
|
2248 | 0 | extraArgs.push_back(recordreplay::gRecordingFileOption); |
2249 | 0 | extraArgs.push_back(NS_ConvertUTF16toUTF8(mRecordingFile).get()); |
2250 | 0 | } |
2251 | 0 |
|
2252 | 0 | SetOtherProcessId(kInvalidProcessId, ProcessIdState::ePending); |
2253 | | #ifdef ASYNC_CONTENTPROC_LAUNCH |
2254 | | if (!mSubprocess->Launch(extraArgs)) { |
2255 | | #else |
2256 | 0 | if (!mSubprocess->LaunchAndWaitForProcessHandle(extraArgs)) { |
2257 | 0 | #endif |
2258 | 0 | NS_ERROR("failed to launch child in the parent"); |
2259 | 0 | MarkAsDead(); |
2260 | 0 | return false; |
2261 | 0 | } |
2262 | 0 |
|
2263 | | #ifdef ASYNC_CONTENTPROC_LAUNCH |
2264 | | OpenWithAsyncPid(mSubprocess->GetChannel()); |
2265 | | #else |
2266 | 0 | base::ProcessId procId = |
2267 | 0 | base::GetProcId(mSubprocess->GetChildProcessHandle()); |
2268 | 0 | Open(mSubprocess->GetChannel(), procId); |
2269 | | #ifdef MOZ_CODE_COVERAGE |
2270 | | Unused << SendShareCodeCoverageMutex( |
2271 | | CodeCoverageHandler::Get()->GetMutexHandle(procId)); |
2272 | | #endif |
2273 | | #endif // ASYNC_CONTENTPROC_LAUNCH |
2274 | 0 |
|
2275 | 0 | InitInternal(aInitialPriority); |
2276 | 0 |
|
2277 | 0 | ContentProcessManager::GetSingleton()->AddContentProcess(this); |
2278 | 0 |
|
2279 | 0 | mHangMonitorActor = ProcessHangMonitor::AddProcess(this); |
2280 | 0 |
|
2281 | 0 | // Set a reply timeout for CPOWs. |
2282 | 0 | SetReplyTimeoutMs(Preferences::GetInt("dom.ipc.cpow.timeout", 0)); |
2283 | 0 |
|
2284 | 0 | // TODO: In ASYNC_CONTENTPROC_LAUNCH, if OtherPid() is not called between |
2285 | 0 | // mSubprocess->Launch() and this, then we're not really measuring how long it |
2286 | 0 | // took to spawn the process. |
2287 | 0 | Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_TIME_MS, |
2288 | 0 | static_cast<uint32_t>((TimeStamp::Now() - mLaunchTS) |
2289 | 0 | .ToMilliseconds())); |
2290 | 0 |
|
2291 | 0 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
2292 | 0 | if (obs) { |
2293 | 0 | nsAutoString cpId; |
2294 | 0 | cpId.AppendInt(static_cast<uint64_t>(this->ChildID())); |
2295 | 0 | obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-initializing", cpId.get()); |
2296 | 0 | } |
2297 | 0 |
|
2298 | 0 | Init(); |
2299 | 0 |
|
2300 | 0 | return true; |
2301 | 0 | } |
2302 | | |
2303 | | ContentParent::ContentParent(ContentParent* aOpener, |
2304 | | const nsAString& aRemoteType, |
2305 | | RecordReplayState aRecordReplayState, |
2306 | | const nsAString& aRecordingFile, |
2307 | | int32_t aJSPluginID) |
2308 | | : nsIContentParent() |
2309 | | , mSubprocess(nullptr) |
2310 | | , mLaunchTS(TimeStamp::Now()) |
2311 | | , mActivateTS(TimeStamp::Now()) |
2312 | | , mOpener(aOpener) |
2313 | | , mRemoteType(aRemoteType) |
2314 | | , mChildID(gContentChildID++) |
2315 | | , mGeolocationWatchID(-1) |
2316 | | , mJSPluginID(aJSPluginID) |
2317 | | , mNumDestroyingTabs(0) |
2318 | | , mIsAvailable(true) |
2319 | | , mIsAlive(true) |
2320 | | , mIsForBrowser(!mRemoteType.IsEmpty()) |
2321 | | , mRecordReplayState(aRecordReplayState) |
2322 | | , mRecordingFile(aRecordingFile) |
2323 | | , mCalledClose(false) |
2324 | | , mCalledKillHard(false) |
2325 | | , mCreatedPairedMinidumps(false) |
2326 | | , mShutdownPending(false) |
2327 | | , mIPCOpen(true) |
2328 | | , mIsRemoteInputEventQueueEnabled(false) |
2329 | | , mIsInputPriorityEventEnabled(false) |
2330 | | , mHangMonitorActor(nullptr) |
2331 | 0 | { |
2332 | 0 | // Insert ourselves into the global linked list of ContentParent objects. |
2333 | 0 | if (!sContentParents) { |
2334 | 0 | sContentParents = new LinkedList<ContentParent>(); |
2335 | 0 | } |
2336 | 0 | sContentParents->insertBack(this); |
2337 | 0 |
|
2338 | 0 | // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the |
2339 | 0 | // PID along with the warning. |
2340 | 0 | nsDebugImpl::SetMultiprocessMode("Parent"); |
2341 | 0 |
|
2342 | | #if defined(XP_WIN) |
2343 | | if (XRE_IsParentProcess()) { |
2344 | | audio::AudioNotificationSender::Init(); |
2345 | | } |
2346 | | // Request Windows message deferral behavior on our side of the PContent |
2347 | | // channel. Generally only applies to the situation where we get caught in |
2348 | | // a deadlock with the plugin process when sending CPOWs. |
2349 | | GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION); |
2350 | | #endif |
2351 | |
|
2352 | 0 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
2353 | 0 | bool isFile = mRemoteType.EqualsLiteral(FILE_REMOTE_TYPE); |
2354 | 0 | mSubprocess = new ContentProcessHost(this, isFile); |
2355 | 0 | } |
2356 | | |
2357 | | ContentParent::~ContentParent() |
2358 | 0 | { |
2359 | 0 | if (mForceKillTimer) { |
2360 | 0 | mForceKillTimer->Cancel(); |
2361 | 0 | } |
2362 | 0 |
|
2363 | 0 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
2364 | 0 |
|
2365 | 0 | // We should be removed from all these lists in ActorDestroy. |
2366 | 0 | MOZ_ASSERT(!sPrivateContent || !sPrivateContent->Contains(this)); |
2367 | 0 | if (IsForJSPlugin()) { |
2368 | 0 | MOZ_ASSERT(!sJSPluginContentParents || |
2369 | 0 | !sJSPluginContentParents->Get(mJSPluginID)); |
2370 | 0 | } else { |
2371 | 0 | MOZ_ASSERT(!sBrowserContentParents || |
2372 | 0 | !sBrowserContentParents->Contains(mRemoteType) || |
2373 | 0 | !sBrowserContentParents->Get(mRemoteType)->Contains(this)); |
2374 | 0 | } |
2375 | 0 | } |
2376 | | |
2377 | | void |
2378 | | ContentParent::InitInternal(ProcessPriority aInitialPriority) |
2379 | 0 | { |
2380 | 0 | Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_TIME_MS, |
2381 | 0 | static_cast<uint32_t>((TimeStamp::Now() - mLaunchTS) |
2382 | 0 | .ToMilliseconds())); |
2383 | 0 |
|
2384 | 0 | XPCOMInitData xpcomInit; |
2385 | 0 |
|
2386 | 0 | nsCOMPtr<nsIIOService> io(do_GetIOService()); |
2387 | 0 | MOZ_ASSERT(io, "No IO service?"); |
2388 | 0 | DebugOnly<nsresult> rv = io->GetOffline(&xpcomInit.isOffline()); |
2389 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?"); |
2390 | 0 |
|
2391 | 0 | rv = io->GetConnectivity(&xpcomInit.isConnected()); |
2392 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?"); |
2393 | 0 |
|
2394 | 0 | xpcomInit.captivePortalState() = nsICaptivePortalService::UNKNOWN; |
2395 | 0 | nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CONTRACTID); |
2396 | 0 | if (cps) { |
2397 | 0 | cps->GetState(&xpcomInit.captivePortalState()); |
2398 | 0 | } |
2399 | 0 |
|
2400 | 0 | nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard(); |
2401 | 0 |
|
2402 | 0 | xpcomInit.isLangRTL() = false; |
2403 | 0 | xpcomInit.haveBidiKeyboards() = false; |
2404 | 0 | if (bidi) { |
2405 | 0 | bidi->IsLangRTL(&xpcomInit.isLangRTL()); |
2406 | 0 | bidi->GetHaveBidiKeyboards(&xpcomInit.haveBidiKeyboards()); |
2407 | 0 | } |
2408 | 0 |
|
2409 | 0 | nsCOMPtr<nsISpellChecker> spellChecker(mozSpellChecker::Create()); |
2410 | 0 | MOZ_ASSERT(spellChecker, "No spell checker?"); |
2411 | 0 |
|
2412 | 0 | spellChecker->GetDictionaryList(&xpcomInit.dictionaries()); |
2413 | 0 |
|
2414 | 0 | LocaleService::GetInstance()->GetAppLocalesAsLangTags(xpcomInit.appLocales()); |
2415 | 0 | LocaleService::GetInstance()->GetRequestedLocales(xpcomInit.requestedLocales()); |
2416 | 0 |
|
2417 | 0 | nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1")); |
2418 | 0 | MOZ_ASSERT(clipboard, "No clipboard?"); |
2419 | 0 |
|
2420 | 0 | rv = clipboard->SupportsSelectionClipboard(&xpcomInit.clipboardCaps().supportsSelectionClipboard()); |
2421 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
2422 | 0 |
|
2423 | 0 | rv = clipboard->SupportsFindClipboard(&xpcomInit.clipboardCaps().supportsFindClipboard()); |
2424 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
2425 | 0 |
|
2426 | 0 | // Let's copy the domain policy from the parent to the child (if it's active). |
2427 | 0 | StructuredCloneData initialData; |
2428 | 0 | nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); |
2429 | 0 | if (ssm) { |
2430 | 0 | ssm->CloneDomainPolicy(&xpcomInit.domainPolicy()); |
2431 | 0 |
|
2432 | 0 | if (ParentProcessMessageManager* mm = nsFrameMessageManager::sParentProcessManager) { |
2433 | 0 | AutoJSAPI jsapi; |
2434 | 0 | if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) { |
2435 | 0 | MOZ_CRASH(); |
2436 | 0 | } |
2437 | 0 | JS::RootedValue init(jsapi.cx()); |
2438 | 0 | // We'll crash on failure, so use a IgnoredErrorResult (which also auto-suppresses |
2439 | 0 | // exceptions). |
2440 | 0 | IgnoredErrorResult rv; |
2441 | 0 | mm->GetInitialProcessData(jsapi.cx(), &init, rv); |
2442 | 0 | if (NS_WARN_IF(rv.Failed())) { |
2443 | 0 | MOZ_CRASH(); |
2444 | 0 | } |
2445 | 0 |
|
2446 | 0 | initialData.Write(jsapi.cx(), init, rv); |
2447 | 0 | if (NS_WARN_IF(rv.Failed())) { |
2448 | 0 | MOZ_CRASH(); |
2449 | 0 | } |
2450 | 0 | } |
2451 | 0 | } |
2452 | 0 | // This is only implemented (returns a non-empty list) by MacOSX and Linux |
2453 | 0 | // at present. |
2454 | 0 | nsTArray<SystemFontListEntry> fontList; |
2455 | 0 | gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList); |
2456 | 0 | nsTArray<LookAndFeelInt> lnfCache = LookAndFeel::GetIntCache(); |
2457 | 0 |
|
2458 | 0 | // Content processes have no permission to access profile directory, so we |
2459 | 0 | // send the file URL instead. |
2460 | 0 | StyleSheet* ucs = nsLayoutStylesheetCache::Singleton()->UserContentSheet(); |
2461 | 0 | if (ucs) { |
2462 | 0 | SerializeURI(ucs->GetSheetURI(), xpcomInit.userContentSheetURL()); |
2463 | 0 | } else { |
2464 | 0 | SerializeURI(nullptr, xpcomInit.userContentSheetURL()); |
2465 | 0 | } |
2466 | 0 |
|
2467 | 0 | // 1. Build ContentDeviceData first, as it may affect some gfxVars. |
2468 | 0 | gfxPlatform::GetPlatform()->BuildContentDeviceData(&xpcomInit.contentDeviceData()); |
2469 | 0 | // 2. Gather non-default gfxVars. |
2470 | 0 | xpcomInit.gfxNonDefaultVarUpdates() = gfxVars::FetchNonDefaultVars(); |
2471 | 0 | // 3. Start listening for gfxVars updates, to notify content process later on. |
2472 | 0 | gfxVars::AddReceiver(this); |
2473 | 0 |
|
2474 | 0 | nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); |
2475 | 0 | if (gfxInfo) { |
2476 | 0 | for (int32_t i = 1; i <= nsIGfxInfo::FEATURE_MAX_VALUE; ++i) { |
2477 | 0 | int32_t status = 0; |
2478 | 0 | nsAutoCString failureId; |
2479 | 0 | gfxInfo->GetFeatureStatus(i, failureId, &status); |
2480 | 0 | dom::GfxInfoFeatureStatus gfxFeatureStatus; |
2481 | 0 | gfxFeatureStatus.feature() = i; |
2482 | 0 | gfxFeatureStatus.status() = status; |
2483 | 0 | gfxFeatureStatus.failureId() = failureId; |
2484 | 0 | xpcomInit.gfxFeatureStatus().AppendElement(gfxFeatureStatus); |
2485 | 0 | } |
2486 | 0 | } |
2487 | 0 |
|
2488 | 0 | DataStorage::GetAllChildProcessData(xpcomInit.dataStorage()); |
2489 | 0 |
|
2490 | 0 | // Send the dynamic scalar definitions to the new process. |
2491 | 0 | TelemetryIPC::GetDynamicScalarDefinitions(xpcomInit.dynamicScalarDefs()); |
2492 | 0 |
|
2493 | 0 | // Must send screen info before send initialData |
2494 | 0 | ScreenManager& screenManager = ScreenManager::GetSingleton(); |
2495 | 0 | screenManager.CopyScreensToRemote(this); |
2496 | 0 |
|
2497 | 0 | Unused << SendSetXPCOMProcessAttributes(xpcomInit, initialData, lnfCache, |
2498 | 0 | fontList); |
2499 | 0 |
|
2500 | 0 | ipc::WritableSharedMap* sharedData = nsFrameMessageManager::sParentProcessManager->SharedData(); |
2501 | 0 | sharedData->Flush(); |
2502 | 0 | sharedData->SendTo(this); |
2503 | 0 |
|
2504 | 0 | nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService(); |
2505 | 0 | nsChromeRegistryChrome* chromeRegistry = |
2506 | 0 | static_cast<nsChromeRegistryChrome*>(registrySvc.get()); |
2507 | 0 | chromeRegistry->SendRegisteredChrome(this); |
2508 | 0 |
|
2509 | 0 | nsCOMPtr<nsIStringBundleService> stringBundleService = |
2510 | 0 | services::GetStringBundleService(); |
2511 | 0 | stringBundleService->SendContentBundles(this); |
2512 | 0 |
|
2513 | 0 | if (gAppData) { |
2514 | 0 | nsCString version(gAppData->version); |
2515 | 0 | nsCString buildID(gAppData->buildID); |
2516 | 0 | nsCString name(gAppData->name); |
2517 | 0 | nsCString UAName(gAppData->UAName); |
2518 | 0 | nsCString ID(gAppData->ID); |
2519 | 0 | nsCString vendor(gAppData->vendor); |
2520 | 0 | nsCString sourceURL(gAppData->sourceURL); |
2521 | 0 |
|
2522 | 0 | // Sending all information to content process. |
2523 | 0 | Unused << SendAppInfo(version, buildID, name, UAName, ID, vendor, sourceURL); |
2524 | 0 | } |
2525 | 0 |
|
2526 | 0 | // Send the child its remote type. On Mac, this needs to be sent prior |
2527 | 0 | // to the message we send to enable the Sandbox (SendStartProcessSandbox) |
2528 | 0 | // because different remote types require different sandbox privileges. |
2529 | 0 | Unused << SendRemoteType(mRemoteType); |
2530 | 0 |
|
2531 | 0 | ScriptPreloader::InitContentChild(*this); |
2532 | 0 |
|
2533 | 0 | // Initialize the message manager (and load delayed scripts) now that we |
2534 | 0 | // have established communications with the child. |
2535 | 0 | mMessageManager->InitWithCallback(this); |
2536 | 0 |
|
2537 | 0 | // Set the subprocess's priority. We do this early on because we're likely |
2538 | 0 | // /lowering/ the process's CPU and memory priority, which it has inherited |
2539 | 0 | // from this process. |
2540 | 0 | // |
2541 | 0 | // This call can cause us to send IPC messages to the child process, so it |
2542 | 0 | // must come after the Open() call above. |
2543 | 0 | ProcessPriorityManager::SetProcessPriority(this, aInitialPriority); |
2544 | 0 |
|
2545 | 0 | // NB: internally, this will send an IPC message to the child |
2546 | 0 | // process to get it to create the CompositorBridgeChild. This |
2547 | 0 | // message goes through the regular IPC queue for this |
2548 | 0 | // channel, so delivery will happen-before any other messages |
2549 | 0 | // we send. The CompositorBridgeChild must be created before any |
2550 | 0 | // PBrowsers are created, because they rely on the Compositor |
2551 | 0 | // already being around. (Creation is async, so can't happen |
2552 | 0 | // on demand.) |
2553 | 0 | GPUProcessManager* gpm = GPUProcessManager::Get(); |
2554 | 0 |
|
2555 | 0 | Endpoint<PCompositorManagerChild> compositor; |
2556 | 0 | Endpoint<PImageBridgeChild> imageBridge; |
2557 | 0 | Endpoint<PVRManagerChild> vrBridge; |
2558 | 0 | Endpoint<PVideoDecoderManagerChild> videoManager; |
2559 | 0 | AutoTArray<uint32_t, 3> namespaces; |
2560 | 0 |
|
2561 | 0 | DebugOnly<bool> opened = gpm->CreateContentBridges(OtherPid(), |
2562 | 0 | &compositor, |
2563 | 0 | &imageBridge, |
2564 | 0 | &vrBridge, |
2565 | 0 | &videoManager, |
2566 | 0 | &namespaces); |
2567 | 0 | MOZ_ASSERT(opened); |
2568 | 0 |
|
2569 | 0 | Unused << SendInitRendering(std::move(compositor), |
2570 | 0 | std::move(imageBridge), |
2571 | 0 | std::move(vrBridge), |
2572 | 0 | std::move(videoManager), |
2573 | 0 | namespaces); |
2574 | 0 |
|
2575 | 0 | gpm->AddListener(this); |
2576 | 0 |
|
2577 | 0 | nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance(); |
2578 | 0 | if (sheetService) { |
2579 | 0 | // This looks like a lot of work, but in a normal browser session we just |
2580 | 0 | // send two loads. |
2581 | 0 | // |
2582 | 0 | // The URIs of the Gecko and Servo sheets should be the same, so it |
2583 | 0 | // shouldn't matter which we look at. |
2584 | 0 |
|
2585 | 0 | for (StyleSheet* sheet : *sheetService->AgentStyleSheets()) { |
2586 | 0 | URIParams uri; |
2587 | 0 | SerializeURI(sheet->GetSheetURI(), uri); |
2588 | 0 | Unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AGENT_SHEET); |
2589 | 0 | } |
2590 | 0 |
|
2591 | 0 | for (StyleSheet* sheet : *sheetService->UserStyleSheets()) { |
2592 | 0 | URIParams uri; |
2593 | 0 | SerializeURI(sheet->GetSheetURI(), uri); |
2594 | 0 | Unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::USER_SHEET); |
2595 | 0 | } |
2596 | 0 |
|
2597 | 0 | for (StyleSheet* sheet : *sheetService->AuthorStyleSheets()) { |
2598 | 0 | URIParams uri; |
2599 | 0 | SerializeURI(sheet->GetSheetURI(), uri); |
2600 | 0 | Unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AUTHOR_SHEET); |
2601 | 0 | } |
2602 | 0 | } |
2603 | 0 |
|
2604 | | #if defined(XP_WIN) |
2605 | | // Send the info needed to join the browser process's audio session. |
2606 | | nsID id; |
2607 | | nsString sessionName; |
2608 | | nsString iconPath; |
2609 | | if (NS_SUCCEEDED(mozilla::widget::GetAudioSessionData(id, sessionName, |
2610 | | iconPath))) { |
2611 | | Unused << SendSetAudioSessionData(id, sessionName, iconPath); |
2612 | | } |
2613 | | #endif |
2614 | |
|
2615 | 0 | #ifdef MOZ_CONTENT_SANDBOX |
2616 | 0 | bool shouldSandbox = true; |
2617 | 0 | MaybeFileDesc brokerFd = void_t(); |
2618 | 0 | // XXX: Checking the pref here makes it possible to enable/disable sandboxing |
2619 | 0 | // during an active session. Currently the pref is only used for testing |
2620 | 0 | // purpose. If the decision is made to permanently rely on the pref, this |
2621 | 0 | // should be changed so that it is required to restart firefox for the change |
2622 | 0 | // of value to take effect. |
2623 | 0 | shouldSandbox = IsContentSandboxEnabled(); |
2624 | 0 |
|
2625 | 0 | #ifdef XP_LINUX |
2626 | 0 | if (shouldSandbox) { |
2627 | 0 | MOZ_ASSERT(!mSandboxBroker); |
2628 | 0 | bool isFileProcess = mRemoteType.EqualsLiteral(FILE_REMOTE_TYPE); |
2629 | 0 | UniquePtr<SandboxBroker::Policy> policy = |
2630 | 0 | sSandboxBrokerPolicyFactory->GetContentPolicy(Pid(), isFileProcess); |
2631 | 0 | if (policy) { |
2632 | 0 | brokerFd = FileDescriptor(); |
2633 | 0 | mSandboxBroker = SandboxBroker::Create(std::move(policy), Pid(), brokerFd); |
2634 | 0 | if (!mSandboxBroker) { |
2635 | 0 | KillHard("SandboxBroker::Create failed"); |
2636 | 0 | return; |
2637 | 0 | } |
2638 | 0 | MOZ_ASSERT(static_cast<const FileDescriptor&>(brokerFd).IsValid()); |
2639 | 0 | } |
2640 | 0 | } |
2641 | 0 | #endif |
2642 | 0 | if (shouldSandbox && !SendSetProcessSandbox(brokerFd)) { |
2643 | 0 | KillHard("SandboxInitFailed"); |
2644 | 0 | } |
2645 | 0 | #endif |
2646 | 0 |
|
2647 | 0 | if (!ServiceWorkerParentInterceptEnabled()) { |
2648 | 0 | RefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get(); |
2649 | 0 | MOZ_ASSERT(swr); |
2650 | 0 |
|
2651 | 0 | nsTArray<ServiceWorkerRegistrationData> registrations; |
2652 | 0 | swr->GetRegistrations(registrations); |
2653 | 0 |
|
2654 | 0 | // Send down to the content process the permissions for each of the |
2655 | 0 | // registered service worker scopes. |
2656 | 0 | for (auto& registration : registrations) { |
2657 | 0 | nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(registration.principal()); |
2658 | 0 | if (principal) { |
2659 | 0 | TransmitPermissionsForPrincipal(principal); |
2660 | 0 | } |
2661 | 0 | } |
2662 | 0 |
|
2663 | 0 | Unused << SendInitServiceWorkers(ServiceWorkerConfiguration(registrations)); |
2664 | 0 | } |
2665 | 0 |
|
2666 | 0 | { |
2667 | 0 | nsTArray<BlobURLRegistrationData> registrations; |
2668 | 0 | if (BlobURLProtocolHandler::GetAllBlobURLEntries(registrations, this)) { |
2669 | 0 | for (const BlobURLRegistrationData& registration : registrations) { |
2670 | 0 | nsresult rv = TransmitPermissionsForPrincipal(registration.principal()); |
2671 | 0 | Unused << NS_WARN_IF(NS_FAILED(rv)); |
2672 | 0 | } |
2673 | 0 |
|
2674 | 0 | Unused << SendInitBlobURLs(registrations); |
2675 | 0 | } |
2676 | 0 | } |
2677 | 0 |
|
2678 | 0 | // Start up nsPluginHost and run FindPlugins to cache the plugin list. |
2679 | 0 | // If this isn't our first content process, just send over cached list. |
2680 | 0 | RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst(); |
2681 | 0 | pluginHost->SendPluginsToContent(); |
2682 | 0 | MaybeEnableRemoteInputEventQueue(); |
2683 | 0 | } |
2684 | | |
2685 | | bool |
2686 | | ContentParent::IsAlive() const |
2687 | 0 | { |
2688 | 0 | return mIsAlive; |
2689 | 0 | } |
2690 | | |
2691 | | int32_t |
2692 | | ContentParent::Pid() const |
2693 | 0 | { |
2694 | 0 | if (!mSubprocess || !mSubprocess->GetChildProcessHandle()) { |
2695 | 0 | return -1; |
2696 | 0 | } |
2697 | 0 | return base::GetProcId(mSubprocess->GetChildProcessHandle()); |
2698 | 0 | } |
2699 | | |
2700 | | mozilla::ipc::IPCResult |
2701 | | ContentParent::RecvGetGfxVars(InfallibleTArray<GfxVarUpdate>* aVars) |
2702 | 0 | { |
2703 | 0 | // Ensure gfxVars is initialized (for xpcshell tests). |
2704 | 0 | gfxVars::Initialize(); |
2705 | 0 |
|
2706 | 0 | *aVars = gfxVars::FetchNonDefaultVars(); |
2707 | 0 |
|
2708 | 0 | // Now that content has initialized gfxVars, we can start listening for |
2709 | 0 | // updates. |
2710 | 0 | gfxVars::AddReceiver(this); |
2711 | 0 | return IPC_OK(); |
2712 | 0 | } |
2713 | | |
2714 | | void |
2715 | | ContentParent::OnCompositorUnexpectedShutdown() |
2716 | 0 | { |
2717 | 0 | GPUProcessManager* gpm = GPUProcessManager::Get(); |
2718 | 0 |
|
2719 | 0 | Endpoint<PCompositorManagerChild> compositor; |
2720 | 0 | Endpoint<PImageBridgeChild> imageBridge; |
2721 | 0 | Endpoint<PVRManagerChild> vrBridge; |
2722 | 0 | Endpoint<PVideoDecoderManagerChild> videoManager; |
2723 | 0 | AutoTArray<uint32_t, 3> namespaces; |
2724 | 0 |
|
2725 | 0 | DebugOnly<bool> opened = gpm->CreateContentBridges( |
2726 | 0 | OtherPid(), |
2727 | 0 | &compositor, |
2728 | 0 | &imageBridge, |
2729 | 0 | &vrBridge, |
2730 | 0 | &videoManager, |
2731 | 0 | &namespaces); |
2732 | 0 | MOZ_ASSERT(opened); |
2733 | 0 |
|
2734 | 0 | Unused << SendReinitRendering( |
2735 | 0 | std::move(compositor), |
2736 | 0 | std::move(imageBridge), |
2737 | 0 | std::move(vrBridge), |
2738 | 0 | std::move(videoManager), |
2739 | 0 | namespaces); |
2740 | 0 | } |
2741 | | |
2742 | | void |
2743 | | ContentParent::OnCompositorDeviceReset() |
2744 | 0 | { |
2745 | 0 | Unused << SendReinitRenderingForDeviceReset(); |
2746 | 0 | } |
2747 | | |
2748 | | PClientOpenWindowOpParent* |
2749 | | ContentParent::AllocPClientOpenWindowOpParent(const ClientOpenWindowArgs& aArgs) |
2750 | 0 | { |
2751 | 0 | return AllocClientOpenWindowOpParent(aArgs); |
2752 | 0 | } |
2753 | | |
2754 | | bool |
2755 | | ContentParent::DeallocPClientOpenWindowOpParent(PClientOpenWindowOpParent* aActor) |
2756 | 0 | { |
2757 | 0 | return DeallocClientOpenWindowOpParent(aActor); |
2758 | 0 | } |
2759 | | |
2760 | | void |
2761 | | ContentParent::MaybeEnableRemoteInputEventQueue() |
2762 | 0 | { |
2763 | 0 | MOZ_ASSERT(!mIsRemoteInputEventQueueEnabled); |
2764 | 0 | if (!IsInputEventQueueSupported()) { |
2765 | 0 | return; |
2766 | 0 | } |
2767 | 0 | mIsRemoteInputEventQueueEnabled = true; |
2768 | 0 | Unused << SendSetInputEventQueueEnabled(); |
2769 | 0 | SetInputPriorityEventEnabled(true); |
2770 | 0 | } |
2771 | | |
2772 | | void |
2773 | | ContentParent::SetInputPriorityEventEnabled(bool aEnabled) |
2774 | 0 | { |
2775 | 0 | if (!IsInputEventQueueSupported() || |
2776 | 0 | !mIsRemoteInputEventQueueEnabled || |
2777 | 0 | mIsInputPriorityEventEnabled == aEnabled) { |
2778 | 0 | return; |
2779 | 0 | } |
2780 | 0 | mIsInputPriorityEventEnabled = aEnabled; |
2781 | 0 | // Send IPC messages to flush the pending events in the input event queue and |
2782 | 0 | // the normal event queue. See PContent.ipdl for more details. |
2783 | 0 | Unused << SendSuspendInputEventQueue(); |
2784 | 0 | Unused << SendFlushInputEventQueue(); |
2785 | 0 | Unused << SendResumeInputEventQueue(); |
2786 | 0 | } |
2787 | | |
2788 | | /*static*/ bool |
2789 | | ContentParent::IsInputEventQueueSupported() |
2790 | 0 | { |
2791 | 0 | static bool sSupported = false; |
2792 | 0 | static bool sInitialized = false; |
2793 | 0 | if (!sInitialized) { |
2794 | 0 | MOZ_ASSERT(Preferences::IsServiceAvailable()); |
2795 | 0 | sSupported = Preferences::GetBool("input_event_queue.supported", false); |
2796 | 0 | sInitialized = true; |
2797 | 0 | } |
2798 | 0 | return sSupported; |
2799 | 0 | } |
2800 | | |
2801 | | void |
2802 | | ContentParent::OnVarChanged(const GfxVarUpdate& aVar) |
2803 | 0 | { |
2804 | 0 | if (!mIPCOpen) { |
2805 | 0 | return; |
2806 | 0 | } |
2807 | 0 | Unused << SendVarUpdate(aVar); |
2808 | 0 | } |
2809 | | |
2810 | | mozilla::ipc::IPCResult |
2811 | | ContentParent::RecvReadFontList(InfallibleTArray<FontListEntry>* retValue) |
2812 | 0 | { |
2813 | | #ifdef ANDROID |
2814 | | gfxAndroidPlatform::GetPlatform()->GetSystemFontList(retValue); |
2815 | | #endif |
2816 | 0 | return IPC_OK(); |
2817 | 0 | } |
2818 | | |
2819 | | mozilla::ipc::IPCResult |
2820 | | ContentParent::RecvSetClipboard(const IPCDataTransfer& aDataTransfer, |
2821 | | const bool& aIsPrivateData, |
2822 | | const IPC::Principal& aRequestingPrincipal, |
2823 | | const uint32_t& aContentPolicyType, |
2824 | | const int32_t& aWhichClipboard) |
2825 | 0 | { |
2826 | 0 | nsresult rv; |
2827 | 0 | nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv)); |
2828 | 0 | NS_ENSURE_SUCCESS(rv, IPC_OK()); |
2829 | 0 |
|
2830 | 0 | nsCOMPtr<nsITransferable> trans = |
2831 | 0 | do_CreateInstance("@mozilla.org/widget/transferable;1", &rv); |
2832 | 0 | NS_ENSURE_SUCCESS(rv, IPC_OK()); |
2833 | 0 | trans->Init(nullptr); |
2834 | 0 |
|
2835 | 0 | rv = nsContentUtils::IPCTransferableToTransferable(aDataTransfer, |
2836 | 0 | aIsPrivateData, |
2837 | 0 | aRequestingPrincipal, |
2838 | 0 | aContentPolicyType, |
2839 | 0 | trans, this, nullptr); |
2840 | 0 | NS_ENSURE_SUCCESS(rv, IPC_OK()); |
2841 | 0 |
|
2842 | 0 | clipboard->SetData(trans, nullptr, aWhichClipboard); |
2843 | 0 | return IPC_OK(); |
2844 | 0 | } |
2845 | | |
2846 | | mozilla::ipc::IPCResult |
2847 | | ContentParent::RecvGetClipboard(nsTArray<nsCString>&& aTypes, |
2848 | | const int32_t& aWhichClipboard, |
2849 | | IPCDataTransfer* aDataTransfer) |
2850 | 0 | { |
2851 | 0 | nsresult rv; |
2852 | 0 | nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv)); |
2853 | 0 | NS_ENSURE_SUCCESS(rv, IPC_OK()); |
2854 | 0 |
|
2855 | 0 | nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1", &rv); |
2856 | 0 | NS_ENSURE_SUCCESS(rv, IPC_OK()); |
2857 | 0 | trans->Init(nullptr); |
2858 | 0 |
|
2859 | 0 | for (uint32_t t = 0; t < aTypes.Length(); t++) { |
2860 | 0 | trans->AddDataFlavor(aTypes[t].get()); |
2861 | 0 | } |
2862 | 0 |
|
2863 | 0 | clipboard->GetData(trans, aWhichClipboard); |
2864 | 0 | nsContentUtils::TransferableToIPCTransferable(trans, aDataTransfer, |
2865 | 0 | true, nullptr, this); |
2866 | 0 | return IPC_OK(); |
2867 | 0 | } |
2868 | | |
2869 | | mozilla::ipc::IPCResult |
2870 | | ContentParent::RecvEmptyClipboard(const int32_t& aWhichClipboard) |
2871 | 0 | { |
2872 | 0 | nsresult rv; |
2873 | 0 | nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv)); |
2874 | 0 | NS_ENSURE_SUCCESS(rv, IPC_OK()); |
2875 | 0 |
|
2876 | 0 | clipboard->EmptyClipboard(aWhichClipboard); |
2877 | 0 |
|
2878 | 0 | return IPC_OK(); |
2879 | 0 | } |
2880 | | |
2881 | | mozilla::ipc::IPCResult |
2882 | | ContentParent::RecvClipboardHasType(nsTArray<nsCString>&& aTypes, |
2883 | | const int32_t& aWhichClipboard, |
2884 | | bool* aHasType) |
2885 | 0 | { |
2886 | 0 | nsresult rv; |
2887 | 0 | nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv)); |
2888 | 0 | NS_ENSURE_SUCCESS(rv, IPC_OK()); |
2889 | 0 |
|
2890 | 0 | const char** typesChrs = new const char *[aTypes.Length()]; |
2891 | 0 | for (uint32_t t = 0; t < aTypes.Length(); t++) { |
2892 | 0 | typesChrs[t] = aTypes[t].get(); |
2893 | 0 | } |
2894 | 0 |
|
2895 | 0 | clipboard->HasDataMatchingFlavors(typesChrs, aTypes.Length(), |
2896 | 0 | aWhichClipboard, aHasType); |
2897 | 0 |
|
2898 | 0 | delete [] typesChrs; |
2899 | 0 | return IPC_OK(); |
2900 | 0 | } |
2901 | | |
2902 | | mozilla::ipc::IPCResult |
2903 | | ContentParent::RecvGetExternalClipboardFormats(const int32_t& aWhichClipboard, |
2904 | | const bool& aPlainTextOnly, |
2905 | | nsTArray<nsCString>* aTypes) |
2906 | 0 | { |
2907 | 0 | MOZ_ASSERT(aTypes); |
2908 | 0 | DataTransfer::GetExternalClipboardFormats(aWhichClipboard, aPlainTextOnly, aTypes); |
2909 | 0 | return IPC_OK(); |
2910 | 0 | } |
2911 | | |
2912 | | mozilla::ipc::IPCResult |
2913 | | ContentParent::RecvPlaySound(const URIParams& aURI) |
2914 | 0 | { |
2915 | 0 | nsCOMPtr<nsIURI> soundURI = DeserializeURI(aURI); |
2916 | 0 | bool isChrome = false; |
2917 | 0 | // If the check here fails, it can only mean that this message was spoofed. |
2918 | 0 | if (!soundURI || NS_FAILED(soundURI->SchemeIs("chrome", &isChrome)) || !isChrome) { |
2919 | 0 | // PlaySound only accepts a valid chrome URI. |
2920 | 0 | return IPC_FAIL_NO_REASON(this); |
2921 | 0 | } |
2922 | 0 | nsCOMPtr<nsIURL> soundURL(do_QueryInterface(soundURI)); |
2923 | 0 | if (!soundURL) { |
2924 | 0 | return IPC_OK(); |
2925 | 0 | } |
2926 | 0 |
|
2927 | 0 | nsresult rv; |
2928 | 0 | nsCOMPtr<nsISound> sound(do_GetService(NS_SOUND_CID, &rv)); |
2929 | 0 | NS_ENSURE_SUCCESS(rv, IPC_OK()); |
2930 | 0 |
|
2931 | 0 | sound->Play(soundURL); |
2932 | 0 |
|
2933 | 0 | return IPC_OK(); |
2934 | 0 | } |
2935 | | |
2936 | | mozilla::ipc::IPCResult |
2937 | | ContentParent::RecvBeep() |
2938 | 0 | { |
2939 | 0 | nsresult rv; |
2940 | 0 | nsCOMPtr<nsISound> sound(do_GetService(NS_SOUND_CID, &rv)); |
2941 | 0 | NS_ENSURE_SUCCESS(rv, IPC_OK()); |
2942 | 0 |
|
2943 | 0 | sound->Beep(); |
2944 | 0 |
|
2945 | 0 | return IPC_OK(); |
2946 | 0 | } |
2947 | | |
2948 | | mozilla::ipc::IPCResult |
2949 | | ContentParent::RecvPlayEventSound(const uint32_t& aEventId) |
2950 | 0 | { |
2951 | 0 | nsresult rv; |
2952 | 0 | nsCOMPtr<nsISound> sound(do_GetService(NS_SOUND_CID, &rv)); |
2953 | 0 | NS_ENSURE_SUCCESS(rv, IPC_OK()); |
2954 | 0 |
|
2955 | 0 | sound->PlayEventSound(aEventId); |
2956 | 0 |
|
2957 | 0 | return IPC_OK(); |
2958 | 0 | } |
2959 | | |
2960 | | mozilla::ipc::IPCResult |
2961 | | ContentParent::RecvGetSystemColors(const uint32_t& colorsCount, |
2962 | | InfallibleTArray<uint32_t>* colors) |
2963 | 0 | { |
2964 | | #ifdef MOZ_WIDGET_ANDROID |
2965 | | NS_ASSERTION(AndroidBridge::Bridge() != nullptr, "AndroidBridge is not available"); |
2966 | | if (AndroidBridge::Bridge() == nullptr) { |
2967 | | // Do not fail - the colors won't be right, but it's not critical |
2968 | | return IPC_OK(); |
2969 | | } |
2970 | | |
2971 | | colors->AppendElements(colorsCount); |
2972 | | |
2973 | | // The array elements correspond to the members of AndroidSystemColors structure, |
2974 | | // so just pass the pointer to the elements buffer |
2975 | | AndroidBridge::Bridge()->GetSystemColors((AndroidSystemColors*)colors->Elements()); |
2976 | | #endif |
2977 | 0 | return IPC_OK(); |
2978 | 0 | } |
2979 | | |
2980 | | mozilla::ipc::IPCResult |
2981 | | ContentParent::RecvGetIconForExtension(const nsCString& aFileExt, |
2982 | | const uint32_t& aIconSize, |
2983 | | InfallibleTArray<uint8_t>* bits) |
2984 | 0 | { |
2985 | | #ifdef MOZ_WIDGET_ANDROID |
2986 | | NS_ASSERTION(AndroidBridge::Bridge() != nullptr, "AndroidBridge is not available"); |
2987 | | if (AndroidBridge::Bridge() == nullptr) { |
2988 | | // Do not fail - just no icon will be shown |
2989 | | return IPC_OK(); |
2990 | | } |
2991 | | |
2992 | | bits->AppendElements(aIconSize * aIconSize * 4); |
2993 | | |
2994 | | AndroidBridge::Bridge()->GetIconForExtension(aFileExt, aIconSize, bits->Elements()); |
2995 | | #endif |
2996 | 0 | return IPC_OK(); |
2997 | 0 | } |
2998 | | |
2999 | | mozilla::ipc::IPCResult |
3000 | | ContentParent::RecvGetShowPasswordSetting(bool* showPassword) |
3001 | 0 | { |
3002 | 0 | // default behavior is to show the last password character |
3003 | 0 | *showPassword = true; |
3004 | | #ifdef MOZ_WIDGET_ANDROID |
3005 | | NS_ASSERTION(AndroidBridge::Bridge() != nullptr, "AndroidBridge is not available"); |
3006 | | |
3007 | | *showPassword = java::GeckoAppShell::GetShowPasswordSetting(); |
3008 | | #endif |
3009 | 0 | return IPC_OK(); |
3010 | 0 | } |
3011 | | |
3012 | | mozilla::ipc::IPCResult |
3013 | | ContentParent::RecvFirstIdle() |
3014 | 0 | { |
3015 | 0 | // When the ContentChild goes idle, it sends us a FirstIdle message |
3016 | 0 | // which we use as a good time to signal the PreallocatedProcessManager |
3017 | 0 | // that it can start allocating processes from now on. |
3018 | 0 | PreallocatedProcessManager::RemoveBlocker(this); |
3019 | 0 | return IPC_OK(); |
3020 | 0 | } |
3021 | | |
3022 | | // We want ContentParent to show up in CC logs for debugging purposes, but we |
3023 | | // don't actually cycle collect it. |
3024 | | NS_IMPL_CYCLE_COLLECTION_0(ContentParent) |
3025 | | |
3026 | | NS_IMPL_CYCLE_COLLECTING_ADDREF(ContentParent) |
3027 | | NS_IMPL_CYCLE_COLLECTING_RELEASE(ContentParent) |
3028 | | |
3029 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ContentParent) |
3030 | 0 | NS_INTERFACE_MAP_ENTRY(nsIContentParent) |
3031 | 0 | NS_INTERFACE_MAP_ENTRY(nsIObserver) |
3032 | 0 | NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionCallback) |
3033 | 0 | NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionErrorCallback) |
3034 | 0 | NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) |
3035 | 0 | NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver) |
3036 | 0 | NS_INTERFACE_MAP_END |
3037 | | |
3038 | | NS_IMETHODIMP |
3039 | | ContentParent::Observe(nsISupports* aSubject, |
3040 | | const char* aTopic, |
3041 | | const char16_t* aData) |
3042 | 0 | { |
3043 | 0 | if (mSubprocess && (!strcmp(aTopic, "profile-before-change") || |
3044 | 0 | !strcmp(aTopic, "xpcom-shutdown"))) { |
3045 | 0 | // Make sure that our process will get scheduled. |
3046 | 0 | ProcessPriorityManager::SetProcessPriority(this, |
3047 | 0 | PROCESS_PRIORITY_FOREGROUND); |
3048 | 0 |
|
3049 | 0 | // Okay to call ShutDownProcess multiple times. |
3050 | 0 | ShutDownProcess(SEND_SHUTDOWN_MESSAGE); |
3051 | 0 | MarkAsDead(); |
3052 | 0 |
|
3053 | 0 | // Wait for shutdown to complete, so that we receive any shutdown |
3054 | 0 | // data (e.g. telemetry) from the child before we quit. |
3055 | 0 | // This loop terminate prematurely based on mForceKillTimer. |
3056 | 0 | SpinEventLoopUntil([&]() { return !mIPCOpen || mCalledKillHard; }); |
3057 | 0 | NS_ASSERTION(!mSubprocess, "Close should have nulled mSubprocess"); |
3058 | 0 | } |
3059 | 0 |
|
3060 | 0 | if (!mIsAlive || !mSubprocess) |
3061 | 0 | return NS_OK; |
3062 | 0 | |
3063 | 0 | // listening for memory pressure event |
3064 | 0 | if (!strcmp(aTopic, "memory-pressure")) { |
3065 | 0 | Unused << SendFlushMemory(nsDependentString(aData)); |
3066 | 0 | } |
3067 | 0 | else if (!strcmp(aTopic, "nsPref:changed")) { |
3068 | 0 | // A pref changed. If it's not on the blacklist, inform child processes. |
3069 | 0 | #define BLACKLIST_ENTRY(s) { s, (sizeof(s)/sizeof(char16_t)) - 1 } |
3070 | 0 | struct BlacklistEntry { |
3071 | 0 | const char16_t* mPrefBranch; |
3072 | 0 | size_t mLen; |
3073 | 0 | }; |
3074 | 0 | // These prefs are not useful in child processes. |
3075 | 0 | static const BlacklistEntry sContentPrefBranchBlacklist[] = { |
3076 | 0 | BLACKLIST_ENTRY(u"app.update.lastUpdateTime."), |
3077 | 0 | BLACKLIST_ENTRY(u"datareporting.policy."), |
3078 | 0 | BLACKLIST_ENTRY(u"browser.safebrowsing.provider."), |
3079 | 0 | BLACKLIST_ENTRY(u"browser.shell."), |
3080 | 0 | BLACKLIST_ENTRY(u"browser.slowstartup."), |
3081 | 0 | BLACKLIST_ENTRY(u"extensions.getAddons.cache."), |
3082 | 0 | BLACKLIST_ENTRY(u"media.gmp-manager."), |
3083 | 0 | BLACKLIST_ENTRY(u"media.gmp-gmpopenh264."), |
3084 | 0 | BLACKLIST_ENTRY(u"privacy.sanitize."), |
3085 | 0 | }; |
3086 | 0 | #undef BLACKLIST_ENTRY |
3087 | 0 |
|
3088 | 0 | for (const auto& entry : sContentPrefBranchBlacklist) { |
3089 | 0 | if (NS_strncmp(entry.mPrefBranch, aData, entry.mLen) == 0) { |
3090 | 0 | return NS_OK; |
3091 | 0 | } |
3092 | 0 | } |
3093 | 0 |
|
3094 | 0 | // We know prefs are ASCII here. |
3095 | 0 | NS_LossyConvertUTF16toASCII strData(aData); |
3096 | 0 |
|
3097 | 0 | Pref pref(strData, /* isLocked */ false, null_t(), null_t()); |
3098 | 0 | Preferences::GetPreference(&pref); |
3099 | 0 | if (!SendPreferenceUpdate(pref)) { |
3100 | 0 | return NS_ERROR_NOT_AVAILABLE; |
3101 | 0 | } |
3102 | 0 | } |
3103 | 0 | else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) { |
3104 | 0 | NS_ConvertUTF16toUTF8 dataStr(aData); |
3105 | 0 | const char *offline = dataStr.get(); |
3106 | 0 | if (!SendSetOffline(!strcmp(offline, "true") ? true : false)) { |
3107 | 0 | return NS_ERROR_NOT_AVAILABLE; |
3108 | 0 | } |
3109 | 0 | } |
3110 | 0 | else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC)) { |
3111 | 0 | if (!SendSetConnectivity(NS_LITERAL_STRING("true").Equals(aData))) { |
3112 | 0 | return NS_ERROR_NOT_AVAILABLE; |
3113 | 0 | } |
3114 | 0 | } else if (!strcmp(aTopic, NS_IPC_CAPTIVE_PORTAL_SET_STATE)) { |
3115 | 0 | nsCOMPtr<nsICaptivePortalService> cps = do_QueryInterface(aSubject); |
3116 | 0 | MOZ_ASSERT(cps, "Should QI to a captive portal service"); |
3117 | 0 | if (!cps) { |
3118 | 0 | return NS_ERROR_FAILURE; |
3119 | 0 | } |
3120 | 0 | int32_t state; |
3121 | 0 | cps->GetState(&state); |
3122 | 0 | if (!SendSetCaptivePortalState(state)) { |
3123 | 0 | return NS_ERROR_NOT_AVAILABLE; |
3124 | 0 | } |
3125 | 0 | } |
3126 | 0 | // listening for alert notifications |
3127 | 0 | else if (!strcmp(aTopic, "alertfinished") || |
3128 | 0 | !strcmp(aTopic, "alertclickcallback") || |
3129 | 0 | !strcmp(aTopic, "alertshow") || |
3130 | 0 | !strcmp(aTopic, "alertdisablecallback") || |
3131 | 0 | !strcmp(aTopic, "alertsettingscallback")) { |
3132 | 0 | if (!SendNotifyAlertsObserver(nsDependentCString(aTopic), |
3133 | 0 | nsDependentString(aData))) |
3134 | 0 | return NS_ERROR_NOT_AVAILABLE; |
3135 | 0 | } |
3136 | 0 | else if (!strcmp(aTopic, "child-gc-request")){ |
3137 | 0 | Unused << SendGarbageCollect(); |
3138 | 0 | } |
3139 | 0 | else if (!strcmp(aTopic, "child-cc-request")){ |
3140 | 0 | Unused << SendCycleCollect(); |
3141 | 0 | } |
3142 | 0 | else if (!strcmp(aTopic, "child-mmu-request")){ |
3143 | 0 | Unused << SendMinimizeMemoryUsage(); |
3144 | 0 | } |
3145 | 0 | else if (!strcmp(aTopic, "child-ghost-request")){ |
3146 | 0 | Unused << SendUnlinkGhosts(); |
3147 | 0 | } |
3148 | 0 | else if (!strcmp(aTopic, "last-pb-context-exited")) { |
3149 | 0 | Unused << SendLastPrivateDocShellDestroyed(); |
3150 | 0 | } |
3151 | 0 | #ifdef ACCESSIBILITY |
3152 | 0 | else if (aData && !strcmp(aTopic, "a11y-init-or-shutdown")) { |
3153 | 0 | if (*aData == '1') { |
3154 | 0 | // Make sure accessibility is running in content process when |
3155 | 0 | // accessibility gets initiated in chrome process. |
3156 | | #if defined(XP_WIN) |
3157 | | // Don't init content a11y if we detect an incompat version of JAWS in use. |
3158 | | if (!mozilla::a11y::Compatibility::IsOldJAWS()) { |
3159 | | Unused << SendActivateA11y(::GetCurrentThreadId(), |
3160 | | a11y::AccessibleWrap::GetContentProcessIdFor(ChildID())); |
3161 | | } |
3162 | | #else |
3163 | | Unused << SendActivateA11y(0, 0); |
3164 | 0 | #endif |
3165 | 0 | } else { |
3166 | 0 | // If possible, shut down accessibility in content process when |
3167 | 0 | // accessibility gets shutdown in chrome process. |
3168 | 0 | Unused << SendShutdownA11y(); |
3169 | 0 | } |
3170 | 0 | } |
3171 | 0 | #endif |
3172 | 0 | else if (!strcmp(aTopic, "cacheservice:empty-cache")) { |
3173 | 0 | Unused << SendNotifyEmptyHTTPCache(); |
3174 | 0 | } |
3175 | 0 | else if (!strcmp(aTopic, "intl:app-locales-changed")) { |
3176 | 0 | nsTArray<nsCString> appLocales; |
3177 | 0 | LocaleService::GetInstance()->GetAppLocalesAsBCP47(appLocales); |
3178 | 0 | Unused << SendUpdateAppLocales(appLocales); |
3179 | 0 | } |
3180 | 0 | else if (!strcmp(aTopic, "intl:requested-locales-changed")) { |
3181 | 0 | nsTArray<nsCString> requestedLocales; |
3182 | 0 | LocaleService::GetInstance()->GetRequestedLocales(requestedLocales); |
3183 | 0 | Unused << SendUpdateRequestedLocales(requestedLocales); |
3184 | 0 | } |
3185 | 0 | else if (!strcmp(aTopic, "cookie-changed") || |
3186 | 0 | !strcmp(aTopic, "private-cookie-changed")) { |
3187 | 0 | if (!aData) { |
3188 | 0 | return NS_ERROR_UNEXPECTED; |
3189 | 0 | } |
3190 | 0 | PNeckoParent *neckoParent = LoneManagedOrNullAsserts(ManagedPNeckoParent()); |
3191 | 0 | if (!neckoParent) { |
3192 | 0 | return NS_OK; |
3193 | 0 | } |
3194 | 0 | PCookieServiceParent *csParent = LoneManagedOrNullAsserts(neckoParent->ManagedPCookieServiceParent()); |
3195 | 0 | if (!csParent) { |
3196 | 0 | return NS_OK; |
3197 | 0 | } |
3198 | 0 | auto *cs = static_cast<CookieServiceParent*>(csParent); |
3199 | 0 | // Do not push these cookie updates to the same process they originated from. |
3200 | 0 | if (cs->ProcessingCookie()) { |
3201 | 0 | return NS_OK; |
3202 | 0 | } |
3203 | 0 | if (!nsCRT::strcmp(aData, u"batch-deleted")) { |
3204 | 0 | nsCOMPtr<nsIArray> cookieList = do_QueryInterface(aSubject); |
3205 | 0 | NS_ASSERTION(cookieList, "couldn't get cookie list"); |
3206 | 0 | cs->RemoveBatchDeletedCookies(cookieList); |
3207 | 0 | return NS_OK; |
3208 | 0 | } |
3209 | 0 |
|
3210 | 0 | if (!nsCRT::strcmp(aData, u"cleared")) { |
3211 | 0 | cs->RemoveAll(); |
3212 | 0 | return NS_OK; |
3213 | 0 | } |
3214 | 0 | |
3215 | 0 | nsCOMPtr<nsICookie> xpcCookie = do_QueryInterface(aSubject); |
3216 | 0 | NS_ASSERTION(xpcCookie, "couldn't get cookie"); |
3217 | 0 | if (!nsCRT::strcmp(aData, u"deleted")) { |
3218 | 0 | cs->RemoveCookie(xpcCookie); |
3219 | 0 | } else if ((!nsCRT::strcmp(aData, u"added")) || |
3220 | 0 | (!nsCRT::strcmp(aData, u"changed"))) { |
3221 | 0 | cs->AddCookie(xpcCookie); |
3222 | 0 | } |
3223 | 0 | } else if (!strcmp(aTopic, "clear-site-data-reload-needed")) { |
3224 | 0 | // Rebroadcast "clear-site-data-reload-needed". |
3225 | 0 | Unused << SendClearSiteDataReloadNeeded(nsString(aData)); |
3226 | 0 | } |
3227 | 0 | return NS_OK; |
3228 | 0 | } |
3229 | | |
3230 | | NS_IMETHODIMP |
3231 | | ContentParent::GetInterface(const nsIID& aIID, void** aResult) |
3232 | 0 | { |
3233 | 0 | NS_ENSURE_ARG_POINTER(aResult); |
3234 | 0 |
|
3235 | 0 | if (aIID.Equals(NS_GET_IID(nsIMessageSender))) { |
3236 | 0 | nsCOMPtr<nsIMessageSender> mm = GetMessageManager(); |
3237 | 0 | mm.forget(aResult); |
3238 | 0 | return NS_OK; |
3239 | 0 | } |
3240 | 0 | |
3241 | 0 | return NS_NOINTERFACE; |
3242 | 0 | } |
3243 | | |
3244 | | mozilla::ipc::IPCResult |
3245 | | ContentParent::RecvInitBackground(Endpoint<PBackgroundParent>&& aEndpoint) |
3246 | 0 | { |
3247 | 0 | if (!BackgroundParent::Alloc(this, std::move(aEndpoint))) { |
3248 | 0 | return IPC_FAIL(this, "BackgroundParent::Alloc failed"); |
3249 | 0 | } |
3250 | 0 |
|
3251 | 0 | return IPC_OK(); |
3252 | 0 | } |
3253 | | |
3254 | | mozilla::jsipc::PJavaScriptParent * |
3255 | | ContentParent::AllocPJavaScriptParent() |
3256 | 0 | { |
3257 | 0 | MOZ_ASSERT(ManagedPJavaScriptParent().IsEmpty()); |
3258 | 0 | return nsIContentParent::AllocPJavaScriptParent(); |
3259 | 0 | } |
3260 | | |
3261 | | bool |
3262 | | ContentParent::DeallocPJavaScriptParent(PJavaScriptParent *parent) |
3263 | 0 | { |
3264 | 0 | return nsIContentParent::DeallocPJavaScriptParent(parent); |
3265 | 0 | } |
3266 | | |
3267 | | PBrowserParent* |
3268 | | ContentParent::AllocPBrowserParent(const TabId& aTabId, |
3269 | | const TabId& aSameTabGroupAs, |
3270 | | const IPCTabContext& aContext, |
3271 | | const uint32_t& aChromeFlags, |
3272 | | const ContentParentId& aCpId, |
3273 | | const bool& aIsForBrowser) |
3274 | 0 | { |
3275 | 0 | return nsIContentParent::AllocPBrowserParent(aTabId, |
3276 | 0 | aSameTabGroupAs, |
3277 | 0 | aContext, |
3278 | 0 | aChromeFlags, |
3279 | 0 | aCpId, |
3280 | 0 | aIsForBrowser); |
3281 | 0 | } |
3282 | | |
3283 | | bool |
3284 | | ContentParent::DeallocPBrowserParent(PBrowserParent* frame) |
3285 | 0 | { |
3286 | 0 | return nsIContentParent::DeallocPBrowserParent(frame); |
3287 | 0 | } |
3288 | | |
3289 | | mozilla::ipc::IPCResult |
3290 | | ContentParent::RecvPBrowserConstructor(PBrowserParent* actor, |
3291 | | const TabId& tabId, |
3292 | | const TabId& sameTabGroupAs, |
3293 | | const IPCTabContext& context, |
3294 | | const uint32_t& chromeFlags, |
3295 | | const ContentParentId& cpId, |
3296 | | const bool& isForBrowser) |
3297 | 0 | { |
3298 | 0 | return nsIContentParent::RecvPBrowserConstructor(actor, |
3299 | 0 | tabId, |
3300 | 0 | sameTabGroupAs, |
3301 | 0 | context, |
3302 | 0 | chromeFlags, |
3303 | 0 | cpId, |
3304 | 0 | isForBrowser); |
3305 | 0 | } |
3306 | | |
3307 | | PIPCBlobInputStreamParent* |
3308 | | ContentParent::AllocPIPCBlobInputStreamParent(const nsID& aID, |
3309 | | const uint64_t& aSize) |
3310 | 0 | { |
3311 | 0 | return nsIContentParent::AllocPIPCBlobInputStreamParent(aID, aSize); |
3312 | 0 | } |
3313 | | |
3314 | | bool |
3315 | | ContentParent::DeallocPIPCBlobInputStreamParent(PIPCBlobInputStreamParent* aActor) |
3316 | 0 | { |
3317 | 0 | return nsIContentParent::DeallocPIPCBlobInputStreamParent(aActor); |
3318 | 0 | } |
3319 | | |
3320 | | mozilla::PRemoteSpellcheckEngineParent * |
3321 | | ContentParent::AllocPRemoteSpellcheckEngineParent() |
3322 | 0 | { |
3323 | 0 | mozilla::RemoteSpellcheckEngineParent *parent = new mozilla::RemoteSpellcheckEngineParent(); |
3324 | 0 | return parent; |
3325 | 0 | } |
3326 | | |
3327 | | bool |
3328 | | ContentParent::DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent *parent) |
3329 | 0 | { |
3330 | 0 | delete parent; |
3331 | 0 | return true; |
3332 | 0 | } |
3333 | | |
3334 | | /* static */ void |
3335 | | ContentParent::ForceKillTimerCallback(nsITimer* aTimer, void* aClosure) |
3336 | 0 | { |
3337 | 0 | // We don't want to time out the content process during XPCShell tests. This |
3338 | 0 | // is the easiest way to ensure that. |
3339 | 0 | if (PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR")) { |
3340 | 0 | return; |
3341 | 0 | } |
3342 | 0 | |
3343 | 0 | auto self = static_cast<ContentParent*>(aClosure); |
3344 | 0 | self->KillHard("ShutDownKill"); |
3345 | 0 | } |
3346 | | |
3347 | | // WARNING: aReason appears in telemetry, so any new value passed in requires |
3348 | | // data review. |
3349 | | void |
3350 | | ContentParent::KillHard(const char* aReason) |
3351 | 0 | { |
3352 | 0 | AUTO_PROFILER_LABEL("ContentParent::KillHard", OTHER); |
3353 | 0 |
|
3354 | 0 | // On Windows, calling KillHard multiple times causes problems - the |
3355 | 0 | // process handle becomes invalid on the first call, causing a second call |
3356 | 0 | // to crash our process - more details in bug 890840. |
3357 | 0 | if (mCalledKillHard) { |
3358 | 0 | return; |
3359 | 0 | } |
3360 | 0 | mCalledKillHard = true; |
3361 | 0 | mForceKillTimer = nullptr; |
3362 | 0 |
|
3363 | 0 | MessageChannel* channel = GetIPCChannel(); |
3364 | 0 | if (channel) { |
3365 | 0 | channel->SetInKillHardShutdown(); |
3366 | 0 | } |
3367 | 0 |
|
3368 | 0 | // We're about to kill the child process associated with this content. |
3369 | 0 | // Something has gone wrong to get us here, so we generate a minidump |
3370 | 0 | // of the parent and child for submission to the crash server. |
3371 | 0 | if (mCrashReporter) { |
3372 | 0 | // GeneratePairedMinidump creates two minidumps for us - the main |
3373 | 0 | // one is for the content process we're about to kill, and the other |
3374 | 0 | // one is for the main browser process. That second one is the extra |
3375 | 0 | // minidump tagging along, so we have to tell the crash reporter that |
3376 | 0 | // it exists and is being appended. |
3377 | 0 | nsAutoCString additionalDumps("browser"); |
3378 | 0 | mCrashReporter->AddAnnotation( |
3379 | 0 | CrashReporter::Annotation::additional_minidumps, additionalDumps); |
3380 | 0 | nsDependentCString reason(aReason); |
3381 | 0 | mCrashReporter->AddAnnotation(CrashReporter::Annotation::ipc_channel_error, |
3382 | 0 | reason); |
3383 | 0 |
|
3384 | 0 | // Generate the report and insert into the queue for submittal. |
3385 | 0 | if (mCrashReporter->GenerateMinidumpAndPair(this, |
3386 | 0 | nullptr, |
3387 | 0 | NS_LITERAL_CSTRING("browser"))) |
3388 | 0 | { |
3389 | 0 | mCreatedPairedMinidumps = mCrashReporter->FinalizeCrashReport(); |
3390 | 0 | } |
3391 | 0 |
|
3392 | 0 | Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1); |
3393 | 0 | } |
3394 | 0 |
|
3395 | 0 | ProcessHandle otherProcessHandle; |
3396 | 0 | if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle)) { |
3397 | 0 | NS_ERROR("Failed to open child process when attempting kill."); |
3398 | 0 | return; |
3399 | 0 | } |
3400 | 0 |
|
3401 | 0 | if (!KillProcess(otherProcessHandle, base::PROCESS_END_KILLED_BY_USER, |
3402 | 0 | false)) { |
3403 | 0 | NS_WARNING("failed to kill subprocess!"); |
3404 | 0 | } |
3405 | 0 |
|
3406 | 0 | if (mSubprocess) { |
3407 | 0 | mSubprocess->SetAlreadyDead(); |
3408 | 0 | } |
3409 | 0 |
|
3410 | 0 | // EnsureProcessTerminated has responsibilty for closing otherProcessHandle. |
3411 | 0 | XRE_GetIOMessageLoop()->PostTask( |
3412 | 0 | NewRunnableFunction("EnsureProcessTerminatedRunnable", |
3413 | 0 | &ProcessWatcher::EnsureProcessTerminated, |
3414 | 0 | otherProcessHandle, /*force=*/true)); |
3415 | 0 | } |
3416 | | |
3417 | | void |
3418 | | ContentParent::FriendlyName(nsAString& aName, bool aAnonymize) |
3419 | 0 | { |
3420 | 0 | aName.Truncate(); |
3421 | 0 | if (mIsForBrowser) { |
3422 | 0 | aName.AssignLiteral("Browser"); |
3423 | 0 | } else if (aAnonymize) { |
3424 | 0 | aName.AssignLiteral("<anonymized-name>"); |
3425 | 0 | } else { |
3426 | 0 | aName.AssignLiteral("???"); |
3427 | 0 | } |
3428 | 0 | } |
3429 | | |
3430 | | mozilla::ipc::IPCResult |
3431 | | ContentParent::RecvInitCrashReporter(Shmem&& aShmem, const NativeThreadId& aThreadId) |
3432 | 0 | { |
3433 | 0 | mCrashReporter = MakeUnique<CrashReporterHost>( |
3434 | 0 | GeckoProcessType_Content, |
3435 | 0 | aShmem, |
3436 | 0 | aThreadId); |
3437 | 0 |
|
3438 | 0 | return IPC_OK(); |
3439 | 0 | } |
3440 | | |
3441 | | hal_sandbox::PHalParent* |
3442 | | ContentParent::AllocPHalParent() |
3443 | 0 | { |
3444 | 0 | return hal_sandbox::CreateHalParent(); |
3445 | 0 | } |
3446 | | |
3447 | | bool |
3448 | | ContentParent::DeallocPHalParent(hal_sandbox::PHalParent* aHal) |
3449 | 0 | { |
3450 | 0 | delete aHal; |
3451 | 0 | return true; |
3452 | 0 | } |
3453 | | |
3454 | | devtools::PHeapSnapshotTempFileHelperParent* |
3455 | | ContentParent::AllocPHeapSnapshotTempFileHelperParent() |
3456 | 0 | { |
3457 | 0 | return devtools::HeapSnapshotTempFileHelperParent::Create(); |
3458 | 0 | } |
3459 | | |
3460 | | bool |
3461 | | ContentParent::DeallocPHeapSnapshotTempFileHelperParent( |
3462 | | devtools::PHeapSnapshotTempFileHelperParent* aHeapSnapshotHelper) |
3463 | 0 | { |
3464 | 0 | delete aHeapSnapshotHelper; |
3465 | 0 | return true; |
3466 | 0 | } |
3467 | | |
3468 | | bool |
3469 | | ContentParent::SendRequestMemoryReport(const uint32_t& aGeneration, |
3470 | | const bool& aAnonymize, |
3471 | | const bool& aMinimizeMemoryUsage, |
3472 | | const MaybeFileDesc& aDMDFile) |
3473 | 0 | { |
3474 | 0 | // This automatically cancels the previous request. |
3475 | 0 | mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration); |
3476 | 0 | Unused << PContentParent::SendRequestMemoryReport( |
3477 | 0 | aGeneration, |
3478 | 0 | aAnonymize, |
3479 | 0 | aMinimizeMemoryUsage, |
3480 | 0 | aDMDFile); |
3481 | 0 | return IPC_OK(); |
3482 | 0 | } |
3483 | | |
3484 | | mozilla::ipc::IPCResult |
3485 | | ContentParent::RecvAddMemoryReport(const MemoryReport& aReport) |
3486 | 0 | { |
3487 | 0 | if (mMemoryReportRequest) { |
3488 | 0 | mMemoryReportRequest->RecvReport(aReport); |
3489 | 0 | } |
3490 | 0 | return IPC_OK(); |
3491 | 0 | } |
3492 | | |
3493 | | mozilla::ipc::IPCResult |
3494 | | ContentParent::RecvFinishMemoryReport(const uint32_t& aGeneration) |
3495 | 0 | { |
3496 | 0 | if (mMemoryReportRequest) { |
3497 | 0 | mMemoryReportRequest->Finish(aGeneration); |
3498 | 0 | mMemoryReportRequest = nullptr; |
3499 | 0 | } |
3500 | 0 | return IPC_OK(); |
3501 | 0 | } |
3502 | | |
3503 | | mozilla::ipc::IPCResult |
3504 | | ContentParent::RecvAddPerformanceMetrics(const nsID& aID, |
3505 | | nsTArray<PerformanceInfo>&& aMetrics) |
3506 | 0 | { |
3507 | 0 | if (!mozilla::StaticPrefs::dom_performance_enable_scheduler_timing()) { |
3508 | 0 | // The pref is off, we should not get a performance metrics from the content |
3509 | 0 | // child |
3510 | 0 | return IPC_OK(); |
3511 | 0 | } |
3512 | 0 | nsresult rv = PerformanceMetricsCollector::DataReceived(aID, aMetrics); |
3513 | 0 | Unused << NS_WARN_IF(NS_FAILED(rv)); |
3514 | 0 | return IPC_OK(); |
3515 | 0 | } |
3516 | | |
3517 | | PCycleCollectWithLogsParent* |
3518 | | ContentParent::AllocPCycleCollectWithLogsParent(const bool& aDumpAllTraces, |
3519 | | const FileDescriptor& aGCLog, |
3520 | | const FileDescriptor& aCCLog) |
3521 | 0 | { |
3522 | 0 | MOZ_CRASH("Don't call this; use ContentParent::CycleCollectWithLogs"); |
3523 | 0 | } |
3524 | | |
3525 | | bool |
3526 | | ContentParent::DeallocPCycleCollectWithLogsParent(PCycleCollectWithLogsParent* aActor) |
3527 | 0 | { |
3528 | 0 | delete aActor; |
3529 | 0 | return true; |
3530 | 0 | } |
3531 | | |
3532 | | bool |
3533 | | ContentParent::CycleCollectWithLogs(bool aDumpAllTraces, |
3534 | | nsICycleCollectorLogSink* aSink, |
3535 | | nsIDumpGCAndCCLogsCallback* aCallback) |
3536 | 0 | { |
3537 | 0 | return CycleCollectWithLogsParent::AllocAndSendConstructor(this, |
3538 | 0 | aDumpAllTraces, |
3539 | 0 | aSink, |
3540 | 0 | aCallback); |
3541 | 0 | } |
3542 | | |
3543 | | PTestShellParent* |
3544 | | ContentParent::AllocPTestShellParent() |
3545 | 0 | { |
3546 | 0 | return new TestShellParent(); |
3547 | 0 | } |
3548 | | |
3549 | | bool |
3550 | | ContentParent::DeallocPTestShellParent(PTestShellParent* shell) |
3551 | 0 | { |
3552 | 0 | delete shell; |
3553 | 0 | return true; |
3554 | 0 | } |
3555 | | |
3556 | | PScriptCacheParent* |
3557 | | ContentParent::AllocPScriptCacheParent(const FileDescOrError& cacheFile, const bool& wantCacheData) |
3558 | 0 | { |
3559 | 0 | return new loader::ScriptCacheParent(wantCacheData); |
3560 | 0 | } |
3561 | | |
3562 | | bool |
3563 | | ContentParent::DeallocPScriptCacheParent(PScriptCacheParent* cache) |
3564 | 0 | { |
3565 | 0 | delete static_cast<loader::ScriptCacheParent*>(cache); |
3566 | 0 | return true; |
3567 | 0 | } |
3568 | | |
3569 | | PNeckoParent* |
3570 | | ContentParent::AllocPNeckoParent() |
3571 | 0 | { |
3572 | 0 | return new NeckoParent(); |
3573 | 0 | } |
3574 | | |
3575 | | bool |
3576 | | ContentParent::DeallocPNeckoParent(PNeckoParent* necko) |
3577 | 0 | { |
3578 | 0 | delete necko; |
3579 | 0 | return true; |
3580 | 0 | } |
3581 | | |
3582 | | PPrintingParent* |
3583 | | ContentParent::AllocPPrintingParent() |
3584 | 0 | { |
3585 | 0 | #ifdef NS_PRINTING |
3586 | 0 | if (mPrintingParent) { |
3587 | 0 | // Only one PrintingParent should be created per process. |
3588 | 0 | return nullptr; |
3589 | 0 | } |
3590 | 0 | |
3591 | 0 | // Create the printing singleton for this process. |
3592 | 0 | mPrintingParent = new PrintingParent(); |
3593 | 0 |
|
3594 | 0 | // Take another reference for IPDL code. |
3595 | 0 | mPrintingParent.get()->AddRef(); |
3596 | 0 |
|
3597 | 0 | return mPrintingParent.get(); |
3598 | | #else |
3599 | | MOZ_ASSERT_UNREACHABLE("Should never be created if no printing."); |
3600 | | return nullptr; |
3601 | | #endif |
3602 | | } |
3603 | | |
3604 | | bool |
3605 | | ContentParent::DeallocPPrintingParent(PPrintingParent* printing) |
3606 | 0 | { |
3607 | 0 | #ifdef NS_PRINTING |
3608 | 0 | MOZ_RELEASE_ASSERT(mPrintingParent == printing, |
3609 | 0 | "Only one PrintingParent should have been created per process."); |
3610 | 0 |
|
3611 | 0 | // Release reference taken for IPDL code. |
3612 | 0 | static_cast<PrintingParent*>(printing)->Release(); |
3613 | 0 |
|
3614 | 0 | mPrintingParent = nullptr; |
3615 | | #else |
3616 | | MOZ_ASSERT_UNREACHABLE("Should never have been created if no printing."); |
3617 | | #endif |
3618 | | return true; |
3619 | 0 | } |
3620 | | |
3621 | | #ifdef NS_PRINTING |
3622 | | already_AddRefed<embedding::PrintingParent> |
3623 | | ContentParent::GetPrintingParent() |
3624 | 0 | { |
3625 | 0 | MOZ_ASSERT(mPrintingParent); |
3626 | 0 |
|
3627 | 0 | RefPtr<embedding::PrintingParent> printingParent = mPrintingParent; |
3628 | 0 | return printingParent.forget(); |
3629 | 0 | } |
3630 | | #endif |
3631 | | |
3632 | | mozilla::ipc::IPCResult |
3633 | | ContentParent::RecvInitStreamFilter(const uint64_t& aChannelId, |
3634 | | const nsString& aAddonId, |
3635 | | InitStreamFilterResolver&& aResolver) |
3636 | 0 | { |
3637 | 0 | Endpoint<PStreamFilterChild> endpoint; |
3638 | 0 | Unused << extensions::StreamFilterParent::Create(this, aChannelId, aAddonId, &endpoint); |
3639 | 0 |
|
3640 | 0 | aResolver(std::move(endpoint)); |
3641 | 0 |
|
3642 | 0 | return IPC_OK(); |
3643 | 0 | } |
3644 | | |
3645 | | PChildToParentStreamParent* |
3646 | | ContentParent::AllocPChildToParentStreamParent() |
3647 | 0 | { |
3648 | 0 | return nsIContentParent::AllocPChildToParentStreamParent(); |
3649 | 0 | } |
3650 | | |
3651 | | bool |
3652 | | ContentParent::DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor) |
3653 | 0 | { |
3654 | 0 | return nsIContentParent::DeallocPChildToParentStreamParent(aActor); |
3655 | 0 | } |
3656 | | |
3657 | | PParentToChildStreamParent* |
3658 | | ContentParent::SendPParentToChildStreamConstructor(PParentToChildStreamParent* aActor) |
3659 | 0 | { |
3660 | 0 | return PContentParent::SendPParentToChildStreamConstructor(aActor); |
3661 | 0 | } |
3662 | | |
3663 | | PParentToChildStreamParent* |
3664 | | ContentParent::AllocPParentToChildStreamParent() |
3665 | 0 | { |
3666 | 0 | return nsIContentParent::AllocPParentToChildStreamParent(); |
3667 | 0 | } |
3668 | | |
3669 | | bool |
3670 | | ContentParent::DeallocPParentToChildStreamParent(PParentToChildStreamParent* aActor) |
3671 | 0 | { |
3672 | 0 | return nsIContentParent::DeallocPParentToChildStreamParent(aActor); |
3673 | 0 | } |
3674 | | |
3675 | | PPSMContentDownloaderParent* |
3676 | | ContentParent::AllocPPSMContentDownloaderParent(const uint32_t& aCertType) |
3677 | 0 | { |
3678 | 0 | RefPtr<PSMContentDownloaderParent> downloader = |
3679 | 0 | new PSMContentDownloaderParent(aCertType); |
3680 | 0 | return downloader.forget().take(); |
3681 | 0 | } |
3682 | | |
3683 | | bool |
3684 | | ContentParent::DeallocPPSMContentDownloaderParent(PPSMContentDownloaderParent* aListener) |
3685 | 0 | { |
3686 | 0 | auto* listener = static_cast<PSMContentDownloaderParent*>(aListener); |
3687 | 0 | RefPtr<PSMContentDownloaderParent> downloader = dont_AddRef(listener); |
3688 | 0 | return true; |
3689 | 0 | } |
3690 | | |
3691 | | PExternalHelperAppParent* |
3692 | | ContentParent::AllocPExternalHelperAppParent(const OptionalURIParams& uri, |
3693 | | const nsCString& aMimeContentType, |
3694 | | const nsCString& aContentDisposition, |
3695 | | const uint32_t& aContentDispositionHint, |
3696 | | const nsString& aContentDispositionFilename, |
3697 | | const bool& aForceSave, |
3698 | | const int64_t& aContentLength, |
3699 | | const bool& aWasFileChannel, |
3700 | | const OptionalURIParams& aReferrer, |
3701 | | PBrowserParent* aBrowser) |
3702 | 0 | { |
3703 | 0 | ExternalHelperAppParent* parent = |
3704 | 0 | new ExternalHelperAppParent(uri, |
3705 | 0 | aContentLength, |
3706 | 0 | aWasFileChannel, |
3707 | 0 | aContentDisposition, |
3708 | 0 | aContentDispositionHint, |
3709 | 0 | aContentDispositionFilename); |
3710 | 0 | parent->AddRef(); |
3711 | 0 | parent->Init(this, |
3712 | 0 | aMimeContentType, |
3713 | 0 | aForceSave, |
3714 | 0 | aReferrer, |
3715 | 0 | aBrowser); |
3716 | 0 | return parent; |
3717 | 0 | } |
3718 | | |
3719 | | bool |
3720 | | ContentParent::DeallocPExternalHelperAppParent(PExternalHelperAppParent* aService) |
3721 | 0 | { |
3722 | 0 | ExternalHelperAppParent *parent = static_cast<ExternalHelperAppParent *>(aService); |
3723 | 0 | parent->Release(); |
3724 | 0 | return true; |
3725 | 0 | } |
3726 | | |
3727 | | PHandlerServiceParent* |
3728 | | ContentParent::AllocPHandlerServiceParent() |
3729 | 0 | { |
3730 | 0 | HandlerServiceParent* actor = new HandlerServiceParent(); |
3731 | 0 | actor->AddRef(); |
3732 | 0 | return actor; |
3733 | 0 | } |
3734 | | |
3735 | | bool |
3736 | | ContentParent::DeallocPHandlerServiceParent(PHandlerServiceParent* aHandlerServiceParent) |
3737 | 0 | { |
3738 | 0 | static_cast<HandlerServiceParent*>(aHandlerServiceParent)->Release(); |
3739 | 0 | return true; |
3740 | 0 | } |
3741 | | |
3742 | | media::PMediaParent* |
3743 | | ContentParent::AllocPMediaParent() |
3744 | 0 | { |
3745 | 0 | return media::AllocPMediaParent(); |
3746 | 0 | } |
3747 | | |
3748 | | bool |
3749 | | ContentParent::DeallocPMediaParent(media::PMediaParent *aActor) |
3750 | 0 | { |
3751 | 0 | return media::DeallocPMediaParent(aActor); |
3752 | 0 | } |
3753 | | |
3754 | | PPresentationParent* |
3755 | | ContentParent::AllocPPresentationParent() |
3756 | 0 | { |
3757 | 0 | RefPtr<PresentationParent> actor = new PresentationParent(); |
3758 | 0 | return actor.forget().take(); |
3759 | 0 | } |
3760 | | |
3761 | | bool |
3762 | | ContentParent::DeallocPPresentationParent(PPresentationParent* aActor) |
3763 | 0 | { |
3764 | 0 | RefPtr<PresentationParent> actor = |
3765 | 0 | dont_AddRef(static_cast<PresentationParent*>(aActor)); |
3766 | 0 | return true; |
3767 | 0 | } |
3768 | | |
3769 | | mozilla::ipc::IPCResult |
3770 | | ContentParent::RecvPPresentationConstructor(PPresentationParent* aActor) |
3771 | 0 | { |
3772 | 0 | if (!static_cast<PresentationParent*>(aActor)->Init(mChildID)) { |
3773 | 0 | return IPC_FAIL_NO_REASON(this); |
3774 | 0 | } |
3775 | 0 | return IPC_OK(); |
3776 | 0 | } |
3777 | | |
3778 | | PSpeechSynthesisParent* |
3779 | | ContentParent::AllocPSpeechSynthesisParent() |
3780 | 0 | { |
3781 | 0 | #ifdef MOZ_WEBSPEECH |
3782 | 0 | return new mozilla::dom::SpeechSynthesisParent(); |
3783 | | #else |
3784 | | return nullptr; |
3785 | | #endif |
3786 | | } |
3787 | | |
3788 | | bool |
3789 | | ContentParent::DeallocPSpeechSynthesisParent(PSpeechSynthesisParent* aActor) |
3790 | 0 | { |
3791 | 0 | #ifdef MOZ_WEBSPEECH |
3792 | 0 | delete aActor; |
3793 | 0 | return true; |
3794 | | #else |
3795 | | return false; |
3796 | | #endif |
3797 | | } |
3798 | | |
3799 | | mozilla::ipc::IPCResult |
3800 | | ContentParent::RecvPSpeechSynthesisConstructor(PSpeechSynthesisParent* aActor) |
3801 | 0 | { |
3802 | 0 | #ifdef MOZ_WEBSPEECH |
3803 | 0 | if (!static_cast<SpeechSynthesisParent*>(aActor)->SendInit()) { |
3804 | 0 | return IPC_FAIL_NO_REASON(this); |
3805 | 0 | } |
3806 | 0 | return IPC_OK(); |
3807 | | #else |
3808 | | return IPC_FAIL_NO_REASON(this); |
3809 | | #endif |
3810 | | } |
3811 | | |
3812 | | mozilla::ipc::IPCResult |
3813 | | ContentParent::RecvStartVisitedQuery(const URIParams& aURI) |
3814 | 0 | { |
3815 | 0 | nsCOMPtr<nsIURI> newURI = DeserializeURI(aURI); |
3816 | 0 | if (!newURI) { |
3817 | 0 | return IPC_FAIL_NO_REASON(this); |
3818 | 0 | } |
3819 | 0 | nsCOMPtr<IHistory> history = services::GetHistoryService(); |
3820 | 0 | if (history) { |
3821 | 0 | history->RegisterVisitedCallback(newURI, nullptr); |
3822 | 0 | } |
3823 | 0 | return IPC_OK(); |
3824 | 0 | } |
3825 | | |
3826 | | |
3827 | | mozilla::ipc::IPCResult |
3828 | | ContentParent::RecvVisitURI(const URIParams& uri, |
3829 | | const OptionalURIParams& referrer, |
3830 | | const uint32_t& flags) |
3831 | 0 | { |
3832 | 0 | nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri); |
3833 | 0 | if (!ourURI) { |
3834 | 0 | return IPC_FAIL_NO_REASON(this); |
3835 | 0 | } |
3836 | 0 | nsCOMPtr<nsIURI> ourReferrer = DeserializeURI(referrer); |
3837 | 0 | nsCOMPtr<IHistory> history = services::GetHistoryService(); |
3838 | 0 | if (history) { |
3839 | 0 | history->VisitURI(ourURI, ourReferrer, flags); |
3840 | 0 | } |
3841 | 0 | return IPC_OK(); |
3842 | 0 | } |
3843 | | |
3844 | | |
3845 | | mozilla::ipc::IPCResult |
3846 | | ContentParent::RecvSetURITitle(const URIParams& uri, |
3847 | | const nsString& title) |
3848 | 0 | { |
3849 | 0 | nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri); |
3850 | 0 | if (!ourURI) { |
3851 | 0 | return IPC_FAIL_NO_REASON(this); |
3852 | 0 | } |
3853 | 0 | nsCOMPtr<IHistory> history = services::GetHistoryService(); |
3854 | 0 | if (history) { |
3855 | 0 | history->SetURITitle(ourURI, title); |
3856 | 0 | } |
3857 | 0 | return IPC_OK(); |
3858 | 0 | } |
3859 | | |
3860 | | mozilla::ipc::IPCResult |
3861 | | ContentParent::RecvIsSecureURI(const uint32_t& aType, |
3862 | | const URIParams& aURI, |
3863 | | const uint32_t& aFlags, |
3864 | | const OriginAttributes& aOriginAttributes, |
3865 | | bool* aIsSecureURI) |
3866 | 0 | { |
3867 | 0 | nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID)); |
3868 | 0 | if (!sss) { |
3869 | 0 | return IPC_FAIL_NO_REASON(this); |
3870 | 0 | } |
3871 | 0 | nsCOMPtr<nsIURI> ourURI = DeserializeURI(aURI); |
3872 | 0 | if (!ourURI) { |
3873 | 0 | return IPC_FAIL_NO_REASON(this); |
3874 | 0 | } |
3875 | 0 | nsresult rv = sss->IsSecureURI(aType, ourURI, aFlags, aOriginAttributes, nullptr, |
3876 | 0 | nullptr, aIsSecureURI); |
3877 | 0 | if (NS_FAILED(rv)) { |
3878 | 0 | return IPC_FAIL_NO_REASON(this); |
3879 | 0 | } |
3880 | 0 | return IPC_OK(); |
3881 | 0 | } |
3882 | | |
3883 | | mozilla::ipc::IPCResult |
3884 | | ContentParent::RecvAccumulateMixedContentHSTS(const URIParams& aURI, const bool& aActive, |
3885 | | const OriginAttributes& aOriginAttributes) |
3886 | 0 | { |
3887 | 0 | nsCOMPtr<nsIURI> ourURI = DeserializeURI(aURI); |
3888 | 0 | if (!ourURI) { |
3889 | 0 | return IPC_FAIL_NO_REASON(this); |
3890 | 0 | } |
3891 | 0 | nsMixedContentBlocker::AccumulateMixedContentHSTS(ourURI, aActive, aOriginAttributes); |
3892 | 0 | return IPC_OK(); |
3893 | 0 | } |
3894 | | |
3895 | | mozilla::ipc::IPCResult |
3896 | | ContentParent::RecvLoadURIExternal(const URIParams& uri, |
3897 | | PBrowserParent* windowContext) |
3898 | 0 | { |
3899 | 0 | nsCOMPtr<nsIExternalProtocolService> extProtService(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID)); |
3900 | 0 | if (!extProtService) { |
3901 | 0 | return IPC_OK(); |
3902 | 0 | } |
3903 | 0 | nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri); |
3904 | 0 | if (!ourURI) { |
3905 | 0 | return IPC_FAIL_NO_REASON(this); |
3906 | 0 | } |
3907 | 0 |
|
3908 | 0 | RefPtr<RemoteWindowContext> context = |
3909 | 0 | new RemoteWindowContext(static_cast<TabParent*>(windowContext)); |
3910 | 0 | extProtService->LoadURI(ourURI, context); |
3911 | 0 | return IPC_OK(); |
3912 | 0 | } |
3913 | | |
3914 | | mozilla::ipc::IPCResult |
3915 | | ContentParent::RecvExtProtocolChannelConnectParent(const uint32_t& registrarId) |
3916 | 0 | { |
3917 | 0 | nsresult rv; |
3918 | 0 |
|
3919 | 0 | // First get the real channel created before redirect on the parent. |
3920 | 0 | nsCOMPtr<nsIChannel> channel; |
3921 | 0 | rv = NS_LinkRedirectChannels(registrarId, nullptr, getter_AddRefs(channel)); |
3922 | 0 | NS_ENSURE_SUCCESS(rv, IPC_OK()); |
3923 | 0 |
|
3924 | 0 | nsCOMPtr<nsIParentChannel> parent = do_QueryInterface(channel, &rv); |
3925 | 0 | NS_ENSURE_SUCCESS(rv, IPC_OK()); |
3926 | 0 |
|
3927 | 0 | // The channel itself is its own (faked) parent, link it. |
3928 | 0 | rv = NS_LinkRedirectChannels(registrarId, parent, getter_AddRefs(channel)); |
3929 | 0 | NS_ENSURE_SUCCESS(rv, IPC_OK()); |
3930 | 0 |
|
3931 | 0 | // Signal the parent channel that it's a redirect-to parent. This will |
3932 | 0 | // make AsyncOpen on it do nothing (what we want). |
3933 | 0 | // Yes, this is a bit of a hack, but I don't think it's necessary to invent |
3934 | 0 | // a new interface just to set this flag on the channel. |
3935 | 0 | parent->SetParentListener(nullptr); |
3936 | 0 |
|
3937 | 0 | return IPC_OK(); |
3938 | 0 | } |
3939 | | |
3940 | | bool |
3941 | | ContentParent::HasNotificationPermission(const IPC::Principal& aPrincipal) |
3942 | 0 | { |
3943 | 0 | return true; |
3944 | 0 | } |
3945 | | |
3946 | | mozilla::ipc::IPCResult |
3947 | | ContentParent::RecvShowAlert(nsIAlertNotification* aAlert) |
3948 | 0 | { |
3949 | 0 | if (!aAlert) { |
3950 | 0 | return IPC_FAIL_NO_REASON(this); |
3951 | 0 | } |
3952 | 0 | nsCOMPtr<nsIPrincipal> principal; |
3953 | 0 | nsresult rv = aAlert->GetPrincipal(getter_AddRefs(principal)); |
3954 | 0 | if (NS_WARN_IF(NS_FAILED(rv)) || |
3955 | 0 | !HasNotificationPermission(IPC::Principal(principal))) { |
3956 | 0 |
|
3957 | 0 | return IPC_OK(); |
3958 | 0 | } |
3959 | 0 |
|
3960 | 0 | nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_ALERTSERVICE_CONTRACTID)); |
3961 | 0 | if (sysAlerts) { |
3962 | 0 | sysAlerts->ShowAlert(aAlert, this); |
3963 | 0 | } |
3964 | 0 | return IPC_OK(); |
3965 | 0 | } |
3966 | | |
3967 | | mozilla::ipc::IPCResult |
3968 | | ContentParent::RecvCloseAlert(const nsString& aName, |
3969 | | const IPC::Principal& aPrincipal) |
3970 | 0 | { |
3971 | 0 | if (!HasNotificationPermission(aPrincipal)) { |
3972 | 0 | return IPC_OK(); |
3973 | 0 | } |
3974 | 0 |
|
3975 | 0 | nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_ALERTSERVICE_CONTRACTID)); |
3976 | 0 | if (sysAlerts) { |
3977 | 0 | sysAlerts->CloseAlert(aName, aPrincipal); |
3978 | 0 | } |
3979 | 0 |
|
3980 | 0 | return IPC_OK(); |
3981 | 0 | } |
3982 | | |
3983 | | mozilla::ipc::IPCResult |
3984 | | ContentParent::RecvDisableNotifications(const IPC::Principal& aPrincipal) |
3985 | 0 | { |
3986 | 0 | if (HasNotificationPermission(aPrincipal)) { |
3987 | 0 | Unused << Notification::RemovePermission(aPrincipal); |
3988 | 0 | } |
3989 | 0 | return IPC_OK(); |
3990 | 0 | } |
3991 | | |
3992 | | mozilla::ipc::IPCResult |
3993 | | ContentParent::RecvOpenNotificationSettings(const IPC::Principal& aPrincipal) |
3994 | 0 | { |
3995 | 0 | if (HasNotificationPermission(aPrincipal)) { |
3996 | 0 | Unused << Notification::OpenSettings(aPrincipal); |
3997 | 0 | } |
3998 | 0 | return IPC_OK(); |
3999 | 0 | } |
4000 | | |
4001 | | mozilla::ipc::IPCResult |
4002 | | ContentParent::RecvSyncMessage(const nsString& aMsg, |
4003 | | const ClonedMessageData& aData, |
4004 | | InfallibleTArray<CpowEntry>&& aCpows, |
4005 | | const IPC::Principal& aPrincipal, |
4006 | | nsTArray<StructuredCloneData>* aRetvals) |
4007 | 0 | { |
4008 | 0 | return nsIContentParent::RecvSyncMessage(aMsg, aData, std::move(aCpows), |
4009 | 0 | aPrincipal, aRetvals); |
4010 | 0 | } |
4011 | | |
4012 | | mozilla::ipc::IPCResult |
4013 | | ContentParent::RecvRpcMessage(const nsString& aMsg, |
4014 | | const ClonedMessageData& aData, |
4015 | | InfallibleTArray<CpowEntry>&& aCpows, |
4016 | | const IPC::Principal& aPrincipal, |
4017 | | nsTArray<StructuredCloneData>* aRetvals) |
4018 | 0 | { |
4019 | 0 | return nsIContentParent::RecvRpcMessage(aMsg, aData, std::move(aCpows), aPrincipal, |
4020 | 0 | aRetvals); |
4021 | 0 | } |
4022 | | |
4023 | | mozilla::ipc::IPCResult |
4024 | | ContentParent::RecvAsyncMessage(const nsString& aMsg, |
4025 | | InfallibleTArray<CpowEntry>&& aCpows, |
4026 | | const IPC::Principal& aPrincipal, |
4027 | | const ClonedMessageData& aData) |
4028 | 0 | { |
4029 | 0 | return nsIContentParent::RecvAsyncMessage(aMsg, std::move(aCpows), aPrincipal, |
4030 | 0 | aData); |
4031 | 0 | } |
4032 | | |
4033 | | static int32_t |
4034 | | AddGeolocationListener(nsIDOMGeoPositionCallback* watcher, |
4035 | | nsIDOMGeoPositionErrorCallback* errorCallBack, |
4036 | | bool highAccuracy) |
4037 | 0 | { |
4038 | 0 | RefPtr<Geolocation> geo = Geolocation::NonWindowSingleton(); |
4039 | 0 |
|
4040 | 0 | UniquePtr<PositionOptions> options = MakeUnique<PositionOptions>(); |
4041 | 0 | options->mTimeout = 0; |
4042 | 0 | options->mMaximumAge = 0; |
4043 | 0 | options->mEnableHighAccuracy = highAccuracy; |
4044 | 0 | return geo->WatchPosition(watcher, errorCallBack, std::move(options)); |
4045 | 0 | } |
4046 | | |
4047 | | mozilla::ipc::IPCResult |
4048 | | ContentParent::RecvAddGeolocationListener(const IPC::Principal& aPrincipal, |
4049 | | const bool& aHighAccuracy) |
4050 | 0 | { |
4051 | 0 | // To ensure no geolocation updates are skipped, we always force the |
4052 | 0 | // creation of a new listener. |
4053 | 0 | RecvRemoveGeolocationListener(); |
4054 | 0 | mGeolocationWatchID = AddGeolocationListener(this, this, aHighAccuracy); |
4055 | 0 | return IPC_OK(); |
4056 | 0 | } |
4057 | | |
4058 | | mozilla::ipc::IPCResult |
4059 | | ContentParent::RecvRemoveGeolocationListener() |
4060 | 0 | { |
4061 | 0 | if (mGeolocationWatchID != -1) { |
4062 | 0 | RefPtr<Geolocation> geo = Geolocation::NonWindowSingleton(); |
4063 | 0 | geo->ClearWatch(mGeolocationWatchID); |
4064 | 0 | mGeolocationWatchID = -1; |
4065 | 0 | } |
4066 | 0 | return IPC_OK(); |
4067 | 0 | } |
4068 | | |
4069 | | mozilla::ipc::IPCResult |
4070 | | ContentParent::RecvSetGeolocationHigherAccuracy(const bool& aEnable) |
4071 | 0 | { |
4072 | 0 | // This should never be called without a listener already present, |
4073 | 0 | // so this check allows us to forgo securing privileges. |
4074 | 0 | if (mGeolocationWatchID != -1) { |
4075 | 0 | RecvRemoveGeolocationListener(); |
4076 | 0 | mGeolocationWatchID = AddGeolocationListener(this, this, aEnable); |
4077 | 0 | } |
4078 | 0 | return IPC_OK(); |
4079 | 0 | } |
4080 | | |
4081 | | NS_IMETHODIMP |
4082 | | ContentParent::HandleEvent(nsIDOMGeoPosition* postion) |
4083 | 0 | { |
4084 | 0 | Unused << SendGeolocationUpdate(postion); |
4085 | 0 | return NS_OK; |
4086 | 0 | } |
4087 | | |
4088 | | NS_IMETHODIMP |
4089 | | ContentParent::HandleEvent(PositionError* positionError) |
4090 | 0 | { |
4091 | 0 | Unused << SendGeolocationError(positionError->Code()); |
4092 | 0 | return NS_OK; |
4093 | 0 | } |
4094 | | |
4095 | | nsConsoleService * |
4096 | | ContentParent::GetConsoleService() |
4097 | 0 | { |
4098 | 0 | if (mConsoleService) { |
4099 | 0 | return mConsoleService.get(); |
4100 | 0 | } |
4101 | 0 | |
4102 | 0 | // XXXkhuey everything about this is terrible. |
4103 | 0 | // Get the ConsoleService by CID rather than ContractID, so that we |
4104 | 0 | // can cast the returned pointer to an nsConsoleService (rather than |
4105 | 0 | // just an nsIConsoleService). This allows us to call the non-idl function |
4106 | 0 | // nsConsoleService::LogMessageWithMode. |
4107 | 0 | NS_DEFINE_CID(consoleServiceCID, NS_CONSOLESERVICE_CID); |
4108 | 0 | nsCOMPtr<nsIConsoleService> consoleService(do_GetService(consoleServiceCID)); |
4109 | 0 | mConsoleService = static_cast<nsConsoleService*>(consoleService.get()); |
4110 | 0 | return mConsoleService.get(); |
4111 | 0 | } |
4112 | | |
4113 | | mozilla::ipc::IPCResult |
4114 | | ContentParent::RecvConsoleMessage(const nsString& aMessage) |
4115 | 0 | { |
4116 | 0 | RefPtr<nsConsoleService> consoleService = GetConsoleService(); |
4117 | 0 | if (!consoleService) { |
4118 | 0 | return IPC_OK(); |
4119 | 0 | } |
4120 | 0 |
|
4121 | 0 | RefPtr<nsConsoleMessage> msg(new nsConsoleMessage(aMessage.get())); |
4122 | 0 | consoleService->LogMessageWithMode(msg, nsConsoleService::SuppressLog); |
4123 | 0 | return IPC_OK(); |
4124 | 0 | } |
4125 | | |
4126 | | mozilla::ipc::IPCResult |
4127 | | ContentParent::RecvScriptError(const nsString& aMessage, |
4128 | | const nsString& aSourceName, |
4129 | | const nsString& aSourceLine, |
4130 | | const uint32_t& aLineNumber, |
4131 | | const uint32_t& aColNumber, |
4132 | | const uint32_t& aFlags, |
4133 | | const nsCString& aCategory, |
4134 | | const bool& aFromPrivateWindow) |
4135 | 0 | { |
4136 | 0 | return RecvScriptErrorInternal(aMessage, aSourceName, aSourceLine, |
4137 | 0 | aLineNumber, aColNumber, aFlags, |
4138 | 0 | aCategory, aFromPrivateWindow); |
4139 | 0 | } |
4140 | | |
4141 | | mozilla::ipc::IPCResult |
4142 | | ContentParent::RecvScriptErrorWithStack(const nsString& aMessage, |
4143 | | const nsString& aSourceName, |
4144 | | const nsString& aSourceLine, |
4145 | | const uint32_t& aLineNumber, |
4146 | | const uint32_t& aColNumber, |
4147 | | const uint32_t& aFlags, |
4148 | | const nsCString& aCategory, |
4149 | | const bool& aFromPrivateWindow, |
4150 | | const ClonedMessageData& aFrame) |
4151 | 0 | { |
4152 | 0 | return RecvScriptErrorInternal(aMessage, aSourceName, aSourceLine, |
4153 | 0 | aLineNumber, aColNumber, aFlags, |
4154 | 0 | aCategory, aFromPrivateWindow, &aFrame); |
4155 | 0 | } |
4156 | | |
4157 | | mozilla::ipc::IPCResult |
4158 | | ContentParent::RecvScriptErrorInternal(const nsString& aMessage, |
4159 | | const nsString& aSourceName, |
4160 | | const nsString& aSourceLine, |
4161 | | const uint32_t& aLineNumber, |
4162 | | const uint32_t& aColNumber, |
4163 | | const uint32_t& aFlags, |
4164 | | const nsCString& aCategory, |
4165 | | const bool& aFromPrivateWindow, |
4166 | | const ClonedMessageData* aStack) |
4167 | 0 | { |
4168 | 0 | RefPtr<nsConsoleService> consoleService = GetConsoleService(); |
4169 | 0 | if (!consoleService) { |
4170 | 0 | return IPC_OK(); |
4171 | 0 | } |
4172 | 0 |
|
4173 | 0 | nsCOMPtr<nsIScriptError> msg; |
4174 | 0 |
|
4175 | 0 | if (aStack) { |
4176 | 0 | StructuredCloneData data; |
4177 | 0 | UnpackClonedMessageDataForParent(*aStack, data); |
4178 | 0 |
|
4179 | 0 | AutoJSAPI jsapi; |
4180 | 0 | if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) { |
4181 | 0 | MOZ_CRASH(); |
4182 | 0 | } |
4183 | 0 | JSContext* cx = jsapi.cx(); |
4184 | 0 |
|
4185 | 0 | JS::RootedValue stack(cx); |
4186 | 0 | ErrorResult rv; |
4187 | 0 | data.Read(cx, &stack, rv); |
4188 | 0 | if (rv.Failed() || !stack.isObject()) { |
4189 | 0 | rv.SuppressException(); |
4190 | 0 | return IPC_OK(); |
4191 | 0 | } |
4192 | 0 |
|
4193 | 0 | JS::RootedObject stackObj(cx, &stack.toObject()); |
4194 | 0 | MOZ_ASSERT(JS::IsUnwrappedSavedFrame(stackObj)); |
4195 | 0 |
|
4196 | 0 | JS::RootedObject stackGlobal(cx, JS::GetNonCCWObjectGlobal(stackObj)); |
4197 | 0 | msg = new nsScriptErrorWithStack(stackObj, stackGlobal); |
4198 | 0 | } else { |
4199 | 0 | msg = new nsScriptError(); |
4200 | 0 | } |
4201 | 0 |
|
4202 | 0 | nsresult rv = msg->Init(aMessage, aSourceName, aSourceLine, |
4203 | 0 | aLineNumber, aColNumber, aFlags, |
4204 | 0 | aCategory.get(), aFromPrivateWindow); |
4205 | 0 | if (NS_FAILED(rv)) |
4206 | 0 | return IPC_OK(); |
4207 | 0 | |
4208 | 0 | consoleService->LogMessageWithMode(msg, nsConsoleService::SuppressLog); |
4209 | 0 | return IPC_OK(); |
4210 | 0 | } |
4211 | | |
4212 | | mozilla::ipc::IPCResult |
4213 | | ContentParent::RecvPrivateDocShellsExist(const bool& aExist) |
4214 | 0 | { |
4215 | 0 | if (!sPrivateContent) { |
4216 | 0 | sPrivateContent = new nsTArray<ContentParent*>(); |
4217 | 0 | if (!sHasSeenPrivateDocShell) { |
4218 | 0 | sHasSeenPrivateDocShell = true; |
4219 | 0 | Telemetry::ScalarSet(Telemetry::ScalarID::DOM_PARENTPROCESS_PRIVATE_WINDOW_USED, true); |
4220 | 0 | } |
4221 | 0 | } |
4222 | 0 | if (aExist) { |
4223 | 0 | sPrivateContent->AppendElement(this); |
4224 | 0 | } else { |
4225 | 0 | sPrivateContent->RemoveElement(this); |
4226 | 0 |
|
4227 | 0 | // Only fire the notification if we have private and non-private |
4228 | 0 | // windows: if privatebrowsing.autostart is true, all windows are |
4229 | 0 | // private. |
4230 | 0 | if (!sPrivateContent->Length() && |
4231 | 0 | !Preferences::GetBool("browser.privatebrowsing.autostart")) { |
4232 | 0 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
4233 | 0 | obs->NotifyObservers(nullptr, "last-pb-context-exited", nullptr); |
4234 | 0 | delete sPrivateContent; |
4235 | 0 | sPrivateContent = nullptr; |
4236 | 0 | } |
4237 | 0 | } |
4238 | 0 | return IPC_OK(); |
4239 | 0 | } |
4240 | | |
4241 | | bool |
4242 | | ContentParent::DoLoadMessageManagerScript(const nsAString& aURL, |
4243 | | bool aRunInGlobalScope) |
4244 | 0 | { |
4245 | 0 | MOZ_ASSERT(!aRunInGlobalScope); |
4246 | 0 | return SendLoadProcessScript(nsString(aURL)); |
4247 | 0 | } |
4248 | | |
4249 | | nsresult |
4250 | | ContentParent::DoSendAsyncMessage(JSContext* aCx, |
4251 | | const nsAString& aMessage, |
4252 | | StructuredCloneData& aHelper, |
4253 | | JS::Handle<JSObject *> aCpows, |
4254 | | nsIPrincipal* aPrincipal) |
4255 | 0 | { |
4256 | 0 | ClonedMessageData data; |
4257 | 0 | if (!BuildClonedMessageDataForParent(this, aHelper, data)) { |
4258 | 0 | return NS_ERROR_DOM_DATA_CLONE_ERR; |
4259 | 0 | } |
4260 | 0 | InfallibleTArray<CpowEntry> cpows; |
4261 | 0 | jsipc::CPOWManager* mgr = GetCPOWManager(); |
4262 | 0 | if (aCpows && (!mgr || !mgr->Wrap(aCx, aCpows, &cpows))) { |
4263 | 0 | return NS_ERROR_UNEXPECTED; |
4264 | 0 | } |
4265 | 0 | if (!SendAsyncMessage(nsString(aMessage), cpows, Principal(aPrincipal), data)) { |
4266 | 0 | return NS_ERROR_UNEXPECTED; |
4267 | 0 | } |
4268 | 0 | return NS_OK; |
4269 | 0 | } |
4270 | | |
4271 | | PIPCBlobInputStreamParent* |
4272 | | ContentParent::SendPIPCBlobInputStreamConstructor(PIPCBlobInputStreamParent* aActor, |
4273 | | const nsID& aID, |
4274 | | const uint64_t& aSize) |
4275 | 0 | { |
4276 | 0 | return PContentParent::SendPIPCBlobInputStreamConstructor(aActor, aID, aSize); |
4277 | 0 | } |
4278 | | |
4279 | | PBrowserParent* |
4280 | | ContentParent::SendPBrowserConstructor(PBrowserParent* aActor, |
4281 | | const TabId& aTabId, |
4282 | | const TabId& aSameTabGroupAs, |
4283 | | const IPCTabContext& aContext, |
4284 | | const uint32_t& aChromeFlags, |
4285 | | const ContentParentId& aCpId, |
4286 | | const bool& aIsForBrowser) |
4287 | 0 | { |
4288 | 0 | return PContentParent::SendPBrowserConstructor(aActor, |
4289 | 0 | aTabId, |
4290 | 0 | aSameTabGroupAs, |
4291 | 0 | aContext, |
4292 | 0 | aChromeFlags, |
4293 | 0 | aCpId, |
4294 | 0 | aIsForBrowser); |
4295 | 0 | } |
4296 | | |
4297 | | mozilla::ipc::IPCResult |
4298 | | ContentParent::RecvKeywordToURI(const nsCString& aKeyword, |
4299 | | nsString* aProviderName, |
4300 | | RefPtr<nsIInputStream>* aPostData, |
4301 | | OptionalURIParams* aURI) |
4302 | 0 | { |
4303 | 0 | *aPostData = nullptr; |
4304 | 0 | *aURI = void_t(); |
4305 | 0 |
|
4306 | 0 | nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID); |
4307 | 0 | if (!fixup) { |
4308 | 0 | return IPC_OK(); |
4309 | 0 | } |
4310 | 0 |
|
4311 | 0 | nsCOMPtr<nsIURIFixupInfo> info; |
4312 | 0 |
|
4313 | 0 | if (NS_FAILED(fixup->KeywordToURI(aKeyword, getter_AddRefs(*aPostData), |
4314 | 0 | getter_AddRefs(info)))) { |
4315 | 0 | return IPC_OK(); |
4316 | 0 | } |
4317 | 0 | info->GetKeywordProviderName(*aProviderName); |
4318 | 0 |
|
4319 | 0 | nsCOMPtr<nsIURI> uri; |
4320 | 0 | info->GetPreferredURI(getter_AddRefs(uri)); |
4321 | 0 | SerializeURI(uri, *aURI); |
4322 | 0 | return IPC_OK(); |
4323 | 0 | } |
4324 | | |
4325 | | mozilla::ipc::IPCResult |
4326 | | ContentParent::RecvNotifyKeywordSearchLoading(const nsString &aProvider, |
4327 | | const nsString &aKeyword) |
4328 | 0 | { |
4329 | 0 | #ifdef MOZ_TOOLKIT_SEARCH |
4330 | 0 | nsCOMPtr<nsIBrowserSearchService> searchSvc = do_GetService("@mozilla.org/browser/search-service;1"); |
4331 | 0 | if (searchSvc) { |
4332 | 0 | nsCOMPtr<nsISearchEngine> searchEngine; |
4333 | 0 | searchSvc->GetEngineByName(aProvider, getter_AddRefs(searchEngine)); |
4334 | 0 | if (searchEngine) { |
4335 | 0 | nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService(); |
4336 | 0 | if (obsSvc) { |
4337 | 0 | // Note that "keyword-search" refers to a search via the url |
4338 | 0 | // bar, not a bookmarks keyword search. |
4339 | 0 | obsSvc->NotifyObservers(searchEngine, "keyword-search", aKeyword.get()); |
4340 | 0 | } |
4341 | 0 | } |
4342 | 0 | } |
4343 | 0 | #endif |
4344 | 0 | return IPC_OK(); |
4345 | 0 | } |
4346 | | |
4347 | | mozilla::ipc::IPCResult |
4348 | | ContentParent::RecvCopyFavicon(const URIParams& aOldURI, |
4349 | | const URIParams& aNewURI, |
4350 | | const IPC::Principal& aLoadingPrincipal, |
4351 | | const bool& aInPrivateBrowsing) |
4352 | 0 | { |
4353 | 0 | nsCOMPtr<nsIURI> oldURI = DeserializeURI(aOldURI); |
4354 | 0 | if (!oldURI) { |
4355 | 0 | return IPC_OK(); |
4356 | 0 | } |
4357 | 0 | nsCOMPtr<nsIURI> newURI = DeserializeURI(aNewURI); |
4358 | 0 | if (!newURI) { |
4359 | 0 | return IPC_OK(); |
4360 | 0 | } |
4361 | 0 |
|
4362 | 0 | nsDocShell::CopyFavicon(oldURI, newURI, aLoadingPrincipal, aInPrivateBrowsing); |
4363 | 0 | return IPC_OK(); |
4364 | 0 | } |
4365 | | |
4366 | | bool |
4367 | | ContentParent::ShouldContinueFromReplyTimeout() |
4368 | 0 | { |
4369 | 0 | RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get(); |
4370 | 0 | return !monitor || !monitor->ShouldTimeOutCPOWs(); |
4371 | 0 | } |
4372 | | |
4373 | | mozilla::ipc::IPCResult |
4374 | | ContentParent::RecvRecordingDeviceEvents(const nsString& aRecordingStatus, |
4375 | | const nsString& aPageURL, |
4376 | | const bool& aIsAudio, |
4377 | | const bool& aIsVideo) |
4378 | 0 | { |
4379 | 0 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
4380 | 0 | if (obs) { |
4381 | 0 | // recording-device-ipc-events needs to gather more information from content process |
4382 | 0 | RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag(); |
4383 | 0 | props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), ChildID()); |
4384 | 0 | props->SetPropertyAsBool(NS_LITERAL_STRING("isAudio"), aIsAudio); |
4385 | 0 | props->SetPropertyAsBool(NS_LITERAL_STRING("isVideo"), aIsVideo); |
4386 | 0 | props->SetPropertyAsAString(NS_LITERAL_STRING("requestURL"), aPageURL); |
4387 | 0 |
|
4388 | 0 | obs->NotifyObservers((nsIPropertyBag2*) props, |
4389 | 0 | "recording-device-ipc-events", |
4390 | 0 | aRecordingStatus.get()); |
4391 | 0 | } else { |
4392 | 0 | NS_WARNING("Could not get the Observer service for ContentParent::RecvRecordingDeviceEvents."); |
4393 | 0 | } |
4394 | 0 | return IPC_OK(); |
4395 | 0 | } |
4396 | | |
4397 | | mozilla::ipc::IPCResult |
4398 | | ContentParent::RecvAddIdleObserver(const uint64_t& aObserver, |
4399 | | const uint32_t& aIdleTimeInS) |
4400 | 0 | { |
4401 | 0 | nsresult rv; |
4402 | 0 | nsCOMPtr<nsIIdleService> idleService = |
4403 | 0 | do_GetService("@mozilla.org/widget/idleservice;1", &rv); |
4404 | 0 | NS_ENSURE_SUCCESS(rv, IPC_FAIL_NO_REASON(this)); |
4405 | 0 |
|
4406 | 0 | RefPtr<ParentIdleListener> listener = |
4407 | 0 | new ParentIdleListener(this, aObserver, aIdleTimeInS); |
4408 | 0 | rv = idleService->AddIdleObserver(listener, aIdleTimeInS); |
4409 | 0 | NS_ENSURE_SUCCESS(rv, IPC_FAIL_NO_REASON(this)); |
4410 | 0 | mIdleListeners.AppendElement(listener); |
4411 | 0 | return IPC_OK(); |
4412 | 0 | } |
4413 | | |
4414 | | mozilla::ipc::IPCResult |
4415 | | ContentParent::RecvRemoveIdleObserver(const uint64_t& aObserver, |
4416 | | const uint32_t& aIdleTimeInS) |
4417 | 0 | { |
4418 | 0 | RefPtr<ParentIdleListener> listener; |
4419 | 0 | for (int32_t i = mIdleListeners.Length() - 1; i >= 0; --i) { |
4420 | 0 | listener = static_cast<ParentIdleListener*>(mIdleListeners[i].get()); |
4421 | 0 | if (listener->mObserver == aObserver && |
4422 | 0 | listener->mTime == aIdleTimeInS) { |
4423 | 0 | nsresult rv; |
4424 | 0 | nsCOMPtr<nsIIdleService> idleService = |
4425 | 0 | do_GetService("@mozilla.org/widget/idleservice;1", &rv); |
4426 | 0 | NS_ENSURE_SUCCESS(rv, IPC_FAIL_NO_REASON(this)); |
4427 | 0 | idleService->RemoveIdleObserver(listener, aIdleTimeInS); |
4428 | 0 | mIdleListeners.RemoveElementAt(i); |
4429 | 0 | break; |
4430 | 0 | } |
4431 | 0 | } |
4432 | 0 | return IPC_OK(); |
4433 | 0 | } |
4434 | | |
4435 | | mozilla::ipc::IPCResult |
4436 | | ContentParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd) |
4437 | 0 | { |
4438 | | #ifndef MOZ_X11 |
4439 | | MOZ_CRASH("This message only makes sense on X11 platforms"); |
4440 | | #else |
4441 | 0 | MOZ_ASSERT(0 > mChildXSocketFdDup.get(), |
4442 | 0 | "Already backed up X resources??"); |
4443 | 0 | if (aXSocketFd.IsValid()) { |
4444 | 0 | auto rawFD = aXSocketFd.ClonePlatformHandle(); |
4445 | 0 | mChildXSocketFdDup.reset(rawFD.release()); |
4446 | 0 | } |
4447 | 0 | #endif |
4448 | 0 | return IPC_OK(); |
4449 | 0 | } |
4450 | | |
4451 | | class AnonymousTemporaryFileRequestor final : public Runnable |
4452 | | { |
4453 | | public: |
4454 | | AnonymousTemporaryFileRequestor(ContentParent* aCP, const uint64_t& aID) |
4455 | | : Runnable("dom::AnonymousTemporaryFileRequestor") |
4456 | | , mCP(aCP) |
4457 | | , mID(aID) |
4458 | | , mRv(NS_OK) |
4459 | | , mPRFD(nullptr) |
4460 | 0 | { |
4461 | 0 | } |
4462 | | |
4463 | | NS_IMETHOD Run() override |
4464 | 0 | { |
4465 | 0 | if (NS_IsMainThread()) { |
4466 | 0 | FileDescOrError result; |
4467 | 0 | if (NS_WARN_IF(NS_FAILED(mRv))) { |
4468 | 0 | // Returning false will kill the child process; instead |
4469 | 0 | // propagate the error and let the child handle it. |
4470 | 0 | result = mRv; |
4471 | 0 | } else { |
4472 | 0 | result = FileDescriptor(FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mPRFD))); |
4473 | 0 | // The FileDescriptor object owns a duplicate of the file handle; we |
4474 | 0 | // must close the original (and clean up the NSPR descriptor). |
4475 | 0 | PR_Close(mPRFD); |
4476 | 0 | } |
4477 | 0 | Unused << mCP->SendProvideAnonymousTemporaryFile(mID, result); |
4478 | 0 | // It's important to release this reference while wr're on the main thread! |
4479 | 0 | mCP = nullptr; |
4480 | 0 | } else { |
4481 | 0 | mRv = NS_OpenAnonymousTemporaryFile(&mPRFD); |
4482 | 0 | NS_DispatchToMainThread(this); |
4483 | 0 | } |
4484 | 0 | return NS_OK; |
4485 | 0 | } |
4486 | | |
4487 | | private: |
4488 | | RefPtr<ContentParent> mCP; |
4489 | | uint64_t mID; |
4490 | | nsresult mRv; |
4491 | | PRFileDesc* mPRFD; |
4492 | | }; |
4493 | | |
4494 | | mozilla::ipc::IPCResult |
4495 | | ContentParent::RecvRequestAnonymousTemporaryFile(const uint64_t& aID) |
4496 | 0 | { |
4497 | 0 | // Make sure to send a callback to the child if we bail out early. |
4498 | 0 | nsresult rv = NS_OK; |
4499 | 0 | RefPtr<ContentParent> self(this); |
4500 | 0 | auto autoNotifyChildOnError = MakeScopeExit([&, self]() { |
4501 | 0 | if (NS_FAILED(rv)) { |
4502 | 0 | FileDescOrError result(rv); |
4503 | 0 | Unused << self->SendProvideAnonymousTemporaryFile(aID, result); |
4504 | 0 | } |
4505 | 0 | }); |
4506 | 0 |
|
4507 | 0 | // We use a helper runnable to open the anonymous temporary file on the IO |
4508 | 0 | // thread. The same runnable will call us back on the main thread when the |
4509 | 0 | // file has been opened. |
4510 | 0 | nsCOMPtr<nsIEventTarget> target |
4511 | 0 | = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); |
4512 | 0 | if (!target) { |
4513 | 0 | return IPC_OK(); |
4514 | 0 | } |
4515 | 0 |
|
4516 | 0 | rv = target->Dispatch(new AnonymousTemporaryFileRequestor(this, aID), |
4517 | 0 | NS_DISPATCH_NORMAL); |
4518 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
4519 | 0 | return IPC_OK(); |
4520 | 0 | } |
4521 | 0 |
|
4522 | 0 | rv = NS_OK; |
4523 | 0 | return IPC_OK(); |
4524 | 0 | } |
4525 | | |
4526 | | mozilla::ipc::IPCResult |
4527 | | ContentParent::RecvCreateAudioIPCConnection(CreateAudioIPCConnectionResolver&& aResolver) |
4528 | 0 | { |
4529 | 0 | FileDescriptor fd = CubebUtils::CreateAudioIPCConnection(); |
4530 | 0 | if (!fd.IsValid()) { |
4531 | 0 | return IPC_FAIL(this, "CubebUtils::CreateAudioIPCConnection failed"); |
4532 | 0 | } |
4533 | 0 | aResolver(std::move(fd)); |
4534 | 0 | return IPC_OK(); |
4535 | 0 | } |
4536 | | |
4537 | | static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID); |
4538 | | |
4539 | | mozilla::ipc::IPCResult |
4540 | | ContentParent::RecvKeygenProcessValue(const nsString& oldValue, |
4541 | | const nsString& challenge, |
4542 | | const nsString& keytype, |
4543 | | const nsString& keyparams, |
4544 | | nsString* newValue) |
4545 | 0 | { |
4546 | 0 | nsCOMPtr<nsIFormProcessor> formProcessor = |
4547 | 0 | do_GetService(kFormProcessorCID); |
4548 | 0 | if (!formProcessor) { |
4549 | 0 | newValue->Truncate(); |
4550 | 0 | return IPC_OK(); |
4551 | 0 | } |
4552 | 0 |
|
4553 | 0 | formProcessor->ProcessValueIPC(oldValue, challenge, keytype, keyparams, |
4554 | 0 | *newValue); |
4555 | 0 | return IPC_OK(); |
4556 | 0 | } |
4557 | | |
4558 | | mozilla::ipc::IPCResult |
4559 | | ContentParent::RecvKeygenProvideContent(nsString* aAttribute, |
4560 | | nsTArray<nsString>* aContent) |
4561 | 0 | { |
4562 | 0 | nsCOMPtr<nsIFormProcessor> formProcessor = |
4563 | 0 | do_GetService(kFormProcessorCID); |
4564 | 0 | if (!formProcessor) { |
4565 | 0 | return IPC_OK(); |
4566 | 0 | } |
4567 | 0 |
|
4568 | 0 | formProcessor->ProvideContent(NS_LITERAL_STRING("SELECT"), *aContent, |
4569 | 0 | *aAttribute); |
4570 | 0 | return IPC_OK(); |
4571 | 0 | } |
4572 | | |
4573 | | PFileDescriptorSetParent* |
4574 | | ContentParent::SendPFileDescriptorSetConstructor(const FileDescriptor& aFD) |
4575 | 0 | { |
4576 | 0 | return PContentParent::SendPFileDescriptorSetConstructor(aFD); |
4577 | 0 | } |
4578 | | |
4579 | | PFileDescriptorSetParent* |
4580 | | ContentParent::AllocPFileDescriptorSetParent(const FileDescriptor& aFD) |
4581 | 0 | { |
4582 | 0 | return nsIContentParent::AllocPFileDescriptorSetParent(aFD); |
4583 | 0 | } |
4584 | | |
4585 | | bool |
4586 | | ContentParent::DeallocPFileDescriptorSetParent(PFileDescriptorSetParent* aActor) |
4587 | 0 | { |
4588 | 0 | return nsIContentParent::DeallocPFileDescriptorSetParent(aActor); |
4589 | 0 | } |
4590 | | |
4591 | | bool |
4592 | | ContentParent::IgnoreIPCPrincipal() |
4593 | 0 | { |
4594 | 0 | static bool sDidAddVarCache = false; |
4595 | 0 | static bool sIgnoreIPCPrincipal = false; |
4596 | 0 | if (!sDidAddVarCache) { |
4597 | 0 | sDidAddVarCache = true; |
4598 | 0 | Preferences::AddBoolVarCache(&sIgnoreIPCPrincipal, |
4599 | 0 | "dom.testing.ignore_ipc_principal", false); |
4600 | 0 | } |
4601 | 0 | return sIgnoreIPCPrincipal; |
4602 | 0 | } |
4603 | | |
4604 | | void |
4605 | | ContentParent::NotifyUpdatedDictionaries() |
4606 | 0 | { |
4607 | 0 | nsCOMPtr<nsISpellChecker> spellChecker(mozSpellChecker::Create()); |
4608 | 0 | MOZ_ASSERT(spellChecker, "No spell checker?"); |
4609 | 0 |
|
4610 | 0 | InfallibleTArray<nsString> dictionaries; |
4611 | 0 | spellChecker->GetDictionaryList(&dictionaries); |
4612 | 0 |
|
4613 | 0 | for (auto* cp : AllProcesses(eLive)) { |
4614 | 0 | Unused << cp->SendUpdateDictionaryList(dictionaries); |
4615 | 0 | } |
4616 | 0 | } |
4617 | | |
4618 | | void |
4619 | | ContentParent::NotifyUpdatedFonts() |
4620 | 0 | { |
4621 | 0 | InfallibleTArray<SystemFontListEntry> fontList; |
4622 | 0 | gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList); |
4623 | 0 |
|
4624 | 0 | for (auto* cp : AllProcesses(eLive)) { |
4625 | 0 | Unused << cp->SendUpdateFontList(fontList); |
4626 | 0 | } |
4627 | 0 | } |
4628 | | |
4629 | | /*static*/ void |
4630 | | ContentParent::UnregisterRemoteFrame(const TabId& aTabId, |
4631 | | const ContentParentId& aCpId, |
4632 | | bool aMarkedDestroying) |
4633 | 0 | { |
4634 | 0 | if (XRE_IsParentProcess()) { |
4635 | 0 | ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); |
4636 | 0 | ContentParent* cp = cpm->GetContentProcessById(aCpId); |
4637 | 0 |
|
4638 | 0 | if (!cp) { |
4639 | 0 | return; |
4640 | 0 | } |
4641 | 0 | |
4642 | 0 | cp->NotifyTabDestroyed(aTabId, aMarkedDestroying); |
4643 | 0 |
|
4644 | 0 | ContentProcessManager::GetSingleton()->UnregisterRemoteFrame(aCpId, aTabId); |
4645 | 0 | } else { |
4646 | 0 | ContentChild::GetSingleton()->SendUnregisterRemoteFrame(aTabId, aCpId, |
4647 | 0 | aMarkedDestroying); |
4648 | 0 | } |
4649 | 0 | } |
4650 | | |
4651 | | mozilla::ipc::IPCResult |
4652 | | ContentParent::RecvUnregisterRemoteFrame(const TabId& aTabId, |
4653 | | const ContentParentId& aCpId, |
4654 | | const bool& aMarkedDestroying) |
4655 | 0 | { |
4656 | 0 | UnregisterRemoteFrame(aTabId, aCpId, aMarkedDestroying); |
4657 | 0 | return IPC_OK(); |
4658 | 0 | } |
4659 | | |
4660 | | mozilla::ipc::IPCResult |
4661 | | ContentParent::RecvNotifyTabDestroying(const TabId& aTabId, |
4662 | | const ContentParentId& aCpId) |
4663 | 0 | { |
4664 | 0 | NotifyTabDestroying(aTabId, aCpId); |
4665 | 0 | return IPC_OK(); |
4666 | 0 | } |
4667 | | |
4668 | | nsTArray<TabContext> |
4669 | | ContentParent::GetManagedTabContext() |
4670 | 0 | { |
4671 | 0 | return ContentProcessManager::GetSingleton()-> |
4672 | 0 | GetTabContextByContentProcess(this->ChildID()); |
4673 | 0 | } |
4674 | | |
4675 | | mozilla::docshell::POfflineCacheUpdateParent* |
4676 | | ContentParent::AllocPOfflineCacheUpdateParent(const URIParams& aManifestURI, |
4677 | | const URIParams& aDocumentURI, |
4678 | | const PrincipalInfo& aLoadingPrincipalInfo, |
4679 | | const bool& aStickDocument) |
4680 | 0 | { |
4681 | 0 | RefPtr<mozilla::docshell::OfflineCacheUpdateParent> update = |
4682 | 0 | new mozilla::docshell::OfflineCacheUpdateParent(); |
4683 | 0 | // Use this reference as the IPDL reference. |
4684 | 0 | return update.forget().take(); |
4685 | 0 | } |
4686 | | |
4687 | | mozilla::ipc::IPCResult |
4688 | | ContentParent::RecvPOfflineCacheUpdateConstructor(POfflineCacheUpdateParent* aActor, |
4689 | | const URIParams& aManifestURI, |
4690 | | const URIParams& aDocumentURI, |
4691 | | const PrincipalInfo& aLoadingPrincipal, |
4692 | | const bool& aStickDocument) |
4693 | 0 | { |
4694 | 0 | MOZ_ASSERT(aActor); |
4695 | 0 |
|
4696 | 0 | RefPtr<mozilla::docshell::OfflineCacheUpdateParent> update = |
4697 | 0 | static_cast<mozilla::docshell::OfflineCacheUpdateParent*>(aActor); |
4698 | 0 |
|
4699 | 0 | nsresult rv = update->Schedule(aManifestURI, aDocumentURI, aLoadingPrincipal, aStickDocument); |
4700 | 0 | if (NS_FAILED(rv) && IsAlive()) { |
4701 | 0 | // Inform the child of failure. |
4702 | 0 | Unused << update->SendFinish(false, false); |
4703 | 0 | } |
4704 | 0 |
|
4705 | 0 | return IPC_OK(); |
4706 | 0 | } |
4707 | | |
4708 | | bool |
4709 | | ContentParent::DeallocPOfflineCacheUpdateParent(POfflineCacheUpdateParent* aActor) |
4710 | 0 | { |
4711 | 0 | // Reclaim the IPDL reference. |
4712 | 0 | RefPtr<mozilla::docshell::OfflineCacheUpdateParent> update = |
4713 | 0 | dont_AddRef(static_cast<mozilla::docshell::OfflineCacheUpdateParent*>(aActor)); |
4714 | 0 | return true; |
4715 | 0 | } |
4716 | | |
4717 | | PWebrtcGlobalParent * |
4718 | | ContentParent::AllocPWebrtcGlobalParent() |
4719 | 0 | { |
4720 | 0 | #ifdef MOZ_WEBRTC |
4721 | 0 | return WebrtcGlobalParent::Alloc(); |
4722 | | #else |
4723 | | return nullptr; |
4724 | | #endif |
4725 | | } |
4726 | | |
4727 | | bool |
4728 | | ContentParent::DeallocPWebrtcGlobalParent(PWebrtcGlobalParent *aActor) |
4729 | 0 | { |
4730 | 0 | #ifdef MOZ_WEBRTC |
4731 | 0 | WebrtcGlobalParent::Dealloc(static_cast<WebrtcGlobalParent*>(aActor)); |
4732 | 0 | return true; |
4733 | | #else |
4734 | | return false; |
4735 | | #endif |
4736 | | } |
4737 | | |
4738 | | mozilla::ipc::IPCResult |
4739 | | ContentParent::RecvSetOfflinePermission(const Principal& aPrincipal) |
4740 | 0 | { |
4741 | 0 | nsIPrincipal* principal = aPrincipal; |
4742 | 0 | nsContentUtils::MaybeAllowOfflineAppByDefault(principal); |
4743 | 0 | return IPC_OK(); |
4744 | 0 | } |
4745 | | |
4746 | | void |
4747 | | ContentParent::MaybeInvokeDragSession(TabParent* aParent) |
4748 | 0 | { |
4749 | 0 | // dnd uses IPCBlob to transfer data to the content process and the IPC |
4750 | 0 | // message is sent as normal priority. When sending input events with input |
4751 | 0 | // priority, the message may be preempted by the later dnd events. To make |
4752 | 0 | // sure the input events and the blob message are processed in time order |
4753 | 0 | // on the content process, we temporarily send the input events with normal |
4754 | 0 | // priority when there is an active dnd session. |
4755 | 0 | SetInputPriorityEventEnabled(false); |
4756 | 0 |
|
4757 | 0 | nsCOMPtr<nsIDragService> dragService = |
4758 | 0 | do_GetService("@mozilla.org/widget/dragservice;1"); |
4759 | 0 | if (dragService && dragService->MaybeAddChildProcess(this)) { |
4760 | 0 | // We need to send transferable data to child process. |
4761 | 0 | nsCOMPtr<nsIDragSession> session; |
4762 | 0 | dragService->GetCurrentSession(getter_AddRefs(session)); |
4763 | 0 | if (session) { |
4764 | 0 | nsTArray<IPCDataTransfer> dataTransfers; |
4765 | 0 | RefPtr<DataTransfer> transfer = session->GetDataTransfer(); |
4766 | 0 | if (!transfer) { |
4767 | 0 | // Pass eDrop to get DataTransfer with external |
4768 | 0 | // drag formats cached. |
4769 | 0 | transfer = new DataTransfer(nullptr, eDrop, true, -1); |
4770 | 0 | session->SetDataTransfer(transfer); |
4771 | 0 | } |
4772 | 0 | // Note, even though this fills the DataTransfer object with |
4773 | 0 | // external data, the data is usually transfered over IPC lazily when |
4774 | 0 | // needed. |
4775 | 0 | transfer->FillAllExternalData(); |
4776 | 0 | nsCOMPtr<nsILoadContext> lc = aParent ? |
4777 | 0 | aParent->GetLoadContext() : nullptr; |
4778 | 0 | nsCOMPtr<nsIArray> transferables = |
4779 | 0 | transfer->GetTransferables(lc); |
4780 | 0 | nsContentUtils::TransferablesToIPCTransferables(transferables, |
4781 | 0 | dataTransfers, |
4782 | 0 | false, |
4783 | 0 | nullptr, |
4784 | 0 | this); |
4785 | 0 | uint32_t action; |
4786 | 0 | session->GetDragAction(&action); |
4787 | 0 | mozilla::Unused << SendInvokeDragSession(dataTransfers, action); |
4788 | 0 | } |
4789 | 0 | } |
4790 | 0 | } |
4791 | | |
4792 | | mozilla::ipc::IPCResult |
4793 | | ContentParent::RecvUpdateDropEffect(const uint32_t& aDragAction, |
4794 | | const uint32_t& aDropEffect) |
4795 | 0 | { |
4796 | 0 | nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession(); |
4797 | 0 | if (dragSession) { |
4798 | 0 | dragSession->SetDragAction(aDragAction); |
4799 | 0 | RefPtr<DataTransfer> dt = dragSession->GetDataTransfer(); |
4800 | 0 | if (dt) { |
4801 | 0 | dt->SetDropEffectInt(aDropEffect); |
4802 | 0 | } |
4803 | 0 | dragSession->UpdateDragEffect(); |
4804 | 0 | } |
4805 | 0 | return IPC_OK(); |
4806 | 0 | } |
4807 | | |
4808 | | PContentPermissionRequestParent* |
4809 | | ContentParent::AllocPContentPermissionRequestParent(const InfallibleTArray<PermissionRequest>& aRequests, |
4810 | | const IPC::Principal& aPrincipal, |
4811 | | const bool& aIsHandlingUserInput, |
4812 | | const TabId& aTabId) |
4813 | 0 | { |
4814 | 0 | ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); |
4815 | 0 | RefPtr<TabParent> tp = |
4816 | 0 | cpm->GetTopLevelTabParentByProcessAndTabId(this->ChildID(), aTabId); |
4817 | 0 | if (!tp) { |
4818 | 0 | return nullptr; |
4819 | 0 | } |
4820 | 0 | |
4821 | 0 | return nsContentPermissionUtils::CreateContentPermissionRequestParent(aRequests, |
4822 | 0 | tp->GetOwnerElement(), |
4823 | 0 | aPrincipal, |
4824 | 0 | aIsHandlingUserInput, |
4825 | 0 | aTabId); |
4826 | 0 | } |
4827 | | |
4828 | | bool |
4829 | | ContentParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor) |
4830 | 0 | { |
4831 | 0 | nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent(actor); |
4832 | 0 | delete actor; |
4833 | 0 | return true; |
4834 | 0 | } |
4835 | | |
4836 | | PWebBrowserPersistDocumentParent* |
4837 | | ContentParent::AllocPWebBrowserPersistDocumentParent(PBrowserParent* aBrowser, |
4838 | | const uint64_t& aOuterWindowID) |
4839 | 0 | { |
4840 | 0 | return new WebBrowserPersistDocumentParent(); |
4841 | 0 | } |
4842 | | |
4843 | | bool |
4844 | | ContentParent::DeallocPWebBrowserPersistDocumentParent(PWebBrowserPersistDocumentParent* aActor) |
4845 | 0 | { |
4846 | 0 | delete aActor; |
4847 | 0 | return true; |
4848 | 0 | } |
4849 | | |
4850 | | mozilla::ipc::IPCResult |
4851 | | ContentParent::CommonCreateWindow(PBrowserParent* aThisTab, |
4852 | | bool aSetOpener, |
4853 | | const uint32_t& aChromeFlags, |
4854 | | const bool& aCalledFromJS, |
4855 | | const bool& aPositionSpecified, |
4856 | | const bool& aSizeSpecified, |
4857 | | nsIURI* aURIToLoad, |
4858 | | const nsCString& aFeatures, |
4859 | | const nsCString& aBaseURI, |
4860 | | const float& aFullZoom, |
4861 | | uint64_t aNextTabParentId, |
4862 | | const nsString& aName, |
4863 | | nsresult& aResult, |
4864 | | nsCOMPtr<nsITabParent>& aNewTabParent, |
4865 | | bool* aWindowIsNew, |
4866 | | int32_t& aOpenLocation, |
4867 | | nsIPrincipal* aTriggeringPrincipal, |
4868 | | uint32_t aReferrerPolicy, |
4869 | | bool aLoadURI) |
4870 | | |
4871 | 0 | { |
4872 | 0 | // The content process should never be in charge of computing whether or |
4873 | 0 | // not a window should be private or remote - the parent will do that. |
4874 | 0 | const uint32_t badFlags = nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW | |
4875 | 0 | nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW | |
4876 | 0 | nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME | |
4877 | 0 | nsIWebBrowserChrome::CHROME_REMOTE_WINDOW; |
4878 | 0 | if (!!(aChromeFlags & badFlags)) { |
4879 | 0 | return IPC_FAIL(this, "Forbidden aChromeFlags passed"); |
4880 | 0 | } |
4881 | 0 |
|
4882 | 0 | TabParent* thisTabParent = TabParent::GetFrom(aThisTab); |
4883 | 0 | nsCOMPtr<nsIContent> frame; |
4884 | 0 | if (thisTabParent) { |
4885 | 0 | frame = do_QueryInterface(thisTabParent->GetOwnerElement()); |
4886 | 0 |
|
4887 | 0 | if (NS_WARN_IF(thisTabParent->IsMozBrowser())) { |
4888 | 0 | return IPC_FAIL(this, "aThisTab is not a MozBrowser"); |
4889 | 0 | } |
4890 | 0 | } |
4891 | 0 |
|
4892 | 0 | nsCOMPtr<nsPIDOMWindowOuter> outerWin; |
4893 | 0 | if (frame) { |
4894 | 0 | outerWin = frame->OwnerDoc()->GetWindow(); |
4895 | 0 |
|
4896 | 0 | // If our chrome window is in the process of closing, don't try to open a |
4897 | 0 | // new tab in it. |
4898 | 0 | if (outerWin && outerWin->Closed()) { |
4899 | 0 | outerWin = nullptr; |
4900 | 0 | } |
4901 | 0 | } |
4902 | 0 |
|
4903 | 0 | nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin; |
4904 | 0 | if (thisTabParent) { |
4905 | 0 | browserDOMWin = thisTabParent->GetBrowserDOMWindow(); |
4906 | 0 | } |
4907 | 0 |
|
4908 | 0 | // If we haven't found a chrome window to open in, just use the most recently |
4909 | 0 | // opened one. |
4910 | 0 | if (!outerWin) { |
4911 | 0 | outerWin = nsContentUtils::GetMostRecentNonPBWindow(); |
4912 | 0 | if (NS_WARN_IF(!outerWin)) { |
4913 | 0 | aResult = NS_ERROR_FAILURE; |
4914 | 0 | return IPC_OK(); |
4915 | 0 | } |
4916 | 0 |
|
4917 | 0 | nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(outerWin); |
4918 | 0 | if (rootChromeWin) { |
4919 | 0 | rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin)); |
4920 | 0 | } |
4921 | 0 | } |
4922 | 0 |
|
4923 | 0 | aOpenLocation = nsWindowWatcher::GetWindowOpenLocation( |
4924 | 0 | outerWin, aChromeFlags, aCalledFromJS, aPositionSpecified, aSizeSpecified); |
4925 | 0 |
|
4926 | 0 | MOZ_ASSERT(aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB || |
4927 | 0 | aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW); |
4928 | 0 |
|
4929 | 0 | // Read the origin attributes for the tab from the opener tabParent. |
4930 | 0 | OriginAttributes openerOriginAttributes; |
4931 | 0 | if (thisTabParent) { |
4932 | 0 | nsCOMPtr<nsILoadContext> loadContext = thisTabParent->GetLoadContext(); |
4933 | 0 | loadContext->GetOriginAttributes(openerOriginAttributes); |
4934 | 0 | } else if (Preferences::GetBool("browser.privatebrowsing.autostart")) { |
4935 | 0 | openerOriginAttributes.mPrivateBrowsingId = 1; |
4936 | 0 | } |
4937 | 0 |
|
4938 | 0 | if (aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB) { |
4939 | 0 | if (NS_WARN_IF(!browserDOMWin)) { |
4940 | 0 | aResult = NS_ERROR_ABORT; |
4941 | 0 | return IPC_OK(); |
4942 | 0 | } |
4943 | 0 |
|
4944 | 0 | nsCOMPtr<nsIFrameLoaderOwner> opener = do_QueryInterface(frame); |
4945 | 0 |
|
4946 | 0 | nsCOMPtr<nsIOpenURIInFrameParams> params = |
4947 | 0 | new nsOpenURIInFrameParams(openerOriginAttributes, opener); |
4948 | 0 | params->SetReferrer(NS_ConvertUTF8toUTF16(aBaseURI)); |
4949 | 0 | MOZ_ASSERT(aTriggeringPrincipal, "need a valid triggeringPrincipal"); |
4950 | 0 | params->SetTriggeringPrincipal(aTriggeringPrincipal); |
4951 | 0 | params->SetReferrerPolicy(aReferrerPolicy); |
4952 | 0 |
|
4953 | 0 | nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner; |
4954 | 0 | if (aLoadURI) { |
4955 | 0 | aResult = browserDOMWin->OpenURIInFrame(aURIToLoad, |
4956 | 0 | params, aOpenLocation, |
4957 | 0 | nsIBrowserDOMWindow::OPEN_NEW, |
4958 | 0 | aNextTabParentId, aName, |
4959 | 0 | getter_AddRefs(frameLoaderOwner)); |
4960 | 0 | } else { |
4961 | 0 | aResult = browserDOMWin->CreateContentWindowInFrame(aURIToLoad, |
4962 | 0 | params, aOpenLocation, |
4963 | 0 | nsIBrowserDOMWindow::OPEN_NEW, |
4964 | 0 | aNextTabParentId, aName, |
4965 | 0 | getter_AddRefs(frameLoaderOwner)); |
4966 | 0 | } |
4967 | 0 | if (NS_SUCCEEDED(aResult) && frameLoaderOwner) { |
4968 | 0 | RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader(); |
4969 | 0 | if (frameLoader) { |
4970 | 0 | aNewTabParent = frameLoader->GetTabParent(); |
4971 | 0 | // At this point, it's possible the inserted frameloader hasn't gone through |
4972 | 0 | // layout yet. To ensure that the dimensions that we send down when telling the |
4973 | 0 | // frameloader to display will be correct (instead of falling back to a 10x10 |
4974 | 0 | // default), we force layout if necessary to get the most up-to-date dimensions. |
4975 | 0 | // See bug 1358712 for details. |
4976 | 0 | frameLoader->ForceLayoutIfNecessary(); |
4977 | 0 | } |
4978 | 0 | } else if (NS_SUCCEEDED(aResult) && !frameLoaderOwner) { |
4979 | 0 | // Fall through to the normal window opening code path when there is no |
4980 | 0 | // window which we can open a new tab in. |
4981 | 0 | aOpenLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW; |
4982 | 0 | } else { |
4983 | 0 | *aWindowIsNew = false; |
4984 | 0 | } |
4985 | 0 |
|
4986 | 0 | // If we didn't retarget our window open into a new window, we should return now. |
4987 | 0 | if (aOpenLocation != nsIBrowserDOMWindow::OPEN_NEWWINDOW) { |
4988 | 0 | return IPC_OK(); |
4989 | 0 | } |
4990 | 0 | } |
4991 | 0 |
|
4992 | 0 | nsCOMPtr<nsPIWindowWatcher> pwwatch = |
4993 | 0 | do_GetService(NS_WINDOWWATCHER_CONTRACTID, &aResult); |
4994 | 0 | if (NS_WARN_IF(NS_FAILED(aResult))) { |
4995 | 0 | return IPC_OK(); |
4996 | 0 | } |
4997 | 0 |
|
4998 | 0 | aResult = pwwatch->OpenWindowWithTabParent(thisTabParent, |
4999 | 0 | aFeatures, aCalledFromJS, aFullZoom, |
5000 | 0 | aNextTabParentId, |
5001 | 0 | !aSetOpener, |
5002 | 0 | getter_AddRefs(aNewTabParent)); |
5003 | 0 | if (NS_WARN_IF(NS_FAILED(aResult))) { |
5004 | 0 | return IPC_OK(); |
5005 | 0 | } |
5006 | 0 |
|
5007 | 0 | MOZ_ASSERT(aNewTabParent); |
5008 | 0 |
|
5009 | 0 | // At this point, it's possible the inserted frameloader hasn't gone through |
5010 | 0 | // layout yet. To ensure that the dimensions that we send down when telling the |
5011 | 0 | // frameloader to display will be correct (instead of falling back to a 10x10 |
5012 | 0 | // default), we force layout if necessary to get the most up-to-date dimensions. |
5013 | 0 | // See bug 1358712 for details. |
5014 | 0 | // |
5015 | 0 | // This involves doing a bit of gymnastics in order to get at the FrameLoader, |
5016 | 0 | // so we scope this to avoid polluting the main function scope. |
5017 | 0 | { |
5018 | 0 | nsCOMPtr<Element> frameElement = |
5019 | 0 | TabParent::GetFrom(aNewTabParent)->GetOwnerElement(); |
5020 | 0 | MOZ_ASSERT(frameElement); |
5021 | 0 | nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner = do_QueryInterface(frameElement); |
5022 | 0 | MOZ_ASSERT(frameLoaderOwner); |
5023 | 0 | RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader(); |
5024 | 0 | MOZ_ASSERT(frameLoader); |
5025 | 0 | frameLoader->ForceLayoutIfNecessary(); |
5026 | 0 | } |
5027 | 0 |
|
5028 | 0 | // If we were passed a name for the window which would override the default, |
5029 | 0 | // we should send it down to the new tab. |
5030 | 0 | if (nsContentUtils::IsOverridingWindowName(aName)) { |
5031 | 0 | Unused << TabParent::GetFrom(aNewTabParent)->SendSetWindowName(aName); |
5032 | 0 | } |
5033 | 0 |
|
5034 | 0 | // Don't send down the OriginAttributes if the content process is handling |
5035 | 0 | // setting up the window for us. We only want to send them in the async case. |
5036 | 0 | // |
5037 | 0 | // If we send it down in the non-async case, then we might set the |
5038 | 0 | // OriginAttributes after the document has already navigated. |
5039 | 0 | if (!aSetOpener) { |
5040 | 0 | Unused << TabParent::GetFrom(aNewTabParent) |
5041 | 0 | ->SendSetOriginAttributes(openerOriginAttributes); |
5042 | 0 | } |
5043 | 0 |
|
5044 | 0 | if (aURIToLoad && aLoadURI) { |
5045 | 0 | nsCOMPtr<mozIDOMWindowProxy> openerWindow; |
5046 | 0 | if (aSetOpener && thisTabParent) { |
5047 | 0 | openerWindow = thisTabParent->GetParentWindowOuter(); |
5048 | 0 | } |
5049 | 0 | nsCOMPtr<nsIBrowserDOMWindow> newBrowserDOMWin = |
5050 | 0 | TabParent::GetFrom(aNewTabParent)->GetBrowserDOMWindow(); |
5051 | 0 | if (NS_WARN_IF(!newBrowserDOMWin)) { |
5052 | 0 | aResult = NS_ERROR_ABORT; |
5053 | 0 | return IPC_OK(); |
5054 | 0 | } |
5055 | 0 | nsCOMPtr<mozIDOMWindowProxy> win; |
5056 | 0 | aResult = newBrowserDOMWin->OpenURI(aURIToLoad, openerWindow, |
5057 | 0 | nsIBrowserDOMWindow::OPEN_CURRENTWINDOW, |
5058 | 0 | nsIBrowserDOMWindow::OPEN_NEW, |
5059 | 0 | aTriggeringPrincipal, |
5060 | 0 | getter_AddRefs(win)); |
5061 | 0 | } |
5062 | 0 |
|
5063 | 0 | return IPC_OK(); |
5064 | 0 | } |
5065 | | |
5066 | | mozilla::ipc::IPCResult |
5067 | | ContentParent::RecvCreateWindow(PBrowserParent* aThisTab, |
5068 | | PBrowserParent* aNewTab, |
5069 | | PRenderFrameParent* aRenderFrame, |
5070 | | const uint32_t& aChromeFlags, |
5071 | | const bool& aCalledFromJS, |
5072 | | const bool& aPositionSpecified, |
5073 | | const bool& aSizeSpecified, |
5074 | | const OptionalURIParams& aURIToLoad, |
5075 | | const nsCString& aFeatures, |
5076 | | const nsCString& aBaseURI, |
5077 | | const float& aFullZoom, |
5078 | | const IPC::Principal& aTriggeringPrincipal, |
5079 | | const uint32_t& aReferrerPolicy, |
5080 | | CreateWindowResolver&& aResolve) |
5081 | 0 | { |
5082 | 0 | nsresult rv = NS_OK; |
5083 | 0 | CreatedWindowInfo cwi; |
5084 | 0 |
|
5085 | 0 | // We always expect to open a new window here. If we don't, it's an error. |
5086 | 0 | cwi.windowOpened() = true; |
5087 | 0 | cwi.layersId() = LayersId{0}; |
5088 | 0 | cwi.maxTouchPoints() = 0; |
5089 | 0 | cwi.hasSiblings() = false; |
5090 | 0 |
|
5091 | 0 | // Make sure to resolve the resolver when this function exits, even if we |
5092 | 0 | // failed to generate a valid response. |
5093 | 0 | auto resolveOnExit = MakeScopeExit([&] { |
5094 | 0 | // Copy over the nsresult, and then resolve. |
5095 | 0 | cwi.rv() = rv; |
5096 | 0 | aResolve(cwi); |
5097 | 0 | }); |
5098 | 0 |
|
5099 | 0 | TabParent* newTab = TabParent::GetFrom(aNewTab); |
5100 | 0 | MOZ_ASSERT(newTab); |
5101 | 0 |
|
5102 | 0 | auto destroyNewTabOnError = MakeScopeExit([&] { |
5103 | 0 | // We always expect to open a new window here. If we don't, it's an error. |
5104 | 0 | if (!cwi.windowOpened() || NS_FAILED(rv)) { |
5105 | 0 | if (newTab) { |
5106 | 0 | newTab->Destroy(); |
5107 | 0 | } |
5108 | 0 | } |
5109 | 0 | }); |
5110 | 0 |
|
5111 | 0 | // Content has requested that we open this new content window, so |
5112 | 0 | // we must have an opener. |
5113 | 0 | newTab->SetHasContentOpener(true); |
5114 | 0 |
|
5115 | 0 | TabParent::AutoUseNewTab aunt(newTab, &cwi.urlToLoad()); |
5116 | 0 | const uint64_t nextTabParentId = ++sNextTabParentId; |
5117 | 0 | sNextTabParents.Put(nextTabParentId, newTab); |
5118 | 0 |
|
5119 | 0 | const nsCOMPtr<nsIURI> uriToLoad = DeserializeURI(aURIToLoad); |
5120 | 0 |
|
5121 | 0 | nsCOMPtr<nsITabParent> newRemoteTab; |
5122 | 0 | int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW; |
5123 | 0 | mozilla::ipc::IPCResult ipcResult = |
5124 | 0 | CommonCreateWindow(aThisTab, /* aSetOpener = */ true, aChromeFlags, |
5125 | 0 | aCalledFromJS, aPositionSpecified, aSizeSpecified, |
5126 | 0 | uriToLoad, aFeatures, aBaseURI, aFullZoom, |
5127 | 0 | nextTabParentId, VoidString(), rv, |
5128 | 0 | newRemoteTab, &cwi.windowOpened(), openLocation, |
5129 | 0 | aTriggeringPrincipal, aReferrerPolicy, |
5130 | 0 | /* aLoadUri = */ false); |
5131 | 0 | if (!ipcResult) { |
5132 | 0 | return ipcResult; |
5133 | 0 | } |
5134 | 0 | |
5135 | 0 | if (NS_WARN_IF(NS_FAILED(rv)) || !newRemoteTab) { |
5136 | 0 | return IPC_OK(); |
5137 | 0 | } |
5138 | 0 |
|
5139 | 0 | if (sNextTabParents.GetAndRemove(nextTabParentId).valueOr(nullptr)) { |
5140 | 0 | cwi.windowOpened() = false; |
5141 | 0 | } |
5142 | 0 | MOZ_ASSERT(TabParent::GetFrom(newRemoteTab) == newTab); |
5143 | 0 |
|
5144 | 0 | newTab->SwapFrameScriptsFrom(cwi.frameScripts()); |
5145 | 0 |
|
5146 | 0 | RenderFrameParent* rfp = static_cast<RenderFrameParent*>(aRenderFrame); |
5147 | 0 | if (!newTab->SetRenderFrame(rfp) || |
5148 | 0 | !newTab->GetRenderFrameInfo(&cwi.textureFactoryIdentifier(), &cwi.layersId())) { |
5149 | 0 | rv = NS_ERROR_FAILURE; |
5150 | 0 | } |
5151 | 0 | cwi.compositorOptions() = rfp->GetCompositorOptions(); |
5152 | 0 |
|
5153 | 0 | nsCOMPtr<nsIWidget> widget = newTab->GetWidget(); |
5154 | 0 | if (widget) { |
5155 | 0 | cwi.maxTouchPoints() = widget->GetMaxTouchPoints(); |
5156 | 0 | cwi.dimensions() = newTab->GetDimensionInfo(); |
5157 | 0 | } |
5158 | 0 |
|
5159 | 0 | cwi.hasSiblings() = (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB); |
5160 | 0 |
|
5161 | 0 | return IPC_OK(); |
5162 | 0 | } |
5163 | | |
5164 | | mozilla::ipc::IPCResult |
5165 | | ContentParent::RecvCreateWindowInDifferentProcess( |
5166 | | PBrowserParent* aThisTab, |
5167 | | const uint32_t& aChromeFlags, |
5168 | | const bool& aCalledFromJS, |
5169 | | const bool& aPositionSpecified, |
5170 | | const bool& aSizeSpecified, |
5171 | | const OptionalURIParams& aURIToLoad, |
5172 | | const nsCString& aFeatures, |
5173 | | const nsCString& aBaseURI, |
5174 | | const float& aFullZoom, |
5175 | | const nsString& aName, |
5176 | | const IPC::Principal& aTriggeringPrincipal, |
5177 | | const uint32_t& aReferrerPolicy) |
5178 | 0 | { |
5179 | 0 | nsCOMPtr<nsITabParent> newRemoteTab; |
5180 | 0 | bool windowIsNew; |
5181 | 0 | nsCOMPtr<nsIURI> uriToLoad = DeserializeURI(aURIToLoad); |
5182 | 0 | int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW; |
5183 | 0 | nsresult rv; |
5184 | 0 | mozilla::ipc::IPCResult ipcResult = |
5185 | 0 | CommonCreateWindow(aThisTab, /* aSetOpener = */ false, aChromeFlags, |
5186 | 0 | aCalledFromJS, aPositionSpecified, aSizeSpecified, |
5187 | 0 | uriToLoad, aFeatures, aBaseURI, aFullZoom, |
5188 | 0 | /* aNextTabParentId = */ 0, aName, rv, |
5189 | 0 | newRemoteTab, &windowIsNew, openLocation, |
5190 | 0 | aTriggeringPrincipal, aReferrerPolicy, |
5191 | 0 | /* aLoadUri = */ true); |
5192 | 0 | if (!ipcResult) { |
5193 | 0 | return ipcResult; |
5194 | 0 | } |
5195 | 0 | |
5196 | 0 | if (NS_FAILED(rv)) { |
5197 | 0 | NS_WARNING("Call to CommonCreateWindow failed."); |
5198 | 0 | } |
5199 | 0 |
|
5200 | 0 | return IPC_OK(); |
5201 | 0 | } |
5202 | | |
5203 | | mozilla::ipc::IPCResult |
5204 | | ContentParent::RecvShutdownProfile(const nsCString& aProfile) |
5205 | 0 | { |
5206 | 0 | #ifdef MOZ_GECKO_PROFILER |
5207 | 0 | nsCOMPtr<nsIProfiler> profiler(do_GetService("@mozilla.org/tools/profiler;1")); |
5208 | 0 | profiler->ReceiveShutdownProfile(aProfile); |
5209 | 0 | #endif |
5210 | 0 | return IPC_OK(); |
5211 | 0 | } |
5212 | | |
5213 | | mozilla::ipc::IPCResult |
5214 | | ContentParent::RecvGetGraphicsDeviceInitData(ContentDeviceData* aOut) |
5215 | 0 | { |
5216 | 0 | gfxPlatform::GetPlatform()->BuildContentDeviceData(aOut); |
5217 | 0 | return IPC_OK(); |
5218 | 0 | } |
5219 | | |
5220 | | mozilla::ipc::IPCResult |
5221 | | ContentParent::RecvGraphicsError(const nsCString& aError) |
5222 | 0 | { |
5223 | 0 | gfx::LogForwarder* lf = gfx::Factory::GetLogForwarder(); |
5224 | 0 | if (lf) { |
5225 | 0 | std::stringstream message; |
5226 | 0 | message << "CP+" << aError.get(); |
5227 | 0 | lf->UpdateStringsVector(message.str()); |
5228 | 0 | } |
5229 | 0 | return IPC_OK(); |
5230 | 0 | } |
5231 | | |
5232 | | mozilla::ipc::IPCResult |
5233 | | ContentParent::RecvBeginDriverCrashGuard(const uint32_t& aGuardType, bool* aOutCrashed) |
5234 | 0 | { |
5235 | 0 | // Only one driver crash guard should be active at a time, per-process. |
5236 | 0 | MOZ_ASSERT(!mDriverCrashGuard); |
5237 | 0 |
|
5238 | 0 | UniquePtr<gfx::DriverCrashGuard> guard; |
5239 | 0 | switch (gfx::CrashGuardType(aGuardType)) { |
5240 | 0 | case gfx::CrashGuardType::D3D11Layers: |
5241 | 0 | guard = MakeUnique<gfx::D3D11LayersCrashGuard>(this); |
5242 | 0 | break; |
5243 | 0 | case gfx::CrashGuardType::D3D9Video: |
5244 | 0 | guard = MakeUnique<gfx::D3D9VideoCrashGuard>(this); |
5245 | 0 | break; |
5246 | 0 | case gfx::CrashGuardType::GLContext: |
5247 | 0 | guard = MakeUnique<gfx::GLContextCrashGuard>(this); |
5248 | 0 | break; |
5249 | 0 | case gfx::CrashGuardType::D3D11Video: |
5250 | 0 | guard = MakeUnique<gfx::D3D11VideoCrashGuard>(this); |
5251 | 0 | break; |
5252 | 0 | default: |
5253 | 0 | MOZ_ASSERT_UNREACHABLE("unknown crash guard type"); |
5254 | 0 | return IPC_FAIL_NO_REASON(this); |
5255 | 0 | } |
5256 | 0 | |
5257 | 0 | if (guard->Crashed()) { |
5258 | 0 | *aOutCrashed = true; |
5259 | 0 | return IPC_OK(); |
5260 | 0 | } |
5261 | 0 |
|
5262 | 0 | *aOutCrashed = false; |
5263 | 0 | mDriverCrashGuard = std::move(guard); |
5264 | 0 | return IPC_OK(); |
5265 | 0 | } |
5266 | | |
5267 | | mozilla::ipc::IPCResult |
5268 | | ContentParent::RecvEndDriverCrashGuard(const uint32_t& aGuardType) |
5269 | 0 | { |
5270 | 0 | mDriverCrashGuard = nullptr; |
5271 | 0 | return IPC_OK(); |
5272 | 0 | } |
5273 | | |
5274 | | mozilla::ipc::IPCResult |
5275 | | ContentParent::RecvGetAndroidSystemInfo(AndroidSystemInfo* aInfo) |
5276 | 0 | { |
5277 | | #ifdef MOZ_WIDGET_ANDROID |
5278 | | nsSystemInfo::GetAndroidSystemInfo(aInfo); |
5279 | | return IPC_OK(); |
5280 | | #else |
5281 | 0 | MOZ_CRASH("wrong platform!"); |
5282 | 0 | return IPC_FAIL_NO_REASON(this); |
5283 | 0 | #endif |
5284 | 0 | } |
5285 | | |
5286 | | mozilla::ipc::IPCResult |
5287 | | ContentParent::RecvNotifyBenchmarkResult(const nsString& aCodecName, |
5288 | | const uint32_t& aDecodeFPS) |
5289 | | |
5290 | 0 | { |
5291 | 0 | if (aCodecName.EqualsLiteral("VP9")) { |
5292 | 0 | Preferences::SetUint(VP9Benchmark::sBenchmarkFpsPref, aDecodeFPS); |
5293 | 0 | Preferences::SetUint(VP9Benchmark::sBenchmarkFpsVersionCheck, |
5294 | 0 | VP9Benchmark::sBenchmarkVersionID); |
5295 | 0 | } |
5296 | 0 | return IPC_OK(); |
5297 | 0 | } |
5298 | | |
5299 | | mozilla::ipc::IPCResult |
5300 | | ContentParent::RecvNotifyPushObservers(const nsCString& aScope, |
5301 | | const IPC::Principal& aPrincipal, |
5302 | | const nsString& aMessageId) |
5303 | 0 | { |
5304 | 0 | PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Nothing()); |
5305 | 0 | Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers())); |
5306 | 0 | return IPC_OK(); |
5307 | 0 | } |
5308 | | |
5309 | | mozilla::ipc::IPCResult |
5310 | | ContentParent::RecvNotifyPushObserversWithData(const nsCString& aScope, |
5311 | | const IPC::Principal& aPrincipal, |
5312 | | const nsString& aMessageId, |
5313 | | InfallibleTArray<uint8_t>&& aData) |
5314 | 0 | { |
5315 | 0 | PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Some(aData)); |
5316 | 0 | Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers())); |
5317 | 0 | return IPC_OK(); |
5318 | 0 | } |
5319 | | |
5320 | | mozilla::ipc::IPCResult |
5321 | | ContentParent::RecvNotifyPushSubscriptionChangeObservers(const nsCString& aScope, |
5322 | | const IPC::Principal& aPrincipal) |
5323 | 0 | { |
5324 | 0 | PushSubscriptionChangeDispatcher dispatcher(aScope, aPrincipal); |
5325 | 0 | Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers())); |
5326 | 0 | return IPC_OK(); |
5327 | 0 | } |
5328 | | |
5329 | | mozilla::ipc::IPCResult |
5330 | | ContentParent::RecvNotifyPushSubscriptionModifiedObservers(const nsCString& aScope, |
5331 | | const IPC::Principal& aPrincipal) |
5332 | 0 | { |
5333 | 0 | PushSubscriptionModifiedDispatcher dispatcher(aScope, aPrincipal); |
5334 | 0 | Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers())); |
5335 | 0 | return IPC_OK(); |
5336 | 0 | } |
5337 | | |
5338 | | /* static */ void |
5339 | | ContentParent::BroadcastBlobURLRegistration(const nsACString& aURI, |
5340 | | BlobImpl* aBlobImpl, |
5341 | | nsIPrincipal* aPrincipal, |
5342 | | ContentParent* aIgnoreThisCP) |
5343 | 0 | { |
5344 | 0 | nsCString uri(aURI); |
5345 | 0 | IPC::Principal principal(aPrincipal); |
5346 | 0 |
|
5347 | 0 | for (auto* cp : AllProcesses(eLive)) { |
5348 | 0 | if (cp != aIgnoreThisCP) { |
5349 | 0 | nsresult rv = cp->TransmitPermissionsForPrincipal(principal); |
5350 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
5351 | 0 | break; |
5352 | 0 | } |
5353 | 0 | |
5354 | 0 | IPCBlob ipcBlob; |
5355 | 0 | rv = IPCBlobUtils::Serialize(aBlobImpl, cp, ipcBlob); |
5356 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
5357 | 0 | break; |
5358 | 0 | } |
5359 | 0 | |
5360 | 0 | Unused << cp->SendBlobURLRegistration(uri, ipcBlob, principal); |
5361 | 0 | } |
5362 | 0 | } |
5363 | 0 | } |
5364 | | |
5365 | | /* static */ void |
5366 | | ContentParent::BroadcastBlobURLUnregistration(const nsACString& aURI, |
5367 | | ContentParent* aIgnoreThisCP) |
5368 | 0 | { |
5369 | 0 | nsCString uri(aURI); |
5370 | 0 |
|
5371 | 0 | for (auto* cp : AllProcesses(eLive)) { |
5372 | 0 | if (cp != aIgnoreThisCP) { |
5373 | 0 | Unused << cp->SendBlobURLUnregistration(uri); |
5374 | 0 | } |
5375 | 0 | } |
5376 | 0 | } |
5377 | | |
5378 | | mozilla::ipc::IPCResult |
5379 | | ContentParent::RecvStoreAndBroadcastBlobURLRegistration(const nsCString& aURI, |
5380 | | const IPCBlob& aBlob, |
5381 | | const Principal& aPrincipal) |
5382 | 0 | { |
5383 | 0 | RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(aBlob); |
5384 | 0 | if (NS_WARN_IF(!blobImpl)) { |
5385 | 0 | return IPC_FAIL_NO_REASON(this); |
5386 | 0 | } |
5387 | 0 |
|
5388 | 0 | if (NS_SUCCEEDED(BlobURLProtocolHandler::AddDataEntry(aURI, aPrincipal, |
5389 | 0 | blobImpl))) { |
5390 | 0 | BroadcastBlobURLRegistration(aURI, blobImpl, aPrincipal, this); |
5391 | 0 |
|
5392 | 0 | // We want to store this blobURL, so we can unregister it if the child |
5393 | 0 | // crashes. |
5394 | 0 | mBlobURLs.AppendElement(aURI); |
5395 | 0 | } |
5396 | 0 |
|
5397 | 0 | BroadcastBlobURLRegistration(aURI, blobImpl, aPrincipal, this); |
5398 | 0 | return IPC_OK(); |
5399 | 0 | } |
5400 | | |
5401 | | mozilla::ipc::IPCResult |
5402 | | ContentParent::RecvUnstoreAndBroadcastBlobURLUnregistration(const nsCString& aURI) |
5403 | 0 | { |
5404 | 0 | BlobURLProtocolHandler::RemoveDataEntry(aURI, false /* Don't broadcast */); |
5405 | 0 | BroadcastBlobURLUnregistration(aURI, this); |
5406 | 0 | mBlobURLs.RemoveElement(aURI); |
5407 | 0 |
|
5408 | 0 | return IPC_OK(); |
5409 | 0 | } |
5410 | | |
5411 | | mozilla::ipc::IPCResult |
5412 | | ContentParent::RecvGetA11yContentId(uint32_t* aContentId) |
5413 | 0 | { |
5414 | | #if defined(XP_WIN32) && defined(ACCESSIBILITY) |
5415 | | *aContentId = a11y::AccessibleWrap::GetContentProcessIdFor(ChildID()); |
5416 | | MOZ_ASSERT(*aContentId); |
5417 | | return IPC_OK(); |
5418 | | #else |
5419 | 0 | return IPC_FAIL_NO_REASON(this); |
5420 | 0 | #endif |
5421 | 0 | } |
5422 | | |
5423 | | mozilla::ipc::IPCResult |
5424 | | ContentParent::RecvA11yHandlerControl(const uint32_t& aPid, |
5425 | | const IHandlerControlHolder& aHandlerControl) |
5426 | 0 | { |
5427 | | #if defined(XP_WIN32) && defined(ACCESSIBILITY) |
5428 | | MOZ_ASSERT(!aHandlerControl.IsNull()); |
5429 | | RefPtr<IHandlerControl> proxy(aHandlerControl.Get()); |
5430 | | a11y::AccessibleWrap::SetHandlerControl(aPid, std::move(proxy)); |
5431 | | return IPC_OK(); |
5432 | | #else |
5433 | 0 | return IPC_FAIL_NO_REASON(this); |
5434 | 0 | #endif |
5435 | 0 | } |
5436 | | |
5437 | | } // namespace dom |
5438 | | } // namespace mozilla |
5439 | | |
5440 | | NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver) |
5441 | | |
5442 | | NS_IMETHODIMP |
5443 | | ParentIdleListener::Observe(nsISupports*, const char* aTopic, const char16_t* aData) |
5444 | 0 | { |
5445 | 0 | mozilla::Unused << mParent->SendNotifyIdleObserver(mObserver, |
5446 | 0 | nsDependentCString(aTopic), |
5447 | 0 | nsDependentString(aData)); |
5448 | 0 | return NS_OK; |
5449 | 0 | } |
5450 | | |
5451 | | bool |
5452 | | ContentParent::HandleWindowsMessages(const Message& aMsg) const |
5453 | 0 | { |
5454 | 0 | MOZ_ASSERT(aMsg.is_sync()); |
5455 | 0 |
|
5456 | 0 | // a11y messages can be triggered by windows messages, which means if we |
5457 | 0 | // allow handling windows messages while we wait for the response to a sync |
5458 | 0 | // a11y message we can reenter the ipc message sending code. |
5459 | 0 | if (a11y::PDocAccessible::PDocAccessibleStart < aMsg.type() && |
5460 | 0 | a11y::PDocAccessible::PDocAccessibleEnd > aMsg.type()) { |
5461 | 0 | return false; |
5462 | 0 | } |
5463 | 0 | |
5464 | 0 | return true; |
5465 | 0 | } |
5466 | | |
5467 | | mozilla::ipc::IPCResult |
5468 | | ContentParent::RecvGetFilesRequest(const nsID& aUUID, |
5469 | | const nsString& aDirectoryPath, |
5470 | | const bool& aRecursiveFlag) |
5471 | 0 | { |
5472 | 0 | MOZ_ASSERT(!mGetFilesPendingRequests.GetWeak(aUUID)); |
5473 | 0 |
|
5474 | 0 | if (!mozilla::Preferences::GetBool("dom.filesystem.pathcheck.disabled", false)) { |
5475 | 0 | RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get(); |
5476 | 0 | if (NS_WARN_IF(!fss || |
5477 | 0 | !fss->ContentProcessHasAccessTo(ChildID(), aDirectoryPath))) { |
5478 | 0 | return IPC_FAIL_NO_REASON(this); |
5479 | 0 | } |
5480 | 0 | } |
5481 | 0 |
|
5482 | 0 | ErrorResult rv; |
5483 | 0 | RefPtr<GetFilesHelper> helper = |
5484 | 0 | GetFilesHelperParent::Create(aUUID, aDirectoryPath, aRecursiveFlag, this, |
5485 | 0 | rv); |
5486 | 0 |
|
5487 | 0 | if (NS_WARN_IF(rv.Failed())) { |
5488 | 0 | if (!SendGetFilesResponse(aUUID, |
5489 | 0 | GetFilesResponseFailure(rv.StealNSResult()))) { |
5490 | 0 | return IPC_FAIL_NO_REASON(this); |
5491 | 0 | } |
5492 | 0 | return IPC_OK(); |
5493 | 0 | } |
5494 | 0 |
|
5495 | 0 | mGetFilesPendingRequests.Put(aUUID, helper); |
5496 | 0 | return IPC_OK(); |
5497 | 0 | } |
5498 | | |
5499 | | mozilla::ipc::IPCResult |
5500 | | ContentParent::RecvDeleteGetFilesRequest(const nsID& aUUID) |
5501 | 0 | { |
5502 | 0 | mGetFilesPendingRequests.Remove(aUUID); |
5503 | 0 | return IPC_OK(); |
5504 | 0 | } |
5505 | | |
5506 | | void |
5507 | | ContentParent::SendGetFilesResponseAndForget(const nsID& aUUID, |
5508 | | const GetFilesResponseResult& aResult) |
5509 | 0 | { |
5510 | 0 | if (mGetFilesPendingRequests.Remove(aUUID)) { |
5511 | 0 | Unused << SendGetFilesResponse(aUUID, aResult); |
5512 | 0 | } |
5513 | 0 | } |
5514 | | |
5515 | | void |
5516 | | ContentParent::PaintTabWhileInterruptingJS(TabParent* aTabParent, |
5517 | | bool aForceRepaint, |
5518 | | const layers::LayersObserverEpoch& aEpoch) |
5519 | 0 | { |
5520 | 0 | if (!mHangMonitorActor) { |
5521 | 0 | return; |
5522 | 0 | } |
5523 | 0 | ProcessHangMonitor::PaintWhileInterruptingJS(mHangMonitorActor, |
5524 | 0 | aTabParent, |
5525 | 0 | aForceRepaint, |
5526 | 0 | aEpoch); |
5527 | 0 | } |
5528 | | |
5529 | | void |
5530 | | ContentParent::UpdateCookieStatus(nsIChannel *aChannel) |
5531 | 0 | { |
5532 | 0 | PNeckoParent *neckoParent = LoneManagedOrNullAsserts(ManagedPNeckoParent()); |
5533 | 0 | PCookieServiceParent *csParent = LoneManagedOrNullAsserts(neckoParent->ManagedPCookieServiceParent()); |
5534 | 0 | if (csParent) { |
5535 | 0 | auto *cs = static_cast<CookieServiceParent*>(csParent); |
5536 | 0 | cs->TrackCookieLoad(aChannel); |
5537 | 0 | } |
5538 | 0 | } |
5539 | | |
5540 | | nsresult |
5541 | | ContentParent::AboutToLoadHttpFtpWyciwygDocumentForChild(nsIChannel* aChannel) |
5542 | 0 | { |
5543 | 0 | MOZ_ASSERT(aChannel); |
5544 | 0 |
|
5545 | 0 | nsresult rv; |
5546 | 0 | bool isDocument = aChannel->IsDocument(); |
5547 | 0 | if (!isDocument) { |
5548 | 0 | // We may be looking at a nsIHttpChannel which has isMainDocumentChannel set |
5549 | 0 | // (e.g. the internal http channel for a view-source: load.). |
5550 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); |
5551 | 0 | if (httpChannel) { |
5552 | 0 | rv = httpChannel->GetIsMainDocumentChannel(&isDocument); |
5553 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5554 | 0 | } |
5555 | 0 | } |
5556 | 0 | if (!isDocument) { |
5557 | 0 | return NS_OK; |
5558 | 0 | } |
5559 | 0 | |
5560 | 0 | // Get the principal for the channel result, so that we can get the permission |
5561 | 0 | // key for the document which will be created from this response. |
5562 | 0 | nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); |
5563 | 0 | if (NS_WARN_IF(!ssm)) { |
5564 | 0 | return NS_ERROR_FAILURE; |
5565 | 0 | } |
5566 | 0 | |
5567 | 0 | nsCOMPtr<nsIPrincipal> principal; |
5568 | 0 | rv = ssm->GetChannelResultPrincipal(aChannel, getter_AddRefs(principal)); |
5569 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5570 | 0 |
|
5571 | 0 | rv = TransmitPermissionsForPrincipal(principal); |
5572 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5573 | 0 |
|
5574 | 0 | nsLoadFlags newLoadFlags; |
5575 | 0 | aChannel->GetLoadFlags(&newLoadFlags); |
5576 | 0 | if (newLoadFlags & nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE) { |
5577 | 0 | UpdateCookieStatus(aChannel); |
5578 | 0 | } |
5579 | 0 |
|
5580 | 0 | return NS_OK; |
5581 | 0 | } |
5582 | | |
5583 | | nsresult |
5584 | | ContentParent::TransmitPermissionsForPrincipal(nsIPrincipal* aPrincipal) |
5585 | 0 | { |
5586 | 0 | // Create the key, and send it down to the content process. |
5587 | 0 | nsTArray<nsCString> keys = |
5588 | 0 | nsPermissionManager::GetAllKeysForPrincipal(aPrincipal); |
5589 | 0 | MOZ_ASSERT(keys.Length() >= 1); |
5590 | 0 | for (auto& key : keys) { |
5591 | 0 | EnsurePermissionsByKey(key); |
5592 | 0 | } |
5593 | 0 |
|
5594 | 0 | return NS_OK; |
5595 | 0 | } |
5596 | | |
5597 | | void |
5598 | | ContentParent::EnsurePermissionsByKey(const nsCString& aKey) |
5599 | 0 | { |
5600 | 0 | // NOTE: Make sure to initialize the permission manager before updating the |
5601 | 0 | // mActivePermissionKeys list. If the permission manager is being initialized |
5602 | 0 | // by this call to GetPermissionManager, and we've added the key to |
5603 | 0 | // mActivePermissionKeys, then the permission manager will send down a |
5604 | 0 | // SendAddPermission before receiving the SendSetPermissionsWithKey message. |
5605 | 0 | nsCOMPtr<nsIPermissionManager> permManager = |
5606 | 0 | services::GetPermissionManager(); |
5607 | 0 |
|
5608 | 0 | if (mActivePermissionKeys.Contains(aKey)) { |
5609 | 0 | return; |
5610 | 0 | } |
5611 | 0 | mActivePermissionKeys.PutEntry(aKey); |
5612 | 0 |
|
5613 | 0 | nsTArray<IPC::Permission> perms; |
5614 | 0 | nsresult rv = permManager->GetPermissionsWithKey(aKey, perms); |
5615 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
5616 | 0 | return; |
5617 | 0 | } |
5618 | 0 | |
5619 | 0 | Unused << SendSetPermissionsWithKey(aKey, perms); |
5620 | 0 | } |
5621 | | |
5622 | | bool |
5623 | | ContentParent::NeedsPermissionsUpdate(const nsACString& aPermissionKey) const |
5624 | 0 | { |
5625 | 0 | return mActivePermissionKeys.Contains(aPermissionKey); |
5626 | 0 | } |
5627 | | |
5628 | | mozilla::ipc::IPCResult |
5629 | | ContentParent::RecvAccumulateChildHistograms( |
5630 | | InfallibleTArray<HistogramAccumulation>&& aAccumulations) |
5631 | 0 | { |
5632 | 0 | TelemetryIPC::AccumulateChildHistograms(GetTelemetryProcessID(mRemoteType), aAccumulations); |
5633 | 0 | return IPC_OK(); |
5634 | 0 | } |
5635 | | |
5636 | | mozilla::ipc::IPCResult |
5637 | | ContentParent::RecvAccumulateChildKeyedHistograms( |
5638 | | InfallibleTArray<KeyedHistogramAccumulation>&& aAccumulations) |
5639 | 0 | { |
5640 | 0 | TelemetryIPC::AccumulateChildKeyedHistograms(GetTelemetryProcessID(mRemoteType), aAccumulations); |
5641 | 0 | return IPC_OK(); |
5642 | 0 | } |
5643 | | |
5644 | | mozilla::ipc::IPCResult |
5645 | | ContentParent::RecvUpdateChildScalars( |
5646 | | InfallibleTArray<ScalarAction>&& aScalarActions) |
5647 | 0 | { |
5648 | 0 | TelemetryIPC::UpdateChildScalars(GetTelemetryProcessID(mRemoteType), aScalarActions); |
5649 | 0 | return IPC_OK(); |
5650 | 0 | } |
5651 | | |
5652 | | mozilla::ipc::IPCResult |
5653 | | ContentParent::RecvUpdateChildKeyedScalars( |
5654 | | InfallibleTArray<KeyedScalarAction>&& aScalarActions) |
5655 | 0 | { |
5656 | 0 | TelemetryIPC::UpdateChildKeyedScalars(GetTelemetryProcessID(mRemoteType), aScalarActions); |
5657 | 0 | return IPC_OK(); |
5658 | 0 | } |
5659 | | |
5660 | | mozilla::ipc::IPCResult |
5661 | | ContentParent::RecvRecordChildEvents(nsTArray<mozilla::Telemetry::ChildEventData>&& aEvents) |
5662 | 0 | { |
5663 | 0 | TelemetryIPC::RecordChildEvents(GetTelemetryProcessID(mRemoteType), aEvents); |
5664 | 0 | return IPC_OK(); |
5665 | 0 | } |
5666 | | |
5667 | | mozilla::ipc::IPCResult |
5668 | | ContentParent::RecvRecordDiscardedData( |
5669 | | const mozilla::Telemetry::DiscardedData& aDiscardedData) |
5670 | 0 | { |
5671 | 0 | TelemetryIPC::RecordDiscardedData(GetTelemetryProcessID(mRemoteType), |
5672 | 0 | aDiscardedData); |
5673 | 0 | return IPC_OK(); |
5674 | 0 | } |
5675 | | |
5676 | | ////////////////////////////////////////////////////////////////// |
5677 | | // PURLClassifierParent |
5678 | | |
5679 | | PURLClassifierParent* |
5680 | | ContentParent::AllocPURLClassifierParent(const Principal& aPrincipal, |
5681 | | const bool& aUseTrackingProtection, |
5682 | | bool* aSuccess) |
5683 | 0 | { |
5684 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5685 | 0 |
|
5686 | 0 | *aSuccess = true; |
5687 | 0 | RefPtr<URLClassifierParent> actor = new URLClassifierParent(); |
5688 | 0 | return actor.forget().take(); |
5689 | 0 | } |
5690 | | |
5691 | | mozilla::ipc::IPCResult |
5692 | | ContentParent::RecvPURLClassifierConstructor(PURLClassifierParent* aActor, |
5693 | | const Principal& aPrincipal, |
5694 | | const bool& aUseTrackingProtection, |
5695 | | bool* aSuccess) |
5696 | 0 | { |
5697 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5698 | 0 | MOZ_ASSERT(aActor); |
5699 | 0 | *aSuccess = false; |
5700 | 0 |
|
5701 | 0 | auto* actor = static_cast<URLClassifierParent*>(aActor); |
5702 | 0 | nsCOMPtr<nsIPrincipal> principal(aPrincipal); |
5703 | 0 | if (!principal) { |
5704 | 0 | actor->ClassificationFailed(); |
5705 | 0 | return IPC_OK(); |
5706 | 0 | } |
5707 | 0 | return actor->StartClassify(principal, aUseTrackingProtection, aSuccess); |
5708 | 0 | } |
5709 | | |
5710 | | bool |
5711 | | ContentParent::DeallocPURLClassifierParent(PURLClassifierParent* aActor) |
5712 | 0 | { |
5713 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5714 | 0 | MOZ_ASSERT(aActor); |
5715 | 0 |
|
5716 | 0 | RefPtr<URLClassifierParent> actor = |
5717 | 0 | dont_AddRef(static_cast<URLClassifierParent*>(aActor)); |
5718 | 0 | return true; |
5719 | 0 | } |
5720 | | |
5721 | | ////////////////////////////////////////////////////////////////// |
5722 | | // PURLClassifierLocalParent |
5723 | | |
5724 | | PURLClassifierLocalParent* |
5725 | | ContentParent::AllocPURLClassifierLocalParent(const URIParams& aURI, |
5726 | | const nsCString& aTables) |
5727 | 0 | { |
5728 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5729 | 0 |
|
5730 | 0 | RefPtr<URLClassifierLocalParent> actor = new URLClassifierLocalParent(); |
5731 | 0 | return actor.forget().take(); |
5732 | 0 | } |
5733 | | |
5734 | | mozilla::ipc::IPCResult |
5735 | | ContentParent::RecvPURLClassifierLocalConstructor(PURLClassifierLocalParent* aActor, |
5736 | | const URIParams& aURI, |
5737 | | const nsCString& aTables) |
5738 | 0 | { |
5739 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5740 | 0 | MOZ_ASSERT(aActor); |
5741 | 0 |
|
5742 | 0 | nsCOMPtr<nsIURI> uri = DeserializeURI(aURI); |
5743 | 0 | if (!uri) { |
5744 | 0 | NS_WARNING("Failed to DeserializeURI"); |
5745 | 0 | return IPC_FAIL_NO_REASON(this); |
5746 | 0 | } |
5747 | 0 |
|
5748 | 0 | auto* actor = static_cast<URLClassifierLocalParent*>(aActor); |
5749 | 0 | return actor->StartClassify(uri, aTables); |
5750 | 0 | } |
5751 | | |
5752 | | bool |
5753 | | ContentParent::DeallocPURLClassifierLocalParent(PURLClassifierLocalParent* aActor) |
5754 | 0 | { |
5755 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5756 | 0 | MOZ_ASSERT(aActor); |
5757 | 0 |
|
5758 | 0 | RefPtr<URLClassifierLocalParent> actor = |
5759 | 0 | dont_AddRef(static_cast<URLClassifierLocalParent*>(aActor)); |
5760 | 0 | return true; |
5761 | 0 | } |
5762 | | |
5763 | | PLoginReputationParent* |
5764 | | ContentParent::AllocPLoginReputationParent(const URIParams& aURI) |
5765 | 0 | { |
5766 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5767 | 0 |
|
5768 | 0 | RefPtr<LoginReputationParent> actor = new LoginReputationParent(); |
5769 | 0 | return actor.forget().take(); |
5770 | 0 | } |
5771 | | |
5772 | | mozilla::ipc::IPCResult |
5773 | | ContentParent::RecvPLoginReputationConstructor(PLoginReputationParent* aActor, |
5774 | | const URIParams& aURI) |
5775 | 0 | { |
5776 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5777 | 0 | MOZ_ASSERT(aActor); |
5778 | 0 |
|
5779 | 0 | nsCOMPtr<nsIURI> uri = DeserializeURI(aURI); |
5780 | 0 | if (!uri) { |
5781 | 0 | return IPC_FAIL_NO_REASON(this); |
5782 | 0 | } |
5783 | 0 |
|
5784 | 0 | auto* actor = static_cast<LoginReputationParent*>(aActor); |
5785 | 0 | return actor->QueryReputation(uri); |
5786 | 0 | } |
5787 | | |
5788 | | bool |
5789 | | ContentParent::DeallocPLoginReputationParent(PLoginReputationParent* aActor) |
5790 | 0 | { |
5791 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5792 | 0 | MOZ_ASSERT(aActor); |
5793 | 0 |
|
5794 | 0 | RefPtr<LoginReputationParent> actor = |
5795 | 0 | dont_AddRef(static_cast<LoginReputationParent*>(aActor)); |
5796 | 0 | return true; |
5797 | 0 | } |
5798 | | |
5799 | | mozilla::ipc::IPCResult |
5800 | | ContentParent::RecvClassifyLocal(const URIParams& aURI, const nsCString& aTables, |
5801 | | nsresult *aRv, nsTArray<nsCString>* aResults) |
5802 | 0 | { |
5803 | 0 | MOZ_ASSERT(aResults); |
5804 | 0 | nsCOMPtr<nsIURI> uri = DeserializeURI(aURI); |
5805 | 0 | if (!uri) { |
5806 | 0 | return IPC_FAIL_NO_REASON(this); |
5807 | 0 | } |
5808 | 0 | nsCOMPtr<nsIURIClassifier> uriClassifier = |
5809 | 0 | do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID); |
5810 | 0 | if (!uriClassifier) { |
5811 | 0 | return IPC_FAIL_NO_REASON(this); |
5812 | 0 | } |
5813 | 0 | *aRv = uriClassifier->ClassifyLocalWithTables(uri, aTables, *aResults); |
5814 | 0 | return IPC_OK(); |
5815 | 0 | } |
5816 | | |
5817 | | mozilla::ipc::IPCResult |
5818 | | ContentParent::RecvFileCreationRequest(const nsID& aID, |
5819 | | const nsString& aFullPath, |
5820 | | const nsString& aType, |
5821 | | const nsString& aName, |
5822 | | const bool& aLastModifiedPassed, |
5823 | | const int64_t& aLastModified, |
5824 | | const bool& aExistenceCheck, |
5825 | | const bool& aIsFromNsIFile) |
5826 | 0 | { |
5827 | 0 | // We allow the creation of File via this IPC call only for the 'file' process |
5828 | 0 | // or for testing. |
5829 | 0 | if (!mRemoteType.EqualsLiteral(FILE_REMOTE_TYPE) && |
5830 | 0 | !Preferences::GetBool("dom.file.createInChild", false)) { |
5831 | 0 | return IPC_FAIL_NO_REASON(this); |
5832 | 0 | } |
5833 | 0 |
|
5834 | 0 | RefPtr<BlobImpl> blobImpl; |
5835 | 0 | nsresult rv = |
5836 | 0 | FileCreatorHelper::CreateBlobImplForIPC(aFullPath, aType, aName, |
5837 | 0 | aLastModifiedPassed, |
5838 | 0 | aLastModified, aExistenceCheck, |
5839 | 0 | aIsFromNsIFile, |
5840 | 0 | getter_AddRefs(blobImpl)); |
5841 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
5842 | 0 | if (!SendFileCreationResponse(aID, FileCreationErrorResult(rv))) { |
5843 | 0 | return IPC_FAIL_NO_REASON(this); |
5844 | 0 | } |
5845 | 0 |
|
5846 | 0 | return IPC_OK(); |
5847 | 0 | } |
5848 | 0 |
|
5849 | 0 | MOZ_ASSERT(blobImpl); |
5850 | 0 |
|
5851 | 0 | IPCBlob ipcBlob; |
5852 | 0 | rv = IPCBlobUtils::Serialize(blobImpl, this, ipcBlob); |
5853 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
5854 | 0 | if (!SendFileCreationResponse(aID, FileCreationErrorResult(rv))) { |
5855 | 0 | return IPC_FAIL_NO_REASON(this); |
5856 | 0 | } |
5857 | 0 |
|
5858 | 0 | return IPC_OK(); |
5859 | 0 | } |
5860 | 0 |
|
5861 | 0 | if (!SendFileCreationResponse(aID, FileCreationSuccessResult(ipcBlob))) { |
5862 | 0 | return IPC_FAIL_NO_REASON(this); |
5863 | 0 | } |
5864 | 0 |
|
5865 | 0 | return IPC_OK(); |
5866 | 0 | } |
5867 | | |
5868 | | bool |
5869 | | ContentParent::CanCommunicateWith(ContentParentId aOtherProcess) |
5870 | 0 | { |
5871 | 0 | // Normally a process can only communicate with its parent, but a JS plugin process can |
5872 | 0 | // communicate with any process. |
5873 | 0 | ContentProcessManager *cpm = ContentProcessManager::GetSingleton(); |
5874 | 0 | ContentParentId parentId; |
5875 | 0 | if (!cpm->GetParentProcessId(ChildID(), &parentId)) { |
5876 | 0 | return false; |
5877 | 0 | } |
5878 | 0 | if (IsForJSPlugin()) { |
5879 | 0 | return parentId == ContentParentId(0); |
5880 | 0 | } |
5881 | 0 | return parentId == aOtherProcess; |
5882 | 0 | } |
5883 | | |
5884 | | nsresult |
5885 | | ContentParent::SaveRecording(nsIFile* aFile, bool* aRetval) |
5886 | 0 | { |
5887 | 0 | if (mRecordReplayState != eRecording) { |
5888 | 0 | *aRetval = false; |
5889 | 0 | return NS_OK; |
5890 | 0 | } |
5891 | 0 | |
5892 | 0 | PRFileDesc* prfd; |
5893 | 0 | nsresult rv = aFile->OpenNSPRFileDesc(PR_WRONLY | PR_TRUNCATE | PR_CREATE_FILE, 0644, &prfd); |
5894 | 0 | if (NS_FAILED(rv)) { |
5895 | 0 | return rv; |
5896 | 0 | } |
5897 | 0 | |
5898 | 0 | FileDescriptor::PlatformHandleType handle = |
5899 | 0 | FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(prfd)); |
5900 | 0 |
|
5901 | 0 | Unused << SendSaveRecording(FileDescriptor(handle)); |
5902 | 0 |
|
5903 | 0 | PR_Close(prfd); |
5904 | 0 |
|
5905 | 0 | *aRetval = true; |
5906 | 0 | return NS_OK; |
5907 | 0 | } |
5908 | | |
5909 | | mozilla::ipc::IPCResult |
5910 | | ContentParent::RecvMaybeReloadPlugins() |
5911 | 0 | { |
5912 | 0 | RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst(); |
5913 | 0 | pluginHost->ReloadPlugins(); |
5914 | 0 | return IPC_OK(); |
5915 | 0 | } |
5916 | | |
5917 | | mozilla::ipc::IPCResult |
5918 | | ContentParent::RecvDeviceReset() |
5919 | 0 | { |
5920 | 0 | GPUProcessManager* pm = GPUProcessManager::Get(); |
5921 | 0 | if (pm) { |
5922 | 0 | pm->SimulateDeviceReset(); |
5923 | 0 | } |
5924 | 0 |
|
5925 | 0 | return IPC_OK(); |
5926 | 0 | } |
5927 | | |
5928 | | mozilla::ipc::IPCResult |
5929 | | ContentParent::RecvBHRThreadHang(const HangDetails& aDetails) |
5930 | 0 | { |
5931 | 0 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
5932 | 0 | if (obs) { |
5933 | 0 | // Copy the HangDetails recieved over the network into a nsIHangDetails, and |
5934 | 0 | // then fire our own observer notification. |
5935 | 0 | // XXX: We should be able to avoid this potentially expensive copy here by |
5936 | 0 | // moving our deserialized argument. |
5937 | 0 | nsCOMPtr<nsIHangDetails> hangDetails = |
5938 | 0 | new nsHangDetails(HangDetails(aDetails)); |
5939 | 0 | obs->NotifyObservers(hangDetails, "bhr-thread-hang", nullptr); |
5940 | 0 | } |
5941 | 0 | return IPC_OK(); |
5942 | 0 | } |
5943 | | |
5944 | | mozilla::ipc::IPCResult |
5945 | | ContentParent::RecvFirstPartyStorageAccessGrantedForOrigin(const Principal& aParentPrincipal, |
5946 | | const nsCString& aTrackingOrigin, |
5947 | | const nsCString& aGrantedOrigin, |
5948 | | FirstPartyStorageAccessGrantedForOriginResolver&& aResolver) |
5949 | 0 | { |
5950 | 0 | AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(aParentPrincipal, |
5951 | 0 | aTrackingOrigin, |
5952 | 0 | aGrantedOrigin, |
5953 | 0 | std::move(aResolver)); |
5954 | 0 | return IPC_OK(); |
5955 | 0 | } |
5956 | | |
5957 | | mozilla::ipc::IPCResult |
5958 | | ContentParent::RecvStoreUserInteractionAsPermission(const Principal& aPrincipal) |
5959 | 0 | { |
5960 | 0 | AntiTrackingCommon::StoreUserInteractionFor(aPrincipal); |
5961 | 0 | return IPC_OK(); |
5962 | 0 | } |
5963 | | |
5964 | | mozilla::ipc::IPCResult |
5965 | | ContentParent::RecvAttachBrowsingContext( |
5966 | | const BrowsingContextId& aParentId, |
5967 | | const BrowsingContextId& aChildId, |
5968 | | const nsString& aName) |
5969 | 0 | { |
5970 | 0 | RefPtr<ChromeBrowsingContext> parent = ChromeBrowsingContext::Get(aParentId); |
5971 | 0 | if (aParentId && !parent) { |
5972 | 0 | // Unless 'aParentId' is 0 (which it is when the child is a root |
5973 | 0 | // BrowsingContext) there should always be a corresponding |
5974 | 0 | // 'parent'. The only reason for there not beeing one is if the |
5975 | 0 | // parent has already been detached, in which case the |
5976 | 0 | // BrowsingContext that tries to attach itself to the context with |
5977 | 0 | // 'aParentId' is surely doomed and we can safely do nothing. |
5978 | 0 |
|
5979 | 0 | // TODO(farre): When we start syncing/moving BrowsingContexts to |
5980 | 0 | // other child processes is it possible to get into races where |
5981 | 0 | // constructive operations on already detached BrowsingContexts |
5982 | 0 | // are requested? This needs to be answered/handled, but for now |
5983 | 0 | // return early. [Bug 1471598] |
5984 | 0 | MOZ_LOG( |
5985 | 0 | BrowsingContext::GetLog(), |
5986 | 0 | LogLevel::Debug, |
5987 | 0 | ("ParentIPC: Trying to attach to already detached parent 0x%08" PRIx64, |
5988 | 0 | (uint64_t)aParentId)); |
5989 | 0 | return IPC_OK(); |
5990 | 0 | } |
5991 | 0 |
|
5992 | 0 | if (parent && !parent->IsOwnedByProcess(ChildID())) { |
5993 | 0 | // Where trying attach a child BrowsingContext to a parent |
5994 | 0 | // BrowsingContext in another process. This is illegal since the |
5995 | 0 | // only thing that could create that child BrowsingContext is a |
5996 | 0 | // parent docshell in the same process as that BrowsingContext. |
5997 | 0 |
|
5998 | 0 | // TODO(farre): We're doing nothing now, but is that exactly what |
5999 | 0 | // we want? Maybe we want to crash the child currently calling |
6000 | 0 | // SendAttachBrowsingContext and/or the child that originally |
6001 | 0 | // called SendAttachBrowsingContext or possibly all children that |
6002 | 0 | // has a BrowsingContext connected to the child that currently |
6003 | 0 | // called SendAttachBrowsingContext? [Bug 1471598] |
6004 | 0 | MOZ_LOG(BrowsingContext::GetLog(), |
6005 | 0 | LogLevel::Warning, |
6006 | 0 | ("ParentIPC: Trying to attach to out of process parent context " |
6007 | 0 | "0x%08" PRIx64, |
6008 | 0 | parent->Id())); |
6009 | 0 | return IPC_OK(); |
6010 | 0 | } |
6011 | 0 |
|
6012 | 0 | RefPtr<BrowsingContext> child = BrowsingContext::Get(aChildId); |
6013 | 0 | if (child && !child->IsCached()) { |
6014 | 0 | // This is highly suspicious. BrowsingContexts should only be |
6015 | 0 | // attached at most once, but finding one indicates that someone |
6016 | 0 | // is doing something they shouldn't. |
6017 | 0 |
|
6018 | 0 | // TODO(farre): To crash or not to crash. Same reasoning as in |
6019 | 0 | // above TODO. [Bug 1471598] |
6020 | 0 | MOZ_LOG(BrowsingContext::GetLog(), |
6021 | 0 | LogLevel::Warning, |
6022 | 0 | ("ParentIPC: Trying to attach already attached 0x%08" PRIx64 |
6023 | 0 | " to 0x%08" PRIx64, |
6024 | 0 | child->Id(), |
6025 | 0 | (uint64_t)aParentId)); |
6026 | 0 | return IPC_OK(); |
6027 | 0 | } |
6028 | 0 |
|
6029 | 0 | if (!child) { |
6030 | 0 | child = ChromeBrowsingContext::Create(aChildId, aName, ChildID()); |
6031 | 0 | } |
6032 | 0 | child->Attach(parent); |
6033 | 0 |
|
6034 | 0 | return IPC_OK(); |
6035 | 0 | } |
6036 | | |
6037 | | mozilla::ipc::IPCResult |
6038 | | ContentParent::RecvDetachBrowsingContext(const BrowsingContextId& aContextId, |
6039 | | const bool& aMoveToBFCache) |
6040 | 0 | { |
6041 | 0 | RefPtr<ChromeBrowsingContext> context = ChromeBrowsingContext::Get(aContextId); |
6042 | 0 |
|
6043 | 0 | if (!context) { |
6044 | 0 | MOZ_LOG(BrowsingContext::GetLog(), |
6045 | 0 | LogLevel::Debug, |
6046 | 0 | ("ParentIPC: Trying to detach already detached 0x%08" PRIx64, |
6047 | 0 | (uint64_t)aContextId)); |
6048 | 0 | return IPC_OK(); |
6049 | 0 | } |
6050 | 0 |
|
6051 | 0 | if (!context->IsOwnedByProcess(ChildID())) { |
6052 | 0 | // Where trying to detach a child BrowsingContext in another child |
6053 | 0 | // process. This is illegal since the owner of the BrowsingContext |
6054 | 0 | // is the proccess with the in-process docshell, which is tracked |
6055 | 0 | // by OwnerProcessId. |
6056 | 0 |
|
6057 | 0 | // TODO(farre): To crash or not to crash. Same reasoning as in |
6058 | 0 | // above TODO. [Bug 1471598] |
6059 | 0 | MOZ_LOG(BrowsingContext::GetLog(), |
6060 | 0 | LogLevel::Warning, |
6061 | 0 | ("ParentIPC: Trying to detach out of process context 0x%08" PRIx64, |
6062 | 0 | context->Id())); |
6063 | 0 | return IPC_OK(); |
6064 | 0 | } |
6065 | 0 |
|
6066 | 0 | if (aMoveToBFCache) { |
6067 | 0 | context->CacheChildren(); |
6068 | 0 | } else { |
6069 | 0 | context->Detach(); |
6070 | 0 | } |
6071 | 0 |
|
6072 | 0 | return IPC_OK(); |
6073 | 0 | } |