dom/plugins/ipc/PluginModuleParent.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rwxr-xr-x

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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(&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     }
   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(&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     }
   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(&notes);
   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, &notes);
   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);
  1007 NPError
  1008 PluginModuleParent::NPP_SetValue(NPP instance, NPNVariable variable,
  1009                                  void *value)
  1011     PluginInstanceParent* i = InstCast(instance);
  1012     if (!i)
  1013         return NPERR_GENERIC_ERROR;
  1015     return i->NPP_SetValue(variable, value);
  1018 bool
  1019 PluginModuleParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd)
  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());
  1030 #endif
  1031     return true;
  1034 void
  1035 PluginModuleParent::NPP_URLRedirectNotify(NPP instance, const char* url,
  1036                                           int32_t status, void* notifyData)
  1038   PluginInstanceParent* i = InstCast(instance);
  1039   if (!i)
  1040     return;
  1042   i->NPP_URLRedirectNotify(url, status, notifyData);
  1045 bool
  1046 PluginModuleParent::AnswerNPN_UserAgent(nsCString* userAgent)
  1048     *userAgent = NullableString(mNPNIface->uagent(nullptr));
  1049     return true;
  1052 PluginIdentifierParent*
  1053 PluginModuleParent::GetIdentifierForNPIdentifier(NPP npp, NPIdentifier aIdentifier)
  1055     PluginIdentifierParent* ident;
  1056     if (mIdentifiers.Get(aIdentifier, &ident)) {
  1057         if (ident->IsTemporary()) {
  1058             ident->AddTemporaryRef();
  1060         return ident;
  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;
  1072         string.Adopt(chars);
  1073         temporary = !NPStringIdentifierIsPermanent(npp, aIdentifier);
  1075     else {
  1076         intval = mozilla::plugins::parent::_intfromidentifier(aIdentifier);
  1077         string.SetIsVoid(true);
  1080     ident = new PluginIdentifierParent(aIdentifier, temporary);
  1081     if (!SendPPluginIdentifierConstructor(ident, string, intval, temporary))
  1082         return nullptr;
  1084     if (!temporary) {
  1085         mIdentifiers.Put(aIdentifier, ident);
  1087     return ident;
  1090 PluginInstanceParent*
  1091 PluginModuleParent::InstCast(NPP instance)
  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.");
  1104     return ip;
  1107 BrowserStreamParent*
  1108 PluginModuleParent::StreamCast(NPP instance,
  1109                                NPStream* s)
  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.");
  1120     return sp;
  1123 bool
  1124 PluginModuleParent::HasRequiredFunctions()
  1126     return true;
  1129 nsresult
  1130 PluginModuleParent::AsyncSetWindow(NPP instance, NPWindow* window)
  1132     PluginInstanceParent* i = InstCast(instance);
  1133     if (!i)
  1134         return NS_ERROR_FAILURE;
  1136     return i->AsyncSetWindow(window);
  1139 nsresult
  1140 PluginModuleParent::GetImageContainer(NPP instance,
  1141                              mozilla::layers::ImageContainer** aContainer)
  1143     PluginInstanceParent* i = InstCast(instance);
  1144     return !i ? NS_ERROR_FAILURE : i->GetImageContainer(aContainer);
  1147 nsresult
  1148 PluginModuleParent::GetImageSize(NPP instance,
  1149                                  nsIntSize* aSize)
  1151     PluginInstanceParent* i = InstCast(instance);
  1152     return !i ? NS_ERROR_FAILURE : i->GetImageSize(aSize);
  1155 nsresult
  1156 PluginModuleParent::SetBackgroundUnknown(NPP instance)
  1158     PluginInstanceParent* i = InstCast(instance);
  1159     if (!i)
  1160         return NS_ERROR_FAILURE;
  1162     return i->SetBackgroundUnknown();
  1165 nsresult
  1166 PluginModuleParent::BeginUpdateBackground(NPP instance,
  1167                                           const nsIntRect& aRect,
  1168                                           gfxContext** aCtx)
  1170     PluginInstanceParent* i = InstCast(instance);
  1171     if (!i)
  1172         return NS_ERROR_FAILURE;
  1174     return i->BeginUpdateBackground(aRect, aCtx);
  1177 nsresult
  1178 PluginModuleParent::EndUpdateBackground(NPP instance,
  1179                                         gfxContext* aCtx,
  1180                                         const nsIntRect& aRect)
  1182     PluginInstanceParent* i = InstCast(instance);
  1183     if (!i)
  1184         return NS_ERROR_FAILURE;
  1186     return i->EndUpdateBackground(aCtx, aRect);
  1189 #if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK)
  1190 nsresult
  1191 PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error)
  1193     PLUGIN_LOG_DEBUG_METHOD;
  1195     mNPNIface = bFuncs;
  1197     if (mShutdown) {
  1198         *error = NPERR_GENERIC_ERROR;
  1199         return NS_ERROR_FAILURE;
  1202     uint32_t flags = 0;
  1204     if (!CallNP_Initialize(flags, error)) {
  1205         Close();
  1206         return NS_ERROR_FAILURE;
  1208     else if (*error != NPERR_NO_ERROR) {
  1209         Close();
  1210         return NS_OK;
  1213     SetPluginFuncs(pFuncs);
  1215     return NS_OK;
  1217 #else
  1218 nsresult
  1219 PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
  1221     PLUGIN_LOG_DEBUG_METHOD;
  1223     mNPNIface = bFuncs;
  1225     if (mShutdown) {
  1226         *error = NPERR_GENERIC_ERROR;
  1227         return NS_ERROR_FAILURE;
  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;
  1239     if (*error != NPERR_NO_ERROR) {
  1240         Close();
  1241         return NS_OK;
  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;
  1262 #endif
  1264 nsresult
  1265 PluginModuleParent::NP_Shutdown(NPError* error)
  1267     PLUGIN_LOG_DEBUG_METHOD;
  1269     if (mShutdown) {
  1270         *error = NPERR_GENERIC_ERROR;
  1271         return NS_ERROR_FAILURE;
  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;
  1285 nsresult
  1286 PluginModuleParent::NP_GetMIMEDescription(const char** mimeDesc)
  1288     PLUGIN_LOG_DEBUG_METHOD;
  1290     *mimeDesc = "application/x-foobar";
  1291     return NS_OK;
  1294 nsresult
  1295 PluginModuleParent::NP_GetValue(void *future, NPPVariable aVariable,
  1296                                    void *aValue, NPError* error)
  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;
  1306 #if defined(XP_WIN) || defined(XP_MACOSX)
  1307 nsresult
  1308 PluginModuleParent::NP_GetEntryPoints(NPPluginFuncs* pFuncs, NPError* error)
  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;
  1318     else if (*error != NPERR_NO_ERROR) {
  1319         return NS_OK;
  1322     SetPluginFuncs(pFuncs);
  1324     return NS_OK;
  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)
  1334     PLUGIN_LOG_DEBUG_METHOD;
  1336     if (mShutdown) {
  1337         *error = NPERR_GENERIC_ERROR;
  1338         return NS_ERROR_FAILURE;
  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]));
  1350     PluginInstanceParent* parentInstance =
  1351         new PluginInstanceParent(this, instance,
  1352                                  nsDependentCString(pluginType), mNPNIface);
  1354     if (!parentInstance->Init()) {
  1355         delete parentInstance;
  1356         return NS_ERROR_FAILURE;
  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;
  1374     if (*error != NPERR_NO_ERROR) {
  1375         NPP_Destroy(instance, 0);
  1376         return NS_ERROR_FAILURE;
  1379     TimeoutChanged(kParentTimeoutPref, this);
  1381     return NS_OK;
  1384 nsresult
  1385 PluginModuleParent::NPP_ClearSiteData(const char* site, uint64_t flags,
  1386                                       uint64_t maxAge)
  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;
  1407 nsresult
  1408 PluginModuleParent::NPP_GetSitesWithData(InfallibleTArray<nsCString>& result)
  1410     if (!mGetSitesWithDataSupported)
  1411         return NS_ERROR_NOT_AVAILABLE;
  1413     if (!CallNPP_GetSitesWithData(&result))
  1414         return NS_ERROR_FAILURE;
  1416     return NS_OK;
  1419 #if defined(XP_MACOSX)
  1420 nsresult
  1421 PluginModuleParent::IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing)
  1423     PluginInstanceParent* i = InstCast(instance);
  1424     if (!i)
  1425         return NS_ERROR_FAILURE;
  1427     return i->IsRemoteDrawingCoreAnimation(aDrawing);
  1430 nsresult
  1431 PluginModuleParent::ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor)
  1433     PluginInstanceParent* i = InstCast(instance);
  1434     if (!i)
  1435         return NS_ERROR_FAILURE;
  1437     return i->ContentsScaleFactorChanged(aContentsScaleFactor);
  1439 #endif // #if defined(XP_MACOSX)
  1441 bool
  1442 PluginModuleParent::AnswerNPN_GetValue_WithBoolReturn(const NPNVariable& aVariable,
  1443                                                       NPError* aError,
  1444                                                       bool* aBoolVal)
  1446     NPBool boolVal = false;
  1447     *aError = mozilla::plugins::parent::_getvalue(nullptr, aVariable, &boolVal);
  1448     *aBoolVal = boolVal ? true : false;
  1449     return true;
  1452 #if defined(MOZ_WIDGET_QT)
  1453 static const int kMaxtimeToProcessEvents = 30;
  1454 bool
  1455 PluginModuleParent::AnswerProcessSomeEvents()
  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;
  1465 #elif defined(XP_MACOSX)
  1466 bool
  1467 PluginModuleParent::AnswerProcessSomeEvents()
  1469     mozilla::plugins::PluginUtilsOSX::InvokeNativeEventLoop();
  1470     return true;
  1473 #elif !defined(MOZ_WIDGET_GTK)
  1474 bool
  1475 PluginModuleParent::AnswerProcessSomeEvents()
  1477     NS_RUNTIMEABORT("unreached");
  1478     return false;
  1481 #else
  1482 static const int kMaxChancesToProcessEvents = 20;
  1484 bool
  1485 PluginModuleParent::AnswerProcessSomeEvents()
  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;
  1498 #endif
  1500 bool
  1501 PluginModuleParent::RecvProcessNativeEventsInInterruptCall()
  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
  1514 void
  1515 PluginModuleParent::ProcessRemoteNativeEventsInInterruptCall()
  1517 #if defined(OS_WIN)
  1518     unused << SendProcessNativeEventsInInterruptCall();
  1519     return;
  1520 #endif
  1521     NS_NOTREACHED(
  1522         "PluginModuleParent::ProcessRemoteNativeEventsInInterruptCall not implemented!");
  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)
  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
  1542 bool
  1543 PluginModuleParent::RecvPluginHideWindow(const uint32_t& aWindowId)
  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
  1556 PCrashReporterParent*
  1557 PluginModuleParent::AllocPCrashReporterParent(mozilla::dom::NativeThreadId* id,
  1558                                               uint32_t* processType)
  1560 #ifdef MOZ_CRASHREPORTER
  1561     return new CrashReporterParent();
  1562 #else
  1563     return nullptr;
  1564 #endif
  1567 bool
  1568 PluginModuleParent::DeallocPCrashReporterParent(PCrashReporterParent* actor)
  1570 #ifdef MOZ_CRASHREPORTER
  1571 #ifdef XP_WIN
  1572     mozilla::MutexAutoLock lock(mCrashReporterMutex);
  1573     if (actor == static_cast<PCrashReporterParent*>(mCrashReporter)) {
  1574         mCrashReporter = nullptr;
  1576 #endif
  1577 #endif
  1578     delete actor;
  1579     return true;
  1582 bool
  1583 PluginModuleParent::RecvSetCursor(const NSCursorInfo& aCursorInfo)
  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
  1596 bool
  1597 PluginModuleParent::RecvShowCursor(const bool& aShow)
  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
  1610 bool
  1611 PluginModuleParent::RecvPushCursor(const NSCursorInfo& aCursorInfo)
  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
  1624 bool
  1625 PluginModuleParent::RecvPopCursor()
  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
  1638 bool
  1639 PluginModuleParent::RecvGetNativeCursorsSupported(bool* supported)
  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
  1653 bool
  1654 PluginModuleParent::RecvNPN_SetException(PPluginScriptableObjectParent* aActor,
  1655                                          const nsCString& aMessage)
  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;
  1667     mozilla::plugins::parent::_setexception(aNPObj, NullableStringGet(aMessage));
  1668     return true;
  1671 bool
  1672 PluginModuleParent::RecvNPN_ReloadPlugins(const bool& aReloadPages)
  1674     PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
  1676     mozilla::plugins::parent::_reloadplugins(aReloadPages);
  1677     return true;
  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)
  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;
  1703     return 0;
  1706 // We only look for child processes of the Flash plugin, NPSWF*
  1707 #define FLASH_PLUGIN_PREFIX "NPSWF"
  1709 void
  1710 PluginModuleParent::InitializeInjector()
  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);
  1741 void
  1742 PluginModuleParent::OnCrash(DWORD processID)
  1744     if (!mShutdown) {
  1745         GetIPCChannel()->CloseWithError();
  1746         KillProcess(OtherProcess(), 1, false);
  1750 #endif // MOZ_CRASHREPORTER_INJECTOR
  1752 #ifdef MOZ_ENABLE_PROFILER_SPS
  1753 class PluginProfilerObserver MOZ_FINAL : public nsIObserver,
  1754                                          public nsSupportsWeakReference
  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)
  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());
  1783     return NS_OK;
  1786 void
  1787 PluginModuleParent::InitPluginProfiling()
  1789     nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
  1790     if (observerService) {
  1791         mProfilerObserver = new PluginProfilerObserver(this);
  1792         observerService->AddObserver(mProfilerObserver, "profiler-subprocess", false);
  1796 void
  1797 PluginModuleParent::ShutdownPluginProfiling()
  1799     nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
  1800     if (observerService) {
  1801         observerService->RemoveObserver(mProfilerObserver, "profiler-subprocess");
  1804 #endif

mercurial