Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
7 #ifdef MOZ_WIDGET_QT
8 // Must be included first to avoid conflicts.
9 #include <QtCore/QCoreApplication>
10 #include <QtCore/QEventLoop>
11 #include "NestedLoopTimer.h"
12 #endif
14 #include "mozilla/plugins/PluginModuleParent.h"
16 #include "base/process_util.h"
17 #include "mozilla/Attributes.h"
18 #include "mozilla/dom/PCrashReporterParent.h"
19 #include "mozilla/ipc/MessageChannel.h"
20 #include "mozilla/plugins/BrowserStreamParent.h"
21 #include "mozilla/plugins/PluginInstanceParent.h"
22 #include "mozilla/Preferences.h"
23 #include "mozilla/Services.h"
24 #include "mozilla/unused.h"
25 #include "nsAutoPtr.h"
26 #include "nsCRT.h"
27 #include "nsIFile.h"
28 #include "nsIObserverService.h"
29 #include "nsNPAPIPlugin.h"
30 #include "nsPrintfCString.h"
31 #include "PluginIdentifierParent.h"
32 #include "prsystem.h"
33 #include "GeckoProfiler.h"
35 #ifdef XP_WIN
36 #include "PluginHangUIParent.h"
37 #include "mozilla/widget/AudioSession.h"
38 #endif
40 #ifdef MOZ_ENABLE_PROFILER_SPS
41 #include "nsIProfileSaveEvent.h"
42 #endif
44 #ifdef MOZ_WIDGET_GTK
45 #include <glib.h>
46 #elif XP_MACOSX
47 #include "PluginInterposeOSX.h"
48 #include "PluginUtilsOSX.h"
49 #endif
51 using base::KillProcess;
53 using mozilla::PluginLibrary;
54 using mozilla::ipc::MessageChannel;
55 using mozilla::dom::PCrashReporterParent;
56 using mozilla::dom::CrashReporterParent;
58 using namespace mozilla;
59 using namespace mozilla::plugins;
60 using namespace mozilla::plugins::parent;
62 #ifdef MOZ_CRASHREPORTER
63 #include "mozilla/dom/CrashReporterParent.h"
65 using namespace CrashReporter;
66 #endif
68 static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
69 static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs";
70 static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs";
71 #ifdef XP_WIN
72 static const char kHangUITimeoutPref[] = "dom.ipc.plugins.hangUITimeoutSecs";
73 static const char kHangUIMinDisplayPref[] = "dom.ipc.plugins.hangUIMinDisplaySecs";
74 #define CHILD_TIMEOUT_PREF kHangUITimeoutPref
75 #else
76 #define CHILD_TIMEOUT_PREF kChildTimeoutPref
77 #endif
79 template<>
80 struct RunnableMethodTraits<mozilla::plugins::PluginModuleParent>
81 {
82 typedef mozilla::plugins::PluginModuleParent Class;
83 static void RetainCallee(Class* obj) { }
84 static void ReleaseCallee(Class* obj) { }
85 };
87 // static
88 PluginLibrary*
89 PluginModuleParent::LoadModule(const char* aFilePath)
90 {
91 PLUGIN_LOG_DEBUG_FUNCTION;
93 int32_t prefSecs = Preferences::GetInt(kLaunchTimeoutPref, 0);
95 // Block on the child process being launched and initialized.
96 nsAutoPtr<PluginModuleParent> parent(new PluginModuleParent(aFilePath));
97 bool launched = parent->mSubprocess->Launch(prefSecs * 1000);
98 if (!launched) {
99 // We never reached open
100 parent->mShutdown = true;
101 return nullptr;
102 }
103 parent->Open(parent->mSubprocess->GetChannel(),
104 parent->mSubprocess->GetChildProcessHandle());
106 // Request Windows message deferral behavior on our channel. This
107 // applies to the top level and all sub plugin protocols since they
108 // all share the same channel.
109 parent->GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
111 TimeoutChanged(CHILD_TIMEOUT_PREF, parent);
113 #ifdef MOZ_CRASHREPORTER
114 // If this fails, we're having IPC troubles, and we're doomed anyways.
115 if (!CrashReporterParent::CreateCrashReporter(parent.get())) {
116 parent->Close();
117 return nullptr;
118 }
119 #ifdef XP_WIN
120 mozilla::MutexAutoLock lock(parent->mCrashReporterMutex);
121 parent->mCrashReporter = parent->CrashReporter();
122 #endif
123 #endif
125 return parent.forget();
126 }
129 PluginModuleParent::PluginModuleParent(const char* aFilePath)
130 : mSubprocess(new PluginProcessParent(aFilePath))
131 , mShutdown(false)
132 , mClearSiteDataSupported(false)
133 , mGetSitesWithDataSupported(false)
134 , mNPNIface(nullptr)
135 , mPlugin(nullptr)
136 , mTaskFactory(MOZ_THIS_IN_INITIALIZER_LIST())
137 #ifdef XP_WIN
138 , mPluginCpuUsageOnHang()
139 , mHangUIParent(nullptr)
140 , mHangUIEnabled(true)
141 , mIsTimerReset(true)
142 #ifdef MOZ_CRASHREPORTER
143 , mCrashReporterMutex("PluginModuleParent::mCrashReporterMutex")
144 , mCrashReporter(nullptr)
145 #endif
146 #endif
147 #ifdef MOZ_CRASHREPORTER_INJECTOR
148 , mFlashProcess1(0)
149 , mFlashProcess2(0)
150 #endif
151 {
152 NS_ASSERTION(mSubprocess, "Out of memory!");
154 Preferences::RegisterCallback(TimeoutChanged, kChildTimeoutPref, this);
155 Preferences::RegisterCallback(TimeoutChanged, kParentTimeoutPref, this);
156 #ifdef XP_WIN
157 Preferences::RegisterCallback(TimeoutChanged, kHangUITimeoutPref, this);
158 Preferences::RegisterCallback(TimeoutChanged, kHangUIMinDisplayPref, this);
159 #endif
161 #ifdef MOZ_ENABLE_PROFILER_SPS
162 InitPluginProfiling();
163 #endif
164 }
166 PluginModuleParent::~PluginModuleParent()
167 {
168 if (!OkToCleanup()) {
169 NS_RUNTIMEABORT("unsafe destruction");
170 }
172 #ifdef MOZ_ENABLE_PROFILER_SPS
173 ShutdownPluginProfiling();
174 #endif
176 if (!mShutdown) {
177 NS_WARNING("Plugin host deleted the module without shutting down.");
178 NPError err;
179 NP_Shutdown(&err);
180 }
182 NS_ASSERTION(mShutdown, "NP_Shutdown didn't");
184 if (mSubprocess) {
185 mSubprocess->Delete();
186 mSubprocess = nullptr;
187 }
189 #ifdef MOZ_CRASHREPORTER_INJECTOR
190 if (mFlashProcess1)
191 UnregisterInjectorCallback(mFlashProcess1);
192 if (mFlashProcess2)
193 UnregisterInjectorCallback(mFlashProcess2);
194 #endif
196 Preferences::UnregisterCallback(TimeoutChanged, kChildTimeoutPref, this);
197 Preferences::UnregisterCallback(TimeoutChanged, kParentTimeoutPref, this);
198 #ifdef XP_WIN
199 Preferences::UnregisterCallback(TimeoutChanged, kHangUITimeoutPref, this);
200 Preferences::UnregisterCallback(TimeoutChanged, kHangUIMinDisplayPref, this);
202 if (mHangUIParent) {
203 delete mHangUIParent;
204 mHangUIParent = nullptr;
205 }
206 #endif
207 }
209 #ifdef MOZ_CRASHREPORTER
210 void
211 PluginModuleParent::WriteExtraDataForMinidump(AnnotationTable& notes)
212 {
213 #ifdef XP_WIN
214 // mCrashReporterMutex is already held by the caller
215 mCrashReporterMutex.AssertCurrentThreadOwns();
216 #endif
217 typedef nsDependentCString CS;
219 // Get the plugin filename, try to get just the file leafname
220 const std::string& pluginFile = mSubprocess->GetPluginFilePath();
221 size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR);
222 if (filePos == std::string::npos)
223 filePos = 0;
224 else
225 filePos++;
226 notes.Put(NS_LITERAL_CSTRING("PluginFilename"), CS(pluginFile.substr(filePos).c_str()));
228 nsCString pluginName;
229 nsCString pluginVersion;
231 nsRefPtr<nsPluginHost> ph = nsPluginHost::GetInst();
232 if (ph) {
233 nsPluginTag* tag = ph->TagForPlugin(mPlugin);
234 if (tag) {
235 pluginName = tag->mName;
236 pluginVersion = tag->mVersion;
237 }
238 }
240 notes.Put(NS_LITERAL_CSTRING("PluginName"), pluginName);
241 notes.Put(NS_LITERAL_CSTRING("PluginVersion"), pluginVersion);
243 CrashReporterParent* crashReporter = CrashReporter();
244 if (crashReporter) {
245 #ifdef XP_WIN
246 if (mPluginCpuUsageOnHang.Length() > 0) {
247 notes.Put(NS_LITERAL_CSTRING("NumberOfProcessors"),
248 nsPrintfCString("%d", PR_GetNumberOfProcessors()));
250 nsCString cpuUsageStr;
251 cpuUsageStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[0] * 100) / 100);
252 notes.Put(NS_LITERAL_CSTRING("PluginCpuUsage"), cpuUsageStr);
254 #ifdef MOZ_CRASHREPORTER_INJECTOR
255 for (uint32_t i=1; i<mPluginCpuUsageOnHang.Length(); ++i) {
256 nsCString tempStr;
257 tempStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[i] * 100) / 100);
258 notes.Put(nsPrintfCString("CpuUsageFlashProcess%d", i), tempStr);
259 }
260 #endif
261 }
262 #endif
263 }
264 }
265 #endif // MOZ_CRASHREPORTER
267 void
268 PluginModuleParent::SetChildTimeout(const int32_t aChildTimeout)
269 {
270 int32_t timeoutMs = (aChildTimeout > 0) ? (1000 * aChildTimeout) :
271 MessageChannel::kNoTimeout;
272 SetReplyTimeoutMs(timeoutMs);
273 }
275 void
276 PluginModuleParent::TimeoutChanged(const char* aPref, void* aModule)
277 {
278 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
279 #ifndef XP_WIN
280 if (!strcmp(aPref, kChildTimeoutPref)) {
281 // The timeout value used by the parent for children
282 int32_t timeoutSecs = Preferences::GetInt(kChildTimeoutPref, 0);
283 static_cast<PluginModuleParent*>(aModule)->SetChildTimeout(timeoutSecs);
284 #else
285 if (!strcmp(aPref, kChildTimeoutPref) ||
286 !strcmp(aPref, kHangUIMinDisplayPref) ||
287 !strcmp(aPref, kHangUITimeoutPref)) {
288 static_cast<PluginModuleParent*>(aModule)->EvaluateHangUIState(true);
289 #endif // XP_WIN
290 } else if (!strcmp(aPref, kParentTimeoutPref)) {
291 // The timeout value used by the child for its parent
292 int32_t timeoutSecs = Preferences::GetInt(kParentTimeoutPref, 0);
293 unused << static_cast<PluginModuleParent*>(aModule)->SendSetParentHangTimeout(timeoutSecs);
294 }
295 }
297 void
298 PluginModuleParent::CleanupFromTimeout(const bool aFromHangUI)
299 {
300 if (mShutdown) {
301 return;
302 }
304 if (!OkToCleanup()) {
305 // there's still plugin code on the C++ stack, try again
306 MessageLoop::current()->PostDelayedTask(
307 FROM_HERE,
308 mTaskFactory.NewRunnableMethod(
309 &PluginModuleParent::CleanupFromTimeout, aFromHangUI), 10);
310 return;
311 }
313 /* If the plugin container was terminated by the Plugin Hang UI,
314 then either the I/O thread detects a channel error, or the
315 main thread must set the error (whomever gets there first).
316 OTOH, if we terminate and return false from
317 ShouldContinueFromReplyTimeout, then the channel state has
318 already been set to ChannelTimeout and we should call the
319 regular Close function. */
320 if (aFromHangUI) {
321 GetIPCChannel()->CloseWithError();
322 } else {
323 Close();
324 }
325 }
327 #ifdef XP_WIN
328 namespace {
330 uint64_t
331 FileTimeToUTC(const FILETIME& ftime)
332 {
333 ULARGE_INTEGER li;
334 li.LowPart = ftime.dwLowDateTime;
335 li.HighPart = ftime.dwHighDateTime;
336 return li.QuadPart;
337 }
339 struct CpuUsageSamples
340 {
341 uint64_t sampleTimes[2];
342 uint64_t cpuTimes[2];
343 };
345 bool
346 GetProcessCpuUsage(const InfallibleTArray<base::ProcessHandle>& processHandles, InfallibleTArray<float>& cpuUsage)
347 {
348 InfallibleTArray<CpuUsageSamples> samples(processHandles.Length());
349 FILETIME creationTime, exitTime, kernelTime, userTime, currentTime;
350 BOOL res;
352 for (uint32_t i = 0; i < processHandles.Length(); ++i) {
353 ::GetSystemTimeAsFileTime(¤tTime);
354 res = ::GetProcessTimes(processHandles[i], &creationTime, &exitTime, &kernelTime, &userTime);
355 if (!res) {
356 NS_WARNING("failed to get process times");
357 return false;
358 }
360 CpuUsageSamples s;
361 s.sampleTimes[0] = FileTimeToUTC(currentTime);
362 s.cpuTimes[0] = FileTimeToUTC(kernelTime) + FileTimeToUTC(userTime);
363 samples.AppendElement(s);
364 }
366 // we already hung for a while, a little bit longer won't matter
367 ::Sleep(50);
369 const int32_t numberOfProcessors = PR_GetNumberOfProcessors();
371 for (uint32_t i = 0; i < processHandles.Length(); ++i) {
372 ::GetSystemTimeAsFileTime(¤tTime);
373 res = ::GetProcessTimes(processHandles[i], &creationTime, &exitTime, &kernelTime, &userTime);
374 if (!res) {
375 NS_WARNING("failed to get process times");
376 return false;
377 }
379 samples[i].sampleTimes[1] = FileTimeToUTC(currentTime);
380 samples[i].cpuTimes[1] = FileTimeToUTC(kernelTime) + FileTimeToUTC(userTime);
382 const uint64_t deltaSampleTime = samples[i].sampleTimes[1] - samples[i].sampleTimes[0];
383 const uint64_t deltaCpuTime = samples[i].cpuTimes[1] - samples[i].cpuTimes[0];
384 const float usage = 100.f * (float(deltaCpuTime) / deltaSampleTime) / numberOfProcessors;
385 cpuUsage.AppendElement(usage);
386 }
388 return true;
389 }
391 } // anonymous namespace
393 void
394 PluginModuleParent::ExitedCxxStack()
395 {
396 FinishHangUI();
397 }
399 #endif // #ifdef XP_WIN
401 #ifdef MOZ_CRASHREPORTER_INJECTOR
402 static bool
403 CreateFlashMinidump(DWORD processId, ThreadId childThread,
404 nsIFile* parentMinidump, const nsACString& name)
405 {
406 if (processId == 0) {
407 return false;
408 }
410 base::ProcessHandle handle;
411 if (!base::OpenPrivilegedProcessHandle(processId, &handle)) {
412 return false;
413 }
415 bool res = CreateAdditionalChildMinidump(handle, 0, parentMinidump, name);
416 base::CloseProcessHandle(handle);
418 return res;
419 }
420 #endif
422 bool
423 PluginModuleParent::ShouldContinueFromReplyTimeout()
424 {
425 #ifdef XP_WIN
426 if (LaunchHangUI()) {
427 return true;
428 }
429 // If LaunchHangUI returned false then we should proceed with the
430 // original plugin hang behaviour and kill the plugin container.
431 FinishHangUI();
432 #endif // XP_WIN
433 TerminateChildProcess(MessageLoop::current());
434 return false;
435 }
437 void
438 PluginModuleParent::TerminateChildProcess(MessageLoop* aMsgLoop)
439 {
440 #ifdef MOZ_CRASHREPORTER
441 #ifdef XP_WIN
442 mozilla::MutexAutoLock lock(mCrashReporterMutex);
443 CrashReporterParent* crashReporter = mCrashReporter;
444 if (!crashReporter) {
445 // If mCrashReporter is null then the hang has ended, the plugin module
446 // is shutting down. There's nothing to do here.
447 return;
448 }
449 #else
450 CrashReporterParent* crashReporter = CrashReporter();
451 #endif
452 crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("PluginHang"),
453 NS_LITERAL_CSTRING("1"));
454 #ifdef XP_WIN
455 if (mHangUIParent) {
456 unsigned int hangUIDuration = mHangUIParent->LastShowDurationMs();
457 if (hangUIDuration) {
458 nsPrintfCString strHangUIDuration("%u", hangUIDuration);
459 crashReporter->AnnotateCrashReport(
460 NS_LITERAL_CSTRING("PluginHangUIDuration"),
461 strHangUIDuration);
462 }
463 }
464 #endif // XP_WIN
465 if (crashReporter->GeneratePairedMinidump(this)) {
466 mPluginDumpID = crashReporter->ChildDumpID();
467 PLUGIN_LOG_DEBUG(
468 ("generated paired browser/plugin minidumps: %s)",
469 NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
471 nsAutoCString additionalDumps("browser");
473 #ifdef MOZ_CRASHREPORTER_INJECTOR
474 nsCOMPtr<nsIFile> pluginDumpFile;
476 if (GetMinidumpForID(mPluginDumpID, getter_AddRefs(pluginDumpFile)) &&
477 pluginDumpFile) {
478 nsCOMPtr<nsIFile> childDumpFile;
480 if (CreateFlashMinidump(mFlashProcess1, 0, pluginDumpFile,
481 NS_LITERAL_CSTRING("flash1"))) {
482 additionalDumps.Append(",flash1");
483 }
484 if (CreateFlashMinidump(mFlashProcess2, 0, pluginDumpFile,
485 NS_LITERAL_CSTRING("flash2"))) {
486 additionalDumps.Append(",flash2");
487 }
488 }
489 #endif
491 crashReporter->AnnotateCrashReport(
492 NS_LITERAL_CSTRING("additional_minidumps"),
493 additionalDumps);
494 } else {
495 NS_WARNING("failed to capture paired minidumps from hang");
496 }
497 #endif
499 #ifdef XP_WIN
500 // collect cpu usage for plugin processes
502 InfallibleTArray<base::ProcessHandle> processHandles;
504 processHandles.AppendElement(OtherProcess());
506 #ifdef MOZ_CRASHREPORTER_INJECTOR
507 {
508 base::ProcessHandle handle;
509 if (mFlashProcess1 && base::OpenProcessHandle(mFlashProcess1, &handle)) {
510 processHandles.AppendElement(handle);
511 }
512 if (mFlashProcess2 && base::OpenProcessHandle(mFlashProcess2, &handle)) {
513 processHandles.AppendElement(handle);
514 }
515 }
516 #endif
518 if (!GetProcessCpuUsage(processHandles, mPluginCpuUsageOnHang)) {
519 mPluginCpuUsageOnHang.Clear();
520 }
521 #endif
523 // this must run before the error notification from the channel,
524 // or not at all
525 bool isFromHangUI = aMsgLoop != MessageLoop::current();
526 aMsgLoop->PostTask(
527 FROM_HERE,
528 mTaskFactory.NewRunnableMethod(
529 &PluginModuleParent::CleanupFromTimeout, isFromHangUI));
531 if (!KillProcess(OtherProcess(), 1, false))
532 NS_WARNING("failed to kill subprocess!");
533 }
535 #ifdef XP_WIN
536 void
537 PluginModuleParent::EvaluateHangUIState(const bool aReset)
538 {
539 int32_t minDispSecs = Preferences::GetInt(kHangUIMinDisplayPref, 10);
540 int32_t autoStopSecs = Preferences::GetInt(kChildTimeoutPref, 0);
541 int32_t timeoutSecs = 0;
542 if (autoStopSecs > 0 && autoStopSecs < minDispSecs) {
543 /* If we're going to automatically terminate the plugin within a
544 time frame shorter than minDispSecs, there's no point in
545 showing the hang UI; it would just flash briefly on the screen. */
546 mHangUIEnabled = false;
547 } else {
548 timeoutSecs = Preferences::GetInt(kHangUITimeoutPref, 0);
549 mHangUIEnabled = timeoutSecs > 0;
550 }
551 if (mHangUIEnabled) {
552 if (aReset) {
553 mIsTimerReset = true;
554 SetChildTimeout(timeoutSecs);
555 return;
556 } else if (mIsTimerReset) {
557 /* The Hang UI is being shown, so now we're setting the
558 timeout to kChildTimeoutPref while we wait for a user
559 response. ShouldContinueFromReplyTimeout will fire
560 after (reply timeout / 2) seconds, which is not what
561 we want. Doubling the timeout value here so that we get
562 the right result. */
563 autoStopSecs *= 2;
564 }
565 }
566 mIsTimerReset = false;
567 SetChildTimeout(autoStopSecs);
568 }
570 bool
571 PluginModuleParent::GetPluginName(nsAString& aPluginName)
572 {
573 nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
574 if (!host) {
575 return false;
576 }
577 nsPluginTag* pluginTag = host->TagForPlugin(mPlugin);
578 if (!pluginTag) {
579 return false;
580 }
581 CopyUTF8toUTF16(pluginTag->mName, aPluginName);
582 return true;
583 }
585 bool
586 PluginModuleParent::LaunchHangUI()
587 {
588 if (!mHangUIEnabled) {
589 return false;
590 }
591 if (mHangUIParent) {
592 if (mHangUIParent->IsShowing()) {
593 // We've already shown the UI but the timeout has expired again.
594 return false;
595 }
596 if (mHangUIParent->DontShowAgain()) {
597 return !mHangUIParent->WasLastHangStopped();
598 }
599 delete mHangUIParent;
600 mHangUIParent = nullptr;
601 }
602 mHangUIParent = new PluginHangUIParent(this,
603 Preferences::GetInt(kHangUITimeoutPref, 0),
604 Preferences::GetInt(kChildTimeoutPref, 0));
605 nsAutoString pluginName;
606 if (!GetPluginName(pluginName)) {
607 return false;
608 }
609 bool retval = mHangUIParent->Init(pluginName);
610 if (retval) {
611 /* Once the UI is shown we switch the timeout over to use
612 kChildTimeoutPref, allowing us to terminate a hung plugin
613 after kChildTimeoutPref seconds if the user doesn't respond to
614 the hang UI. */
615 EvaluateHangUIState(false);
616 }
617 return retval;
618 }
620 void
621 PluginModuleParent::FinishHangUI()
622 {
623 if (mHangUIEnabled && mHangUIParent) {
624 bool needsCancel = mHangUIParent->IsShowing();
625 // If we're still showing, send a Cancel notification
626 if (needsCancel) {
627 mHangUIParent->Cancel();
628 }
629 /* If we cancelled the UI or if the user issued a response,
630 we need to reset the child process timeout. */
631 if (needsCancel ||
632 !mIsTimerReset && mHangUIParent->WasShown()) {
633 /* We changed the timeout to kChildTimeoutPref when the plugin hang
634 UI was displayed. Now that we're finishing the UI, we need to
635 switch it back to kHangUITimeoutPref. */
636 EvaluateHangUIState(true);
637 }
638 }
639 }
640 #endif // XP_WIN
642 #ifdef MOZ_CRASHREPORTER
643 CrashReporterParent*
644 PluginModuleParent::CrashReporter()
645 {
646 return static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
647 }
649 #ifdef MOZ_CRASHREPORTER_INJECTOR
650 static void
651 RemoveMinidump(nsIFile* minidump)
652 {
653 if (!minidump)
654 return;
656 minidump->Remove(false);
657 nsCOMPtr<nsIFile> extraFile;
658 if (GetExtraFileForMinidump(minidump,
659 getter_AddRefs(extraFile))) {
660 extraFile->Remove(true);
661 }
662 }
663 #endif // MOZ_CRASHREPORTER_INJECTOR
665 void
666 PluginModuleParent::ProcessFirstMinidump()
667 {
668 #ifdef XP_WIN
669 mozilla::MutexAutoLock lock(mCrashReporterMutex);
670 #endif
671 CrashReporterParent* crashReporter = CrashReporter();
672 if (!crashReporter)
673 return;
675 AnnotationTable notes(4);
676 WriteExtraDataForMinidump(notes);
678 if (!mPluginDumpID.IsEmpty()) {
679 crashReporter->GenerateChildData(¬es);
680 return;
681 }
683 uint32_t sequence = UINT32_MAX;
684 nsCOMPtr<nsIFile> dumpFile;
685 nsAutoCString flashProcessType;
686 TakeMinidump(getter_AddRefs(dumpFile), &sequence);
688 #ifdef MOZ_CRASHREPORTER_INJECTOR
689 nsCOMPtr<nsIFile> childDumpFile;
690 uint32_t childSequence;
692 if (mFlashProcess1 &&
693 TakeMinidumpForChild(mFlashProcess1,
694 getter_AddRefs(childDumpFile),
695 &childSequence)) {
696 if (childSequence < sequence) {
697 RemoveMinidump(dumpFile);
698 dumpFile = childDumpFile;
699 sequence = childSequence;
700 flashProcessType.AssignLiteral("Broker");
701 }
702 else {
703 RemoveMinidump(childDumpFile);
704 }
705 }
706 if (mFlashProcess2 &&
707 TakeMinidumpForChild(mFlashProcess2,
708 getter_AddRefs(childDumpFile),
709 &childSequence)) {
710 if (childSequence < sequence) {
711 RemoveMinidump(dumpFile);
712 dumpFile = childDumpFile;
713 sequence = childSequence;
714 flashProcessType.AssignLiteral("Sandbox");
715 }
716 else {
717 RemoveMinidump(childDumpFile);
718 }
719 }
720 #endif
722 if (!dumpFile) {
723 NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
724 return;
725 }
727 PLUGIN_LOG_DEBUG(("got child minidump: %s",
728 NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
730 GetIDFromMinidump(dumpFile, mPluginDumpID);
731 if (!flashProcessType.IsEmpty()) {
732 notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"), flashProcessType);
733 }
734 crashReporter->GenerateCrashReportForMinidump(dumpFile, ¬es);
735 }
736 #endif
738 void
739 PluginModuleParent::ActorDestroy(ActorDestroyReason why)
740 {
741 switch (why) {
742 case AbnormalShutdown: {
743 #ifdef MOZ_CRASHREPORTER
744 ProcessFirstMinidump();
745 #endif
747 mShutdown = true;
748 // Defer the PluginCrashed method so that we don't re-enter
749 // and potentially modify the actor child list while enumerating it.
750 if (mPlugin)
751 MessageLoop::current()->PostTask(
752 FROM_HERE,
753 mTaskFactory.NewRunnableMethod(
754 &PluginModuleParent::NotifyPluginCrashed));
755 break;
756 }
757 case NormalShutdown:
758 mShutdown = true;
759 break;
761 default:
762 NS_RUNTIMEABORT("Unexpected shutdown reason for toplevel actor.");
763 }
764 }
766 void
767 PluginModuleParent::NotifyPluginCrashed()
768 {
769 if (!OkToCleanup()) {
770 // there's still plugin code on the C++ stack. try again
771 MessageLoop::current()->PostDelayedTask(
772 FROM_HERE,
773 mTaskFactory.NewRunnableMethod(
774 &PluginModuleParent::NotifyPluginCrashed), 10);
775 return;
776 }
778 if (mPlugin)
779 mPlugin->PluginCrashed(mPluginDumpID, mBrowserDumpID);
780 }
782 PPluginIdentifierParent*
783 PluginModuleParent::AllocPPluginIdentifierParent(const nsCString& aString,
784 const int32_t& aInt,
785 const bool& aTemporary)
786 {
787 if (aTemporary) {
788 NS_ERROR("Plugins don't create temporary identifiers.");
789 return nullptr; // should abort the plugin
790 }
792 NPIdentifier npident = aString.IsVoid() ?
793 mozilla::plugins::parent::_getintidentifier(aInt) :
794 mozilla::plugins::parent::_getstringidentifier(aString.get());
796 if (!npident) {
797 NS_WARNING("Failed to get identifier!");
798 return nullptr;
799 }
801 PluginIdentifierParent* ident = new PluginIdentifierParent(npident, false);
802 mIdentifiers.Put(npident, ident);
803 return ident;
804 }
806 bool
807 PluginModuleParent::DeallocPPluginIdentifierParent(PPluginIdentifierParent* aActor)
808 {
809 delete aActor;
810 return true;
811 }
813 PPluginInstanceParent*
814 PluginModuleParent::AllocPPluginInstanceParent(const nsCString& aMimeType,
815 const uint16_t& aMode,
816 const InfallibleTArray<nsCString>& aNames,
817 const InfallibleTArray<nsCString>& aValues,
818 NPError* rv)
819 {
820 NS_ERROR("Not reachable!");
821 return nullptr;
822 }
824 bool
825 PluginModuleParent::DeallocPPluginInstanceParent(PPluginInstanceParent* aActor)
826 {
827 PLUGIN_LOG_DEBUG_METHOD;
828 delete aActor;
829 return true;
830 }
832 void
833 PluginModuleParent::SetPluginFuncs(NPPluginFuncs* aFuncs)
834 {
835 aFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
836 aFuncs->javaClass = nullptr;
838 // Gecko should always call these functions through a PluginLibrary object.
839 aFuncs->newp = nullptr;
840 aFuncs->clearsitedata = nullptr;
841 aFuncs->getsiteswithdata = nullptr;
843 aFuncs->destroy = NPP_Destroy;
844 aFuncs->setwindow = NPP_SetWindow;
845 aFuncs->newstream = NPP_NewStream;
846 aFuncs->destroystream = NPP_DestroyStream;
847 aFuncs->asfile = NPP_StreamAsFile;
848 aFuncs->writeready = NPP_WriteReady;
849 aFuncs->write = NPP_Write;
850 aFuncs->print = NPP_Print;
851 aFuncs->event = NPP_HandleEvent;
852 aFuncs->urlnotify = NPP_URLNotify;
853 aFuncs->getvalue = NPP_GetValue;
854 aFuncs->setvalue = NPP_SetValue;
855 aFuncs->gotfocus = nullptr;
856 aFuncs->lostfocus = nullptr;
857 aFuncs->urlredirectnotify = nullptr;
859 // Provide 'NPP_URLRedirectNotify', 'NPP_ClearSiteData', and
860 // 'NPP_GetSitesWithData' functionality if it is supported by the plugin.
861 bool urlRedirectSupported = false;
862 unused << CallOptionalFunctionsSupported(&urlRedirectSupported,
863 &mClearSiteDataSupported,
864 &mGetSitesWithDataSupported);
865 if (urlRedirectSupported) {
866 aFuncs->urlredirectnotify = NPP_URLRedirectNotify;
867 }
868 }
870 NPError
871 PluginModuleParent::NPP_Destroy(NPP instance,
872 NPSavedData** /*saved*/)
873 {
874 // FIXME/cjones:
875 // (1) send a "destroy" message to the child
876 // (2) the child shuts down its instance
877 // (3) remove both parent and child IDs from map
878 // (4) free parent
879 PLUGIN_LOG_DEBUG_FUNCTION;
881 PluginInstanceParent* parentInstance =
882 static_cast<PluginInstanceParent*>(instance->pdata);
884 if (!parentInstance)
885 return NPERR_NO_ERROR;
887 NPError retval = parentInstance->Destroy();
888 instance->pdata = nullptr;
890 unused << PluginInstanceParent::Call__delete__(parentInstance);
891 return retval;
892 }
894 NPError
895 PluginModuleParent::NPP_NewStream(NPP instance, NPMIMEType type,
896 NPStream* stream, NPBool seekable,
897 uint16_t* stype)
898 {
899 PROFILER_LABEL("PluginModuleParent", "NPP_NewStream");
900 PluginInstanceParent* i = InstCast(instance);
901 if (!i)
902 return NPERR_GENERIC_ERROR;
904 return i->NPP_NewStream(type, stream, seekable,
905 stype);
906 }
908 NPError
909 PluginModuleParent::NPP_SetWindow(NPP instance, NPWindow* window)
910 {
911 PluginInstanceParent* i = InstCast(instance);
912 if (!i)
913 return NPERR_GENERIC_ERROR;
915 return i->NPP_SetWindow(window);
916 }
918 NPError
919 PluginModuleParent::NPP_DestroyStream(NPP instance,
920 NPStream* stream,
921 NPReason reason)
922 {
923 PluginInstanceParent* i = InstCast(instance);
924 if (!i)
925 return NPERR_GENERIC_ERROR;
927 return i->NPP_DestroyStream(stream, reason);
928 }
930 int32_t
931 PluginModuleParent::NPP_WriteReady(NPP instance,
932 NPStream* stream)
933 {
934 BrowserStreamParent* s = StreamCast(instance, stream);
935 if (!s)
936 return -1;
938 return s->WriteReady();
939 }
941 int32_t
942 PluginModuleParent::NPP_Write(NPP instance,
943 NPStream* stream,
944 int32_t offset,
945 int32_t len,
946 void* buffer)
947 {
948 BrowserStreamParent* s = StreamCast(instance, stream);
949 if (!s)
950 return -1;
952 return s->Write(offset, len, buffer);
953 }
955 void
956 PluginModuleParent::NPP_StreamAsFile(NPP instance,
957 NPStream* stream,
958 const char* fname)
959 {
960 BrowserStreamParent* s = StreamCast(instance, stream);
961 if (!s)
962 return;
964 s->StreamAsFile(fname);
965 }
967 void
968 PluginModuleParent::NPP_Print(NPP instance, NPPrint* platformPrint)
969 {
970 PluginInstanceParent* i = InstCast(instance);
971 if (i)
972 i->NPP_Print(platformPrint);
973 }
975 int16_t
976 PluginModuleParent::NPP_HandleEvent(NPP instance, void* event)
977 {
978 PluginInstanceParent* i = InstCast(instance);
979 if (!i)
980 return false;
982 return i->NPP_HandleEvent(event);
983 }
985 void
986 PluginModuleParent::NPP_URLNotify(NPP instance, const char* url,
987 NPReason reason, void* notifyData)
988 {
989 PluginInstanceParent* i = InstCast(instance);
990 if (!i)
991 return;
993 i->NPP_URLNotify(url, reason, notifyData);
994 }
996 NPError
997 PluginModuleParent::NPP_GetValue(NPP instance,
998 NPPVariable variable, void *ret_value)
999 {
1000 PluginInstanceParent* i = InstCast(instance);
1001 if (!i)
1002 return NPERR_GENERIC_ERROR;
1004 return i->NPP_GetValue(variable, ret_value);
1005 }
1007 NPError
1008 PluginModuleParent::NPP_SetValue(NPP instance, NPNVariable variable,
1009 void *value)
1010 {
1011 PluginInstanceParent* i = InstCast(instance);
1012 if (!i)
1013 return NPERR_GENERIC_ERROR;
1015 return i->NPP_SetValue(variable, value);
1016 }
1018 bool
1019 PluginModuleParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd)
1020 {
1021 #ifndef MOZ_X11
1022 NS_RUNTIMEABORT("This message only makes sense on X11 platforms");
1023 #else
1024 NS_ABORT_IF_FALSE(0 > mPluginXSocketFdDup.get(),
1025 "Already backed up X resources??");
1026 mPluginXSocketFdDup.forget();
1027 if (aXSocketFd.IsValid()) {
1028 mPluginXSocketFdDup.reset(aXSocketFd.PlatformHandle());
1029 }
1030 #endif
1031 return true;
1032 }
1034 void
1035 PluginModuleParent::NPP_URLRedirectNotify(NPP instance, const char* url,
1036 int32_t status, void* notifyData)
1037 {
1038 PluginInstanceParent* i = InstCast(instance);
1039 if (!i)
1040 return;
1042 i->NPP_URLRedirectNotify(url, status, notifyData);
1043 }
1045 bool
1046 PluginModuleParent::AnswerNPN_UserAgent(nsCString* userAgent)
1047 {
1048 *userAgent = NullableString(mNPNIface->uagent(nullptr));
1049 return true;
1050 }
1052 PluginIdentifierParent*
1053 PluginModuleParent::GetIdentifierForNPIdentifier(NPP npp, NPIdentifier aIdentifier)
1054 {
1055 PluginIdentifierParent* ident;
1056 if (mIdentifiers.Get(aIdentifier, &ident)) {
1057 if (ident->IsTemporary()) {
1058 ident->AddTemporaryRef();
1059 }
1060 return ident;
1061 }
1063 nsCString string;
1064 int32_t intval = -1;
1065 bool temporary = false;
1066 if (mozilla::plugins::parent::_identifierisstring(aIdentifier)) {
1067 NPUTF8* chars =
1068 mozilla::plugins::parent::_utf8fromidentifier(aIdentifier);
1069 if (!chars) {
1070 return nullptr;
1071 }
1072 string.Adopt(chars);
1073 temporary = !NPStringIdentifierIsPermanent(npp, aIdentifier);
1074 }
1075 else {
1076 intval = mozilla::plugins::parent::_intfromidentifier(aIdentifier);
1077 string.SetIsVoid(true);
1078 }
1080 ident = new PluginIdentifierParent(aIdentifier, temporary);
1081 if (!SendPPluginIdentifierConstructor(ident, string, intval, temporary))
1082 return nullptr;
1084 if (!temporary) {
1085 mIdentifiers.Put(aIdentifier, ident);
1086 }
1087 return ident;
1088 }
1090 PluginInstanceParent*
1091 PluginModuleParent::InstCast(NPP instance)
1092 {
1093 PluginInstanceParent* ip =
1094 static_cast<PluginInstanceParent*>(instance->pdata);
1096 // If the plugin crashed and the PluginInstanceParent was deleted,
1097 // instance->pdata will be nullptr.
1098 if (!ip)
1099 return nullptr;
1101 if (instance != ip->mNPP) {
1102 NS_RUNTIMEABORT("Corrupted plugin data.");
1103 }
1104 return ip;
1105 }
1107 BrowserStreamParent*
1108 PluginModuleParent::StreamCast(NPP instance,
1109 NPStream* s)
1110 {
1111 PluginInstanceParent* ip = InstCast(instance);
1112 if (!ip)
1113 return nullptr;
1115 BrowserStreamParent* sp =
1116 static_cast<BrowserStreamParent*>(static_cast<AStream*>(s->pdata));
1117 if (sp->mNPP != ip || s != sp->mStream) {
1118 NS_RUNTIMEABORT("Corrupted plugin stream data.");
1119 }
1120 return sp;
1121 }
1123 bool
1124 PluginModuleParent::HasRequiredFunctions()
1125 {
1126 return true;
1127 }
1129 nsresult
1130 PluginModuleParent::AsyncSetWindow(NPP instance, NPWindow* window)
1131 {
1132 PluginInstanceParent* i = InstCast(instance);
1133 if (!i)
1134 return NS_ERROR_FAILURE;
1136 return i->AsyncSetWindow(window);
1137 }
1139 nsresult
1140 PluginModuleParent::GetImageContainer(NPP instance,
1141 mozilla::layers::ImageContainer** aContainer)
1142 {
1143 PluginInstanceParent* i = InstCast(instance);
1144 return !i ? NS_ERROR_FAILURE : i->GetImageContainer(aContainer);
1145 }
1147 nsresult
1148 PluginModuleParent::GetImageSize(NPP instance,
1149 nsIntSize* aSize)
1150 {
1151 PluginInstanceParent* i = InstCast(instance);
1152 return !i ? NS_ERROR_FAILURE : i->GetImageSize(aSize);
1153 }
1155 nsresult
1156 PluginModuleParent::SetBackgroundUnknown(NPP instance)
1157 {
1158 PluginInstanceParent* i = InstCast(instance);
1159 if (!i)
1160 return NS_ERROR_FAILURE;
1162 return i->SetBackgroundUnknown();
1163 }
1165 nsresult
1166 PluginModuleParent::BeginUpdateBackground(NPP instance,
1167 const nsIntRect& aRect,
1168 gfxContext** aCtx)
1169 {
1170 PluginInstanceParent* i = InstCast(instance);
1171 if (!i)
1172 return NS_ERROR_FAILURE;
1174 return i->BeginUpdateBackground(aRect, aCtx);
1175 }
1177 nsresult
1178 PluginModuleParent::EndUpdateBackground(NPP instance,
1179 gfxContext* aCtx,
1180 const nsIntRect& aRect)
1181 {
1182 PluginInstanceParent* i = InstCast(instance);
1183 if (!i)
1184 return NS_ERROR_FAILURE;
1186 return i->EndUpdateBackground(aCtx, aRect);
1187 }
1189 #if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK)
1190 nsresult
1191 PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error)
1192 {
1193 PLUGIN_LOG_DEBUG_METHOD;
1195 mNPNIface = bFuncs;
1197 if (mShutdown) {
1198 *error = NPERR_GENERIC_ERROR;
1199 return NS_ERROR_FAILURE;
1200 }
1202 uint32_t flags = 0;
1204 if (!CallNP_Initialize(flags, error)) {
1205 Close();
1206 return NS_ERROR_FAILURE;
1207 }
1208 else if (*error != NPERR_NO_ERROR) {
1209 Close();
1210 return NS_OK;
1211 }
1213 SetPluginFuncs(pFuncs);
1215 return NS_OK;
1216 }
1217 #else
1218 nsresult
1219 PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
1220 {
1221 PLUGIN_LOG_DEBUG_METHOD;
1223 mNPNIface = bFuncs;
1225 if (mShutdown) {
1226 *error = NPERR_GENERIC_ERROR;
1227 return NS_ERROR_FAILURE;
1228 }
1230 uint32_t flags = 0;
1231 #ifdef XP_WIN
1232 flags |= kAllowAsyncDrawing;
1233 #endif
1235 if (!CallNP_Initialize(flags, error)) {
1236 Close();
1237 return NS_ERROR_FAILURE;
1238 }
1239 if (*error != NPERR_NO_ERROR) {
1240 Close();
1241 return NS_OK;
1242 }
1244 #if defined XP_WIN
1245 // Send the info needed to join the chrome process's audio session to the
1246 // plugin process
1247 nsID id;
1248 nsString sessionName;
1249 nsString iconPath;
1251 if (NS_SUCCEEDED(mozilla::widget::GetAudioSessionData(id, sessionName,
1252 iconPath)))
1253 unused << SendSetAudioSessionData(id, sessionName, iconPath);
1254 #endif
1256 #ifdef MOZ_CRASHREPORTER_INJECTOR
1257 InitializeInjector();
1258 #endif
1260 return NS_OK;
1261 }
1262 #endif
1264 nsresult
1265 PluginModuleParent::NP_Shutdown(NPError* error)
1266 {
1267 PLUGIN_LOG_DEBUG_METHOD;
1269 if (mShutdown) {
1270 *error = NPERR_GENERIC_ERROR;
1271 return NS_ERROR_FAILURE;
1272 }
1274 bool ok = CallNP_Shutdown(error);
1276 // if NP_Shutdown() is nested within another interrupt call, this will
1277 // break things. but lord help us if we're doing that anyway; the
1278 // plugin dso will have been unloaded on the other side by the
1279 // CallNP_Shutdown() message
1280 Close();
1282 return ok ? NS_OK : NS_ERROR_FAILURE;
1283 }
1285 nsresult
1286 PluginModuleParent::NP_GetMIMEDescription(const char** mimeDesc)
1287 {
1288 PLUGIN_LOG_DEBUG_METHOD;
1290 *mimeDesc = "application/x-foobar";
1291 return NS_OK;
1292 }
1294 nsresult
1295 PluginModuleParent::NP_GetValue(void *future, NPPVariable aVariable,
1296 void *aValue, NPError* error)
1297 {
1298 PR_LOG(GetPluginLog(), PR_LOG_WARNING, ("%s Not implemented, requested variable %i", __FUNCTION__,
1299 (int) aVariable));
1301 //TODO: implement this correctly
1302 *error = NPERR_GENERIC_ERROR;
1303 return NS_OK;
1304 }
1306 #if defined(XP_WIN) || defined(XP_MACOSX)
1307 nsresult
1308 PluginModuleParent::NP_GetEntryPoints(NPPluginFuncs* pFuncs, NPError* error)
1309 {
1310 NS_ASSERTION(pFuncs, "Null pointer!");
1312 // We need to have the child process update its function table
1313 // here by actually calling NP_GetEntryPoints since the parent's
1314 // function table can reflect nullptr entries in the child's table.
1315 if (!CallNP_GetEntryPoints(error)) {
1316 return NS_ERROR_FAILURE;
1317 }
1318 else if (*error != NPERR_NO_ERROR) {
1319 return NS_OK;
1320 }
1322 SetPluginFuncs(pFuncs);
1324 return NS_OK;
1325 }
1326 #endif
1328 nsresult
1329 PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance,
1330 uint16_t mode, int16_t argc, char* argn[],
1331 char* argv[], NPSavedData* saved,
1332 NPError* error)
1333 {
1334 PLUGIN_LOG_DEBUG_METHOD;
1336 if (mShutdown) {
1337 *error = NPERR_GENERIC_ERROR;
1338 return NS_ERROR_FAILURE;
1339 }
1341 // create the instance on the other side
1342 InfallibleTArray<nsCString> names;
1343 InfallibleTArray<nsCString> values;
1345 for (int i = 0; i < argc; ++i) {
1346 names.AppendElement(NullableString(argn[i]));
1347 values.AppendElement(NullableString(argv[i]));
1348 }
1350 PluginInstanceParent* parentInstance =
1351 new PluginInstanceParent(this, instance,
1352 nsDependentCString(pluginType), mNPNIface);
1354 if (!parentInstance->Init()) {
1355 delete parentInstance;
1356 return NS_ERROR_FAILURE;
1357 }
1359 instance->pdata = parentInstance;
1361 if (!CallPPluginInstanceConstructor(parentInstance,
1362 nsDependentCString(pluginType), mode,
1363 names, values, error)) {
1364 // |parentInstance| is automatically deleted.
1365 instance->pdata = nullptr;
1366 // if IPC is down, we'll get an immediate "failed" return, but
1367 // without *error being set. So make sure that the error
1368 // condition is signaled to nsNPAPIPluginInstance
1369 if (NPERR_NO_ERROR == *error)
1370 *error = NPERR_GENERIC_ERROR;
1371 return NS_ERROR_FAILURE;
1372 }
1374 if (*error != NPERR_NO_ERROR) {
1375 NPP_Destroy(instance, 0);
1376 return NS_ERROR_FAILURE;
1377 }
1379 TimeoutChanged(kParentTimeoutPref, this);
1381 return NS_OK;
1382 }
1384 nsresult
1385 PluginModuleParent::NPP_ClearSiteData(const char* site, uint64_t flags,
1386 uint64_t maxAge)
1387 {
1388 if (!mClearSiteDataSupported)
1389 return NS_ERROR_NOT_AVAILABLE;
1391 NPError result;
1392 if (!CallNPP_ClearSiteData(NullableString(site), flags, maxAge, &result))
1393 return NS_ERROR_FAILURE;
1395 switch (result) {
1396 case NPERR_NO_ERROR:
1397 return NS_OK;
1398 case NPERR_TIME_RANGE_NOT_SUPPORTED:
1399 return NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED;
1400 case NPERR_MALFORMED_SITE:
1401 return NS_ERROR_INVALID_ARG;
1402 default:
1403 return NS_ERROR_FAILURE;
1404 }
1405 }
1407 nsresult
1408 PluginModuleParent::NPP_GetSitesWithData(InfallibleTArray<nsCString>& result)
1409 {
1410 if (!mGetSitesWithDataSupported)
1411 return NS_ERROR_NOT_AVAILABLE;
1413 if (!CallNPP_GetSitesWithData(&result))
1414 return NS_ERROR_FAILURE;
1416 return NS_OK;
1417 }
1419 #if defined(XP_MACOSX)
1420 nsresult
1421 PluginModuleParent::IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing)
1422 {
1423 PluginInstanceParent* i = InstCast(instance);
1424 if (!i)
1425 return NS_ERROR_FAILURE;
1427 return i->IsRemoteDrawingCoreAnimation(aDrawing);
1428 }
1430 nsresult
1431 PluginModuleParent::ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor)
1432 {
1433 PluginInstanceParent* i = InstCast(instance);
1434 if (!i)
1435 return NS_ERROR_FAILURE;
1437 return i->ContentsScaleFactorChanged(aContentsScaleFactor);
1438 }
1439 #endif // #if defined(XP_MACOSX)
1441 bool
1442 PluginModuleParent::AnswerNPN_GetValue_WithBoolReturn(const NPNVariable& aVariable,
1443 NPError* aError,
1444 bool* aBoolVal)
1445 {
1446 NPBool boolVal = false;
1447 *aError = mozilla::plugins::parent::_getvalue(nullptr, aVariable, &boolVal);
1448 *aBoolVal = boolVal ? true : false;
1449 return true;
1450 }
1452 #if defined(MOZ_WIDGET_QT)
1453 static const int kMaxtimeToProcessEvents = 30;
1454 bool
1455 PluginModuleParent::AnswerProcessSomeEvents()
1456 {
1457 PLUGIN_LOG_DEBUG(("Spinning mini nested loop ..."));
1458 QCoreApplication::processEvents(QEventLoop::AllEvents, kMaxtimeToProcessEvents);
1460 PLUGIN_LOG_DEBUG(("... quitting mini nested loop"));
1462 return true;
1463 }
1465 #elif defined(XP_MACOSX)
1466 bool
1467 PluginModuleParent::AnswerProcessSomeEvents()
1468 {
1469 mozilla::plugins::PluginUtilsOSX::InvokeNativeEventLoop();
1470 return true;
1471 }
1473 #elif !defined(MOZ_WIDGET_GTK)
1474 bool
1475 PluginModuleParent::AnswerProcessSomeEvents()
1476 {
1477 NS_RUNTIMEABORT("unreached");
1478 return false;
1479 }
1481 #else
1482 static const int kMaxChancesToProcessEvents = 20;
1484 bool
1485 PluginModuleParent::AnswerProcessSomeEvents()
1486 {
1487 PLUGIN_LOG_DEBUG(("Spinning mini nested loop ..."));
1489 int i = 0;
1490 for (; i < kMaxChancesToProcessEvents; ++i)
1491 if (!g_main_context_iteration(nullptr, FALSE))
1492 break;
1494 PLUGIN_LOG_DEBUG(("... quitting mini nested loop; processed %i tasks", i));
1496 return true;
1497 }
1498 #endif
1500 bool
1501 PluginModuleParent::RecvProcessNativeEventsInInterruptCall()
1502 {
1503 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1504 #if defined(OS_WIN)
1505 ProcessNativeEventsInInterruptCall();
1506 return true;
1507 #else
1508 NS_NOTREACHED(
1509 "PluginModuleParent::RecvProcessNativeEventsInInterruptCall not implemented!");
1510 return false;
1511 #endif
1512 }
1514 void
1515 PluginModuleParent::ProcessRemoteNativeEventsInInterruptCall()
1516 {
1517 #if defined(OS_WIN)
1518 unused << SendProcessNativeEventsInInterruptCall();
1519 return;
1520 #endif
1521 NS_NOTREACHED(
1522 "PluginModuleParent::ProcessRemoteNativeEventsInInterruptCall not implemented!");
1523 }
1525 bool
1526 PluginModuleParent::RecvPluginShowWindow(const uint32_t& aWindowId, const bool& aModal,
1527 const int32_t& aX, const int32_t& aY,
1528 const size_t& aWidth, const size_t& aHeight)
1529 {
1530 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1531 #if defined(XP_MACOSX)
1532 CGRect windowBound = ::CGRectMake(aX, aY, aWidth, aHeight);
1533 mac_plugin_interposing::parent::OnPluginShowWindow(aWindowId, windowBound, aModal);
1534 return true;
1535 #else
1536 NS_NOTREACHED(
1537 "PluginInstanceParent::RecvPluginShowWindow not implemented!");
1538 return false;
1539 #endif
1540 }
1542 bool
1543 PluginModuleParent::RecvPluginHideWindow(const uint32_t& aWindowId)
1544 {
1545 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1546 #if defined(XP_MACOSX)
1547 mac_plugin_interposing::parent::OnPluginHideWindow(aWindowId, OtherSidePID());
1548 return true;
1549 #else
1550 NS_NOTREACHED(
1551 "PluginInstanceParent::RecvPluginHideWindow not implemented!");
1552 return false;
1553 #endif
1554 }
1556 PCrashReporterParent*
1557 PluginModuleParent::AllocPCrashReporterParent(mozilla::dom::NativeThreadId* id,
1558 uint32_t* processType)
1559 {
1560 #ifdef MOZ_CRASHREPORTER
1561 return new CrashReporterParent();
1562 #else
1563 return nullptr;
1564 #endif
1565 }
1567 bool
1568 PluginModuleParent::DeallocPCrashReporterParent(PCrashReporterParent* actor)
1569 {
1570 #ifdef MOZ_CRASHREPORTER
1571 #ifdef XP_WIN
1572 mozilla::MutexAutoLock lock(mCrashReporterMutex);
1573 if (actor == static_cast<PCrashReporterParent*>(mCrashReporter)) {
1574 mCrashReporter = nullptr;
1575 }
1576 #endif
1577 #endif
1578 delete actor;
1579 return true;
1580 }
1582 bool
1583 PluginModuleParent::RecvSetCursor(const NSCursorInfo& aCursorInfo)
1584 {
1585 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1586 #if defined(XP_MACOSX)
1587 mac_plugin_interposing::parent::OnSetCursor(aCursorInfo);
1588 return true;
1589 #else
1590 NS_NOTREACHED(
1591 "PluginInstanceParent::RecvSetCursor not implemented!");
1592 return false;
1593 #endif
1594 }
1596 bool
1597 PluginModuleParent::RecvShowCursor(const bool& aShow)
1598 {
1599 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1600 #if defined(XP_MACOSX)
1601 mac_plugin_interposing::parent::OnShowCursor(aShow);
1602 return true;
1603 #else
1604 NS_NOTREACHED(
1605 "PluginInstanceParent::RecvShowCursor not implemented!");
1606 return false;
1607 #endif
1608 }
1610 bool
1611 PluginModuleParent::RecvPushCursor(const NSCursorInfo& aCursorInfo)
1612 {
1613 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1614 #if defined(XP_MACOSX)
1615 mac_plugin_interposing::parent::OnPushCursor(aCursorInfo);
1616 return true;
1617 #else
1618 NS_NOTREACHED(
1619 "PluginInstanceParent::RecvPushCursor not implemented!");
1620 return false;
1621 #endif
1622 }
1624 bool
1625 PluginModuleParent::RecvPopCursor()
1626 {
1627 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1628 #if defined(XP_MACOSX)
1629 mac_plugin_interposing::parent::OnPopCursor();
1630 return true;
1631 #else
1632 NS_NOTREACHED(
1633 "PluginInstanceParent::RecvPopCursor not implemented!");
1634 return false;
1635 #endif
1636 }
1638 bool
1639 PluginModuleParent::RecvGetNativeCursorsSupported(bool* supported)
1640 {
1641 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1642 #if defined(XP_MACOSX)
1643 *supported =
1644 Preferences::GetBool("dom.ipc.plugins.nativeCursorSupport", false);
1645 return true;
1646 #else
1647 NS_NOTREACHED(
1648 "PluginInstanceParent::RecvGetNativeCursorSupportLevel not implemented!");
1649 return false;
1650 #endif
1651 }
1653 bool
1654 PluginModuleParent::RecvNPN_SetException(PPluginScriptableObjectParent* aActor,
1655 const nsCString& aMessage)
1656 {
1657 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1659 NPObject* aNPObj = nullptr;
1660 if (aActor) {
1661 aNPObj = static_cast<PluginScriptableObjectParent*>(aActor)->GetObject(true);
1662 if (!aNPObj) {
1663 NS_ERROR("Failed to get object!");
1664 return false;
1665 }
1666 }
1667 mozilla::plugins::parent::_setexception(aNPObj, NullableStringGet(aMessage));
1668 return true;
1669 }
1671 bool
1672 PluginModuleParent::RecvNPN_ReloadPlugins(const bool& aReloadPages)
1673 {
1674 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1676 mozilla::plugins::parent::_reloadplugins(aReloadPages);
1677 return true;
1678 }
1680 #ifdef MOZ_CRASHREPORTER_INJECTOR
1682 // We only add the crash reporter to subprocess which have the filename
1683 // FlashPlayerPlugin*
1684 #define FLASH_PROCESS_PREFIX "FLASHPLAYERPLUGIN"
1686 static DWORD
1687 GetFlashChildOfPID(DWORD pid, HANDLE snapshot)
1688 {
1689 PROCESSENTRY32 entry = {
1690 sizeof(entry)
1691 };
1692 for (BOOL ok = Process32First(snapshot, &entry);
1693 ok;
1694 ok = Process32Next(snapshot, &entry)) {
1695 if (entry.th32ParentProcessID == pid) {
1696 nsString name(entry.szExeFile);
1697 ToUpperCase(name);
1698 if (StringBeginsWith(name, NS_LITERAL_STRING(FLASH_PROCESS_PREFIX))) {
1699 return entry.th32ProcessID;
1700 }
1701 }
1702 }
1703 return 0;
1704 }
1706 // We only look for child processes of the Flash plugin, NPSWF*
1707 #define FLASH_PLUGIN_PREFIX "NPSWF"
1709 void
1710 PluginModuleParent::InitializeInjector()
1711 {
1712 if (!Preferences::GetBool("dom.ipc.plugins.flash.subprocess.crashreporter.enabled", false))
1713 return;
1715 nsCString path(Process()->GetPluginFilePath().c_str());
1716 ToUpperCase(path);
1717 int32_t lastSlash = path.RFindCharInSet("\\/");
1718 if (kNotFound == lastSlash)
1719 return;
1721 if (!StringBeginsWith(Substring(path, lastSlash + 1),
1722 NS_LITERAL_CSTRING(FLASH_PLUGIN_PREFIX)))
1723 return;
1725 HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1726 if (INVALID_HANDLE_VALUE == snapshot)
1727 return;
1729 DWORD pluginProcessPID = GetProcessId(Process()->GetChildProcessHandle());
1730 mFlashProcess1 = GetFlashChildOfPID(pluginProcessPID, snapshot);
1731 if (mFlashProcess1) {
1732 InjectCrashReporterIntoProcess(mFlashProcess1, this);
1734 mFlashProcess2 = GetFlashChildOfPID(mFlashProcess1, snapshot);
1735 if (mFlashProcess2) {
1736 InjectCrashReporterIntoProcess(mFlashProcess2, this);
1737 }
1738 }
1739 }
1741 void
1742 PluginModuleParent::OnCrash(DWORD processID)
1743 {
1744 if (!mShutdown) {
1745 GetIPCChannel()->CloseWithError();
1746 KillProcess(OtherProcess(), 1, false);
1747 }
1748 }
1750 #endif // MOZ_CRASHREPORTER_INJECTOR
1752 #ifdef MOZ_ENABLE_PROFILER_SPS
1753 class PluginProfilerObserver MOZ_FINAL : public nsIObserver,
1754 public nsSupportsWeakReference
1755 {
1756 public:
1757 NS_DECL_ISUPPORTS
1758 NS_DECL_NSIOBSERVER
1760 explicit PluginProfilerObserver(PluginModuleParent* pmp)
1761 : mPmp(pmp)
1762 {}
1764 private:
1765 PluginModuleParent* mPmp;
1766 };
1768 NS_IMPL_ISUPPORTS(PluginProfilerObserver, nsIObserver, nsISupportsWeakReference)
1770 NS_IMETHODIMP
1771 PluginProfilerObserver::Observe(nsISupports *aSubject,
1772 const char *aTopic,
1773 const char16_t *aData)
1774 {
1775 nsCOMPtr<nsIProfileSaveEvent> pse = do_QueryInterface(aSubject);
1776 if (pse) {
1777 nsCString result;
1778 bool success = mPmp->CallGeckoGetProfile(&result);
1779 if (success && !result.IsEmpty()) {
1780 pse->AddSubProfile(result.get());
1781 }
1782 }
1783 return NS_OK;
1784 }
1786 void
1787 PluginModuleParent::InitPluginProfiling()
1788 {
1789 nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
1790 if (observerService) {
1791 mProfilerObserver = new PluginProfilerObserver(this);
1792 observerService->AddObserver(mProfilerObserver, "profiler-subprocess", false);
1793 }
1794 }
1796 void
1797 PluginModuleParent::ShutdownPluginProfiling()
1798 {
1799 nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
1800 if (observerService) {
1801 observerService->RemoveObserver(mProfilerObserver, "profiler-subprocess");
1802 }
1803 }
1804 #endif