dom/plugins/ipc/PluginModuleParent.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:3d4230298b7b
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 #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
13
14 #include "mozilla/plugins/PluginModuleParent.h"
15
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"
34
35 #ifdef XP_WIN
36 #include "PluginHangUIParent.h"
37 #include "mozilla/widget/AudioSession.h"
38 #endif
39
40 #ifdef MOZ_ENABLE_PROFILER_SPS
41 #include "nsIProfileSaveEvent.h"
42 #endif
43
44 #ifdef MOZ_WIDGET_GTK
45 #include <glib.h>
46 #elif XP_MACOSX
47 #include "PluginInterposeOSX.h"
48 #include "PluginUtilsOSX.h"
49 #endif
50
51 using base::KillProcess;
52
53 using mozilla::PluginLibrary;
54 using mozilla::ipc::MessageChannel;
55 using mozilla::dom::PCrashReporterParent;
56 using mozilla::dom::CrashReporterParent;
57
58 using namespace mozilla;
59 using namespace mozilla::plugins;
60 using namespace mozilla::plugins::parent;
61
62 #ifdef MOZ_CRASHREPORTER
63 #include "mozilla/dom/CrashReporterParent.h"
64
65 using namespace CrashReporter;
66 #endif
67
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
78
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 };
86
87 // static
88 PluginLibrary*
89 PluginModuleParent::LoadModule(const char* aFilePath)
90 {
91 PLUGIN_LOG_DEBUG_FUNCTION;
92
93 int32_t prefSecs = Preferences::GetInt(kLaunchTimeoutPref, 0);
94
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());
105
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);
110
111 TimeoutChanged(CHILD_TIMEOUT_PREF, parent);
112
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
124
125 return parent.forget();
126 }
127
128
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!");
153
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
160
161 #ifdef MOZ_ENABLE_PROFILER_SPS
162 InitPluginProfiling();
163 #endif
164 }
165
166 PluginModuleParent::~PluginModuleParent()
167 {
168 if (!OkToCleanup()) {
169 NS_RUNTIMEABORT("unsafe destruction");
170 }
171
172 #ifdef MOZ_ENABLE_PROFILER_SPS
173 ShutdownPluginProfiling();
174 #endif
175
176 if (!mShutdown) {
177 NS_WARNING("Plugin host deleted the module without shutting down.");
178 NPError err;
179 NP_Shutdown(&err);
180 }
181
182 NS_ASSERTION(mShutdown, "NP_Shutdown didn't");
183
184 if (mSubprocess) {
185 mSubprocess->Delete();
186 mSubprocess = nullptr;
187 }
188
189 #ifdef MOZ_CRASHREPORTER_INJECTOR
190 if (mFlashProcess1)
191 UnregisterInjectorCallback(mFlashProcess1);
192 if (mFlashProcess2)
193 UnregisterInjectorCallback(mFlashProcess2);
194 #endif
195
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);
201
202 if (mHangUIParent) {
203 delete mHangUIParent;
204 mHangUIParent = nullptr;
205 }
206 #endif
207 }
208
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;
218
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()));
227
228 nsCString pluginName;
229 nsCString pluginVersion;
230
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 }
239
240 notes.Put(NS_LITERAL_CSTRING("PluginName"), pluginName);
241 notes.Put(NS_LITERAL_CSTRING("PluginVersion"), pluginVersion);
242
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()));
249
250 nsCString cpuUsageStr;
251 cpuUsageStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[0] * 100) / 100);
252 notes.Put(NS_LITERAL_CSTRING("PluginCpuUsage"), cpuUsageStr);
253
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
266
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 }
274
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 }
296
297 void
298 PluginModuleParent::CleanupFromTimeout(const bool aFromHangUI)
299 {
300 if (mShutdown) {
301 return;
302 }
303
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 }
312
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 }
326
327 #ifdef XP_WIN
328 namespace {
329
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 }
338
339 struct CpuUsageSamples
340 {
341 uint64_t sampleTimes[2];
342 uint64_t cpuTimes[2];
343 };
344
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;
351
352 for (uint32_t i = 0; i < processHandles.Length(); ++i) {
353 ::GetSystemTimeAsFileTime(&currentTime);
354 res = ::GetProcessTimes(processHandles[i], &creationTime, &exitTime, &kernelTime, &userTime);
355 if (!res) {
356 NS_WARNING("failed to get process times");
357 return false;
358 }
359
360 CpuUsageSamples s;
361 s.sampleTimes[0] = FileTimeToUTC(currentTime);
362 s.cpuTimes[0] = FileTimeToUTC(kernelTime) + FileTimeToUTC(userTime);
363 samples.AppendElement(s);
364 }
365
366 // we already hung for a while, a little bit longer won't matter
367 ::Sleep(50);
368
369 const int32_t numberOfProcessors = PR_GetNumberOfProcessors();
370
371 for (uint32_t i = 0; i < processHandles.Length(); ++i) {
372 ::GetSystemTimeAsFileTime(&currentTime);
373 res = ::GetProcessTimes(processHandles[i], &creationTime, &exitTime, &kernelTime, &userTime);
374 if (!res) {
375 NS_WARNING("failed to get process times");
376 return false;
377 }
378
379 samples[i].sampleTimes[1] = FileTimeToUTC(currentTime);
380 samples[i].cpuTimes[1] = FileTimeToUTC(kernelTime) + FileTimeToUTC(userTime);
381
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 }
387
388 return true;
389 }
390
391 } // anonymous namespace
392
393 void
394 PluginModuleParent::ExitedCxxStack()
395 {
396 FinishHangUI();
397 }
398
399 #endif // #ifdef XP_WIN
400
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 }
409
410 base::ProcessHandle handle;
411 if (!base::OpenPrivilegedProcessHandle(processId, &handle)) {
412 return false;
413 }
414
415 bool res = CreateAdditionalChildMinidump(handle, 0, parentMinidump, name);
416 base::CloseProcessHandle(handle);
417
418 return res;
419 }
420 #endif
421
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 }
436
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()));
470
471 nsAutoCString additionalDumps("browser");
472
473 #ifdef MOZ_CRASHREPORTER_INJECTOR
474 nsCOMPtr<nsIFile> pluginDumpFile;
475
476 if (GetMinidumpForID(mPluginDumpID, getter_AddRefs(pluginDumpFile)) &&
477 pluginDumpFile) {
478 nsCOMPtr<nsIFile> childDumpFile;
479
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
490
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
498
499 #ifdef XP_WIN
500 // collect cpu usage for plugin processes
501
502 InfallibleTArray<base::ProcessHandle> processHandles;
503
504 processHandles.AppendElement(OtherProcess());
505
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
517
518 if (!GetProcessCpuUsage(processHandles, mPluginCpuUsageOnHang)) {
519 mPluginCpuUsageOnHang.Clear();
520 }
521 #endif
522
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));
530
531 if (!KillProcess(OtherProcess(), 1, false))
532 NS_WARNING("failed to kill subprocess!");
533 }
534
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 }
569
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 }
584
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 }
619
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
641
642 #ifdef MOZ_CRASHREPORTER
643 CrashReporterParent*
644 PluginModuleParent::CrashReporter()
645 {
646 return static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
647 }
648
649 #ifdef MOZ_CRASHREPORTER_INJECTOR
650 static void
651 RemoveMinidump(nsIFile* minidump)
652 {
653 if (!minidump)
654 return;
655
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
664
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;
674
675 AnnotationTable notes(4);
676 WriteExtraDataForMinidump(notes);
677
678 if (!mPluginDumpID.IsEmpty()) {
679 crashReporter->GenerateChildData(&notes);
680 return;
681 }
682
683 uint32_t sequence = UINT32_MAX;
684 nsCOMPtr<nsIFile> dumpFile;
685 nsAutoCString flashProcessType;
686 TakeMinidump(getter_AddRefs(dumpFile), &sequence);
687
688 #ifdef MOZ_CRASHREPORTER_INJECTOR
689 nsCOMPtr<nsIFile> childDumpFile;
690 uint32_t childSequence;
691
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
721
722 if (!dumpFile) {
723 NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
724 return;
725 }
726
727 PLUGIN_LOG_DEBUG(("got child minidump: %s",
728 NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
729
730 GetIDFromMinidump(dumpFile, mPluginDumpID);
731 if (!flashProcessType.IsEmpty()) {
732 notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"), flashProcessType);
733 }
734 crashReporter->GenerateCrashReportForMinidump(dumpFile, &notes);
735 }
736 #endif
737
738 void
739 PluginModuleParent::ActorDestroy(ActorDestroyReason why)
740 {
741 switch (why) {
742 case AbnormalShutdown: {
743 #ifdef MOZ_CRASHREPORTER
744 ProcessFirstMinidump();
745 #endif
746
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;
760
761 default:
762 NS_RUNTIMEABORT("Unexpected shutdown reason for toplevel actor.");
763 }
764 }
765
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 }
777
778 if (mPlugin)
779 mPlugin->PluginCrashed(mPluginDumpID, mBrowserDumpID);
780 }
781
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 }
791
792 NPIdentifier npident = aString.IsVoid() ?
793 mozilla::plugins::parent::_getintidentifier(aInt) :
794 mozilla::plugins::parent::_getstringidentifier(aString.get());
795
796 if (!npident) {
797 NS_WARNING("Failed to get identifier!");
798 return nullptr;
799 }
800
801 PluginIdentifierParent* ident = new PluginIdentifierParent(npident, false);
802 mIdentifiers.Put(npident, ident);
803 return ident;
804 }
805
806 bool
807 PluginModuleParent::DeallocPPluginIdentifierParent(PPluginIdentifierParent* aActor)
808 {
809 delete aActor;
810 return true;
811 }
812
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 }
823
824 bool
825 PluginModuleParent::DeallocPPluginInstanceParent(PPluginInstanceParent* aActor)
826 {
827 PLUGIN_LOG_DEBUG_METHOD;
828 delete aActor;
829 return true;
830 }
831
832 void
833 PluginModuleParent::SetPluginFuncs(NPPluginFuncs* aFuncs)
834 {
835 aFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
836 aFuncs->javaClass = nullptr;
837
838 // Gecko should always call these functions through a PluginLibrary object.
839 aFuncs->newp = nullptr;
840 aFuncs->clearsitedata = nullptr;
841 aFuncs->getsiteswithdata = nullptr;
842
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;
858
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 }
869
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;
880
881 PluginInstanceParent* parentInstance =
882 static_cast<PluginInstanceParent*>(instance->pdata);
883
884 if (!parentInstance)
885 return NPERR_NO_ERROR;
886
887 NPError retval = parentInstance->Destroy();
888 instance->pdata = nullptr;
889
890 unused << PluginInstanceParent::Call__delete__(parentInstance);
891 return retval;
892 }
893
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;
903
904 return i->NPP_NewStream(type, stream, seekable,
905 stype);
906 }
907
908 NPError
909 PluginModuleParent::NPP_SetWindow(NPP instance, NPWindow* window)
910 {
911 PluginInstanceParent* i = InstCast(instance);
912 if (!i)
913 return NPERR_GENERIC_ERROR;
914
915 return i->NPP_SetWindow(window);
916 }
917
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;
926
927 return i->NPP_DestroyStream(stream, reason);
928 }
929
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;
937
938 return s->WriteReady();
939 }
940
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;
951
952 return s->Write(offset, len, buffer);
953 }
954
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;
963
964 s->StreamAsFile(fname);
965 }
966
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 }
974
975 int16_t
976 PluginModuleParent::NPP_HandleEvent(NPP instance, void* event)
977 {
978 PluginInstanceParent* i = InstCast(instance);
979 if (!i)
980 return false;
981
982 return i->NPP_HandleEvent(event);
983 }
984
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;
992
993 i->NPP_URLNotify(url, reason, notifyData);
994 }
995
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;
1003
1004 return i->NPP_GetValue(variable, ret_value);
1005 }
1006
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;
1014
1015 return i->NPP_SetValue(variable, value);
1016 }
1017
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 }
1033
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;
1041
1042 i->NPP_URLRedirectNotify(url, status, notifyData);
1043 }
1044
1045 bool
1046 PluginModuleParent::AnswerNPN_UserAgent(nsCString* userAgent)
1047 {
1048 *userAgent = NullableString(mNPNIface->uagent(nullptr));
1049 return true;
1050 }
1051
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 }
1062
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 }
1079
1080 ident = new PluginIdentifierParent(aIdentifier, temporary);
1081 if (!SendPPluginIdentifierConstructor(ident, string, intval, temporary))
1082 return nullptr;
1083
1084 if (!temporary) {
1085 mIdentifiers.Put(aIdentifier, ident);
1086 }
1087 return ident;
1088 }
1089
1090 PluginInstanceParent*
1091 PluginModuleParent::InstCast(NPP instance)
1092 {
1093 PluginInstanceParent* ip =
1094 static_cast<PluginInstanceParent*>(instance->pdata);
1095
1096 // If the plugin crashed and the PluginInstanceParent was deleted,
1097 // instance->pdata will be nullptr.
1098 if (!ip)
1099 return nullptr;
1100
1101 if (instance != ip->mNPP) {
1102 NS_RUNTIMEABORT("Corrupted plugin data.");
1103 }
1104 return ip;
1105 }
1106
1107 BrowserStreamParent*
1108 PluginModuleParent::StreamCast(NPP instance,
1109 NPStream* s)
1110 {
1111 PluginInstanceParent* ip = InstCast(instance);
1112 if (!ip)
1113 return nullptr;
1114
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 }
1122
1123 bool
1124 PluginModuleParent::HasRequiredFunctions()
1125 {
1126 return true;
1127 }
1128
1129 nsresult
1130 PluginModuleParent::AsyncSetWindow(NPP instance, NPWindow* window)
1131 {
1132 PluginInstanceParent* i = InstCast(instance);
1133 if (!i)
1134 return NS_ERROR_FAILURE;
1135
1136 return i->AsyncSetWindow(window);
1137 }
1138
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 }
1146
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 }
1154
1155 nsresult
1156 PluginModuleParent::SetBackgroundUnknown(NPP instance)
1157 {
1158 PluginInstanceParent* i = InstCast(instance);
1159 if (!i)
1160 return NS_ERROR_FAILURE;
1161
1162 return i->SetBackgroundUnknown();
1163 }
1164
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;
1173
1174 return i->BeginUpdateBackground(aRect, aCtx);
1175 }
1176
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;
1185
1186 return i->EndUpdateBackground(aCtx, aRect);
1187 }
1188
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;
1194
1195 mNPNIface = bFuncs;
1196
1197 if (mShutdown) {
1198 *error = NPERR_GENERIC_ERROR;
1199 return NS_ERROR_FAILURE;
1200 }
1201
1202 uint32_t flags = 0;
1203
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 }
1212
1213 SetPluginFuncs(pFuncs);
1214
1215 return NS_OK;
1216 }
1217 #else
1218 nsresult
1219 PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
1220 {
1221 PLUGIN_LOG_DEBUG_METHOD;
1222
1223 mNPNIface = bFuncs;
1224
1225 if (mShutdown) {
1226 *error = NPERR_GENERIC_ERROR;
1227 return NS_ERROR_FAILURE;
1228 }
1229
1230 uint32_t flags = 0;
1231 #ifdef XP_WIN
1232 flags |= kAllowAsyncDrawing;
1233 #endif
1234
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 }
1243
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;
1250
1251 if (NS_SUCCEEDED(mozilla::widget::GetAudioSessionData(id, sessionName,
1252 iconPath)))
1253 unused << SendSetAudioSessionData(id, sessionName, iconPath);
1254 #endif
1255
1256 #ifdef MOZ_CRASHREPORTER_INJECTOR
1257 InitializeInjector();
1258 #endif
1259
1260 return NS_OK;
1261 }
1262 #endif
1263
1264 nsresult
1265 PluginModuleParent::NP_Shutdown(NPError* error)
1266 {
1267 PLUGIN_LOG_DEBUG_METHOD;
1268
1269 if (mShutdown) {
1270 *error = NPERR_GENERIC_ERROR;
1271 return NS_ERROR_FAILURE;
1272 }
1273
1274 bool ok = CallNP_Shutdown(error);
1275
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();
1281
1282 return ok ? NS_OK : NS_ERROR_FAILURE;
1283 }
1284
1285 nsresult
1286 PluginModuleParent::NP_GetMIMEDescription(const char** mimeDesc)
1287 {
1288 PLUGIN_LOG_DEBUG_METHOD;
1289
1290 *mimeDesc = "application/x-foobar";
1291 return NS_OK;
1292 }
1293
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));
1300
1301 //TODO: implement this correctly
1302 *error = NPERR_GENERIC_ERROR;
1303 return NS_OK;
1304 }
1305
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!");
1311
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 }
1321
1322 SetPluginFuncs(pFuncs);
1323
1324 return NS_OK;
1325 }
1326 #endif
1327
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;
1335
1336 if (mShutdown) {
1337 *error = NPERR_GENERIC_ERROR;
1338 return NS_ERROR_FAILURE;
1339 }
1340
1341 // create the instance on the other side
1342 InfallibleTArray<nsCString> names;
1343 InfallibleTArray<nsCString> values;
1344
1345 for (int i = 0; i < argc; ++i) {
1346 names.AppendElement(NullableString(argn[i]));
1347 values.AppendElement(NullableString(argv[i]));
1348 }
1349
1350 PluginInstanceParent* parentInstance =
1351 new PluginInstanceParent(this, instance,
1352 nsDependentCString(pluginType), mNPNIface);
1353
1354 if (!parentInstance->Init()) {
1355 delete parentInstance;
1356 return NS_ERROR_FAILURE;
1357 }
1358
1359 instance->pdata = parentInstance;
1360
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 }
1373
1374 if (*error != NPERR_NO_ERROR) {
1375 NPP_Destroy(instance, 0);
1376 return NS_ERROR_FAILURE;
1377 }
1378
1379 TimeoutChanged(kParentTimeoutPref, this);
1380
1381 return NS_OK;
1382 }
1383
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;
1390
1391 NPError result;
1392 if (!CallNPP_ClearSiteData(NullableString(site), flags, maxAge, &result))
1393 return NS_ERROR_FAILURE;
1394
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 }
1406
1407 nsresult
1408 PluginModuleParent::NPP_GetSitesWithData(InfallibleTArray<nsCString>& result)
1409 {
1410 if (!mGetSitesWithDataSupported)
1411 return NS_ERROR_NOT_AVAILABLE;
1412
1413 if (!CallNPP_GetSitesWithData(&result))
1414 return NS_ERROR_FAILURE;
1415
1416 return NS_OK;
1417 }
1418
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;
1426
1427 return i->IsRemoteDrawingCoreAnimation(aDrawing);
1428 }
1429
1430 nsresult
1431 PluginModuleParent::ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor)
1432 {
1433 PluginInstanceParent* i = InstCast(instance);
1434 if (!i)
1435 return NS_ERROR_FAILURE;
1436
1437 return i->ContentsScaleFactorChanged(aContentsScaleFactor);
1438 }
1439 #endif // #if defined(XP_MACOSX)
1440
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 }
1451
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);
1459
1460 PLUGIN_LOG_DEBUG(("... quitting mini nested loop"));
1461
1462 return true;
1463 }
1464
1465 #elif defined(XP_MACOSX)
1466 bool
1467 PluginModuleParent::AnswerProcessSomeEvents()
1468 {
1469 mozilla::plugins::PluginUtilsOSX::InvokeNativeEventLoop();
1470 return true;
1471 }
1472
1473 #elif !defined(MOZ_WIDGET_GTK)
1474 bool
1475 PluginModuleParent::AnswerProcessSomeEvents()
1476 {
1477 NS_RUNTIMEABORT("unreached");
1478 return false;
1479 }
1480
1481 #else
1482 static const int kMaxChancesToProcessEvents = 20;
1483
1484 bool
1485 PluginModuleParent::AnswerProcessSomeEvents()
1486 {
1487 PLUGIN_LOG_DEBUG(("Spinning mini nested loop ..."));
1488
1489 int i = 0;
1490 for (; i < kMaxChancesToProcessEvents; ++i)
1491 if (!g_main_context_iteration(nullptr, FALSE))
1492 break;
1493
1494 PLUGIN_LOG_DEBUG(("... quitting mini nested loop; processed %i tasks", i));
1495
1496 return true;
1497 }
1498 #endif
1499
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 }
1513
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 }
1524
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 }
1541
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 }
1555
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 }
1566
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 }
1581
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 }
1595
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 }
1609
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 }
1623
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 }
1637
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 }
1652
1653 bool
1654 PluginModuleParent::RecvNPN_SetException(PPluginScriptableObjectParent* aActor,
1655 const nsCString& aMessage)
1656 {
1657 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1658
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 }
1670
1671 bool
1672 PluginModuleParent::RecvNPN_ReloadPlugins(const bool& aReloadPages)
1673 {
1674 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1675
1676 mozilla::plugins::parent::_reloadplugins(aReloadPages);
1677 return true;
1678 }
1679
1680 #ifdef MOZ_CRASHREPORTER_INJECTOR
1681
1682 // We only add the crash reporter to subprocess which have the filename
1683 // FlashPlayerPlugin*
1684 #define FLASH_PROCESS_PREFIX "FLASHPLAYERPLUGIN"
1685
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 }
1705
1706 // We only look for child processes of the Flash plugin, NPSWF*
1707 #define FLASH_PLUGIN_PREFIX "NPSWF"
1708
1709 void
1710 PluginModuleParent::InitializeInjector()
1711 {
1712 if (!Preferences::GetBool("dom.ipc.plugins.flash.subprocess.crashreporter.enabled", false))
1713 return;
1714
1715 nsCString path(Process()->GetPluginFilePath().c_str());
1716 ToUpperCase(path);
1717 int32_t lastSlash = path.RFindCharInSet("\\/");
1718 if (kNotFound == lastSlash)
1719 return;
1720
1721 if (!StringBeginsWith(Substring(path, lastSlash + 1),
1722 NS_LITERAL_CSTRING(FLASH_PLUGIN_PREFIX)))
1723 return;
1724
1725 HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1726 if (INVALID_HANDLE_VALUE == snapshot)
1727 return;
1728
1729 DWORD pluginProcessPID = GetProcessId(Process()->GetChildProcessHandle());
1730 mFlashProcess1 = GetFlashChildOfPID(pluginProcessPID, snapshot);
1731 if (mFlashProcess1) {
1732 InjectCrashReporterIntoProcess(mFlashProcess1, this);
1733
1734 mFlashProcess2 = GetFlashChildOfPID(mFlashProcess1, snapshot);
1735 if (mFlashProcess2) {
1736 InjectCrashReporterIntoProcess(mFlashProcess2, this);
1737 }
1738 }
1739 }
1740
1741 void
1742 PluginModuleParent::OnCrash(DWORD processID)
1743 {
1744 if (!mShutdown) {
1745 GetIPCChannel()->CloseWithError();
1746 KillProcess(OtherProcess(), 1, false);
1747 }
1748 }
1749
1750 #endif // MOZ_CRASHREPORTER_INJECTOR
1751
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
1759
1760 explicit PluginProfilerObserver(PluginModuleParent* pmp)
1761 : mPmp(pmp)
1762 {}
1763
1764 private:
1765 PluginModuleParent* mPmp;
1766 };
1767
1768 NS_IMPL_ISUPPORTS(PluginProfilerObserver, nsIObserver, nsISupportsWeakReference)
1769
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 }
1785
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 }
1795
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

mercurial