Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: sw=4 ts=4 et :
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/plugins/PluginModuleParent.h"
8 :
9 : #include "base/process_util.h"
10 : #include "mozilla/Attributes.h"
11 : #include "mozilla/dom/ContentParent.h"
12 : #include "mozilla/dom/ContentChild.h"
13 : #include "mozilla/ipc/GeckoChildProcessHost.h"
14 : #include "mozilla/ipc/MessageChannel.h"
15 : #include "mozilla/ipc/ProtocolUtils.h"
16 : #include "mozilla/plugins/BrowserStreamParent.h"
17 : #include "mozilla/plugins/PluginBridge.h"
18 : #include "mozilla/plugins/PluginInstanceParent.h"
19 : #include "mozilla/Preferences.h"
20 : #include "mozilla/ProcessHangMonitor.h"
21 : #include "mozilla/Services.h"
22 : #include "mozilla/Telemetry.h"
23 : #include "mozilla/Unused.h"
24 : #include "nsAutoPtr.h"
25 : #include "nsCRT.h"
26 : #include "nsIFile.h"
27 : #include "nsIObserverService.h"
28 : #include "nsIXULRuntime.h"
29 : #include "nsNPAPIPlugin.h"
30 : #include "nsPrintfCString.h"
31 : #include "prsystem.h"
32 : #include "prclist.h"
33 : #include "PluginQuirks.h"
34 : #include "gfxPlatform.h"
35 : #include "GeckoProfiler.h"
36 : #include "nsPluginTags.h"
37 : #include "nsUnicharUtils.h"
38 : #include "mozilla/layers/TextureClientRecycleAllocator.h"
39 :
40 : #ifdef XP_WIN
41 : #include "mozilla/plugins/PluginSurfaceParent.h"
42 : #include "mozilla/widget/AudioSession.h"
43 : #include "PluginHangUIParent.h"
44 : #include "PluginUtilsWin.h"
45 : #endif
46 :
47 : #ifdef MOZ_WIDGET_GTK
48 : #include <glib.h>
49 : #elif XP_MACOSX
50 : #include "PluginInterposeOSX.h"
51 : #include "PluginUtilsOSX.h"
52 : #endif
53 :
54 : #ifdef MOZ_GECKO_PROFILER
55 : #include "ProfilerParent.h"
56 : #endif
57 :
58 : using base::KillProcess;
59 :
60 : using mozilla::PluginLibrary;
61 : using mozilla::ipc::MessageChannel;
62 : using mozilla::ipc::GeckoChildProcessHost;
63 :
64 : using namespace mozilla;
65 : using namespace mozilla::plugins;
66 : using namespace mozilla::plugins::parent;
67 :
68 : #ifdef MOZ_CRASHREPORTER
69 : #include "mozilla/ipc/CrashReporterClient.h"
70 : #include "mozilla/ipc/CrashReporterHost.h"
71 :
72 : using namespace CrashReporter;
73 : #endif
74 :
75 : static const char kContentTimeoutPref[] = "dom.ipc.plugins.contentTimeoutSecs";
76 : static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
77 : static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs";
78 : static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs";
79 : #ifdef XP_WIN
80 : static const char kHangUITimeoutPref[] = "dom.ipc.plugins.hangUITimeoutSecs";
81 : static const char kHangUIMinDisplayPref[] = "dom.ipc.plugins.hangUIMinDisplaySecs";
82 : #define CHILD_TIMEOUT_PREF kHangUITimeoutPref
83 : #else
84 : #define CHILD_TIMEOUT_PREF kChildTimeoutPref
85 : #endif
86 :
87 : bool
88 0 : mozilla::plugins::SetupBridge(uint32_t aPluginId,
89 : dom::ContentParent* aContentParent,
90 : nsresult* rv,
91 : uint32_t* runID,
92 : ipc::Endpoint<PPluginModuleParent>* aEndpoint)
93 : {
94 0 : AUTO_PROFILER_LABEL("plugins::SetupBridge", OTHER);
95 0 : if (NS_WARN_IF(!rv) || NS_WARN_IF(!runID)) {
96 0 : return false;
97 : }
98 :
99 0 : RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
100 0 : RefPtr<nsNPAPIPlugin> plugin;
101 0 : *rv = host->GetPluginForContentProcess(aPluginId, getter_AddRefs(plugin));
102 0 : if (NS_FAILED(*rv)) {
103 0 : return true;
104 : }
105 0 : PluginModuleChromeParent* chromeParent = static_cast<PluginModuleChromeParent*>(plugin->GetLibrary());
106 : /*
107 : * We can't accumulate BLOCKED_ON_PLUGIN_MODULE_INIT_MS until here because
108 : * its histogram key is not available until *after* NP_Initialize.
109 : */
110 0 : chromeParent->AccumulateModuleInitBlockedTime();
111 0 : *rv = chromeParent->GetRunID(runID);
112 0 : if (NS_FAILED(*rv)) {
113 0 : return true;
114 : }
115 :
116 0 : ipc::Endpoint<PPluginModuleParent> parent;
117 0 : ipc::Endpoint<PPluginModuleChild> child;
118 :
119 0 : *rv = PPluginModule::CreateEndpoints(aContentParent->OtherPid(),
120 0 : chromeParent->OtherPid(),
121 : &parent, &child);
122 0 : if (NS_FAILED(*rv)) {
123 0 : return true;
124 : }
125 :
126 0 : *aEndpoint = Move(parent);
127 :
128 0 : if (!chromeParent->SendInitPluginModuleChild(Move(child))) {
129 0 : *rv = NS_ERROR_BRIDGE_OPEN_CHILD;
130 0 : return true;
131 : }
132 :
133 0 : return true;
134 : }
135 :
136 : #ifdef MOZ_CRASHREPORTER_INJECTOR
137 :
138 : /**
139 : * Use for executing CreateToolhelp32Snapshot off main thread
140 : */
141 : class mozilla::plugins::FinishInjectorInitTask : public mozilla::CancelableRunnable
142 : {
143 : public:
144 : FinishInjectorInitTask()
145 : : CancelableRunnable("FinishInjectorInitTask")
146 : , mMutex("FlashInjectorInitTask::mMutex")
147 : , mParent(nullptr)
148 : , mMainThreadMsgLoop(MessageLoop::current())
149 : {
150 : MOZ_ASSERT(NS_IsMainThread());
151 : }
152 :
153 : void Init(PluginModuleChromeParent* aParent)
154 : {
155 : MOZ_ASSERT(aParent);
156 : mParent = aParent;
157 : }
158 :
159 : void PostToMainThread()
160 : {
161 : RefPtr<Runnable> self = this;
162 : mSnapshot.own(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
163 : { // Scope for lock
164 : mozilla::MutexAutoLock lock(mMutex);
165 : if (mMainThreadMsgLoop) {
166 : mMainThreadMsgLoop->PostTask(self.forget());
167 : }
168 : }
169 : }
170 :
171 : NS_IMETHOD Run() override
172 : {
173 : mParent->DoInjection(mSnapshot);
174 : // We don't need to hold this lock during DoInjection, but we do need
175 : // to obtain it before returning from Run() to ensure that
176 : // PostToMainThread has completed before we return.
177 : mozilla::MutexAutoLock lock(mMutex);
178 : return NS_OK;
179 : }
180 :
181 : nsresult Cancel() override
182 : {
183 : mozilla::MutexAutoLock lock(mMutex);
184 : mMainThreadMsgLoop = nullptr;
185 : return NS_OK;
186 : }
187 :
188 : private:
189 : mozilla::Mutex mMutex;
190 : nsAutoHandle mSnapshot;
191 : PluginModuleChromeParent* mParent;
192 : MessageLoop* mMainThreadMsgLoop;
193 : };
194 :
195 : #endif // MOZ_CRASHREPORTER_INJECTOR
196 :
197 : namespace {
198 :
199 : /**
200 : * Objects of this class remain linked until an error occurs in the
201 : * plugin initialization sequence.
202 : */
203 : class PluginModuleMapping : public PRCList
204 : {
205 : public:
206 0 : explicit PluginModuleMapping(uint32_t aPluginId)
207 0 : : mPluginId(aPluginId)
208 : , mProcessIdValid(false)
209 : , mModule(nullptr)
210 0 : , mChannelOpened(false)
211 : {
212 0 : MOZ_COUNT_CTOR(PluginModuleMapping);
213 0 : PR_INIT_CLIST(this);
214 0 : PR_APPEND_LINK(this, &sModuleListHead);
215 0 : }
216 :
217 0 : ~PluginModuleMapping()
218 0 : {
219 0 : PR_REMOVE_LINK(this);
220 0 : MOZ_COUNT_DTOR(PluginModuleMapping);
221 0 : }
222 :
223 : bool
224 0 : IsChannelOpened() const
225 : {
226 0 : return mChannelOpened;
227 : }
228 :
229 : void
230 0 : SetChannelOpened()
231 : {
232 0 : mChannelOpened = true;
233 0 : }
234 :
235 : PluginModuleContentParent*
236 0 : GetModule()
237 : {
238 0 : if (!mModule) {
239 0 : mModule = new PluginModuleContentParent();
240 : }
241 0 : return mModule;
242 : }
243 :
244 : static PluginModuleMapping*
245 : AssociateWithProcessId(uint32_t aPluginId, base::ProcessId aProcessId)
246 : {
247 : PluginModuleMapping* mapping =
248 : static_cast<PluginModuleMapping*>(PR_NEXT_LINK(&sModuleListHead));
249 : while (mapping != &sModuleListHead) {
250 : if (mapping->mPluginId == aPluginId) {
251 : mapping->AssociateWithProcessId(aProcessId);
252 : return mapping;
253 : }
254 : mapping = static_cast<PluginModuleMapping*>(PR_NEXT_LINK(mapping));
255 : }
256 : return nullptr;
257 : }
258 :
259 : static PluginModuleMapping*
260 0 : Resolve(base::ProcessId aProcessId)
261 : {
262 0 : PluginModuleMapping* mapping = nullptr;
263 :
264 0 : if (sIsLoadModuleOnStack) {
265 : // Special case: If loading synchronously, we just need to access
266 : // the tail entry of the list.
267 0 : mapping =
268 : static_cast<PluginModuleMapping*>(PR_LIST_TAIL(&sModuleListHead));
269 0 : MOZ_ASSERT(mapping);
270 0 : return mapping;
271 : }
272 :
273 0 : mapping =
274 : static_cast<PluginModuleMapping*>(PR_NEXT_LINK(&sModuleListHead));
275 0 : while (mapping != &sModuleListHead) {
276 0 : if (mapping->mProcessIdValid && mapping->mProcessId == aProcessId) {
277 0 : return mapping;
278 : }
279 0 : mapping = static_cast<PluginModuleMapping*>(PR_NEXT_LINK(mapping));
280 : }
281 0 : return nullptr;
282 : }
283 :
284 : static PluginModuleMapping*
285 : FindModuleByPluginId(uint32_t aPluginId)
286 : {
287 : PluginModuleMapping* mapping =
288 : static_cast<PluginModuleMapping*>(PR_NEXT_LINK(&sModuleListHead));
289 : while (mapping != &sModuleListHead) {
290 : if (mapping->mPluginId == aPluginId) {
291 : return mapping;
292 : }
293 : mapping = static_cast<PluginModuleMapping*>(PR_NEXT_LINK(mapping));
294 : }
295 : return nullptr;
296 : }
297 :
298 : class MOZ_RAII NotifyLoadingModule
299 : {
300 : public:
301 0 : explicit NotifyLoadingModule(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
302 0 : {
303 0 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
304 0 : PluginModuleMapping::sIsLoadModuleOnStack = true;
305 0 : }
306 :
307 0 : ~NotifyLoadingModule()
308 0 : {
309 0 : PluginModuleMapping::sIsLoadModuleOnStack = false;
310 0 : }
311 :
312 : private:
313 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
314 : };
315 :
316 : private:
317 : void
318 : AssociateWithProcessId(base::ProcessId aProcessId)
319 : {
320 : MOZ_ASSERT(!mProcessIdValid);
321 : mProcessId = aProcessId;
322 : mProcessIdValid = true;
323 : }
324 :
325 : uint32_t mPluginId;
326 : bool mProcessIdValid;
327 : base::ProcessId mProcessId;
328 : PluginModuleContentParent* mModule;
329 : bool mChannelOpened;
330 :
331 : friend class NotifyLoadingModule;
332 :
333 : static PRCList sModuleListHead;
334 : static bool sIsLoadModuleOnStack;
335 : };
336 :
337 : PRCList PluginModuleMapping::sModuleListHead =
338 : PR_INIT_STATIC_CLIST(&PluginModuleMapping::sModuleListHead);
339 :
340 : bool PluginModuleMapping::sIsLoadModuleOnStack = false;
341 :
342 : } // namespace
343 :
344 : static PluginModuleChromeParent*
345 0 : PluginModuleChromeParentForId(const uint32_t aPluginId)
346 : {
347 0 : MOZ_ASSERT(XRE_IsParentProcess());
348 :
349 0 : RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
350 0 : nsPluginTag* pluginTag = host->PluginWithId(aPluginId);
351 0 : if (!pluginTag || !pluginTag->mPlugin) {
352 0 : return nullptr;
353 : }
354 0 : RefPtr<nsNPAPIPlugin> plugin = pluginTag->mPlugin;
355 :
356 0 : return static_cast<PluginModuleChromeParent*>(plugin->GetLibrary());
357 : }
358 :
359 : void
360 0 : mozilla::plugins::TakeFullMinidump(uint32_t aPluginId,
361 : base::ProcessId aContentProcessId,
362 : const nsAString& aBrowserDumpId,
363 : std::function<void(nsString)>&& aCallback,
364 : bool aAsync)
365 : {
366 : PluginModuleChromeParent* chromeParent =
367 0 : PluginModuleChromeParentForId(aPluginId);
368 :
369 0 : if (chromeParent) {
370 0 : chromeParent->TakeFullMinidump(aContentProcessId,
371 : aBrowserDumpId,
372 0 : Move(aCallback),
373 0 : aAsync);
374 : } else {
375 0 : aCallback(EmptyString());
376 : }
377 0 : }
378 :
379 : void
380 0 : mozilla::plugins::TerminatePlugin(uint32_t aPluginId,
381 : base::ProcessId aContentProcessId,
382 : const nsCString& aMonitorDescription,
383 : const nsAString& aDumpId,
384 : std::function<void(bool)>&& aCallback)
385 : {
386 : PluginModuleChromeParent* chromeParent =
387 0 : PluginModuleChromeParentForId(aPluginId);
388 :
389 0 : if (chromeParent) {
390 0 : chromeParent->TerminateChildProcess(MessageLoop::current(),
391 : aContentProcessId,
392 : aMonitorDescription,
393 : aDumpId,
394 0 : Move(aCallback),
395 0 : true); // Always runs asynchronously.
396 : } else {
397 0 : aCallback(true);
398 : }
399 0 : }
400 :
401 : /* static */ PluginLibrary*
402 0 : PluginModuleContentParent::LoadModule(uint32_t aPluginId,
403 : nsPluginTag* aPluginTag)
404 : {
405 0 : PluginModuleMapping::NotifyLoadingModule loadingModule;
406 0 : nsAutoPtr<PluginModuleMapping> mapping(new PluginModuleMapping(aPluginId));
407 :
408 0 : MOZ_ASSERT(XRE_IsContentProcess());
409 :
410 : /*
411 : * We send a LoadPlugin message to the chrome process using an intr
412 : * message. Before it sends its response, it sends a message to create
413 : * PluginModuleParent instance. That message is handled by
414 : * PluginModuleContentParent::Initialize, which saves the instance in
415 : * its module mapping. We fetch it from there after LoadPlugin finishes.
416 : */
417 0 : dom::ContentChild* cp = dom::ContentChild::GetSingleton();
418 : nsresult rv;
419 : uint32_t runID;
420 0 : Endpoint<PPluginModuleParent> endpoint;
421 0 : TimeStamp sendLoadPluginStart = TimeStamp::Now();
422 0 : if (!cp->SendLoadPlugin(aPluginId, &rv, &runID, &endpoint) ||
423 0 : NS_FAILED(rv)) {
424 0 : return nullptr;
425 : }
426 0 : Initialize(Move(endpoint));
427 0 : TimeStamp sendLoadPluginEnd = TimeStamp::Now();
428 :
429 0 : PluginModuleContentParent* parent = mapping->GetModule();
430 0 : MOZ_ASSERT(parent);
431 0 : parent->mTimeBlocked += (sendLoadPluginEnd - sendLoadPluginStart);
432 :
433 0 : if (!mapping->IsChannelOpened()) {
434 : // mapping is linked into PluginModuleMapping::sModuleListHead and is
435 : // needed later, so since this function is returning successfully we
436 : // forget it here.
437 0 : mapping.forget();
438 : }
439 :
440 0 : parent->mPluginId = aPluginId;
441 0 : parent->mRunID = runID;
442 :
443 0 : return parent;
444 : }
445 :
446 : /* static */ void
447 0 : PluginModuleContentParent::Initialize(Endpoint<PPluginModuleParent>&& aEndpoint)
448 : {
449 : nsAutoPtr<PluginModuleMapping> moduleMapping(
450 0 : PluginModuleMapping::Resolve(aEndpoint.OtherPid()));
451 0 : MOZ_ASSERT(moduleMapping);
452 0 : PluginModuleContentParent* parent = moduleMapping->GetModule();
453 0 : MOZ_ASSERT(parent);
454 :
455 0 : DebugOnly<bool> ok = aEndpoint.Bind(parent);
456 0 : MOZ_ASSERT(ok);
457 :
458 0 : moduleMapping->SetChannelOpened();
459 :
460 : // Request Windows message deferral behavior on our channel. This
461 : // applies to the top level and all sub plugin protocols since they
462 : // all share the same channel.
463 0 : parent->GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
464 :
465 0 : TimeoutChanged(kContentTimeoutPref, parent);
466 :
467 : // moduleMapping is linked into PluginModuleMapping::sModuleListHead and is
468 : // needed later, so since this function is returning successfully we
469 : // forget it here.
470 0 : moduleMapping.forget();
471 0 : }
472 :
473 : // static
474 : PluginLibrary*
475 0 : PluginModuleChromeParent::LoadModule(const char* aFilePath, uint32_t aPluginId,
476 : nsPluginTag* aPluginTag)
477 : {
478 0 : PLUGIN_LOG_DEBUG_FUNCTION;
479 :
480 : nsAutoPtr<PluginModuleChromeParent> parent(
481 : new PluginModuleChromeParent(aFilePath, aPluginId,
482 0 : aPluginTag->mSandboxLevel));
483 0 : UniquePtr<LaunchCompleteTask> onLaunchedRunnable(new LaunchedTask(parent));
484 0 : TimeStamp launchStart = TimeStamp::Now();
485 0 : bool launched = parent->mSubprocess->Launch(Move(onLaunchedRunnable),
486 0 : aPluginTag->mSandboxLevel);
487 0 : if (!launched) {
488 : // We never reached open
489 0 : parent->mShutdown = true;
490 0 : return nullptr;
491 : }
492 0 : parent->mIsFlashPlugin = aPluginTag->mIsFlashPlugin;
493 : uint32_t blocklistState;
494 0 : nsresult rv = aPluginTag->GetBlocklistState(&blocklistState);
495 0 : parent->mIsBlocklisted = NS_FAILED(rv) || blocklistState != 0;
496 0 : int32_t launchTimeoutSecs = Preferences::GetInt(kLaunchTimeoutPref, 0);
497 0 : if (!parent->mSubprocess->WaitUntilConnected(launchTimeoutSecs * 1000)) {
498 0 : parent->mShutdown = true;
499 0 : return nullptr;
500 : }
501 0 : TimeStamp launchEnd = TimeStamp::Now();
502 0 : parent->mTimeBlocked = (launchEnd - launchStart);
503 0 : return parent.forget();
504 : }
505 :
506 : void
507 0 : PluginModuleChromeParent::OnProcessLaunched(const bool aSucceeded)
508 : {
509 0 : if (!aSucceeded) {
510 0 : mShutdown = true;
511 0 : OnInitFailure();
512 0 : return;
513 : }
514 : // We may have already been initialized by another call that was waiting
515 : // for process connect. If so, this function doesn't need to run.
516 0 : if (mShutdown) {
517 0 : return;
518 : }
519 :
520 0 : Open(mSubprocess->GetChannel(),
521 0 : base::GetProcId(mSubprocess->GetChildProcessHandle()));
522 :
523 : // Request Windows message deferral behavior on our channel. This
524 : // applies to the top level and all sub plugin protocols since they
525 : // all share the same channel.
526 0 : GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
527 :
528 0 : TimeoutChanged(CHILD_TIMEOUT_PREF, this);
529 :
530 0 : Preferences::RegisterCallback(TimeoutChanged, kChildTimeoutPref, this);
531 0 : Preferences::RegisterCallback(TimeoutChanged, kParentTimeoutPref, this);
532 : #ifdef XP_WIN
533 : Preferences::RegisterCallback(TimeoutChanged, kHangUITimeoutPref, this);
534 : Preferences::RegisterCallback(TimeoutChanged, kHangUIMinDisplayPref, this);
535 : #endif
536 :
537 0 : RegisterSettingsCallbacks();
538 :
539 : #ifdef MOZ_CRASHREPORTER
540 : // If this fails, we're having IPC troubles, and we're doomed anyways.
541 0 : if (!InitCrashReporter()) {
542 0 : mShutdown = true;
543 0 : Close();
544 0 : OnInitFailure();
545 0 : return;
546 : }
547 : #endif
548 :
549 : #if defined(XP_WIN) && defined(_X86_)
550 : // Protected mode only applies to Windows and only to x86.
551 : if (!mIsBlocklisted && mIsFlashPlugin &&
552 : (Preferences::GetBool("dom.ipc.plugins.flash.disable-protected-mode", false) ||
553 : mSandboxLevel >= 2)) {
554 : SendDisableFlashProtectedMode();
555 : }
556 : #endif
557 :
558 : #ifdef MOZ_GECKO_PROFILER
559 0 : Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
560 : #endif
561 : }
562 :
563 : bool
564 0 : PluginModuleChromeParent::InitCrashReporter()
565 : {
566 : #ifdef MOZ_CRASHREPORTER
567 0 : ipc::Shmem shmem;
568 0 : if (!ipc::CrashReporterClient::AllocShmem(this, &shmem)) {
569 0 : return false;
570 : }
571 :
572 : NativeThreadId threadId;
573 0 : if (!CallInitCrashReporter(shmem, &threadId)) {
574 0 : return false;
575 : }
576 :
577 : {
578 0 : mozilla::MutexAutoLock lock(mCrashReporterMutex);
579 0 : mCrashReporter = MakeUnique<ipc::CrashReporterHost>(
580 : GeckoProcessType_Plugin,
581 : shmem,
582 0 : threadId);
583 : }
584 : #endif
585 :
586 0 : return true;
587 : }
588 :
589 0 : PluginModuleParent::PluginModuleParent(bool aIsChrome)
590 : : mQuirks(QUIRKS_NOT_INITIALIZED)
591 : , mIsChrome(aIsChrome)
592 : , mShutdown(false)
593 : , mHadLocalInstance(false)
594 : , mClearSiteDataSupported(false)
595 : , mGetSitesWithDataSupported(false)
596 : , mNPNIface(nullptr)
597 : , mNPPIface(nullptr)
598 : , mPlugin(nullptr)
599 : , mTaskFactory(this)
600 : , mSandboxLevel(0)
601 : , mIsFlashPlugin(false)
602 : #ifdef MOZ_CRASHREPORTER
603 0 : , mCrashReporterMutex("PluginModuleChromeParent::mCrashReporterMutex")
604 : #endif
605 : {
606 0 : }
607 :
608 0 : PluginModuleParent::~PluginModuleParent()
609 : {
610 0 : if (!OkToCleanup()) {
611 0 : MOZ_CRASH("unsafe destruction");
612 : }
613 :
614 0 : if (!mShutdown) {
615 0 : NS_WARNING("Plugin host deleted the module without shutting down.");
616 : NPError err;
617 0 : NP_Shutdown(&err);
618 : }
619 0 : }
620 :
621 0 : PluginModuleContentParent::PluginModuleContentParent()
622 0 : : PluginModuleParent(false)
623 : {
624 0 : Preferences::RegisterCallback(TimeoutChanged, kContentTimeoutPref, this);
625 0 : }
626 :
627 0 : PluginModuleContentParent::~PluginModuleContentParent()
628 : {
629 0 : Preferences::UnregisterCallback(TimeoutChanged, kContentTimeoutPref, this);
630 0 : }
631 :
632 0 : PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath,
633 : uint32_t aPluginId,
634 0 : int32_t aSandboxLevel)
635 : : PluginModuleParent(true)
636 0 : , mSubprocess(new PluginProcessParent(aFilePath))
637 : , mPluginId(aPluginId)
638 : , mChromeTaskFactory(this)
639 0 : , mHangAnnotationFlags(0)
640 : #ifdef XP_WIN
641 : , mPluginCpuUsageOnHang()
642 : , mHangUIParent(nullptr)
643 : , mHangUIEnabled(true)
644 : , mIsTimerReset(true)
645 : #endif
646 : #ifdef MOZ_CRASHREPORTER_INJECTOR
647 : , mFlashProcess1(0)
648 : , mFlashProcess2(0)
649 : , mFinishInitTask(nullptr)
650 : #endif
651 : {
652 0 : NS_ASSERTION(mSubprocess, "Out of memory!");
653 0 : mSandboxLevel = aSandboxLevel;
654 0 : mRunID = GeckoChildProcessHost::GetUniqueID();
655 :
656 0 : mozilla::HangMonitor::RegisterAnnotator(*this);
657 0 : }
658 :
659 0 : PluginModuleChromeParent::~PluginModuleChromeParent()
660 : {
661 0 : if (!OkToCleanup()) {
662 0 : MOZ_CRASH("unsafe destruction");
663 : }
664 :
665 : #ifdef XP_WIN
666 : // If we registered for audio notifications, stop.
667 : mozilla::plugins::PluginUtilsWin::RegisterForAudioDeviceChanges(this,
668 : false);
669 : #endif
670 :
671 : #if defined(XP_WIN) && defined(MOZ_SANDBOX)
672 : mSandboxPermissions.RemovePermissionsForProcess(OtherPid());
673 : #endif
674 :
675 0 : if (!mShutdown) {
676 0 : NS_WARNING("Plugin host deleted the module without shutting down.");
677 : NPError err;
678 0 : NP_Shutdown(&err);
679 : }
680 :
681 0 : NS_ASSERTION(mShutdown, "NP_Shutdown didn't");
682 :
683 0 : if (mSubprocess) {
684 0 : mSubprocess->Delete();
685 0 : mSubprocess = nullptr;
686 : }
687 :
688 : #ifdef MOZ_CRASHREPORTER_INJECTOR
689 : if (mFlashProcess1)
690 : UnregisterInjectorCallback(mFlashProcess1);
691 : if (mFlashProcess2)
692 : UnregisterInjectorCallback(mFlashProcess2);
693 : if (mFinishInitTask) {
694 : // mFinishInitTask will be deleted by the main thread message_loop
695 : mFinishInitTask->Cancel();
696 : }
697 : #endif
698 :
699 0 : UnregisterSettingsCallbacks();
700 :
701 0 : Preferences::UnregisterCallback(TimeoutChanged, kChildTimeoutPref, this);
702 0 : Preferences::UnregisterCallback(TimeoutChanged, kParentTimeoutPref, this);
703 : #ifdef XP_WIN
704 : Preferences::UnregisterCallback(TimeoutChanged, kHangUITimeoutPref, this);
705 : Preferences::UnregisterCallback(TimeoutChanged, kHangUIMinDisplayPref, this);
706 :
707 : if (mHangUIParent) {
708 : delete mHangUIParent;
709 : mHangUIParent = nullptr;
710 : }
711 : #endif
712 :
713 0 : mozilla::HangMonitor::UnregisterAnnotator(*this);
714 0 : }
715 :
716 : #ifdef MOZ_CRASHREPORTER
717 : void
718 0 : PluginModuleChromeParent::WriteExtraDataForMinidump()
719 : {
720 : // mCrashReporterMutex is already held by the caller
721 0 : mCrashReporterMutex.AssertCurrentThreadOwns();
722 :
723 : typedef nsDependentCString CS;
724 :
725 : // Get the plugin filename, try to get just the file leafname
726 0 : const std::string& pluginFile = mSubprocess->GetPluginFilePath();
727 0 : size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR);
728 0 : if (filePos == std::string::npos)
729 0 : filePos = 0;
730 : else
731 0 : filePos++;
732 0 : mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginFilename"), CS(pluginFile.substr(filePos).c_str()));
733 :
734 0 : mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginName"), mPluginName);
735 0 : mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginVersion"), mPluginVersion);
736 :
737 0 : if (mCrashReporter) {
738 : #ifdef XP_WIN
739 : if (mPluginCpuUsageOnHang.Length() > 0) {
740 : mCrashReporter->AddNote(NS_LITERAL_CSTRING("NumberOfProcessors"),
741 : nsPrintfCString("%d", PR_GetNumberOfProcessors()));
742 :
743 : nsCString cpuUsageStr;
744 : cpuUsageStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[0] * 100) / 100);
745 : mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginCpuUsage"), cpuUsageStr);
746 :
747 : #ifdef MOZ_CRASHREPORTER_INJECTOR
748 : for (uint32_t i=1; i<mPluginCpuUsageOnHang.Length(); ++i) {
749 : nsCString tempStr;
750 : tempStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[i] * 100) / 100);
751 : mCrashReporter->AddNote(nsPrintfCString("CpuUsageFlashProcess%d", i), tempStr);
752 : }
753 : #endif
754 : }
755 : #endif
756 : }
757 0 : }
758 : #endif // MOZ_CRASHREPORTER
759 :
760 : void
761 0 : PluginModuleParent::SetChildTimeout(const int32_t aChildTimeout)
762 : {
763 0 : int32_t timeoutMs = (aChildTimeout > 0) ? (1000 * aChildTimeout) :
764 0 : MessageChannel::kNoTimeout;
765 0 : SetReplyTimeoutMs(timeoutMs);
766 0 : }
767 :
768 : void
769 0 : PluginModuleParent::TimeoutChanged(const char* aPref, void* aModule)
770 : {
771 0 : PluginModuleParent* module = static_cast<PluginModuleParent*>(aModule);
772 :
773 0 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
774 : #ifndef XP_WIN
775 0 : if (!strcmp(aPref, kChildTimeoutPref)) {
776 0 : MOZ_ASSERT(module->IsChrome());
777 : // The timeout value used by the parent for children
778 0 : int32_t timeoutSecs = Preferences::GetInt(kChildTimeoutPref, 0);
779 0 : module->SetChildTimeout(timeoutSecs);
780 : #else
781 : if (!strcmp(aPref, kChildTimeoutPref) ||
782 : !strcmp(aPref, kHangUIMinDisplayPref) ||
783 : !strcmp(aPref, kHangUITimeoutPref)) {
784 : MOZ_ASSERT(module->IsChrome());
785 : static_cast<PluginModuleChromeParent*>(module)->EvaluateHangUIState(true);
786 : #endif // XP_WIN
787 0 : } else if (!strcmp(aPref, kParentTimeoutPref)) {
788 : // The timeout value used by the child for its parent
789 0 : MOZ_ASSERT(module->IsChrome());
790 0 : int32_t timeoutSecs = Preferences::GetInt(kParentTimeoutPref, 0);
791 0 : Unused << static_cast<PluginModuleChromeParent*>(module)->SendSetParentHangTimeout(timeoutSecs);
792 0 : } else if (!strcmp(aPref, kContentTimeoutPref)) {
793 0 : MOZ_ASSERT(!module->IsChrome());
794 0 : int32_t timeoutSecs = Preferences::GetInt(kContentTimeoutPref, 0);
795 0 : module->SetChildTimeout(timeoutSecs);
796 : }
797 0 : }
798 :
799 : void
800 0 : PluginModuleChromeParent::CleanupFromTimeout(const bool aFromHangUI)
801 : {
802 0 : if (mShutdown) {
803 0 : return;
804 : }
805 :
806 0 : if (!OkToCleanup()) {
807 : // there's still plugin code on the C++ stack, try again
808 0 : MessageLoop::current()->PostDelayedTask(
809 0 : mChromeTaskFactory.NewRunnableMethod(
810 0 : &PluginModuleChromeParent::CleanupFromTimeout, aFromHangUI), 10);
811 0 : return;
812 : }
813 :
814 : /* If the plugin container was terminated by the Plugin Hang UI,
815 : then either the I/O thread detects a channel error, or the
816 : main thread must set the error (whomever gets there first).
817 : OTOH, if we terminate and return false from
818 : ShouldContinueFromReplyTimeout, then the channel state has
819 : already been set to ChannelTimeout and we should call the
820 : regular Close function. */
821 0 : if (aFromHangUI) {
822 0 : GetIPCChannel()->CloseWithError();
823 : } else {
824 0 : Close();
825 : }
826 : }
827 :
828 : #ifdef XP_WIN
829 : namespace {
830 :
831 : uint64_t
832 : FileTimeToUTC(const FILETIME& ftime)
833 : {
834 : ULARGE_INTEGER li;
835 : li.LowPart = ftime.dwLowDateTime;
836 : li.HighPart = ftime.dwHighDateTime;
837 : return li.QuadPart;
838 : }
839 :
840 : struct CpuUsageSamples
841 : {
842 : uint64_t sampleTimes[2];
843 : uint64_t cpuTimes[2];
844 : };
845 :
846 : bool
847 : GetProcessCpuUsage(const InfallibleTArray<base::ProcessHandle>& processHandles, InfallibleTArray<float>& cpuUsage)
848 : {
849 : InfallibleTArray<CpuUsageSamples> samples(processHandles.Length());
850 : FILETIME creationTime, exitTime, kernelTime, userTime, currentTime;
851 : BOOL res;
852 :
853 : for (uint32_t i = 0; i < processHandles.Length(); ++i) {
854 : ::GetSystemTimeAsFileTime(¤tTime);
855 : res = ::GetProcessTimes(processHandles[i], &creationTime, &exitTime, &kernelTime, &userTime);
856 : if (!res) {
857 : NS_WARNING("failed to get process times");
858 : return false;
859 : }
860 :
861 : CpuUsageSamples s;
862 : s.sampleTimes[0] = FileTimeToUTC(currentTime);
863 : s.cpuTimes[0] = FileTimeToUTC(kernelTime) + FileTimeToUTC(userTime);
864 : samples.AppendElement(s);
865 : }
866 :
867 : // we already hung for a while, a little bit longer won't matter
868 : ::Sleep(50);
869 :
870 : const int32_t numberOfProcessors = PR_GetNumberOfProcessors();
871 :
872 : for (uint32_t i = 0; i < processHandles.Length(); ++i) {
873 : ::GetSystemTimeAsFileTime(¤tTime);
874 : res = ::GetProcessTimes(processHandles[i], &creationTime, &exitTime, &kernelTime, &userTime);
875 : if (!res) {
876 : NS_WARNING("failed to get process times");
877 : return false;
878 : }
879 :
880 : samples[i].sampleTimes[1] = FileTimeToUTC(currentTime);
881 : samples[i].cpuTimes[1] = FileTimeToUTC(kernelTime) + FileTimeToUTC(userTime);
882 :
883 : const uint64_t deltaSampleTime = samples[i].sampleTimes[1] - samples[i].sampleTimes[0];
884 : const uint64_t deltaCpuTime = samples[i].cpuTimes[1] - samples[i].cpuTimes[0];
885 : const float usage = 100.f * (float(deltaCpuTime) / deltaSampleTime) / numberOfProcessors;
886 : cpuUsage.AppendElement(usage);
887 : }
888 :
889 : return true;
890 : }
891 :
892 : } // namespace
893 :
894 : #endif // #ifdef XP_WIN
895 :
896 : /**
897 : * This function converts the topmost routing id on the call stack (as recorded
898 : * by the MessageChannel) into a pointer to a IProtocol object.
899 : */
900 : mozilla::ipc::IProtocol*
901 0 : PluginModuleChromeParent::GetInvokingProtocol()
902 : {
903 0 : int32_t routingId = GetIPCChannel()->GetTopmostMessageRoutingId();
904 : // Nothing being routed. No protocol. Just return nullptr.
905 0 : if (routingId == MSG_ROUTING_NONE) {
906 0 : return nullptr;
907 : }
908 : // If routingId is MSG_ROUTING_CONTROL then we're dealing with control
909 : // messages that were initiated by the topmost managing protocol, ie. this.
910 0 : if (routingId == MSG_ROUTING_CONTROL) {
911 0 : return this;
912 : }
913 : // Otherwise we can look up the protocol object by the routing id.
914 0 : mozilla::ipc::IProtocol* protocol = Lookup(routingId);
915 0 : return protocol;
916 : }
917 :
918 : /**
919 : * This function examines the IProtocol object parameter and converts it into
920 : * the PluginInstanceParent object that is associated with that protocol, if
921 : * any. Since PluginInstanceParent manages subprotocols, this function needs
922 : * to determine whether |aProtocol| is a subprotocol, and if so it needs to
923 : * obtain the protocol's manager.
924 : *
925 : * This function needs to be updated if the subprotocols are modified in
926 : * PPluginInstance.ipdl.
927 : */
928 : PluginInstanceParent*
929 0 : PluginModuleChromeParent::GetManagingInstance(mozilla::ipc::IProtocol* aProtocol)
930 : {
931 0 : MOZ_ASSERT(aProtocol);
932 0 : mozilla::ipc::IProtocol* listener = aProtocol;
933 0 : switch (listener->GetProtocolTypeId()) {
934 : case PPluginInstanceMsgStart:
935 : // In this case, aProtocol is the instance itself. Just cast it.
936 0 : return static_cast<PluginInstanceParent*>(aProtocol);
937 : case PPluginBackgroundDestroyerMsgStart: {
938 : PPluginBackgroundDestroyerParent* actor =
939 0 : static_cast<PPluginBackgroundDestroyerParent*>(aProtocol);
940 0 : return static_cast<PluginInstanceParent*>(actor->Manager());
941 : }
942 : case PPluginScriptableObjectMsgStart: {
943 : PPluginScriptableObjectParent* actor =
944 0 : static_cast<PPluginScriptableObjectParent*>(aProtocol);
945 0 : return static_cast<PluginInstanceParent*>(actor->Manager());
946 : }
947 : case PBrowserStreamMsgStart: {
948 : PBrowserStreamParent* actor =
949 0 : static_cast<PBrowserStreamParent*>(aProtocol);
950 0 : return static_cast<PluginInstanceParent*>(actor->Manager());
951 : }
952 : case PStreamNotifyMsgStart: {
953 : PStreamNotifyParent* actor =
954 0 : static_cast<PStreamNotifyParent*>(aProtocol);
955 0 : return static_cast<PluginInstanceParent*>(actor->Manager());
956 : }
957 : #ifdef XP_WIN
958 : case PPluginSurfaceMsgStart: {
959 : PPluginSurfaceParent* actor =
960 : static_cast<PPluginSurfaceParent*>(aProtocol);
961 : return static_cast<PluginInstanceParent*>(actor->Manager());
962 : }
963 : #endif
964 : default:
965 0 : return nullptr;
966 : }
967 : }
968 :
969 : void
970 0 : PluginModuleChromeParent::EnteredCxxStack()
971 : {
972 0 : mHangAnnotationFlags |= kInPluginCall;
973 0 : }
974 :
975 : void
976 0 : PluginModuleChromeParent::ExitedCxxStack()
977 : {
978 0 : mHangAnnotationFlags = 0;
979 : #ifdef XP_WIN
980 : FinishHangUI();
981 : #endif
982 0 : }
983 :
984 : /**
985 : * This function is always called by the HangMonitor thread.
986 : */
987 : void
988 0 : PluginModuleChromeParent::AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations)
989 : {
990 0 : uint32_t flags = mHangAnnotationFlags;
991 0 : if (flags) {
992 : /* We don't actually annotate anything specifically for kInPluginCall;
993 : we use it to determine whether to annotate other things. It will
994 : be pretty obvious from the ChromeHang stack that we're in a plugin
995 : call when the hang occurred. */
996 0 : if (flags & kHangUIShown) {
997 0 : aAnnotations.AddAnnotation(NS_LITERAL_STRING("HangUIShown"),
998 0 : true);
999 : }
1000 0 : if (flags & kHangUIContinued) {
1001 0 : aAnnotations.AddAnnotation(NS_LITERAL_STRING("HangUIContinued"),
1002 0 : true);
1003 : }
1004 0 : if (flags & kHangUIDontShow) {
1005 0 : aAnnotations.AddAnnotation(NS_LITERAL_STRING("HangUIDontShow"),
1006 0 : true);
1007 : }
1008 0 : aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginName"), mPluginName);
1009 0 : aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginVersion"),
1010 0 : mPluginVersion);
1011 : }
1012 0 : }
1013 :
1014 : #ifdef MOZ_CRASHREPORTER
1015 : static bool
1016 0 : CreatePluginMinidump(base::ProcessId processId, ThreadId childThread,
1017 : nsIFile* parentMinidump, const nsACString& name)
1018 : {
1019 0 : mozilla::ipc::ScopedProcessHandle handle;
1020 0 : if (processId == 0 ||
1021 0 : !base::OpenPrivilegedProcessHandle(processId, &handle.rwget())) {
1022 0 : return false;
1023 : }
1024 0 : return CreateAdditionalChildMinidump(handle, 0, parentMinidump, name);
1025 : }
1026 : #endif
1027 :
1028 : bool
1029 0 : PluginModuleChromeParent::ShouldContinueFromReplyTimeout()
1030 : {
1031 0 : if (mIsFlashPlugin) {
1032 0 : MessageLoop::current()->PostTask(
1033 0 : mTaskFactory.NewRunnableMethod(
1034 0 : &PluginModuleChromeParent::NotifyFlashHang));
1035 : }
1036 :
1037 : #ifdef XP_WIN
1038 : if (LaunchHangUI()) {
1039 : return true;
1040 : }
1041 : // If LaunchHangUI returned false then we should proceed with the
1042 : // original plugin hang behaviour and kill the plugin container.
1043 : FinishHangUI();
1044 : #endif // XP_WIN
1045 :
1046 : // Terminate the child process synchronously because this function can be
1047 : // called in sync IPC.
1048 0 : TerminateChildProcess(MessageLoop::current(),
1049 : mozilla::ipc::kInvalidProcessId,
1050 0 : NS_LITERAL_CSTRING("ModalHangUI"),
1051 0 : EmptyString(),
1052 0 : DummyCallback<bool>(),
1053 0 : /* aAsync = */ false);
1054 0 : GetIPCChannel()->CloseWithTimeout();
1055 0 : return false;
1056 : }
1057 :
1058 : bool
1059 0 : PluginModuleContentParent::ShouldContinueFromReplyTimeout()
1060 : {
1061 0 : RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
1062 0 : if (!monitor) {
1063 0 : return true;
1064 : }
1065 0 : monitor->NotifyPluginHang(mPluginId);
1066 0 : return true;
1067 : }
1068 :
1069 : void
1070 0 : PluginModuleContentParent::OnExitedSyncSend()
1071 : {
1072 0 : ProcessHangMonitor::ClearHang();
1073 0 : }
1074 :
1075 : void
1076 0 : PluginModuleChromeParent::TakeFullMinidump(base::ProcessId aContentPid,
1077 : const nsAString& aBrowserDumpId,
1078 : std::function<void(nsString)>&& aCallback,
1079 : bool aAsync)
1080 : {
1081 : #ifdef MOZ_CRASHREPORTER
1082 0 : mozilla::MutexAutoLock lock(mCrashReporterMutex);
1083 :
1084 0 : if (!mCrashReporter || !mTakeFullMinidumpCallback.IsEmpty()) {
1085 0 : aCallback(EmptyString());
1086 0 : return;
1087 : }
1088 0 : mTakeFullMinidumpCallback.Init(Move(aCallback), aAsync);
1089 :
1090 0 : nsString browserDumpId{aBrowserDumpId};
1091 :
1092 : // Check to see if we already have a browser dump id - with e10s plugin
1093 : // hangs we take this earlier (see ProcessHangMonitor) from a background
1094 : // thread. We do this before we message the main thread about the hang
1095 : // since the posted message will trash our browser stack state.
1096 0 : if (CrashReporter::GetMinidumpForID(aBrowserDumpId,
1097 0 : getter_AddRefs(mBrowserDumpFile))) {
1098 :
1099 : // Hold a ref to mPlugin to keep *this* alive until the callback runs.
1100 0 : RetainPluginRef();
1101 : std::function<void(bool)> callback =
1102 0 : [this, aContentPid, browserDumpId, aAsync](bool aResult) {
1103 0 : if (aAsync) {
1104 0 : this->mCrashReporterMutex.Lock();
1105 : }
1106 :
1107 0 : this->TakeBrowserAndPluginMinidumps(aResult,
1108 : aContentPid,
1109 : browserDumpId,
1110 0 : aAsync);
1111 0 : if (aAsync) {
1112 0 : this->mCrashReporterMutex.Unlock();
1113 : }
1114 :
1115 0 : this->ReleasePluginRef();
1116 0 : };
1117 : // We have a single browser report, generate a new plugin process parent
1118 : // report and pair it up with the browser report handed in.
1119 0 : mCrashReporter->GenerateMinidumpAndPair(Process(), mBrowserDumpFile,
1120 0 : NS_LITERAL_CSTRING("browser"),
1121 0 : Move(callback), aAsync);
1122 : } else {
1123 0 : TakeBrowserAndPluginMinidumps(false, aContentPid, browserDumpId, aAsync);
1124 : }
1125 : #else // MOZ_CRASHREPORTER
1126 : aCallback(NS_LITERAL_STRING(""));
1127 : #endif
1128 : }
1129 :
1130 : #ifdef MOZ_CRASHREPORTER
1131 : void
1132 0 : PluginModuleChromeParent::RetainPluginRef()
1133 : {
1134 0 : if (!mPlugin) {
1135 0 : return;
1136 : }
1137 :
1138 0 : if (NS_IsMainThread()) {
1139 0 : mPlugin->AddRef();
1140 : } else {
1141 : // XXX We can't sync-dispatch to the main thread because doing that
1142 : // deadlocks when we are called from
1143 : // PluginHangUIParent::RecvUserResponse().
1144 0 : Unused << NS_DispatchToMainThread(
1145 0 : NewNonOwningRunnableMethod("nsNPAPIPlugin::AddRef",
1146 : mPlugin, &nsNPAPIPlugin::AddRef));
1147 : }
1148 : }
1149 :
1150 : void
1151 0 : PluginModuleChromeParent::ReleasePluginRef()
1152 : {
1153 0 : if (!mPlugin) {
1154 0 : return;
1155 : }
1156 :
1157 0 : if (NS_IsMainThread()) {
1158 0 : mPlugin->Release();
1159 : } else {
1160 : // Async release the reference to mPlugin.
1161 0 : Unused << NS_DispatchToMainThread(
1162 0 : NewNonOwningRunnableMethod("nsNPAPIPlugin::Release",
1163 : mPlugin, &nsNPAPIPlugin::Release));
1164 : }
1165 : }
1166 :
1167 : void
1168 0 : PluginModuleChromeParent::TakeBrowserAndPluginMinidumps(bool aReportsReady,
1169 : base::ProcessId aContentPid,
1170 : const nsAString& aBrowserDumpId,
1171 : bool aAsync)
1172 : {
1173 0 : mCrashReporterMutex.AssertCurrentThreadOwns();
1174 :
1175 : // Generate crash report including plugin and browser process minidumps.
1176 : // The plugin process is the parent report with additional dumps including
1177 : // the browser process, content process when running under e10s, and
1178 : // various flash subprocesses if we're the flash module.
1179 0 : if (!aReportsReady) {
1180 0 : mBrowserDumpFile = nullptr;
1181 0 : CrashReporter::DeleteMinidumpFilesForID(aBrowserDumpId);
1182 :
1183 0 : nsString browserDumpId{aBrowserDumpId};
1184 :
1185 0 : RetainPluginRef();
1186 : std::function<void(bool)> callback =
1187 0 : [this, aContentPid, browserDumpId](bool aResult) {
1188 0 : this->OnTakeFullMinidumpComplete(aResult,
1189 : aContentPid,
1190 0 : browserDumpId);
1191 0 : this->ReleasePluginRef();
1192 0 : };
1193 0 : mCrashReporter->GenerateMinidumpAndPair(Process(),
1194 : nullptr, // Pair with a dump of this process and thread.
1195 0 : NS_LITERAL_CSTRING("browser"),
1196 0 : Move(callback),
1197 0 : aAsync);
1198 : } else {
1199 0 : OnTakeFullMinidumpComplete(aReportsReady, aContentPid, aBrowserDumpId);
1200 : }
1201 0 : }
1202 :
1203 : void
1204 0 : PluginModuleChromeParent::OnTakeFullMinidumpComplete(bool aReportsReady,
1205 : base::ProcessId aContentPid,
1206 : const nsAString& aBrowserDumpId)
1207 : {
1208 0 : mCrashReporterMutex.AssertCurrentThreadOwns();
1209 :
1210 0 : if (aReportsReady) {
1211 0 : nsString dumpId = mCrashReporter->MinidumpID();
1212 0 : PLUGIN_LOG_DEBUG(
1213 : ("generated paired browser/plugin minidumps: %s)",
1214 : NS_ConvertUTF16toUTF8(dumpId).get()));
1215 0 : nsAutoCString additionalDumps("browser");
1216 0 : nsCOMPtr<nsIFile> pluginDumpFile;
1217 0 : if (GetMinidumpForID(dumpId, getter_AddRefs(pluginDumpFile))) {
1218 : #ifdef MOZ_CRASHREPORTER_INJECTOR
1219 : // If we have handles to the flash sandbox processes on Windows,
1220 : // include those minidumps as well.
1221 : if (CreatePluginMinidump(mFlashProcess1, 0, pluginDumpFile,
1222 : NS_LITERAL_CSTRING("flash1"))) {
1223 : additionalDumps.AppendLiteral(",flash1");
1224 : }
1225 : if (CreatePluginMinidump(mFlashProcess2, 0, pluginDumpFile,
1226 : NS_LITERAL_CSTRING("flash2"))) {
1227 : additionalDumps.AppendLiteral(",flash2");
1228 : }
1229 : #endif // MOZ_CRASHREPORTER_INJECTOR
1230 0 : if (aContentPid != mozilla::ipc::kInvalidProcessId) {
1231 : // Include the content process minidump
1232 0 : if (CreatePluginMinidump(aContentPid, 0,
1233 : pluginDumpFile,
1234 0 : NS_LITERAL_CSTRING("content"))) {
1235 0 : additionalDumps.AppendLiteral(",content");
1236 : }
1237 : }
1238 : }
1239 0 : mCrashReporter->AddNote(NS_LITERAL_CSTRING("additional_minidumps"),
1240 0 : additionalDumps);
1241 :
1242 0 : mTakeFullMinidumpCallback.Invoke(mCrashReporter->MinidumpID());
1243 : } else {
1244 0 : mTakeFullMinidumpCallback.Invoke(EmptyString());
1245 0 : NS_WARNING("failed to capture paired minidumps from hang");
1246 : }
1247 0 : }
1248 :
1249 : #endif // MOZ_CRASHREPORTER
1250 :
1251 : void
1252 0 : PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop,
1253 : base::ProcessId aContentPid,
1254 : const nsCString& aMonitorDescription,
1255 : const nsAString& aDumpId,
1256 : std::function<void(bool)>&& aCallback,
1257 : bool aAsync)
1258 : {
1259 0 : if (!mTerminateChildProcessCallback.IsEmpty()) {
1260 0 : aCallback(false);
1261 0 : return;
1262 : }
1263 0 : mTerminateChildProcessCallback.Init(Move(aCallback), aAsync);
1264 :
1265 : #ifdef MOZ_CRASHREPORTER
1266 : // Start by taking a full minidump if necessary, this is done early
1267 : // because it also needs to lock the mCrashReporterMutex and Mutex doesn't
1268 : // support recursive locking.
1269 0 : if (aDumpId.IsEmpty()) {
1270 :
1271 0 : RetainPluginRef();
1272 : std::function<void(nsString)> callback =
1273 0 : [this, aMsgLoop, aMonitorDescription, aAsync](nsString aResult) {
1274 0 : if (aAsync) {
1275 0 : this->mCrashReporterMutex.Lock();
1276 : }
1277 0 : this->TerminateChildProcessOnDumpComplete(aMsgLoop,
1278 0 : aMonitorDescription);
1279 0 : if (aAsync) {
1280 0 : this->mCrashReporterMutex.Unlock();
1281 : }
1282 :
1283 0 : this->ReleasePluginRef();
1284 0 : };
1285 :
1286 0 : TakeFullMinidump(aContentPid, EmptyString(), Move(callback), aAsync);
1287 : } else {
1288 0 : TerminateChildProcessOnDumpComplete(aMsgLoop, aMonitorDescription);
1289 : }
1290 :
1291 : #else
1292 : TerminateChildProcessOnDumpComplete(aMsgLoop, aMonitorDescription);
1293 : #endif
1294 : }
1295 :
1296 : void
1297 0 : PluginModuleChromeParent::TerminateChildProcessOnDumpComplete(MessageLoop* aMsgLoop,
1298 : const nsCString& aMonitorDescription)
1299 : {
1300 : #ifdef MOZ_CRASHREPORTER
1301 0 : mCrashReporterMutex.AssertCurrentThreadOwns();
1302 :
1303 0 : if (!mCrashReporter) {
1304 : // If mCrashReporter is null then the hang has ended, the plugin module
1305 : // is shutting down. There's nothing to do here.
1306 0 : mTerminateChildProcessCallback.Invoke(true);
1307 0 : return;
1308 : }
1309 0 : mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginHang"),
1310 0 : NS_LITERAL_CSTRING("1"));
1311 0 : mCrashReporter->AddNote(NS_LITERAL_CSTRING("HangMonitorDescription"),
1312 0 : aMonitorDescription);
1313 : #ifdef XP_WIN
1314 : if (mHangUIParent) {
1315 : unsigned int hangUIDuration = mHangUIParent->LastShowDurationMs();
1316 : if (hangUIDuration) {
1317 : nsPrintfCString strHangUIDuration("%u", hangUIDuration);
1318 : mCrashReporter->AddNote(
1319 : NS_LITERAL_CSTRING("PluginHangUIDuration"),
1320 : strHangUIDuration);
1321 : }
1322 : }
1323 : #endif // XP_WIN
1324 : #endif // MOZ_CRASHREPORTER
1325 :
1326 0 : mozilla::ipc::ScopedProcessHandle geckoChildProcess;
1327 0 : bool childOpened = base::OpenProcessHandle(OtherPid(),
1328 0 : &geckoChildProcess.rwget());
1329 :
1330 : #ifdef XP_WIN
1331 : // collect cpu usage for plugin processes
1332 :
1333 : InfallibleTArray<base::ProcessHandle> processHandles;
1334 :
1335 : if (childOpened) {
1336 : processHandles.AppendElement(geckoChildProcess);
1337 : }
1338 :
1339 : #ifdef MOZ_CRASHREPORTER_INJECTOR
1340 : mozilla::ipc::ScopedProcessHandle flashBrokerProcess;
1341 : if (mFlashProcess1 &&
1342 : base::OpenProcessHandle(mFlashProcess1, &flashBrokerProcess.rwget())) {
1343 : processHandles.AppendElement(flashBrokerProcess);
1344 : }
1345 : mozilla::ipc::ScopedProcessHandle flashSandboxProcess;
1346 : if (mFlashProcess2 &&
1347 : base::OpenProcessHandle(mFlashProcess2, &flashSandboxProcess.rwget())) {
1348 : processHandles.AppendElement(flashSandboxProcess);
1349 : }
1350 : #endif
1351 :
1352 : if (!GetProcessCpuUsage(processHandles, mPluginCpuUsageOnHang)) {
1353 : mPluginCpuUsageOnHang.Clear();
1354 : }
1355 : #endif // MOZ_CRASHREPORTER
1356 :
1357 : // this must run before the error notification from the channel,
1358 : // or not at all
1359 0 : bool isFromHangUI = aMsgLoop != MessageLoop::current();
1360 0 : aMsgLoop->PostTask(
1361 0 : mChromeTaskFactory.NewRunnableMethod(
1362 0 : &PluginModuleChromeParent::CleanupFromTimeout, isFromHangUI));
1363 :
1364 0 : if (!childOpened || !KillProcess(geckoChildProcess, 1, false)) {
1365 0 : NS_WARNING("failed to kill subprocess!");
1366 : }
1367 :
1368 0 : mTerminateChildProcessCallback.Invoke(true);
1369 : }
1370 :
1371 : bool
1372 0 : PluginModuleParent::GetPluginDetails()
1373 : {
1374 0 : RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
1375 0 : if (!host) {
1376 0 : return false;
1377 : }
1378 0 : nsPluginTag* pluginTag = host->TagForPlugin(mPlugin);
1379 0 : if (!pluginTag) {
1380 0 : return false;
1381 : }
1382 0 : mPluginName = pluginTag->Name();
1383 0 : mPluginVersion = pluginTag->Version();
1384 0 : mPluginFilename = pluginTag->FileName();
1385 0 : mIsFlashPlugin = pluginTag->mIsFlashPlugin;
1386 0 : mSandboxLevel = pluginTag->mSandboxLevel;
1387 0 : return true;
1388 : }
1389 :
1390 : void
1391 0 : PluginModuleParent::InitQuirksModes(const nsCString& aMimeType)
1392 : {
1393 0 : if (mQuirks != QUIRKS_NOT_INITIALIZED) {
1394 0 : return;
1395 : }
1396 :
1397 0 : mQuirks = GetQuirksFromMimeTypeAndFilename(aMimeType, mPluginFilename);
1398 : }
1399 :
1400 : #ifdef XP_WIN
1401 : void
1402 : PluginModuleChromeParent::EvaluateHangUIState(const bool aReset)
1403 : {
1404 : int32_t minDispSecs = Preferences::GetInt(kHangUIMinDisplayPref, 10);
1405 : int32_t autoStopSecs = Preferences::GetInt(kChildTimeoutPref, 0);
1406 : int32_t timeoutSecs = 0;
1407 : if (autoStopSecs > 0 && autoStopSecs < minDispSecs) {
1408 : /* If we're going to automatically terminate the plugin within a
1409 : time frame shorter than minDispSecs, there's no point in
1410 : showing the hang UI; it would just flash briefly on the screen. */
1411 : mHangUIEnabled = false;
1412 : } else {
1413 : timeoutSecs = Preferences::GetInt(kHangUITimeoutPref, 0);
1414 : mHangUIEnabled = timeoutSecs > 0;
1415 : }
1416 : if (mHangUIEnabled) {
1417 : if (aReset) {
1418 : mIsTimerReset = true;
1419 : SetChildTimeout(timeoutSecs);
1420 : return;
1421 : } else if (mIsTimerReset) {
1422 : /* The Hang UI is being shown, so now we're setting the
1423 : timeout to kChildTimeoutPref while we wait for a user
1424 : response. ShouldContinueFromReplyTimeout will fire
1425 : after (reply timeout / 2) seconds, which is not what
1426 : we want. Doubling the timeout value here so that we get
1427 : the right result. */
1428 : autoStopSecs *= 2;
1429 : }
1430 : }
1431 : mIsTimerReset = false;
1432 : SetChildTimeout(autoStopSecs);
1433 : }
1434 :
1435 : bool
1436 : PluginModuleChromeParent::LaunchHangUI()
1437 : {
1438 : if (!mHangUIEnabled) {
1439 : return false;
1440 : }
1441 : if (mHangUIParent) {
1442 : if (mHangUIParent->IsShowing()) {
1443 : // We've already shown the UI but the timeout has expired again.
1444 : return false;
1445 : }
1446 : if (mHangUIParent->DontShowAgain()) {
1447 : mHangAnnotationFlags |= kHangUIDontShow;
1448 : bool wasLastHangStopped = mHangUIParent->WasLastHangStopped();
1449 : if (!wasLastHangStopped) {
1450 : mHangAnnotationFlags |= kHangUIContinued;
1451 : }
1452 : return !wasLastHangStopped;
1453 : }
1454 : delete mHangUIParent;
1455 : mHangUIParent = nullptr;
1456 : }
1457 : mHangUIParent = new PluginHangUIParent(this,
1458 : Preferences::GetInt(kHangUITimeoutPref, 0),
1459 : Preferences::GetInt(kChildTimeoutPref, 0));
1460 : bool retval = mHangUIParent->Init(NS_ConvertUTF8toUTF16(mPluginName));
1461 : if (retval) {
1462 : mHangAnnotationFlags |= kHangUIShown;
1463 : /* Once the UI is shown we switch the timeout over to use
1464 : kChildTimeoutPref, allowing us to terminate a hung plugin
1465 : after kChildTimeoutPref seconds if the user doesn't respond to
1466 : the hang UI. */
1467 : EvaluateHangUIState(false);
1468 : }
1469 : return retval;
1470 : }
1471 :
1472 : void
1473 : PluginModuleChromeParent::FinishHangUI()
1474 : {
1475 : if (mHangUIEnabled && mHangUIParent) {
1476 : bool needsCancel = mHangUIParent->IsShowing();
1477 : // If we're still showing, send a Cancel notification
1478 : if (needsCancel) {
1479 : mHangUIParent->Cancel();
1480 : }
1481 : /* If we cancelled the UI or if the user issued a response,
1482 : we need to reset the child process timeout. */
1483 : if (needsCancel ||
1484 : (!mIsTimerReset && mHangUIParent->WasShown())) {
1485 : /* We changed the timeout to kChildTimeoutPref when the plugin hang
1486 : UI was displayed. Now that we're finishing the UI, we need to
1487 : switch it back to kHangUITimeoutPref. */
1488 : EvaluateHangUIState(true);
1489 : }
1490 : }
1491 : }
1492 :
1493 : void
1494 : PluginModuleChromeParent::OnHangUIContinue()
1495 : {
1496 : mHangAnnotationFlags |= kHangUIContinued;
1497 : }
1498 : #endif // XP_WIN
1499 :
1500 : #ifdef MOZ_CRASHREPORTER
1501 : #ifdef MOZ_CRASHREPORTER_INJECTOR
1502 : static void
1503 : RemoveMinidump(nsIFile* minidump)
1504 : {
1505 : if (!minidump)
1506 : return;
1507 :
1508 : minidump->Remove(false);
1509 : nsCOMPtr<nsIFile> extraFile;
1510 : if (GetExtraFileForMinidump(minidump,
1511 : getter_AddRefs(extraFile))) {
1512 : extraFile->Remove(true);
1513 : }
1514 : }
1515 : #endif // MOZ_CRASHREPORTER_INJECTOR
1516 :
1517 : void
1518 0 : PluginModuleChromeParent::ProcessFirstMinidump()
1519 : {
1520 0 : mozilla::MutexAutoLock lock(mCrashReporterMutex);
1521 :
1522 0 : if (!mCrashReporter)
1523 0 : return;
1524 :
1525 0 : WriteExtraDataForMinidump();
1526 :
1527 0 : if (mCrashReporter->HasMinidump()) {
1528 : // A minidump may be set in TerminateChildProcess, which means the
1529 : // process hang monitor has already collected a 3-way browser, plugin,
1530 : // content crash report. If so, update the existing report with our
1531 : // annotations and finalize it. If not, fall through for standard
1532 : // plugin crash report handling.
1533 0 : mCrashReporter->FinalizeCrashReport();
1534 0 : return;
1535 : }
1536 :
1537 0 : uint32_t sequence = UINT32_MAX;
1538 0 : nsAutoCString flashProcessType;
1539 0 : RefPtr<nsIFile> dumpFile = mCrashReporter->TakeCrashedChildMinidump(OtherPid(), &sequence);
1540 :
1541 : #ifdef MOZ_CRASHREPORTER_INJECTOR
1542 : nsCOMPtr<nsIFile> childDumpFile;
1543 : uint32_t childSequence;
1544 :
1545 : if (mFlashProcess1 &&
1546 : TakeMinidumpForChild(mFlashProcess1,
1547 : getter_AddRefs(childDumpFile),
1548 : &childSequence)) {
1549 : if (childSequence < sequence &&
1550 : mCrashReporter->AdoptMinidump(childDumpFile))
1551 : {
1552 : RemoveMinidump(dumpFile);
1553 : dumpFile = childDumpFile;
1554 : sequence = childSequence;
1555 : flashProcessType.AssignLiteral("Broker");
1556 : }
1557 : else {
1558 : RemoveMinidump(childDumpFile);
1559 : }
1560 : }
1561 : if (mFlashProcess2 &&
1562 : TakeMinidumpForChild(mFlashProcess2,
1563 : getter_AddRefs(childDumpFile),
1564 : &childSequence)) {
1565 : if (childSequence < sequence &&
1566 : mCrashReporter->AdoptMinidump(childDumpFile))
1567 : {
1568 : RemoveMinidump(dumpFile);
1569 : dumpFile = childDumpFile;
1570 : sequence = childSequence;
1571 : flashProcessType.AssignLiteral("Sandbox");
1572 : }
1573 : else {
1574 : RemoveMinidump(childDumpFile);
1575 : }
1576 : }
1577 : #endif
1578 :
1579 0 : if (!dumpFile) {
1580 0 : NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
1581 0 : return;
1582 : }
1583 :
1584 0 : PLUGIN_LOG_DEBUG(("got child minidump: %s",
1585 : NS_ConvertUTF16toUTF8(mCrashReporter->MinidumpID()).get()));
1586 :
1587 0 : if (!flashProcessType.IsEmpty()) {
1588 0 : mCrashReporter->AddNote(NS_LITERAL_CSTRING("FlashProcessDump"), flashProcessType);
1589 : }
1590 0 : mCrashReporter->FinalizeCrashReport();
1591 : }
1592 : #endif
1593 :
1594 : void
1595 0 : PluginModuleParent::ActorDestroy(ActorDestroyReason why)
1596 : {
1597 0 : switch (why) {
1598 : case AbnormalShutdown: {
1599 0 : mShutdown = true;
1600 : // Defer the PluginCrashed method so that we don't re-enter
1601 : // and potentially modify the actor child list while enumerating it.
1602 0 : if (mPlugin)
1603 0 : MessageLoop::current()->PostTask(
1604 0 : mTaskFactory.NewRunnableMethod(
1605 0 : &PluginModuleParent::NotifyPluginCrashed));
1606 0 : break;
1607 : }
1608 : case NormalShutdown:
1609 0 : mShutdown = true;
1610 0 : break;
1611 :
1612 : default:
1613 0 : MOZ_CRASH("Unexpected shutdown reason for toplevel actor.");
1614 : }
1615 0 : }
1616 :
1617 : nsresult
1618 0 : PluginModuleParent::GetRunID(uint32_t* aRunID)
1619 : {
1620 0 : if (NS_WARN_IF(!aRunID)) {
1621 0 : return NS_ERROR_INVALID_POINTER;
1622 : }
1623 0 : *aRunID = mRunID;
1624 0 : return NS_OK;
1625 : }
1626 :
1627 : void
1628 0 : PluginModuleChromeParent::ActorDestroy(ActorDestroyReason why)
1629 : {
1630 0 : if (why == AbnormalShutdown) {
1631 : #ifdef MOZ_CRASHREPORTER
1632 0 : ProcessFirstMinidump();
1633 : #endif
1634 0 : Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
1635 0 : NS_LITERAL_CSTRING("plugin"), 1);
1636 : }
1637 :
1638 : // We can't broadcast settings changes anymore.
1639 0 : UnregisterSettingsCallbacks();
1640 :
1641 0 : PluginModuleParent::ActorDestroy(why);
1642 0 : }
1643 :
1644 : void
1645 0 : PluginModuleParent::NotifyFlashHang()
1646 : {
1647 0 : nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
1648 0 : if (obs) {
1649 0 : obs->NotifyObservers(nullptr, "flash-plugin-hang", nullptr);
1650 : }
1651 0 : }
1652 :
1653 : void
1654 0 : PluginModuleParent::NotifyPluginCrashed()
1655 : {
1656 0 : if (!OkToCleanup()) {
1657 : // there's still plugin code on the C++ stack. try again
1658 0 : MessageLoop::current()->PostDelayedTask(
1659 0 : mTaskFactory.NewRunnableMethod(
1660 0 : &PluginModuleParent::NotifyPluginCrashed), 10);
1661 0 : return;
1662 : }
1663 :
1664 0 : if (!mPlugin) {
1665 0 : return;
1666 : }
1667 :
1668 0 : nsString dumpID;
1669 0 : nsString browserDumpID;
1670 : #ifdef MOZ_CRASHREPORTER
1671 0 : if (mCrashReporter && mCrashReporter->HasMinidump()) {
1672 0 : dumpID = mCrashReporter->MinidumpID();
1673 : }
1674 : #endif
1675 0 : mPlugin->PluginCrashed(dumpID, browserDumpID);
1676 : }
1677 :
1678 : PPluginInstanceParent*
1679 0 : PluginModuleParent::AllocPPluginInstanceParent(const nsCString& aMimeType,
1680 : const InfallibleTArray<nsCString>& aNames,
1681 : const InfallibleTArray<nsCString>& aValues)
1682 : {
1683 0 : NS_ERROR("Not reachable!");
1684 0 : return nullptr;
1685 : }
1686 :
1687 : bool
1688 0 : PluginModuleParent::DeallocPPluginInstanceParent(PPluginInstanceParent* aActor)
1689 : {
1690 0 : PLUGIN_LOG_DEBUG_METHOD;
1691 0 : delete aActor;
1692 0 : return true;
1693 : }
1694 :
1695 : void
1696 0 : PluginModuleParent::SetPluginFuncs(NPPluginFuncs* aFuncs)
1697 : {
1698 0 : MOZ_ASSERT(aFuncs);
1699 :
1700 0 : aFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
1701 0 : aFuncs->javaClass = nullptr;
1702 :
1703 : // Gecko should always call these functions through a PluginLibrary object.
1704 0 : aFuncs->newp = nullptr;
1705 0 : aFuncs->clearsitedata = nullptr;
1706 0 : aFuncs->getsiteswithdata = nullptr;
1707 :
1708 0 : aFuncs->destroy = NPP_Destroy;
1709 0 : aFuncs->setwindow = NPP_SetWindow;
1710 0 : aFuncs->newstream = NPP_NewStream;
1711 0 : aFuncs->destroystream = NPP_DestroyStream;
1712 0 : aFuncs->asfile = NPP_StreamAsFile;
1713 0 : aFuncs->writeready = NPP_WriteReady;
1714 0 : aFuncs->write = NPP_Write;
1715 0 : aFuncs->print = NPP_Print;
1716 0 : aFuncs->event = NPP_HandleEvent;
1717 0 : aFuncs->urlnotify = NPP_URLNotify;
1718 0 : aFuncs->getvalue = NPP_GetValue;
1719 0 : aFuncs->setvalue = NPP_SetValue;
1720 0 : aFuncs->gotfocus = nullptr;
1721 0 : aFuncs->lostfocus = nullptr;
1722 0 : aFuncs->urlredirectnotify = nullptr;
1723 :
1724 : // Provide 'NPP_URLRedirectNotify', 'NPP_ClearSiteData', and
1725 : // 'NPP_GetSitesWithData' functionality if it is supported by the plugin.
1726 0 : bool urlRedirectSupported = false;
1727 0 : Unused << CallOptionalFunctionsSupported(&urlRedirectSupported,
1728 : &mClearSiteDataSupported,
1729 : &mGetSitesWithDataSupported);
1730 0 : if (urlRedirectSupported) {
1731 0 : aFuncs->urlredirectnotify = NPP_URLRedirectNotify;
1732 : }
1733 0 : }
1734 :
1735 : NPError
1736 0 : PluginModuleParent::NPP_Destroy(NPP instance,
1737 : NPSavedData** saved)
1738 : {
1739 : // FIXME/cjones:
1740 : // (1) send a "destroy" message to the child
1741 : // (2) the child shuts down its instance
1742 : // (3) remove both parent and child IDs from map
1743 : // (4) free parent
1744 :
1745 0 : PLUGIN_LOG_DEBUG_FUNCTION;
1746 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1747 0 : if (!pip)
1748 0 : return NPERR_NO_ERROR;
1749 :
1750 0 : NPError retval = pip->Destroy();
1751 0 : instance->pdata = nullptr;
1752 :
1753 0 : Unused << PluginInstanceParent::Call__delete__(pip);
1754 0 : return retval;
1755 : }
1756 :
1757 : NPError
1758 0 : PluginModuleParent::NPP_NewStream(NPP instance, NPMIMEType type,
1759 : NPStream* stream, NPBool seekable,
1760 : uint16_t* stype)
1761 : {
1762 0 : AUTO_PROFILER_LABEL("PluginModuleParent::NPP_NewStream", OTHER);
1763 :
1764 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1765 0 : return pip ? pip->NPP_NewStream(type, stream, seekable, stype)
1766 0 : : NPERR_GENERIC_ERROR;
1767 : }
1768 :
1769 : NPError
1770 0 : PluginModuleParent::NPP_SetWindow(NPP instance, NPWindow* window)
1771 : {
1772 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1773 0 : return pip ? pip->NPP_SetWindow(window) : NPERR_GENERIC_ERROR;
1774 : }
1775 :
1776 : NPError
1777 0 : PluginModuleParent::NPP_DestroyStream(NPP instance,
1778 : NPStream* stream,
1779 : NPReason reason)
1780 : {
1781 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1782 0 : return pip ? pip->NPP_DestroyStream(stream, reason) : NPERR_GENERIC_ERROR;
1783 : }
1784 :
1785 : int32_t
1786 0 : PluginModuleParent::NPP_WriteReady(NPP instance,
1787 : NPStream* stream)
1788 : {
1789 0 : BrowserStreamParent* s = StreamCast(instance, stream);
1790 0 : return s ? s->WriteReady() : -1;
1791 : }
1792 :
1793 : int32_t
1794 0 : PluginModuleParent::NPP_Write(NPP instance,
1795 : NPStream* stream,
1796 : int32_t offset,
1797 : int32_t len,
1798 : void* buffer)
1799 : {
1800 0 : BrowserStreamParent* s = StreamCast(instance, stream);
1801 0 : if (!s)
1802 0 : return -1;
1803 :
1804 0 : return s->Write(offset, len, buffer);
1805 : }
1806 :
1807 : void
1808 0 : PluginModuleParent::NPP_StreamAsFile(NPP instance,
1809 : NPStream* stream,
1810 : const char* fname)
1811 : {
1812 0 : BrowserStreamParent* s = StreamCast(instance, stream);
1813 0 : if (!s)
1814 0 : return;
1815 :
1816 0 : s->StreamAsFile(fname);
1817 : }
1818 :
1819 : void
1820 0 : PluginModuleParent::NPP_Print(NPP instance, NPPrint* platformPrint)
1821 : {
1822 :
1823 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1824 0 : return pip ? pip->NPP_Print(platformPrint) : (void)0;
1825 : }
1826 :
1827 : int16_t
1828 0 : PluginModuleParent::NPP_HandleEvent(NPP instance, void* event)
1829 : {
1830 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1831 0 : return pip ? pip->NPP_HandleEvent(event) : NPERR_GENERIC_ERROR;
1832 : }
1833 :
1834 : void
1835 0 : PluginModuleParent::NPP_URLNotify(NPP instance, const char* url,
1836 : NPReason reason, void* notifyData)
1837 : {
1838 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1839 0 : return pip ? pip->NPP_URLNotify(url, reason, notifyData) : (void)0;
1840 : }
1841 :
1842 : NPError
1843 0 : PluginModuleParent::NPP_GetValue(NPP instance,
1844 : NPPVariable variable, void *ret_value)
1845 : {
1846 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1847 0 : return pip ? pip->NPP_GetValue(variable, ret_value) : NPERR_GENERIC_ERROR;
1848 : }
1849 :
1850 : NPError
1851 0 : PluginModuleParent::NPP_SetValue(NPP instance, NPNVariable variable,
1852 : void *value)
1853 : {
1854 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1855 0 : return pip ? pip->NPP_SetValue(variable, value) : NPERR_GENERIC_ERROR;
1856 : }
1857 :
1858 : mozilla::ipc::IPCResult
1859 0 : PluginModuleChromeParent::AnswerNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
1860 : const bool& shouldRegister, NPError* result)
1861 : {
1862 : #ifdef XP_WIN
1863 : *result = NPERR_NO_ERROR;
1864 : nsresult err =
1865 : mozilla::plugins::PluginUtilsWin::RegisterForAudioDeviceChanges(this,
1866 : shouldRegister);
1867 : if (err != NS_OK) {
1868 : *result = NPERR_GENERIC_ERROR;
1869 : }
1870 : return IPC_OK();
1871 : #else
1872 0 : NS_RUNTIMEABORT("NPPVpluginRequiresAudioDeviceChanges is not valid on this platform.");
1873 0 : *result = NPERR_GENERIC_ERROR;
1874 0 : return IPC_OK();
1875 : #endif
1876 : }
1877 :
1878 : mozilla::ipc::IPCResult
1879 0 : PluginModuleParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd)
1880 : {
1881 : #ifndef MOZ_X11
1882 : MOZ_CRASH("This message only makes sense on X11 platforms");
1883 : #else
1884 0 : MOZ_ASSERT(0 > mPluginXSocketFdDup.get(),
1885 : "Already backed up X resources??");
1886 0 : if (aXSocketFd.IsValid()) {
1887 0 : auto rawFD = aXSocketFd.ClonePlatformHandle();
1888 0 : mPluginXSocketFdDup.reset(rawFD.release());
1889 : }
1890 : #endif
1891 0 : return IPC_OK();
1892 : }
1893 :
1894 : void
1895 0 : PluginModuleParent::NPP_URLRedirectNotify(NPP instance, const char* url,
1896 : int32_t status, void* notifyData)
1897 : {
1898 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1899 0 : return pip ? pip->NPP_URLRedirectNotify(url, status, notifyData) : (void)0;
1900 : }
1901 :
1902 : BrowserStreamParent*
1903 0 : PluginModuleParent::StreamCast(NPP instance, NPStream* s)
1904 : {
1905 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1906 0 : if (!pip) {
1907 0 : return nullptr;
1908 : }
1909 :
1910 : BrowserStreamParent* sp =
1911 0 : static_cast<BrowserStreamParent*>(static_cast<AStream*>(s->pdata));
1912 0 : if (sp && (sp->mNPP != pip || s != sp->mStream)) {
1913 0 : MOZ_CRASH("Corrupted plugin stream data.");
1914 : }
1915 0 : return sp;
1916 : }
1917 :
1918 : bool
1919 0 : PluginModuleParent::HasRequiredFunctions()
1920 : {
1921 0 : return true;
1922 : }
1923 :
1924 : nsresult
1925 0 : PluginModuleParent::AsyncSetWindow(NPP instance, NPWindow* window)
1926 : {
1927 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1928 0 : return pip ? pip->AsyncSetWindow(window) : NS_ERROR_FAILURE;
1929 : }
1930 :
1931 : nsresult
1932 0 : PluginModuleParent::GetImageContainer(NPP instance,
1933 : mozilla::layers::ImageContainer** aContainer)
1934 : {
1935 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1936 0 : return pip ? pip->GetImageContainer(aContainer) : NS_ERROR_FAILURE;
1937 : }
1938 :
1939 : nsresult
1940 0 : PluginModuleParent::GetImageSize(NPP instance,
1941 : nsIntSize* aSize)
1942 : {
1943 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1944 0 : return pip ? pip->GetImageSize(aSize) : NS_ERROR_FAILURE;
1945 : }
1946 :
1947 : void
1948 0 : PluginModuleParent::DidComposite(NPP aInstance)
1949 : {
1950 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(aInstance);
1951 0 : return pip ? pip->DidComposite() : (void)0;
1952 : }
1953 :
1954 : nsresult
1955 0 : PluginModuleParent::SetBackgroundUnknown(NPP instance)
1956 : {
1957 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1958 0 : return pip ? pip->SetBackgroundUnknown() : NS_ERROR_FAILURE;
1959 : }
1960 :
1961 : nsresult
1962 0 : PluginModuleParent::BeginUpdateBackground(NPP instance,
1963 : const nsIntRect& aRect,
1964 : DrawTarget** aDrawTarget)
1965 : {
1966 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1967 0 : return pip ? pip->BeginUpdateBackground(aRect, aDrawTarget)
1968 0 : : NS_ERROR_FAILURE;
1969 : }
1970 :
1971 : nsresult
1972 0 : PluginModuleParent::EndUpdateBackground(NPP instance, const nsIntRect& aRect)
1973 : {
1974 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1975 0 : return pip ? pip->EndUpdateBackground(aRect) : NS_ERROR_FAILURE;
1976 : }
1977 :
1978 : #if defined(XP_WIN)
1979 : nsresult
1980 : PluginModuleParent::GetScrollCaptureContainer(NPP aInstance,
1981 : mozilla::layers::ImageContainer** aContainer)
1982 : {
1983 : PluginInstanceParent* pip = PluginInstanceParent::Cast(aInstance);
1984 : return pip ? pip->GetScrollCaptureContainer(aContainer) : NS_ERROR_FAILURE;
1985 : }
1986 : #endif
1987 :
1988 : nsresult
1989 0 : PluginModuleParent::HandledWindowedPluginKeyEvent(
1990 : NPP aInstance,
1991 : const NativeEventData& aNativeKeyData,
1992 : bool aIsConsumed)
1993 : {
1994 0 : PluginInstanceParent* pip = PluginInstanceParent::Cast(aInstance);
1995 0 : return pip ? pip->HandledWindowedPluginKeyEvent(aNativeKeyData, aIsConsumed)
1996 0 : : NS_ERROR_FAILURE;
1997 : }
1998 :
1999 : void
2000 0 : PluginModuleParent::OnInitFailure()
2001 : {
2002 0 : if (GetIPCChannel()->CanSend()) {
2003 0 : Close();
2004 : }
2005 :
2006 0 : mShutdown = true;
2007 0 : }
2008 :
2009 : class PluginOfflineObserver final : public nsIObserver
2010 : {
2011 : public:
2012 : NS_DECL_ISUPPORTS
2013 : NS_DECL_NSIOBSERVER
2014 :
2015 0 : explicit PluginOfflineObserver(PluginModuleChromeParent* pmp)
2016 0 : : mPmp(pmp)
2017 0 : {}
2018 :
2019 : private:
2020 0 : ~PluginOfflineObserver() {}
2021 : PluginModuleChromeParent* mPmp;
2022 : };
2023 :
2024 0 : NS_IMPL_ISUPPORTS(PluginOfflineObserver, nsIObserver)
2025 :
2026 : NS_IMETHODIMP
2027 0 : PluginOfflineObserver::Observe(nsISupports *aSubject,
2028 : const char *aTopic,
2029 : const char16_t *aData)
2030 : {
2031 0 : MOZ_ASSERT(!strcmp(aTopic, "ipc:network:set-offline"));
2032 0 : mPmp->CachedSettingChanged();
2033 0 : return NS_OK;
2034 : }
2035 :
2036 : static const char* kSettingsPrefs[] =
2037 : {"javascript.enabled",
2038 : "dom.ipc.plugins.nativeCursorSupport"};
2039 :
2040 : void
2041 0 : PluginModuleChromeParent::RegisterSettingsCallbacks()
2042 : {
2043 0 : for (size_t i = 0; i < ArrayLength(kSettingsPrefs); i++) {
2044 0 : Preferences::RegisterCallback(CachedSettingChanged, kSettingsPrefs[i], this);
2045 : }
2046 :
2047 0 : nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
2048 0 : if (observerService) {
2049 0 : mPluginOfflineObserver = new PluginOfflineObserver(this);
2050 0 : observerService->AddObserver(mPluginOfflineObserver, "ipc:network:set-offline", false);
2051 : }
2052 0 : }
2053 :
2054 : void
2055 0 : PluginModuleChromeParent::UnregisterSettingsCallbacks()
2056 : {
2057 0 : for (size_t i = 0; i < ArrayLength(kSettingsPrefs); i++) {
2058 0 : Preferences::UnregisterCallback(CachedSettingChanged, kSettingsPrefs[i], this);
2059 : }
2060 :
2061 0 : nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
2062 0 : if (observerService) {
2063 0 : observerService->RemoveObserver(mPluginOfflineObserver, "ipc:network:set-offline");
2064 0 : mPluginOfflineObserver = nullptr;
2065 : }
2066 0 : }
2067 :
2068 : bool
2069 0 : PluginModuleParent::GetSetting(NPNVariable aVariable)
2070 : {
2071 0 : NPBool boolVal = false;
2072 0 : mozilla::plugins::parent::_getvalue(nullptr, aVariable, &boolVal);
2073 0 : return boolVal;
2074 : }
2075 :
2076 : void
2077 0 : PluginModuleParent::GetSettings(PluginSettings* aSettings)
2078 : {
2079 0 : aSettings->javascriptEnabled() = GetSetting(NPNVjavascriptEnabledBool);
2080 0 : aSettings->asdEnabled() = GetSetting(NPNVasdEnabledBool);
2081 0 : aSettings->isOffline() = GetSetting(NPNVisOfflineBool);
2082 0 : aSettings->supportsXembed() = GetSetting(NPNVSupportsXEmbedBool);
2083 0 : aSettings->supportsWindowless() = GetSetting(NPNVSupportsWindowless);
2084 0 : aSettings->userAgent() = NullableString(mNPNIface->uagent(nullptr));
2085 :
2086 : #if defined(XP_MACOSX)
2087 : aSettings->nativeCursorsSupported() =
2088 : Preferences::GetBool("dom.ipc.plugins.nativeCursorSupport", false);
2089 : #else
2090 : // Need to initialize this to satisfy IPDL.
2091 0 : aSettings->nativeCursorsSupported() = false;
2092 : #endif
2093 0 : }
2094 :
2095 : void
2096 0 : PluginModuleChromeParent::CachedSettingChanged()
2097 : {
2098 0 : PluginSettings settings;
2099 0 : GetSettings(&settings);
2100 0 : Unused << SendSettingChanged(settings);
2101 0 : }
2102 :
2103 : /* static */ void
2104 0 : PluginModuleChromeParent::CachedSettingChanged(const char* aPref, void* aModule)
2105 : {
2106 0 : PluginModuleChromeParent *module = static_cast<PluginModuleChromeParent*>(aModule);
2107 0 : module->CachedSettingChanged();
2108 0 : }
2109 :
2110 : #if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK)
2111 : nsresult
2112 0 : PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error)
2113 : {
2114 0 : PLUGIN_LOG_DEBUG_METHOD;
2115 :
2116 0 : mNPNIface = bFuncs;
2117 0 : mNPPIface = pFuncs;
2118 :
2119 0 : if (mShutdown) {
2120 0 : *error = NPERR_GENERIC_ERROR;
2121 0 : return NS_ERROR_FAILURE;
2122 : }
2123 :
2124 0 : *error = NPERR_NO_ERROR;
2125 0 : SetPluginFuncs(pFuncs);
2126 :
2127 0 : return NS_OK;
2128 : }
2129 :
2130 : nsresult
2131 0 : PluginModuleChromeParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error)
2132 : {
2133 0 : PLUGIN_LOG_DEBUG_METHOD;
2134 :
2135 0 : if (mShutdown) {
2136 0 : *error = NPERR_GENERIC_ERROR;
2137 0 : return NS_ERROR_FAILURE;
2138 : }
2139 :
2140 0 : *error = NPERR_NO_ERROR;
2141 :
2142 0 : mNPNIface = bFuncs;
2143 0 : mNPPIface = pFuncs;
2144 :
2145 0 : PluginSettings settings;
2146 0 : GetSettings(&settings);
2147 :
2148 0 : TimeStamp callNpInitStart = TimeStamp::Now();
2149 0 : if (!CallNP_Initialize(settings, error)) {
2150 0 : Close();
2151 0 : return NS_ERROR_FAILURE;
2152 : }
2153 0 : else if (*error != NPERR_NO_ERROR) {
2154 0 : Close();
2155 0 : return NS_ERROR_FAILURE;
2156 : }
2157 0 : TimeStamp callNpInitEnd = TimeStamp::Now();
2158 0 : mTimeBlocked += (callNpInitEnd - callNpInitStart);
2159 :
2160 0 : if (*error != NPERR_NO_ERROR) {
2161 0 : OnInitFailure();
2162 0 : return NS_OK;
2163 : }
2164 :
2165 0 : SetPluginFuncs(mNPPIface);
2166 :
2167 0 : return NS_OK;
2168 : }
2169 :
2170 : #else
2171 :
2172 : nsresult
2173 : PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
2174 : {
2175 : PLUGIN_LOG_DEBUG_METHOD;
2176 :
2177 : mNPNIface = bFuncs;
2178 :
2179 : if (mShutdown) {
2180 : *error = NPERR_GENERIC_ERROR;
2181 : return NS_ERROR_FAILURE;
2182 : }
2183 :
2184 : *error = NPERR_NO_ERROR;
2185 : return NS_OK;
2186 : }
2187 :
2188 : #if defined(XP_WIN) || defined(XP_MACOSX)
2189 :
2190 : nsresult
2191 : PluginModuleContentParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
2192 : {
2193 : PLUGIN_LOG_DEBUG_METHOD;
2194 : return PluginModuleParent::NP_Initialize(bFuncs, error);
2195 : }
2196 :
2197 : #endif
2198 :
2199 : nsresult
2200 : PluginModuleChromeParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
2201 : {
2202 : nsresult rv = PluginModuleParent::NP_Initialize(bFuncs, error);
2203 : if (NS_FAILED(rv))
2204 : return rv;
2205 :
2206 : PluginSettings settings;
2207 : GetSettings(&settings);
2208 :
2209 : TimeStamp callNpInitStart = TimeStamp::Now();
2210 : if (!CallNP_Initialize(settings, error)) {
2211 : Close();
2212 : return NS_ERROR_FAILURE;
2213 : }
2214 : TimeStamp callNpInitEnd = TimeStamp::Now();
2215 : mTimeBlocked += (callNpInitEnd - callNpInitStart);
2216 :
2217 : bool ok = true;
2218 : if (*error == NPERR_NO_ERROR) {
2219 : // Initialization steps for (e10s && !asyncInit) || !e10s
2220 : #if defined XP_WIN
2221 : // Send the info needed to join the browser process's audio session to
2222 : // the plugin process.
2223 : nsID id;
2224 : nsString sessionName;
2225 : nsString iconPath;
2226 :
2227 : if (NS_SUCCEEDED(mozilla::widget::GetAudioSessionData(id, sessionName,
2228 : iconPath))) {
2229 : Unused << SendSetAudioSessionData(id, sessionName, iconPath);
2230 : }
2231 : #endif
2232 :
2233 : #ifdef MOZ_CRASHREPORTER_INJECTOR
2234 : InitializeInjector();
2235 : #endif
2236 : }
2237 :
2238 : if (!ok) {
2239 : return NS_ERROR_FAILURE;
2240 : }
2241 :
2242 : if (*error != NPERR_NO_ERROR) {
2243 : OnInitFailure();
2244 : return NS_OK;
2245 : }
2246 :
2247 : return NS_OK;
2248 : }
2249 :
2250 : #endif
2251 :
2252 : nsresult
2253 0 : PluginModuleParent::NP_Shutdown(NPError* error)
2254 : {
2255 0 : PLUGIN_LOG_DEBUG_METHOD;
2256 :
2257 0 : if (mShutdown) {
2258 0 : *error = NPERR_GENERIC_ERROR;
2259 0 : return NS_ERROR_FAILURE;
2260 : }
2261 :
2262 0 : if (!DoShutdown(error)) {
2263 0 : return NS_ERROR_FAILURE;
2264 : }
2265 :
2266 0 : return NS_OK;
2267 : }
2268 :
2269 : bool
2270 0 : PluginModuleParent::DoShutdown(NPError* error)
2271 : {
2272 0 : bool ok = true;
2273 0 : if (IsChrome() && mHadLocalInstance) {
2274 : // We synchronously call NP_Shutdown if the chrome process was using
2275 : // plugins itself. That way we can service any requests the plugin
2276 : // makes. If we're in e10s, though, the content processes will have
2277 : // already shut down and there's no one to talk to. So we shut down
2278 : // asynchronously in PluginModuleChild::ActorDestroy.
2279 0 : ok = CallNP_Shutdown(error);
2280 : }
2281 :
2282 : // if NP_Shutdown() is nested within another interrupt call, this will
2283 : // break things. but lord help us if we're doing that anyway; the
2284 : // plugin dso will have been unloaded on the other side by the
2285 : // CallNP_Shutdown() message
2286 0 : Close();
2287 :
2288 : // mShutdown should either be initialized to false, or be transitiong from
2289 : // false to true. It is never ok to go from true to false. Using OR for
2290 : // the following assignment to ensure this.
2291 0 : mShutdown |= ok;
2292 0 : if (!ok) {
2293 0 : *error = NPERR_GENERIC_ERROR;
2294 : }
2295 0 : return ok;
2296 : }
2297 :
2298 : nsresult
2299 0 : PluginModuleParent::NP_GetMIMEDescription(const char** mimeDesc)
2300 : {
2301 0 : PLUGIN_LOG_DEBUG_METHOD;
2302 :
2303 0 : *mimeDesc = "application/x-foobar";
2304 0 : return NS_OK;
2305 : }
2306 :
2307 : nsresult
2308 0 : PluginModuleParent::NP_GetValue(void *future, NPPVariable aVariable,
2309 : void *aValue, NPError* error)
2310 : {
2311 0 : MOZ_LOG(GetPluginLog(), LogLevel::Warning, ("%s Not implemented, requested variable %i", __FUNCTION__,
2312 : (int) aVariable));
2313 :
2314 : //TODO: implement this correctly
2315 0 : *error = NPERR_GENERIC_ERROR;
2316 0 : return NS_OK;
2317 : }
2318 :
2319 : #if defined(XP_WIN) || defined(XP_MACOSX)
2320 : nsresult
2321 : PluginModuleParent::NP_GetEntryPoints(NPPluginFuncs* pFuncs, NPError* error)
2322 : {
2323 : NS_ASSERTION(pFuncs, "Null pointer!");
2324 :
2325 : *error = NPERR_NO_ERROR;
2326 : SetPluginFuncs(pFuncs);
2327 :
2328 : return NS_OK;
2329 : }
2330 :
2331 : nsresult
2332 : PluginModuleChromeParent::NP_GetEntryPoints(NPPluginFuncs* pFuncs, NPError* error)
2333 : {
2334 : #if !defined(XP_MACOSX)
2335 : if (!mSubprocess->IsConnected()) {
2336 : mNPPIface = pFuncs;
2337 : *error = NPERR_NO_ERROR;
2338 : return NS_OK;
2339 : }
2340 : #endif
2341 :
2342 : // We need to have the plugin process update its function table here by
2343 : // actually calling NP_GetEntryPoints. The parent's function table will
2344 : // reflect nullptr entries in the child's table once SetPluginFuncs is
2345 : // called.
2346 :
2347 : if (!CallNP_GetEntryPoints(error)) {
2348 : return NS_ERROR_FAILURE;
2349 : }
2350 : else if (*error != NPERR_NO_ERROR) {
2351 : return NS_OK;
2352 : }
2353 :
2354 : return PluginModuleParent::NP_GetEntryPoints(pFuncs, error);
2355 : }
2356 :
2357 : #endif
2358 :
2359 : nsresult
2360 0 : PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance,
2361 : int16_t argc, char* argn[],
2362 : char* argv[], NPSavedData* saved,
2363 : NPError* error)
2364 : {
2365 0 : PLUGIN_LOG_DEBUG_METHOD;
2366 :
2367 0 : if (mShutdown) {
2368 0 : *error = NPERR_GENERIC_ERROR;
2369 0 : return NS_ERROR_FAILURE;
2370 : }
2371 :
2372 : // create the instance on the other side
2373 0 : InfallibleTArray<nsCString> names;
2374 0 : InfallibleTArray<nsCString> values;
2375 :
2376 0 : for (int i = 0; i < argc; ++i) {
2377 0 : names.AppendElement(NullableString(argn[i]));
2378 0 : values.AppendElement(NullableString(argv[i]));
2379 : }
2380 :
2381 0 : return NPP_NewInternal(pluginType, instance, names, values, saved, error);
2382 : }
2383 :
2384 : class nsCaseInsensitiveUTF8StringArrayComparator
2385 : {
2386 : public:
2387 : template<class A, class B>
2388 0 : bool Equals(const A& a, const B& b) const {
2389 0 : return a.Equals(b.get(), nsCaseInsensitiveUTF8StringComparator());
2390 : }
2391 : };
2392 :
2393 : void
2394 0 : PluginModuleParent::AccumulateModuleInitBlockedTime()
2395 : {
2396 0 : if (mPluginName.IsEmpty()) {
2397 0 : GetPluginDetails();
2398 : }
2399 0 : Telemetry::Accumulate(Telemetry::BLOCKED_ON_PLUGIN_MODULE_INIT_MS,
2400 0 : GetHistogramKey(),
2401 0 : static_cast<uint32_t>(mTimeBlocked.ToMilliseconds()));
2402 0 : mTimeBlocked = TimeDuration();
2403 0 : }
2404 :
2405 : #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
2406 : static void
2407 0 : ForceWindowless(InfallibleTArray<nsCString>& names,
2408 : InfallibleTArray<nsCString>& values)
2409 : {
2410 : nsCaseInsensitiveUTF8StringArrayComparator comparator;
2411 0 : NS_NAMED_LITERAL_CSTRING(wmodeAttributeName, "wmode");
2412 0 : NS_NAMED_LITERAL_CSTRING(opaqueAttributeValue, "opaque");
2413 : auto wmodeAttributeIndex =
2414 0 : names.IndexOf(wmodeAttributeName, 0, comparator);
2415 0 : if (wmodeAttributeIndex != names.NoIndex) {
2416 0 : if (!values[wmodeAttributeIndex].EqualsLiteral("transparent")) {
2417 0 : values[wmodeAttributeIndex].Assign(opaqueAttributeValue);
2418 : }
2419 : } else {
2420 0 : names.AppendElement(wmodeAttributeName);
2421 0 : values.AppendElement(opaqueAttributeValue);
2422 : }
2423 0 : }
2424 : #endif // windows or linux
2425 : #if defined(XP_WIN)
2426 : static void
2427 : ForceDirect(InfallibleTArray<nsCString>& names,
2428 : InfallibleTArray<nsCString>& values)
2429 : {
2430 : nsCaseInsensitiveUTF8StringArrayComparator comparator;
2431 : NS_NAMED_LITERAL_CSTRING(wmodeAttributeName, "wmode");
2432 : NS_NAMED_LITERAL_CSTRING(directAttributeValue, "direct");
2433 : auto wmodeAttributeIndex =
2434 : names.IndexOf(wmodeAttributeName, 0, comparator);
2435 : if (wmodeAttributeIndex != names.NoIndex) {
2436 : if (values[wmodeAttributeIndex].EqualsLiteral("window")) {
2437 : values[wmodeAttributeIndex].Assign(directAttributeValue);
2438 : }
2439 : } else {
2440 : names.AppendElement(wmodeAttributeName);
2441 : values.AppendElement(directAttributeValue);
2442 : }
2443 : }
2444 : #endif // windows
2445 :
2446 : nsresult
2447 0 : PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance,
2448 : InfallibleTArray<nsCString>& names,
2449 : InfallibleTArray<nsCString>& values,
2450 : NPSavedData* saved, NPError* error)
2451 : {
2452 0 : MOZ_ASSERT(names.Length() == values.Length());
2453 0 : if (mPluginName.IsEmpty()) {
2454 0 : GetPluginDetails();
2455 0 : InitQuirksModes(nsDependentCString(pluginType));
2456 : /** mTimeBlocked measures the time that the main thread has been blocked
2457 : * on plugin module initialization. As implemented, this is the sum of
2458 : * plugin-container launch + toolhelp32 snapshot + NP_Initialize.
2459 : * We don't accumulate its value until here because the plugin info
2460 : * for its histogram key is not available until *after* NP_Initialize.
2461 : */
2462 0 : AccumulateModuleInitBlockedTime();
2463 : }
2464 :
2465 : nsCaseInsensitiveUTF8StringArrayComparator comparator;
2466 0 : NS_NAMED_LITERAL_CSTRING(srcAttributeName, "src");
2467 0 : auto srcAttributeIndex = names.IndexOf(srcAttributeName, 0, comparator);
2468 0 : nsAutoCString srcAttribute;
2469 0 : if (srcAttributeIndex != names.NoIndex) {
2470 0 : srcAttribute = values[srcAttributeIndex];
2471 : }
2472 :
2473 0 : nsDependentCString strPluginType(pluginType);
2474 : PluginInstanceParent* parentInstance =
2475 0 : new PluginInstanceParent(this, instance, strPluginType, mNPNIface);
2476 :
2477 0 : if (mIsFlashPlugin) {
2478 0 : parentInstance->InitMetadata(strPluginType, srcAttribute);
2479 : #ifdef XP_WIN
2480 : bool supportsAsyncRender =
2481 : Preferences::GetBool("dom.ipc.plugins.asyncdrawing.enabled", false);
2482 : bool supportsForceDirect =
2483 : Preferences::GetBool("dom.ipc.plugins.forcedirect.enabled", false);
2484 : if (supportsAsyncRender) {
2485 : // Prefs indicates we want async plugin rendering, make sure
2486 : // the flash module has support.
2487 : CallModuleSupportsAsyncRender(&supportsAsyncRender);
2488 : }
2489 : #ifdef _WIN64
2490 : // For 64-bit builds force windowless if the flash library doesn't support
2491 : // async rendering regardless of sandbox level.
2492 : if (!supportsAsyncRender) {
2493 : #else
2494 : // For 32-bit builds force windowless if the flash library doesn't support
2495 : // async rendering and the sandbox level is 2 or greater.
2496 : if (!supportsAsyncRender && mSandboxLevel >= 2) {
2497 : #endif
2498 : ForceWindowless(names, values);
2499 : }
2500 : #elif defined(MOZ_WIDGET_GTK)
2501 : // We no longer support windowed mode on Linux.
2502 0 : ForceWindowless(names, values);
2503 : #endif
2504 : #ifdef XP_WIN
2505 : // For all builds that use async rendering force use of the accelerated
2506 : // direct path for flash objects that have wmode=window or no wmode
2507 : // specified.
2508 : if (supportsAsyncRender && supportsForceDirect &&
2509 : gfxWindowsPlatform::GetPlatform()->SupportsPluginDirectDXGIDrawing()) {
2510 : ForceDirect(names, values);
2511 : }
2512 : #endif
2513 : }
2514 :
2515 0 : instance->pdata = parentInstance;
2516 :
2517 : // Any IPC messages for the PluginInstance actor should be dispatched to the
2518 : // DocGroup for the plugin's document.
2519 0 : RefPtr<nsPluginInstanceOwner> owner = parentInstance->GetOwner();
2520 0 : nsCOMPtr<nsIDOMElement> elt;
2521 0 : owner->GetDOMElement(getter_AddRefs(elt));
2522 0 : if (nsCOMPtr<nsINode> node = do_QueryInterface(elt)) {
2523 0 : nsCOMPtr<nsIDocument> doc = node->OwnerDoc();
2524 0 : if (doc) {
2525 0 : nsCOMPtr<nsIEventTarget> eventTarget = doc->EventTargetFor(TaskCategory::Other);
2526 0 : SetEventTargetForActor(parentInstance, eventTarget);
2527 : }
2528 : }
2529 :
2530 0 : if (!SendPPluginInstanceConstructor(parentInstance,
2531 0 : nsDependentCString(pluginType),
2532 : names, values)) {
2533 : // |parentInstance| is automatically deleted.
2534 0 : instance->pdata = nullptr;
2535 0 : *error = NPERR_GENERIC_ERROR;
2536 0 : return NS_ERROR_FAILURE;
2537 : }
2538 :
2539 : { // Scope for timer
2540 : Telemetry::AutoTimer<Telemetry::BLOCKED_ON_PLUGIN_INSTANCE_INIT_MS>
2541 0 : timer(GetHistogramKey());
2542 0 : if (!CallSyncNPP_New(parentInstance, error)) {
2543 : // if IPC is down, we'll get an immediate "failed" return, but
2544 : // without *error being set. So make sure that the error
2545 : // condition is signaled to nsNPAPIPluginInstance
2546 0 : if (NPERR_NO_ERROR == *error) {
2547 0 : *error = NPERR_GENERIC_ERROR;
2548 : }
2549 0 : return NS_ERROR_FAILURE;
2550 : }
2551 : }
2552 :
2553 0 : if (*error != NPERR_NO_ERROR) {
2554 0 : NPP_Destroy(instance, 0);
2555 0 : return NS_ERROR_FAILURE;
2556 : }
2557 :
2558 0 : UpdatePluginTimeout();
2559 :
2560 0 : return NS_OK;
2561 : }
2562 :
2563 : void
2564 0 : PluginModuleChromeParent::UpdatePluginTimeout()
2565 : {
2566 0 : TimeoutChanged(kParentTimeoutPref, this);
2567 0 : }
2568 :
2569 : nsresult
2570 0 : PluginModuleParent::NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge,
2571 : nsCOMPtr<nsIClearSiteDataCallback> callback)
2572 : {
2573 0 : if (!mClearSiteDataSupported)
2574 0 : return NS_ERROR_NOT_AVAILABLE;
2575 :
2576 : static uint64_t callbackId = 0;
2577 0 : callbackId++;
2578 0 : mClearSiteDataCallbacks[callbackId] = callback;
2579 :
2580 0 : if (!SendNPP_ClearSiteData(NullableString(site), flags, maxAge, callbackId)) {
2581 0 : return NS_ERROR_FAILURE;
2582 : }
2583 0 : return NS_OK;
2584 : }
2585 :
2586 :
2587 : nsresult
2588 0 : PluginModuleParent::NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback> callback)
2589 : {
2590 0 : if (!mGetSitesWithDataSupported)
2591 0 : return NS_ERROR_NOT_AVAILABLE;
2592 :
2593 : static uint64_t callbackId = 0;
2594 0 : callbackId++;
2595 0 : mSitesWithDataCallbacks[callbackId] = callback;
2596 :
2597 0 : if (!SendNPP_GetSitesWithData(callbackId))
2598 0 : return NS_ERROR_FAILURE;
2599 :
2600 0 : return NS_OK;
2601 : }
2602 :
2603 : #if defined(XP_MACOSX)
2604 : nsresult
2605 : PluginModuleParent::IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing)
2606 : {
2607 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
2608 : return pip ? pip->IsRemoteDrawingCoreAnimation(aDrawing) : NS_ERROR_FAILURE;
2609 : }
2610 : #endif
2611 : #if defined(XP_MACOSX) || defined(XP_WIN)
2612 : nsresult
2613 : PluginModuleParent::ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor)
2614 : {
2615 : PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
2616 : return pip ? pip->ContentsScaleFactorChanged(aContentsScaleFactor)
2617 : : NS_ERROR_FAILURE;
2618 : }
2619 : #endif // #if defined(XP_MACOSX)
2620 :
2621 : #if defined(XP_MACOSX)
2622 : mozilla::ipc::IPCResult
2623 : PluginModuleParent::AnswerProcessSomeEvents()
2624 : {
2625 : mozilla::plugins::PluginUtilsOSX::InvokeNativeEventLoop();
2626 : return IPC_OK();
2627 : }
2628 :
2629 : #elif !defined(MOZ_WIDGET_GTK)
2630 : mozilla::ipc::IPCResult
2631 : PluginModuleParent::AnswerProcessSomeEvents()
2632 : {
2633 : NS_RUNTIMEABORT("unreached");
2634 : return IPC_FAIL_NO_REASON(this);
2635 : }
2636 :
2637 : #else
2638 : static const int kMaxChancesToProcessEvents = 20;
2639 :
2640 : mozilla::ipc::IPCResult
2641 0 : PluginModuleParent::AnswerProcessSomeEvents()
2642 : {
2643 0 : PLUGIN_LOG_DEBUG(("Spinning mini nested loop ..."));
2644 :
2645 0 : int i = 0;
2646 0 : for (; i < kMaxChancesToProcessEvents; ++i)
2647 0 : if (!g_main_context_iteration(nullptr, FALSE))
2648 0 : break;
2649 :
2650 0 : PLUGIN_LOG_DEBUG(("... quitting mini nested loop; processed %i tasks", i));
2651 :
2652 0 : return IPC_OK();
2653 : }
2654 : #endif
2655 :
2656 : mozilla::ipc::IPCResult
2657 0 : PluginModuleParent::RecvProcessNativeEventsInInterruptCall()
2658 : {
2659 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2660 : #if defined(OS_WIN)
2661 : ProcessNativeEventsInInterruptCall();
2662 : return IPC_OK();
2663 : #else
2664 0 : NS_NOTREACHED(
2665 : "PluginModuleParent::RecvProcessNativeEventsInInterruptCall not implemented!");
2666 0 : return IPC_FAIL_NO_REASON(this);
2667 : #endif
2668 : }
2669 :
2670 : void
2671 0 : PluginModuleParent::ProcessRemoteNativeEventsInInterruptCall()
2672 : {
2673 : #if defined(OS_WIN)
2674 : Unused << SendProcessNativeEventsInInterruptCall();
2675 : return;
2676 : #endif
2677 0 : NS_NOTREACHED(
2678 : "PluginModuleParent::ProcessRemoteNativeEventsInInterruptCall not implemented!");
2679 0 : }
2680 :
2681 : mozilla::ipc::IPCResult
2682 0 : PluginModuleParent::RecvPluginShowWindow(const uint32_t& aWindowId, const bool& aModal,
2683 : const int32_t& aX, const int32_t& aY,
2684 : const size_t& aWidth, const size_t& aHeight)
2685 : {
2686 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2687 : #if defined(XP_MACOSX)
2688 : CGRect windowBound = ::CGRectMake(aX, aY, aWidth, aHeight);
2689 : mac_plugin_interposing::parent::OnPluginShowWindow(aWindowId, windowBound, aModal);
2690 : return IPC_OK();
2691 : #else
2692 0 : NS_NOTREACHED(
2693 : "PluginInstanceParent::RecvPluginShowWindow not implemented!");
2694 0 : return IPC_FAIL_NO_REASON(this);
2695 : #endif
2696 : }
2697 :
2698 : mozilla::ipc::IPCResult
2699 0 : PluginModuleParent::RecvPluginHideWindow(const uint32_t& aWindowId)
2700 : {
2701 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2702 : #if defined(XP_MACOSX)
2703 : mac_plugin_interposing::parent::OnPluginHideWindow(aWindowId, OtherPid());
2704 : return IPC_OK();
2705 : #else
2706 0 : NS_NOTREACHED(
2707 : "PluginInstanceParent::RecvPluginHideWindow not implemented!");
2708 0 : return IPC_FAIL_NO_REASON(this);
2709 : #endif
2710 : }
2711 :
2712 : mozilla::ipc::IPCResult
2713 0 : PluginModuleParent::RecvSetCursor(const NSCursorInfo& aCursorInfo)
2714 : {
2715 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2716 : #if defined(XP_MACOSX)
2717 : mac_plugin_interposing::parent::OnSetCursor(aCursorInfo);
2718 : return IPC_OK();
2719 : #else
2720 0 : NS_NOTREACHED(
2721 : "PluginInstanceParent::RecvSetCursor not implemented!");
2722 0 : return IPC_FAIL_NO_REASON(this);
2723 : #endif
2724 : }
2725 :
2726 : mozilla::ipc::IPCResult
2727 0 : PluginModuleParent::RecvShowCursor(const bool& aShow)
2728 : {
2729 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2730 : #if defined(XP_MACOSX)
2731 : mac_plugin_interposing::parent::OnShowCursor(aShow);
2732 : return IPC_OK();
2733 : #else
2734 0 : NS_NOTREACHED(
2735 : "PluginInstanceParent::RecvShowCursor not implemented!");
2736 0 : return IPC_FAIL_NO_REASON(this);
2737 : #endif
2738 : }
2739 :
2740 : mozilla::ipc::IPCResult
2741 0 : PluginModuleParent::RecvPushCursor(const NSCursorInfo& aCursorInfo)
2742 : {
2743 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2744 : #if defined(XP_MACOSX)
2745 : mac_plugin_interposing::parent::OnPushCursor(aCursorInfo);
2746 : return IPC_OK();
2747 : #else
2748 0 : NS_NOTREACHED(
2749 : "PluginInstanceParent::RecvPushCursor not implemented!");
2750 0 : return IPC_FAIL_NO_REASON(this);
2751 : #endif
2752 : }
2753 :
2754 : mozilla::ipc::IPCResult
2755 0 : PluginModuleParent::RecvPopCursor()
2756 : {
2757 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2758 : #if defined(XP_MACOSX)
2759 : mac_plugin_interposing::parent::OnPopCursor();
2760 : return IPC_OK();
2761 : #else
2762 0 : NS_NOTREACHED(
2763 : "PluginInstanceParent::RecvPopCursor not implemented!");
2764 0 : return IPC_FAIL_NO_REASON(this);
2765 : #endif
2766 : }
2767 :
2768 : mozilla::ipc::IPCResult
2769 0 : PluginModuleParent::RecvNPN_SetException(const nsCString& aMessage)
2770 : {
2771 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2772 :
2773 : // This function ignores its first argument.
2774 0 : mozilla::plugins::parent::_setexception(nullptr, NullableStringGet(aMessage));
2775 0 : return IPC_OK();
2776 : }
2777 :
2778 : mozilla::ipc::IPCResult
2779 0 : PluginModuleParent::RecvNPN_ReloadPlugins(const bool& aReloadPages)
2780 : {
2781 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2782 :
2783 0 : mozilla::plugins::parent::_reloadplugins(aReloadPages);
2784 0 : return IPC_OK();
2785 : }
2786 :
2787 : mozilla::ipc::IPCResult
2788 0 : PluginModuleChromeParent::RecvNotifyContentModuleDestroyed()
2789 : {
2790 0 : RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
2791 0 : if (host) {
2792 0 : host->NotifyContentModuleDestroyed(mPluginId);
2793 : }
2794 0 : return IPC_OK();
2795 : }
2796 :
2797 : mozilla::ipc::IPCResult
2798 0 : PluginModuleParent::RecvReturnClearSiteData(const NPError& aRv,
2799 : const uint64_t& aCallbackId)
2800 : {
2801 0 : if (mClearSiteDataCallbacks.find(aCallbackId) == mClearSiteDataCallbacks.end()) {
2802 0 : return IPC_OK();
2803 : }
2804 0 : if (!!mClearSiteDataCallbacks[aCallbackId]) {
2805 : nsresult rv;
2806 0 : switch (aRv) {
2807 : case NPERR_NO_ERROR:
2808 0 : rv = NS_OK;
2809 0 : break;
2810 : case NPERR_TIME_RANGE_NOT_SUPPORTED:
2811 0 : rv = NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED;
2812 0 : break;
2813 : case NPERR_MALFORMED_SITE:
2814 0 : rv = NS_ERROR_INVALID_ARG;
2815 0 : break;
2816 : default:
2817 0 : rv = NS_ERROR_FAILURE;
2818 : }
2819 0 : mClearSiteDataCallbacks[aCallbackId]->Callback(rv);
2820 : }
2821 0 : mClearSiteDataCallbacks.erase(aCallbackId);
2822 0 : return IPC_OK();
2823 : }
2824 :
2825 : mozilla::ipc::IPCResult
2826 0 : PluginModuleParent::RecvReturnSitesWithData(nsTArray<nsCString>&& aSites,
2827 : const uint64_t& aCallbackId)
2828 : {
2829 0 : if (mSitesWithDataCallbacks.find(aCallbackId) == mSitesWithDataCallbacks.end()) {
2830 0 : return IPC_OK();
2831 : }
2832 :
2833 0 : if (!!mSitesWithDataCallbacks[aCallbackId]) {
2834 0 : mSitesWithDataCallbacks[aCallbackId]->SitesWithData(aSites);
2835 : }
2836 0 : mSitesWithDataCallbacks.erase(aCallbackId);
2837 0 : return IPC_OK();
2838 : }
2839 :
2840 : layers::TextureClientRecycleAllocator*
2841 0 : PluginModuleParent::EnsureTextureAllocatorForDirectBitmap()
2842 : {
2843 0 : if (!mTextureAllocatorForDirectBitmap) {
2844 0 : mTextureAllocatorForDirectBitmap = new TextureClientRecycleAllocator(ImageBridgeChild::GetSingleton().get());
2845 : }
2846 0 : return mTextureAllocatorForDirectBitmap;
2847 : }
2848 :
2849 : layers::TextureClientRecycleAllocator*
2850 0 : PluginModuleParent::EnsureTextureAllocatorForDXGISurface()
2851 : {
2852 0 : if (!mTextureAllocatorForDXGISurface) {
2853 0 : mTextureAllocatorForDXGISurface = new TextureClientRecycleAllocator(ImageBridgeChild::GetSingleton().get());
2854 : }
2855 0 : return mTextureAllocatorForDXGISurface;
2856 : }
2857 :
2858 :
2859 : mozilla::ipc::IPCResult
2860 0 : PluginModuleParent::AnswerNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
2861 : const bool& shouldRegister,
2862 : NPError* result) {
2863 : NS_RUNTIMEABORT("SetValue_NPPVpluginRequiresAudioDeviceChanges is only valid "
2864 0 : "with PluginModuleChromeParent");
2865 0 : *result = NPERR_GENERIC_ERROR;
2866 0 : return IPC_OK();
2867 : }
2868 :
2869 : #ifdef MOZ_CRASHREPORTER_INJECTOR
2870 :
2871 : // We only add the crash reporter to subprocess which have the filename
2872 : // FlashPlayerPlugin*
2873 : #define FLASH_PROCESS_PREFIX "FLASHPLAYERPLUGIN"
2874 :
2875 : static DWORD
2876 : GetFlashChildOfPID(DWORD pid, HANDLE snapshot)
2877 : {
2878 : PROCESSENTRY32 entry = {
2879 : sizeof(entry)
2880 : };
2881 : for (BOOL ok = Process32First(snapshot, &entry);
2882 : ok;
2883 : ok = Process32Next(snapshot, &entry)) {
2884 : if (entry.th32ParentProcessID == pid) {
2885 : nsString name(entry.szExeFile);
2886 : ToUpperCase(name);
2887 : if (StringBeginsWith(name, NS_LITERAL_STRING(FLASH_PROCESS_PREFIX))) {
2888 : return entry.th32ProcessID;
2889 : }
2890 : }
2891 : }
2892 : return 0;
2893 : }
2894 :
2895 : // We only look for child processes of the Flash plugin, NPSWF*
2896 : #define FLASH_PLUGIN_PREFIX "NPSWF"
2897 :
2898 : void
2899 : PluginModuleChromeParent::InitializeInjector()
2900 : {
2901 : if (!Preferences::GetBool("dom.ipc.plugins.flash.subprocess.crashreporter.enabled", false))
2902 : return;
2903 :
2904 : nsCString path(Process()->GetPluginFilePath().c_str());
2905 : ToUpperCase(path);
2906 : int32_t lastSlash = path.RFindCharInSet("\\/");
2907 : if (kNotFound == lastSlash)
2908 : return;
2909 :
2910 : if (!StringBeginsWith(Substring(path, lastSlash + 1),
2911 : NS_LITERAL_CSTRING(FLASH_PLUGIN_PREFIX)))
2912 : return;
2913 :
2914 : TimeStamp th32Start = TimeStamp::Now();
2915 : mFinishInitTask = mChromeTaskFactory.NewTask<FinishInjectorInitTask>();
2916 : mFinishInitTask->Init(this);
2917 : if (!::QueueUserWorkItem(&PluginModuleChromeParent::GetToolhelpSnapshot,
2918 : mFinishInitTask, WT_EXECUTEDEFAULT)) {
2919 : mFinishInitTask = nullptr;
2920 : return;
2921 : }
2922 : TimeStamp th32End = TimeStamp::Now();
2923 : mTimeBlocked += (th32End - th32Start);
2924 : }
2925 :
2926 : void
2927 : PluginModuleChromeParent::DoInjection(const nsAutoHandle& aSnapshot)
2928 : {
2929 : DWORD pluginProcessPID = GetProcessId(Process()->GetChildProcessHandle());
2930 : mFlashProcess1 = GetFlashChildOfPID(pluginProcessPID, aSnapshot);
2931 : if (mFlashProcess1) {
2932 : InjectCrashReporterIntoProcess(mFlashProcess1, this);
2933 :
2934 : mFlashProcess2 = GetFlashChildOfPID(mFlashProcess1, aSnapshot);
2935 : if (mFlashProcess2) {
2936 : InjectCrashReporterIntoProcess(mFlashProcess2, this);
2937 : }
2938 : }
2939 : mFinishInitTask = nullptr;
2940 : }
2941 :
2942 : DWORD WINAPI
2943 : PluginModuleChromeParent::GetToolhelpSnapshot(LPVOID aContext)
2944 : {
2945 : FinishInjectorInitTask* task = static_cast<FinishInjectorInitTask*>(aContext);
2946 : MOZ_ASSERT(task);
2947 : task->PostToMainThread();
2948 : return 0;
2949 : }
2950 :
2951 : void
2952 : PluginModuleChromeParent::OnCrash(DWORD processID)
2953 : {
2954 : if (!mShutdown) {
2955 : GetIPCChannel()->CloseWithError();
2956 : mozilla::ipc::ScopedProcessHandle geckoPluginChild;
2957 : if (base::OpenProcessHandle(OtherPid(), &geckoPluginChild.rwget())) {
2958 : if (!base::KillProcess(geckoPluginChild,
2959 : base::PROCESS_END_KILLED_BY_USER, false)) {
2960 : NS_ERROR("May have failed to kill child process.");
2961 : }
2962 : } else {
2963 : NS_ERROR("Failed to open child process when attempting kill.");
2964 : }
2965 : }
2966 : }
2967 :
2968 : #endif // MOZ_CRASHREPORTER_INJECTOR
2969 :
2970 : mozilla::ipc::IPCResult
2971 0 : PluginModuleParent::AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet)
2972 : {
2973 0 : return IPC_FAIL_NO_REASON(this);
2974 : }
2975 :
2976 : mozilla::ipc::IPCResult
2977 0 : PluginModuleChromeParent::AnswerGetKeyState(const int32_t& aVirtKey,
2978 : int16_t* aRet)
2979 : {
2980 : #if defined(XP_WIN)
2981 : *aRet = ::GetKeyState(aVirtKey);
2982 : return IPC_OK();
2983 : #else
2984 0 : return PluginModuleParent::AnswerGetKeyState(aVirtKey, aRet);
2985 : #endif
2986 : }
2987 :
2988 : mozilla::ipc::IPCResult
2989 0 : PluginModuleChromeParent::AnswerGetFileName(const GetFileNameFunc& aFunc,
2990 : const OpenFileNameIPC& aOfnIn,
2991 : OpenFileNameRetIPC* aOfnOut,
2992 : bool* aResult)
2993 : {
2994 : #if defined(XP_WIN) && defined(MOZ_SANDBOX)
2995 : OPENFILENAMEW ofn;
2996 : memset(&ofn, 0, sizeof(ofn));
2997 : aOfnIn.AllocateOfnStrings(&ofn);
2998 : aOfnIn.AddToOfn(&ofn);
2999 : switch (aFunc) {
3000 : case OPEN_FUNC:
3001 : *aResult = GetOpenFileName(&ofn);
3002 : break;
3003 : case SAVE_FUNC:
3004 : *aResult = GetSaveFileName(&ofn);
3005 : break;
3006 : }
3007 : if (*aResult) {
3008 : if (ofn.Flags & OFN_ALLOWMULTISELECT) {
3009 : // We only support multiselect with the OFN_EXPLORER flag.
3010 : // This guarantees that ofn.lpstrFile follows the pattern below.
3011 : MOZ_ASSERT(ofn.Flags & OFN_EXPLORER);
3012 :
3013 : // lpstrFile is one of two things:
3014 : // 1. A null terminated full path to a file, or
3015 : // 2. A path to a folder, followed by a NULL, followed by a
3016 : // list of file names, each NULL terminated, followed by an
3017 : // additional NULL (so it is also double-NULL terminated).
3018 : std::wstring path = std::wstring(ofn.lpstrFile);
3019 : MOZ_ASSERT(ofn.nFileOffset > 0);
3020 : // For condition #1, nFileOffset points to the file name in the path.
3021 : // It will be preceeded by a non-NULL character from the path.
3022 : if (ofn.lpstrFile[ofn.nFileOffset-1] != L'\0') {
3023 : mSandboxPermissions.GrantFileAccess(OtherPid(), path.c_str(),
3024 : aFunc == SAVE_FUNC);
3025 : }
3026 : else {
3027 : // This is condition #2
3028 : wchar_t* nextFile = ofn.lpstrFile + path.size() + 1;
3029 : while (*nextFile != L'\0') {
3030 : std::wstring nextFileStr(nextFile);
3031 : std::wstring fullPath =
3032 : path + std::wstring(L"\\") + nextFileStr;
3033 : mSandboxPermissions.GrantFileAccess(OtherPid(), fullPath.c_str(),
3034 : aFunc == SAVE_FUNC);
3035 : nextFile += nextFileStr.size() + 1;
3036 : }
3037 : }
3038 : }
3039 : else {
3040 : mSandboxPermissions.GrantFileAccess(OtherPid(), ofn.lpstrFile,
3041 : aFunc == SAVE_FUNC);
3042 : }
3043 : aOfnOut->CopyFromOfn(&ofn);
3044 : }
3045 : aOfnIn.FreeOfnStrings(&ofn);
3046 : return IPC_OK();
3047 : #else
3048 0 : MOZ_ASSERT_UNREACHABLE("GetFileName IPC message is only available on "
3049 : "Windows builds with sandbox.");
3050 : return IPC_FAIL_NO_REASON(this);
3051 : #endif
3052 : }
3053 :
3054 : mozilla::ipc::IPCResult
3055 0 : PluginModuleChromeParent::AnswerSetCursorPos(const int &x, const int &y,
3056 : bool* aResult)
3057 : {
3058 : #if defined(XP_WIN)
3059 : *aResult = ::SetCursorPos(x, y);
3060 : return IPC_OK();
3061 : #else
3062 0 : return PluginModuleParent::AnswerSetCursorPos(x, y, aResult);
3063 : #endif
3064 : }
|