1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/plugins/ipc/PluginModuleParent.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1804 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: sw=4 ts=4 et : 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifdef MOZ_WIDGET_QT 1.11 +// Must be included first to avoid conflicts. 1.12 +#include <QtCore/QCoreApplication> 1.13 +#include <QtCore/QEventLoop> 1.14 +#include "NestedLoopTimer.h" 1.15 +#endif 1.16 + 1.17 +#include "mozilla/plugins/PluginModuleParent.h" 1.18 + 1.19 +#include "base/process_util.h" 1.20 +#include "mozilla/Attributes.h" 1.21 +#include "mozilla/dom/PCrashReporterParent.h" 1.22 +#include "mozilla/ipc/MessageChannel.h" 1.23 +#include "mozilla/plugins/BrowserStreamParent.h" 1.24 +#include "mozilla/plugins/PluginInstanceParent.h" 1.25 +#include "mozilla/Preferences.h" 1.26 +#include "mozilla/Services.h" 1.27 +#include "mozilla/unused.h" 1.28 +#include "nsAutoPtr.h" 1.29 +#include "nsCRT.h" 1.30 +#include "nsIFile.h" 1.31 +#include "nsIObserverService.h" 1.32 +#include "nsNPAPIPlugin.h" 1.33 +#include "nsPrintfCString.h" 1.34 +#include "PluginIdentifierParent.h" 1.35 +#include "prsystem.h" 1.36 +#include "GeckoProfiler.h" 1.37 + 1.38 +#ifdef XP_WIN 1.39 +#include "PluginHangUIParent.h" 1.40 +#include "mozilla/widget/AudioSession.h" 1.41 +#endif 1.42 + 1.43 +#ifdef MOZ_ENABLE_PROFILER_SPS 1.44 +#include "nsIProfileSaveEvent.h" 1.45 +#endif 1.46 + 1.47 +#ifdef MOZ_WIDGET_GTK 1.48 +#include <glib.h> 1.49 +#elif XP_MACOSX 1.50 +#include "PluginInterposeOSX.h" 1.51 +#include "PluginUtilsOSX.h" 1.52 +#endif 1.53 + 1.54 +using base::KillProcess; 1.55 + 1.56 +using mozilla::PluginLibrary; 1.57 +using mozilla::ipc::MessageChannel; 1.58 +using mozilla::dom::PCrashReporterParent; 1.59 +using mozilla::dom::CrashReporterParent; 1.60 + 1.61 +using namespace mozilla; 1.62 +using namespace mozilla::plugins; 1.63 +using namespace mozilla::plugins::parent; 1.64 + 1.65 +#ifdef MOZ_CRASHREPORTER 1.66 +#include "mozilla/dom/CrashReporterParent.h" 1.67 + 1.68 +using namespace CrashReporter; 1.69 +#endif 1.70 + 1.71 +static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs"; 1.72 +static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs"; 1.73 +static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs"; 1.74 +#ifdef XP_WIN 1.75 +static const char kHangUITimeoutPref[] = "dom.ipc.plugins.hangUITimeoutSecs"; 1.76 +static const char kHangUIMinDisplayPref[] = "dom.ipc.plugins.hangUIMinDisplaySecs"; 1.77 +#define CHILD_TIMEOUT_PREF kHangUITimeoutPref 1.78 +#else 1.79 +#define CHILD_TIMEOUT_PREF kChildTimeoutPref 1.80 +#endif 1.81 + 1.82 +template<> 1.83 +struct RunnableMethodTraits<mozilla::plugins::PluginModuleParent> 1.84 +{ 1.85 + typedef mozilla::plugins::PluginModuleParent Class; 1.86 + static void RetainCallee(Class* obj) { } 1.87 + static void ReleaseCallee(Class* obj) { } 1.88 +}; 1.89 + 1.90 +// static 1.91 +PluginLibrary* 1.92 +PluginModuleParent::LoadModule(const char* aFilePath) 1.93 +{ 1.94 + PLUGIN_LOG_DEBUG_FUNCTION; 1.95 + 1.96 + int32_t prefSecs = Preferences::GetInt(kLaunchTimeoutPref, 0); 1.97 + 1.98 + // Block on the child process being launched and initialized. 1.99 + nsAutoPtr<PluginModuleParent> parent(new PluginModuleParent(aFilePath)); 1.100 + bool launched = parent->mSubprocess->Launch(prefSecs * 1000); 1.101 + if (!launched) { 1.102 + // We never reached open 1.103 + parent->mShutdown = true; 1.104 + return nullptr; 1.105 + } 1.106 + parent->Open(parent->mSubprocess->GetChannel(), 1.107 + parent->mSubprocess->GetChildProcessHandle()); 1.108 + 1.109 + // Request Windows message deferral behavior on our channel. This 1.110 + // applies to the top level and all sub plugin protocols since they 1.111 + // all share the same channel. 1.112 + parent->GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION); 1.113 + 1.114 + TimeoutChanged(CHILD_TIMEOUT_PREF, parent); 1.115 + 1.116 +#ifdef MOZ_CRASHREPORTER 1.117 + // If this fails, we're having IPC troubles, and we're doomed anyways. 1.118 + if (!CrashReporterParent::CreateCrashReporter(parent.get())) { 1.119 + parent->Close(); 1.120 + return nullptr; 1.121 + } 1.122 +#ifdef XP_WIN 1.123 + mozilla::MutexAutoLock lock(parent->mCrashReporterMutex); 1.124 + parent->mCrashReporter = parent->CrashReporter(); 1.125 +#endif 1.126 +#endif 1.127 + 1.128 + return parent.forget(); 1.129 +} 1.130 + 1.131 + 1.132 +PluginModuleParent::PluginModuleParent(const char* aFilePath) 1.133 + : mSubprocess(new PluginProcessParent(aFilePath)) 1.134 + , mShutdown(false) 1.135 + , mClearSiteDataSupported(false) 1.136 + , mGetSitesWithDataSupported(false) 1.137 + , mNPNIface(nullptr) 1.138 + , mPlugin(nullptr) 1.139 + , mTaskFactory(MOZ_THIS_IN_INITIALIZER_LIST()) 1.140 +#ifdef XP_WIN 1.141 + , mPluginCpuUsageOnHang() 1.142 + , mHangUIParent(nullptr) 1.143 + , mHangUIEnabled(true) 1.144 + , mIsTimerReset(true) 1.145 +#ifdef MOZ_CRASHREPORTER 1.146 + , mCrashReporterMutex("PluginModuleParent::mCrashReporterMutex") 1.147 + , mCrashReporter(nullptr) 1.148 +#endif 1.149 +#endif 1.150 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.151 + , mFlashProcess1(0) 1.152 + , mFlashProcess2(0) 1.153 +#endif 1.154 +{ 1.155 + NS_ASSERTION(mSubprocess, "Out of memory!"); 1.156 + 1.157 + Preferences::RegisterCallback(TimeoutChanged, kChildTimeoutPref, this); 1.158 + Preferences::RegisterCallback(TimeoutChanged, kParentTimeoutPref, this); 1.159 +#ifdef XP_WIN 1.160 + Preferences::RegisterCallback(TimeoutChanged, kHangUITimeoutPref, this); 1.161 + Preferences::RegisterCallback(TimeoutChanged, kHangUIMinDisplayPref, this); 1.162 +#endif 1.163 + 1.164 +#ifdef MOZ_ENABLE_PROFILER_SPS 1.165 + InitPluginProfiling(); 1.166 +#endif 1.167 +} 1.168 + 1.169 +PluginModuleParent::~PluginModuleParent() 1.170 +{ 1.171 + if (!OkToCleanup()) { 1.172 + NS_RUNTIMEABORT("unsafe destruction"); 1.173 + } 1.174 + 1.175 +#ifdef MOZ_ENABLE_PROFILER_SPS 1.176 + ShutdownPluginProfiling(); 1.177 +#endif 1.178 + 1.179 + if (!mShutdown) { 1.180 + NS_WARNING("Plugin host deleted the module without shutting down."); 1.181 + NPError err; 1.182 + NP_Shutdown(&err); 1.183 + } 1.184 + 1.185 + NS_ASSERTION(mShutdown, "NP_Shutdown didn't"); 1.186 + 1.187 + if (mSubprocess) { 1.188 + mSubprocess->Delete(); 1.189 + mSubprocess = nullptr; 1.190 + } 1.191 + 1.192 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.193 + if (mFlashProcess1) 1.194 + UnregisterInjectorCallback(mFlashProcess1); 1.195 + if (mFlashProcess2) 1.196 + UnregisterInjectorCallback(mFlashProcess2); 1.197 +#endif 1.198 + 1.199 + Preferences::UnregisterCallback(TimeoutChanged, kChildTimeoutPref, this); 1.200 + Preferences::UnregisterCallback(TimeoutChanged, kParentTimeoutPref, this); 1.201 +#ifdef XP_WIN 1.202 + Preferences::UnregisterCallback(TimeoutChanged, kHangUITimeoutPref, this); 1.203 + Preferences::UnregisterCallback(TimeoutChanged, kHangUIMinDisplayPref, this); 1.204 + 1.205 + if (mHangUIParent) { 1.206 + delete mHangUIParent; 1.207 + mHangUIParent = nullptr; 1.208 + } 1.209 +#endif 1.210 +} 1.211 + 1.212 +#ifdef MOZ_CRASHREPORTER 1.213 +void 1.214 +PluginModuleParent::WriteExtraDataForMinidump(AnnotationTable& notes) 1.215 +{ 1.216 +#ifdef XP_WIN 1.217 + // mCrashReporterMutex is already held by the caller 1.218 + mCrashReporterMutex.AssertCurrentThreadOwns(); 1.219 +#endif 1.220 + typedef nsDependentCString CS; 1.221 + 1.222 + // Get the plugin filename, try to get just the file leafname 1.223 + const std::string& pluginFile = mSubprocess->GetPluginFilePath(); 1.224 + size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR); 1.225 + if (filePos == std::string::npos) 1.226 + filePos = 0; 1.227 + else 1.228 + filePos++; 1.229 + notes.Put(NS_LITERAL_CSTRING("PluginFilename"), CS(pluginFile.substr(filePos).c_str())); 1.230 + 1.231 + nsCString pluginName; 1.232 + nsCString pluginVersion; 1.233 + 1.234 + nsRefPtr<nsPluginHost> ph = nsPluginHost::GetInst(); 1.235 + if (ph) { 1.236 + nsPluginTag* tag = ph->TagForPlugin(mPlugin); 1.237 + if (tag) { 1.238 + pluginName = tag->mName; 1.239 + pluginVersion = tag->mVersion; 1.240 + } 1.241 + } 1.242 + 1.243 + notes.Put(NS_LITERAL_CSTRING("PluginName"), pluginName); 1.244 + notes.Put(NS_LITERAL_CSTRING("PluginVersion"), pluginVersion); 1.245 + 1.246 + CrashReporterParent* crashReporter = CrashReporter(); 1.247 + if (crashReporter) { 1.248 +#ifdef XP_WIN 1.249 + if (mPluginCpuUsageOnHang.Length() > 0) { 1.250 + notes.Put(NS_LITERAL_CSTRING("NumberOfProcessors"), 1.251 + nsPrintfCString("%d", PR_GetNumberOfProcessors())); 1.252 + 1.253 + nsCString cpuUsageStr; 1.254 + cpuUsageStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[0] * 100) / 100); 1.255 + notes.Put(NS_LITERAL_CSTRING("PluginCpuUsage"), cpuUsageStr); 1.256 + 1.257 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.258 + for (uint32_t i=1; i<mPluginCpuUsageOnHang.Length(); ++i) { 1.259 + nsCString tempStr; 1.260 + tempStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[i] * 100) / 100); 1.261 + notes.Put(nsPrintfCString("CpuUsageFlashProcess%d", i), tempStr); 1.262 + } 1.263 +#endif 1.264 + } 1.265 +#endif 1.266 + } 1.267 +} 1.268 +#endif // MOZ_CRASHREPORTER 1.269 + 1.270 +void 1.271 +PluginModuleParent::SetChildTimeout(const int32_t aChildTimeout) 1.272 +{ 1.273 + int32_t timeoutMs = (aChildTimeout > 0) ? (1000 * aChildTimeout) : 1.274 + MessageChannel::kNoTimeout; 1.275 + SetReplyTimeoutMs(timeoutMs); 1.276 +} 1.277 + 1.278 +void 1.279 +PluginModuleParent::TimeoutChanged(const char* aPref, void* aModule) 1.280 +{ 1.281 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.282 +#ifndef XP_WIN 1.283 + if (!strcmp(aPref, kChildTimeoutPref)) { 1.284 + // The timeout value used by the parent for children 1.285 + int32_t timeoutSecs = Preferences::GetInt(kChildTimeoutPref, 0); 1.286 + static_cast<PluginModuleParent*>(aModule)->SetChildTimeout(timeoutSecs); 1.287 +#else 1.288 + if (!strcmp(aPref, kChildTimeoutPref) || 1.289 + !strcmp(aPref, kHangUIMinDisplayPref) || 1.290 + !strcmp(aPref, kHangUITimeoutPref)) { 1.291 + static_cast<PluginModuleParent*>(aModule)->EvaluateHangUIState(true); 1.292 +#endif // XP_WIN 1.293 + } else if (!strcmp(aPref, kParentTimeoutPref)) { 1.294 + // The timeout value used by the child for its parent 1.295 + int32_t timeoutSecs = Preferences::GetInt(kParentTimeoutPref, 0); 1.296 + unused << static_cast<PluginModuleParent*>(aModule)->SendSetParentHangTimeout(timeoutSecs); 1.297 + } 1.298 +} 1.299 + 1.300 +void 1.301 +PluginModuleParent::CleanupFromTimeout(const bool aFromHangUI) 1.302 +{ 1.303 + if (mShutdown) { 1.304 + return; 1.305 + } 1.306 + 1.307 + if (!OkToCleanup()) { 1.308 + // there's still plugin code on the C++ stack, try again 1.309 + MessageLoop::current()->PostDelayedTask( 1.310 + FROM_HERE, 1.311 + mTaskFactory.NewRunnableMethod( 1.312 + &PluginModuleParent::CleanupFromTimeout, aFromHangUI), 10); 1.313 + return; 1.314 + } 1.315 + 1.316 + /* If the plugin container was terminated by the Plugin Hang UI, 1.317 + then either the I/O thread detects a channel error, or the 1.318 + main thread must set the error (whomever gets there first). 1.319 + OTOH, if we terminate and return false from 1.320 + ShouldContinueFromReplyTimeout, then the channel state has 1.321 + already been set to ChannelTimeout and we should call the 1.322 + regular Close function. */ 1.323 + if (aFromHangUI) { 1.324 + GetIPCChannel()->CloseWithError(); 1.325 + } else { 1.326 + Close(); 1.327 + } 1.328 +} 1.329 + 1.330 +#ifdef XP_WIN 1.331 +namespace { 1.332 + 1.333 +uint64_t 1.334 +FileTimeToUTC(const FILETIME& ftime) 1.335 +{ 1.336 + ULARGE_INTEGER li; 1.337 + li.LowPart = ftime.dwLowDateTime; 1.338 + li.HighPart = ftime.dwHighDateTime; 1.339 + return li.QuadPart; 1.340 +} 1.341 + 1.342 +struct CpuUsageSamples 1.343 +{ 1.344 + uint64_t sampleTimes[2]; 1.345 + uint64_t cpuTimes[2]; 1.346 +}; 1.347 + 1.348 +bool 1.349 +GetProcessCpuUsage(const InfallibleTArray<base::ProcessHandle>& processHandles, InfallibleTArray<float>& cpuUsage) 1.350 +{ 1.351 + InfallibleTArray<CpuUsageSamples> samples(processHandles.Length()); 1.352 + FILETIME creationTime, exitTime, kernelTime, userTime, currentTime; 1.353 + BOOL res; 1.354 + 1.355 + for (uint32_t i = 0; i < processHandles.Length(); ++i) { 1.356 + ::GetSystemTimeAsFileTime(¤tTime); 1.357 + res = ::GetProcessTimes(processHandles[i], &creationTime, &exitTime, &kernelTime, &userTime); 1.358 + if (!res) { 1.359 + NS_WARNING("failed to get process times"); 1.360 + return false; 1.361 + } 1.362 + 1.363 + CpuUsageSamples s; 1.364 + s.sampleTimes[0] = FileTimeToUTC(currentTime); 1.365 + s.cpuTimes[0] = FileTimeToUTC(kernelTime) + FileTimeToUTC(userTime); 1.366 + samples.AppendElement(s); 1.367 + } 1.368 + 1.369 + // we already hung for a while, a little bit longer won't matter 1.370 + ::Sleep(50); 1.371 + 1.372 + const int32_t numberOfProcessors = PR_GetNumberOfProcessors(); 1.373 + 1.374 + for (uint32_t i = 0; i < processHandles.Length(); ++i) { 1.375 + ::GetSystemTimeAsFileTime(¤tTime); 1.376 + res = ::GetProcessTimes(processHandles[i], &creationTime, &exitTime, &kernelTime, &userTime); 1.377 + if (!res) { 1.378 + NS_WARNING("failed to get process times"); 1.379 + return false; 1.380 + } 1.381 + 1.382 + samples[i].sampleTimes[1] = FileTimeToUTC(currentTime); 1.383 + samples[i].cpuTimes[1] = FileTimeToUTC(kernelTime) + FileTimeToUTC(userTime); 1.384 + 1.385 + const uint64_t deltaSampleTime = samples[i].sampleTimes[1] - samples[i].sampleTimes[0]; 1.386 + const uint64_t deltaCpuTime = samples[i].cpuTimes[1] - samples[i].cpuTimes[0]; 1.387 + const float usage = 100.f * (float(deltaCpuTime) / deltaSampleTime) / numberOfProcessors; 1.388 + cpuUsage.AppendElement(usage); 1.389 + } 1.390 + 1.391 + return true; 1.392 +} 1.393 + 1.394 +} // anonymous namespace 1.395 + 1.396 +void 1.397 +PluginModuleParent::ExitedCxxStack() 1.398 +{ 1.399 + FinishHangUI(); 1.400 +} 1.401 + 1.402 +#endif // #ifdef XP_WIN 1.403 + 1.404 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.405 +static bool 1.406 +CreateFlashMinidump(DWORD processId, ThreadId childThread, 1.407 + nsIFile* parentMinidump, const nsACString& name) 1.408 +{ 1.409 + if (processId == 0) { 1.410 + return false; 1.411 + } 1.412 + 1.413 + base::ProcessHandle handle; 1.414 + if (!base::OpenPrivilegedProcessHandle(processId, &handle)) { 1.415 + return false; 1.416 + } 1.417 + 1.418 + bool res = CreateAdditionalChildMinidump(handle, 0, parentMinidump, name); 1.419 + base::CloseProcessHandle(handle); 1.420 + 1.421 + return res; 1.422 +} 1.423 +#endif 1.424 + 1.425 +bool 1.426 +PluginModuleParent::ShouldContinueFromReplyTimeout() 1.427 +{ 1.428 +#ifdef XP_WIN 1.429 + if (LaunchHangUI()) { 1.430 + return true; 1.431 + } 1.432 + // If LaunchHangUI returned false then we should proceed with the 1.433 + // original plugin hang behaviour and kill the plugin container. 1.434 + FinishHangUI(); 1.435 +#endif // XP_WIN 1.436 + TerminateChildProcess(MessageLoop::current()); 1.437 + return false; 1.438 +} 1.439 + 1.440 +void 1.441 +PluginModuleParent::TerminateChildProcess(MessageLoop* aMsgLoop) 1.442 +{ 1.443 +#ifdef MOZ_CRASHREPORTER 1.444 +#ifdef XP_WIN 1.445 + mozilla::MutexAutoLock lock(mCrashReporterMutex); 1.446 + CrashReporterParent* crashReporter = mCrashReporter; 1.447 + if (!crashReporter) { 1.448 + // If mCrashReporter is null then the hang has ended, the plugin module 1.449 + // is shutting down. There's nothing to do here. 1.450 + return; 1.451 + } 1.452 +#else 1.453 + CrashReporterParent* crashReporter = CrashReporter(); 1.454 +#endif 1.455 + crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("PluginHang"), 1.456 + NS_LITERAL_CSTRING("1")); 1.457 +#ifdef XP_WIN 1.458 + if (mHangUIParent) { 1.459 + unsigned int hangUIDuration = mHangUIParent->LastShowDurationMs(); 1.460 + if (hangUIDuration) { 1.461 + nsPrintfCString strHangUIDuration("%u", hangUIDuration); 1.462 + crashReporter->AnnotateCrashReport( 1.463 + NS_LITERAL_CSTRING("PluginHangUIDuration"), 1.464 + strHangUIDuration); 1.465 + } 1.466 + } 1.467 +#endif // XP_WIN 1.468 + if (crashReporter->GeneratePairedMinidump(this)) { 1.469 + mPluginDumpID = crashReporter->ChildDumpID(); 1.470 + PLUGIN_LOG_DEBUG( 1.471 + ("generated paired browser/plugin minidumps: %s)", 1.472 + NS_ConvertUTF16toUTF8(mPluginDumpID).get())); 1.473 + 1.474 + nsAutoCString additionalDumps("browser"); 1.475 + 1.476 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.477 + nsCOMPtr<nsIFile> pluginDumpFile; 1.478 + 1.479 + if (GetMinidumpForID(mPluginDumpID, getter_AddRefs(pluginDumpFile)) && 1.480 + pluginDumpFile) { 1.481 + nsCOMPtr<nsIFile> childDumpFile; 1.482 + 1.483 + if (CreateFlashMinidump(mFlashProcess1, 0, pluginDumpFile, 1.484 + NS_LITERAL_CSTRING("flash1"))) { 1.485 + additionalDumps.Append(",flash1"); 1.486 + } 1.487 + if (CreateFlashMinidump(mFlashProcess2, 0, pluginDumpFile, 1.488 + NS_LITERAL_CSTRING("flash2"))) { 1.489 + additionalDumps.Append(",flash2"); 1.490 + } 1.491 + } 1.492 +#endif 1.493 + 1.494 + crashReporter->AnnotateCrashReport( 1.495 + NS_LITERAL_CSTRING("additional_minidumps"), 1.496 + additionalDumps); 1.497 + } else { 1.498 + NS_WARNING("failed to capture paired minidumps from hang"); 1.499 + } 1.500 +#endif 1.501 + 1.502 +#ifdef XP_WIN 1.503 + // collect cpu usage for plugin processes 1.504 + 1.505 + InfallibleTArray<base::ProcessHandle> processHandles; 1.506 + 1.507 + processHandles.AppendElement(OtherProcess()); 1.508 + 1.509 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.510 + { 1.511 + base::ProcessHandle handle; 1.512 + if (mFlashProcess1 && base::OpenProcessHandle(mFlashProcess1, &handle)) { 1.513 + processHandles.AppendElement(handle); 1.514 + } 1.515 + if (mFlashProcess2 && base::OpenProcessHandle(mFlashProcess2, &handle)) { 1.516 + processHandles.AppendElement(handle); 1.517 + } 1.518 + } 1.519 +#endif 1.520 + 1.521 + if (!GetProcessCpuUsage(processHandles, mPluginCpuUsageOnHang)) { 1.522 + mPluginCpuUsageOnHang.Clear(); 1.523 + } 1.524 +#endif 1.525 + 1.526 + // this must run before the error notification from the channel, 1.527 + // or not at all 1.528 + bool isFromHangUI = aMsgLoop != MessageLoop::current(); 1.529 + aMsgLoop->PostTask( 1.530 + FROM_HERE, 1.531 + mTaskFactory.NewRunnableMethod( 1.532 + &PluginModuleParent::CleanupFromTimeout, isFromHangUI)); 1.533 + 1.534 + if (!KillProcess(OtherProcess(), 1, false)) 1.535 + NS_WARNING("failed to kill subprocess!"); 1.536 +} 1.537 + 1.538 +#ifdef XP_WIN 1.539 +void 1.540 +PluginModuleParent::EvaluateHangUIState(const bool aReset) 1.541 +{ 1.542 + int32_t minDispSecs = Preferences::GetInt(kHangUIMinDisplayPref, 10); 1.543 + int32_t autoStopSecs = Preferences::GetInt(kChildTimeoutPref, 0); 1.544 + int32_t timeoutSecs = 0; 1.545 + if (autoStopSecs > 0 && autoStopSecs < minDispSecs) { 1.546 + /* If we're going to automatically terminate the plugin within a 1.547 + time frame shorter than minDispSecs, there's no point in 1.548 + showing the hang UI; it would just flash briefly on the screen. */ 1.549 + mHangUIEnabled = false; 1.550 + } else { 1.551 + timeoutSecs = Preferences::GetInt(kHangUITimeoutPref, 0); 1.552 + mHangUIEnabled = timeoutSecs > 0; 1.553 + } 1.554 + if (mHangUIEnabled) { 1.555 + if (aReset) { 1.556 + mIsTimerReset = true; 1.557 + SetChildTimeout(timeoutSecs); 1.558 + return; 1.559 + } else if (mIsTimerReset) { 1.560 + /* The Hang UI is being shown, so now we're setting the 1.561 + timeout to kChildTimeoutPref while we wait for a user 1.562 + response. ShouldContinueFromReplyTimeout will fire 1.563 + after (reply timeout / 2) seconds, which is not what 1.564 + we want. Doubling the timeout value here so that we get 1.565 + the right result. */ 1.566 + autoStopSecs *= 2; 1.567 + } 1.568 + } 1.569 + mIsTimerReset = false; 1.570 + SetChildTimeout(autoStopSecs); 1.571 +} 1.572 + 1.573 +bool 1.574 +PluginModuleParent::GetPluginName(nsAString& aPluginName) 1.575 +{ 1.576 + nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst(); 1.577 + if (!host) { 1.578 + return false; 1.579 + } 1.580 + nsPluginTag* pluginTag = host->TagForPlugin(mPlugin); 1.581 + if (!pluginTag) { 1.582 + return false; 1.583 + } 1.584 + CopyUTF8toUTF16(pluginTag->mName, aPluginName); 1.585 + return true; 1.586 +} 1.587 + 1.588 +bool 1.589 +PluginModuleParent::LaunchHangUI() 1.590 +{ 1.591 + if (!mHangUIEnabled) { 1.592 + return false; 1.593 + } 1.594 + if (mHangUIParent) { 1.595 + if (mHangUIParent->IsShowing()) { 1.596 + // We've already shown the UI but the timeout has expired again. 1.597 + return false; 1.598 + } 1.599 + if (mHangUIParent->DontShowAgain()) { 1.600 + return !mHangUIParent->WasLastHangStopped(); 1.601 + } 1.602 + delete mHangUIParent; 1.603 + mHangUIParent = nullptr; 1.604 + } 1.605 + mHangUIParent = new PluginHangUIParent(this, 1.606 + Preferences::GetInt(kHangUITimeoutPref, 0), 1.607 + Preferences::GetInt(kChildTimeoutPref, 0)); 1.608 + nsAutoString pluginName; 1.609 + if (!GetPluginName(pluginName)) { 1.610 + return false; 1.611 + } 1.612 + bool retval = mHangUIParent->Init(pluginName); 1.613 + if (retval) { 1.614 + /* Once the UI is shown we switch the timeout over to use 1.615 + kChildTimeoutPref, allowing us to terminate a hung plugin 1.616 + after kChildTimeoutPref seconds if the user doesn't respond to 1.617 + the hang UI. */ 1.618 + EvaluateHangUIState(false); 1.619 + } 1.620 + return retval; 1.621 +} 1.622 + 1.623 +void 1.624 +PluginModuleParent::FinishHangUI() 1.625 +{ 1.626 + if (mHangUIEnabled && mHangUIParent) { 1.627 + bool needsCancel = mHangUIParent->IsShowing(); 1.628 + // If we're still showing, send a Cancel notification 1.629 + if (needsCancel) { 1.630 + mHangUIParent->Cancel(); 1.631 + } 1.632 + /* If we cancelled the UI or if the user issued a response, 1.633 + we need to reset the child process timeout. */ 1.634 + if (needsCancel || 1.635 + !mIsTimerReset && mHangUIParent->WasShown()) { 1.636 + /* We changed the timeout to kChildTimeoutPref when the plugin hang 1.637 + UI was displayed. Now that we're finishing the UI, we need to 1.638 + switch it back to kHangUITimeoutPref. */ 1.639 + EvaluateHangUIState(true); 1.640 + } 1.641 + } 1.642 +} 1.643 +#endif // XP_WIN 1.644 + 1.645 +#ifdef MOZ_CRASHREPORTER 1.646 +CrashReporterParent* 1.647 +PluginModuleParent::CrashReporter() 1.648 +{ 1.649 + return static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]); 1.650 +} 1.651 + 1.652 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.653 +static void 1.654 +RemoveMinidump(nsIFile* minidump) 1.655 +{ 1.656 + if (!minidump) 1.657 + return; 1.658 + 1.659 + minidump->Remove(false); 1.660 + nsCOMPtr<nsIFile> extraFile; 1.661 + if (GetExtraFileForMinidump(minidump, 1.662 + getter_AddRefs(extraFile))) { 1.663 + extraFile->Remove(true); 1.664 + } 1.665 +} 1.666 +#endif // MOZ_CRASHREPORTER_INJECTOR 1.667 + 1.668 +void 1.669 +PluginModuleParent::ProcessFirstMinidump() 1.670 +{ 1.671 +#ifdef XP_WIN 1.672 + mozilla::MutexAutoLock lock(mCrashReporterMutex); 1.673 +#endif 1.674 + CrashReporterParent* crashReporter = CrashReporter(); 1.675 + if (!crashReporter) 1.676 + return; 1.677 + 1.678 + AnnotationTable notes(4); 1.679 + WriteExtraDataForMinidump(notes); 1.680 + 1.681 + if (!mPluginDumpID.IsEmpty()) { 1.682 + crashReporter->GenerateChildData(¬es); 1.683 + return; 1.684 + } 1.685 + 1.686 + uint32_t sequence = UINT32_MAX; 1.687 + nsCOMPtr<nsIFile> dumpFile; 1.688 + nsAutoCString flashProcessType; 1.689 + TakeMinidump(getter_AddRefs(dumpFile), &sequence); 1.690 + 1.691 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.692 + nsCOMPtr<nsIFile> childDumpFile; 1.693 + uint32_t childSequence; 1.694 + 1.695 + if (mFlashProcess1 && 1.696 + TakeMinidumpForChild(mFlashProcess1, 1.697 + getter_AddRefs(childDumpFile), 1.698 + &childSequence)) { 1.699 + if (childSequence < sequence) { 1.700 + RemoveMinidump(dumpFile); 1.701 + dumpFile = childDumpFile; 1.702 + sequence = childSequence; 1.703 + flashProcessType.AssignLiteral("Broker"); 1.704 + } 1.705 + else { 1.706 + RemoveMinidump(childDumpFile); 1.707 + } 1.708 + } 1.709 + if (mFlashProcess2 && 1.710 + TakeMinidumpForChild(mFlashProcess2, 1.711 + getter_AddRefs(childDumpFile), 1.712 + &childSequence)) { 1.713 + if (childSequence < sequence) { 1.714 + RemoveMinidump(dumpFile); 1.715 + dumpFile = childDumpFile; 1.716 + sequence = childSequence; 1.717 + flashProcessType.AssignLiteral("Sandbox"); 1.718 + } 1.719 + else { 1.720 + RemoveMinidump(childDumpFile); 1.721 + } 1.722 + } 1.723 +#endif 1.724 + 1.725 + if (!dumpFile) { 1.726 + NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!"); 1.727 + return; 1.728 + } 1.729 + 1.730 + PLUGIN_LOG_DEBUG(("got child minidump: %s", 1.731 + NS_ConvertUTF16toUTF8(mPluginDumpID).get())); 1.732 + 1.733 + GetIDFromMinidump(dumpFile, mPluginDumpID); 1.734 + if (!flashProcessType.IsEmpty()) { 1.735 + notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"), flashProcessType); 1.736 + } 1.737 + crashReporter->GenerateCrashReportForMinidump(dumpFile, ¬es); 1.738 +} 1.739 +#endif 1.740 + 1.741 +void 1.742 +PluginModuleParent::ActorDestroy(ActorDestroyReason why) 1.743 +{ 1.744 + switch (why) { 1.745 + case AbnormalShutdown: { 1.746 +#ifdef MOZ_CRASHREPORTER 1.747 + ProcessFirstMinidump(); 1.748 +#endif 1.749 + 1.750 + mShutdown = true; 1.751 + // Defer the PluginCrashed method so that we don't re-enter 1.752 + // and potentially modify the actor child list while enumerating it. 1.753 + if (mPlugin) 1.754 + MessageLoop::current()->PostTask( 1.755 + FROM_HERE, 1.756 + mTaskFactory.NewRunnableMethod( 1.757 + &PluginModuleParent::NotifyPluginCrashed)); 1.758 + break; 1.759 + } 1.760 + case NormalShutdown: 1.761 + mShutdown = true; 1.762 + break; 1.763 + 1.764 + default: 1.765 + NS_RUNTIMEABORT("Unexpected shutdown reason for toplevel actor."); 1.766 + } 1.767 +} 1.768 + 1.769 +void 1.770 +PluginModuleParent::NotifyPluginCrashed() 1.771 +{ 1.772 + if (!OkToCleanup()) { 1.773 + // there's still plugin code on the C++ stack. try again 1.774 + MessageLoop::current()->PostDelayedTask( 1.775 + FROM_HERE, 1.776 + mTaskFactory.NewRunnableMethod( 1.777 + &PluginModuleParent::NotifyPluginCrashed), 10); 1.778 + return; 1.779 + } 1.780 + 1.781 + if (mPlugin) 1.782 + mPlugin->PluginCrashed(mPluginDumpID, mBrowserDumpID); 1.783 +} 1.784 + 1.785 +PPluginIdentifierParent* 1.786 +PluginModuleParent::AllocPPluginIdentifierParent(const nsCString& aString, 1.787 + const int32_t& aInt, 1.788 + const bool& aTemporary) 1.789 +{ 1.790 + if (aTemporary) { 1.791 + NS_ERROR("Plugins don't create temporary identifiers."); 1.792 + return nullptr; // should abort the plugin 1.793 + } 1.794 + 1.795 + NPIdentifier npident = aString.IsVoid() ? 1.796 + mozilla::plugins::parent::_getintidentifier(aInt) : 1.797 + mozilla::plugins::parent::_getstringidentifier(aString.get()); 1.798 + 1.799 + if (!npident) { 1.800 + NS_WARNING("Failed to get identifier!"); 1.801 + return nullptr; 1.802 + } 1.803 + 1.804 + PluginIdentifierParent* ident = new PluginIdentifierParent(npident, false); 1.805 + mIdentifiers.Put(npident, ident); 1.806 + return ident; 1.807 +} 1.808 + 1.809 +bool 1.810 +PluginModuleParent::DeallocPPluginIdentifierParent(PPluginIdentifierParent* aActor) 1.811 +{ 1.812 + delete aActor; 1.813 + return true; 1.814 +} 1.815 + 1.816 +PPluginInstanceParent* 1.817 +PluginModuleParent::AllocPPluginInstanceParent(const nsCString& aMimeType, 1.818 + const uint16_t& aMode, 1.819 + const InfallibleTArray<nsCString>& aNames, 1.820 + const InfallibleTArray<nsCString>& aValues, 1.821 + NPError* rv) 1.822 +{ 1.823 + NS_ERROR("Not reachable!"); 1.824 + return nullptr; 1.825 +} 1.826 + 1.827 +bool 1.828 +PluginModuleParent::DeallocPPluginInstanceParent(PPluginInstanceParent* aActor) 1.829 +{ 1.830 + PLUGIN_LOG_DEBUG_METHOD; 1.831 + delete aActor; 1.832 + return true; 1.833 +} 1.834 + 1.835 +void 1.836 +PluginModuleParent::SetPluginFuncs(NPPluginFuncs* aFuncs) 1.837 +{ 1.838 + aFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR; 1.839 + aFuncs->javaClass = nullptr; 1.840 + 1.841 + // Gecko should always call these functions through a PluginLibrary object. 1.842 + aFuncs->newp = nullptr; 1.843 + aFuncs->clearsitedata = nullptr; 1.844 + aFuncs->getsiteswithdata = nullptr; 1.845 + 1.846 + aFuncs->destroy = NPP_Destroy; 1.847 + aFuncs->setwindow = NPP_SetWindow; 1.848 + aFuncs->newstream = NPP_NewStream; 1.849 + aFuncs->destroystream = NPP_DestroyStream; 1.850 + aFuncs->asfile = NPP_StreamAsFile; 1.851 + aFuncs->writeready = NPP_WriteReady; 1.852 + aFuncs->write = NPP_Write; 1.853 + aFuncs->print = NPP_Print; 1.854 + aFuncs->event = NPP_HandleEvent; 1.855 + aFuncs->urlnotify = NPP_URLNotify; 1.856 + aFuncs->getvalue = NPP_GetValue; 1.857 + aFuncs->setvalue = NPP_SetValue; 1.858 + aFuncs->gotfocus = nullptr; 1.859 + aFuncs->lostfocus = nullptr; 1.860 + aFuncs->urlredirectnotify = nullptr; 1.861 + 1.862 + // Provide 'NPP_URLRedirectNotify', 'NPP_ClearSiteData', and 1.863 + // 'NPP_GetSitesWithData' functionality if it is supported by the plugin. 1.864 + bool urlRedirectSupported = false; 1.865 + unused << CallOptionalFunctionsSupported(&urlRedirectSupported, 1.866 + &mClearSiteDataSupported, 1.867 + &mGetSitesWithDataSupported); 1.868 + if (urlRedirectSupported) { 1.869 + aFuncs->urlredirectnotify = NPP_URLRedirectNotify; 1.870 + } 1.871 +} 1.872 + 1.873 +NPError 1.874 +PluginModuleParent::NPP_Destroy(NPP instance, 1.875 + NPSavedData** /*saved*/) 1.876 +{ 1.877 + // FIXME/cjones: 1.878 + // (1) send a "destroy" message to the child 1.879 + // (2) the child shuts down its instance 1.880 + // (3) remove both parent and child IDs from map 1.881 + // (4) free parent 1.882 + PLUGIN_LOG_DEBUG_FUNCTION; 1.883 + 1.884 + PluginInstanceParent* parentInstance = 1.885 + static_cast<PluginInstanceParent*>(instance->pdata); 1.886 + 1.887 + if (!parentInstance) 1.888 + return NPERR_NO_ERROR; 1.889 + 1.890 + NPError retval = parentInstance->Destroy(); 1.891 + instance->pdata = nullptr; 1.892 + 1.893 + unused << PluginInstanceParent::Call__delete__(parentInstance); 1.894 + return retval; 1.895 +} 1.896 + 1.897 +NPError 1.898 +PluginModuleParent::NPP_NewStream(NPP instance, NPMIMEType type, 1.899 + NPStream* stream, NPBool seekable, 1.900 + uint16_t* stype) 1.901 +{ 1.902 + PROFILER_LABEL("PluginModuleParent", "NPP_NewStream"); 1.903 + PluginInstanceParent* i = InstCast(instance); 1.904 + if (!i) 1.905 + return NPERR_GENERIC_ERROR; 1.906 + 1.907 + return i->NPP_NewStream(type, stream, seekable, 1.908 + stype); 1.909 +} 1.910 + 1.911 +NPError 1.912 +PluginModuleParent::NPP_SetWindow(NPP instance, NPWindow* window) 1.913 +{ 1.914 + PluginInstanceParent* i = InstCast(instance); 1.915 + if (!i) 1.916 + return NPERR_GENERIC_ERROR; 1.917 + 1.918 + return i->NPP_SetWindow(window); 1.919 +} 1.920 + 1.921 +NPError 1.922 +PluginModuleParent::NPP_DestroyStream(NPP instance, 1.923 + NPStream* stream, 1.924 + NPReason reason) 1.925 +{ 1.926 + PluginInstanceParent* i = InstCast(instance); 1.927 + if (!i) 1.928 + return NPERR_GENERIC_ERROR; 1.929 + 1.930 + return i->NPP_DestroyStream(stream, reason); 1.931 +} 1.932 + 1.933 +int32_t 1.934 +PluginModuleParent::NPP_WriteReady(NPP instance, 1.935 + NPStream* stream) 1.936 +{ 1.937 + BrowserStreamParent* s = StreamCast(instance, stream); 1.938 + if (!s) 1.939 + return -1; 1.940 + 1.941 + return s->WriteReady(); 1.942 +} 1.943 + 1.944 +int32_t 1.945 +PluginModuleParent::NPP_Write(NPP instance, 1.946 + NPStream* stream, 1.947 + int32_t offset, 1.948 + int32_t len, 1.949 + void* buffer) 1.950 +{ 1.951 + BrowserStreamParent* s = StreamCast(instance, stream); 1.952 + if (!s) 1.953 + return -1; 1.954 + 1.955 + return s->Write(offset, len, buffer); 1.956 +} 1.957 + 1.958 +void 1.959 +PluginModuleParent::NPP_StreamAsFile(NPP instance, 1.960 + NPStream* stream, 1.961 + const char* fname) 1.962 +{ 1.963 + BrowserStreamParent* s = StreamCast(instance, stream); 1.964 + if (!s) 1.965 + return; 1.966 + 1.967 + s->StreamAsFile(fname); 1.968 +} 1.969 + 1.970 +void 1.971 +PluginModuleParent::NPP_Print(NPP instance, NPPrint* platformPrint) 1.972 +{ 1.973 + PluginInstanceParent* i = InstCast(instance); 1.974 + if (i) 1.975 + i->NPP_Print(platformPrint); 1.976 +} 1.977 + 1.978 +int16_t 1.979 +PluginModuleParent::NPP_HandleEvent(NPP instance, void* event) 1.980 +{ 1.981 + PluginInstanceParent* i = InstCast(instance); 1.982 + if (!i) 1.983 + return false; 1.984 + 1.985 + return i->NPP_HandleEvent(event); 1.986 +} 1.987 + 1.988 +void 1.989 +PluginModuleParent::NPP_URLNotify(NPP instance, const char* url, 1.990 + NPReason reason, void* notifyData) 1.991 +{ 1.992 + PluginInstanceParent* i = InstCast(instance); 1.993 + if (!i) 1.994 + return; 1.995 + 1.996 + i->NPP_URLNotify(url, reason, notifyData); 1.997 +} 1.998 + 1.999 +NPError 1.1000 +PluginModuleParent::NPP_GetValue(NPP instance, 1.1001 + NPPVariable variable, void *ret_value) 1.1002 +{ 1.1003 + PluginInstanceParent* i = InstCast(instance); 1.1004 + if (!i) 1.1005 + return NPERR_GENERIC_ERROR; 1.1006 + 1.1007 + return i->NPP_GetValue(variable, ret_value); 1.1008 +} 1.1009 + 1.1010 +NPError 1.1011 +PluginModuleParent::NPP_SetValue(NPP instance, NPNVariable variable, 1.1012 + void *value) 1.1013 +{ 1.1014 + PluginInstanceParent* i = InstCast(instance); 1.1015 + if (!i) 1.1016 + return NPERR_GENERIC_ERROR; 1.1017 + 1.1018 + return i->NPP_SetValue(variable, value); 1.1019 +} 1.1020 + 1.1021 +bool 1.1022 +PluginModuleParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd) 1.1023 +{ 1.1024 +#ifndef MOZ_X11 1.1025 + NS_RUNTIMEABORT("This message only makes sense on X11 platforms"); 1.1026 +#else 1.1027 + NS_ABORT_IF_FALSE(0 > mPluginXSocketFdDup.get(), 1.1028 + "Already backed up X resources??"); 1.1029 + mPluginXSocketFdDup.forget(); 1.1030 + if (aXSocketFd.IsValid()) { 1.1031 + mPluginXSocketFdDup.reset(aXSocketFd.PlatformHandle()); 1.1032 + } 1.1033 +#endif 1.1034 + return true; 1.1035 +} 1.1036 + 1.1037 +void 1.1038 +PluginModuleParent::NPP_URLRedirectNotify(NPP instance, const char* url, 1.1039 + int32_t status, void* notifyData) 1.1040 +{ 1.1041 + PluginInstanceParent* i = InstCast(instance); 1.1042 + if (!i) 1.1043 + return; 1.1044 + 1.1045 + i->NPP_URLRedirectNotify(url, status, notifyData); 1.1046 +} 1.1047 + 1.1048 +bool 1.1049 +PluginModuleParent::AnswerNPN_UserAgent(nsCString* userAgent) 1.1050 +{ 1.1051 + *userAgent = NullableString(mNPNIface->uagent(nullptr)); 1.1052 + return true; 1.1053 +} 1.1054 + 1.1055 +PluginIdentifierParent* 1.1056 +PluginModuleParent::GetIdentifierForNPIdentifier(NPP npp, NPIdentifier aIdentifier) 1.1057 +{ 1.1058 + PluginIdentifierParent* ident; 1.1059 + if (mIdentifiers.Get(aIdentifier, &ident)) { 1.1060 + if (ident->IsTemporary()) { 1.1061 + ident->AddTemporaryRef(); 1.1062 + } 1.1063 + return ident; 1.1064 + } 1.1065 + 1.1066 + nsCString string; 1.1067 + int32_t intval = -1; 1.1068 + bool temporary = false; 1.1069 + if (mozilla::plugins::parent::_identifierisstring(aIdentifier)) { 1.1070 + NPUTF8* chars = 1.1071 + mozilla::plugins::parent::_utf8fromidentifier(aIdentifier); 1.1072 + if (!chars) { 1.1073 + return nullptr; 1.1074 + } 1.1075 + string.Adopt(chars); 1.1076 + temporary = !NPStringIdentifierIsPermanent(npp, aIdentifier); 1.1077 + } 1.1078 + else { 1.1079 + intval = mozilla::plugins::parent::_intfromidentifier(aIdentifier); 1.1080 + string.SetIsVoid(true); 1.1081 + } 1.1082 + 1.1083 + ident = new PluginIdentifierParent(aIdentifier, temporary); 1.1084 + if (!SendPPluginIdentifierConstructor(ident, string, intval, temporary)) 1.1085 + return nullptr; 1.1086 + 1.1087 + if (!temporary) { 1.1088 + mIdentifiers.Put(aIdentifier, ident); 1.1089 + } 1.1090 + return ident; 1.1091 +} 1.1092 + 1.1093 +PluginInstanceParent* 1.1094 +PluginModuleParent::InstCast(NPP instance) 1.1095 +{ 1.1096 + PluginInstanceParent* ip = 1.1097 + static_cast<PluginInstanceParent*>(instance->pdata); 1.1098 + 1.1099 + // If the plugin crashed and the PluginInstanceParent was deleted, 1.1100 + // instance->pdata will be nullptr. 1.1101 + if (!ip) 1.1102 + return nullptr; 1.1103 + 1.1104 + if (instance != ip->mNPP) { 1.1105 + NS_RUNTIMEABORT("Corrupted plugin data."); 1.1106 + } 1.1107 + return ip; 1.1108 +} 1.1109 + 1.1110 +BrowserStreamParent* 1.1111 +PluginModuleParent::StreamCast(NPP instance, 1.1112 + NPStream* s) 1.1113 +{ 1.1114 + PluginInstanceParent* ip = InstCast(instance); 1.1115 + if (!ip) 1.1116 + return nullptr; 1.1117 + 1.1118 + BrowserStreamParent* sp = 1.1119 + static_cast<BrowserStreamParent*>(static_cast<AStream*>(s->pdata)); 1.1120 + if (sp->mNPP != ip || s != sp->mStream) { 1.1121 + NS_RUNTIMEABORT("Corrupted plugin stream data."); 1.1122 + } 1.1123 + return sp; 1.1124 +} 1.1125 + 1.1126 +bool 1.1127 +PluginModuleParent::HasRequiredFunctions() 1.1128 +{ 1.1129 + return true; 1.1130 +} 1.1131 + 1.1132 +nsresult 1.1133 +PluginModuleParent::AsyncSetWindow(NPP instance, NPWindow* window) 1.1134 +{ 1.1135 + PluginInstanceParent* i = InstCast(instance); 1.1136 + if (!i) 1.1137 + return NS_ERROR_FAILURE; 1.1138 + 1.1139 + return i->AsyncSetWindow(window); 1.1140 +} 1.1141 + 1.1142 +nsresult 1.1143 +PluginModuleParent::GetImageContainer(NPP instance, 1.1144 + mozilla::layers::ImageContainer** aContainer) 1.1145 +{ 1.1146 + PluginInstanceParent* i = InstCast(instance); 1.1147 + return !i ? NS_ERROR_FAILURE : i->GetImageContainer(aContainer); 1.1148 +} 1.1149 + 1.1150 +nsresult 1.1151 +PluginModuleParent::GetImageSize(NPP instance, 1.1152 + nsIntSize* aSize) 1.1153 +{ 1.1154 + PluginInstanceParent* i = InstCast(instance); 1.1155 + return !i ? NS_ERROR_FAILURE : i->GetImageSize(aSize); 1.1156 +} 1.1157 + 1.1158 +nsresult 1.1159 +PluginModuleParent::SetBackgroundUnknown(NPP instance) 1.1160 +{ 1.1161 + PluginInstanceParent* i = InstCast(instance); 1.1162 + if (!i) 1.1163 + return NS_ERROR_FAILURE; 1.1164 + 1.1165 + return i->SetBackgroundUnknown(); 1.1166 +} 1.1167 + 1.1168 +nsresult 1.1169 +PluginModuleParent::BeginUpdateBackground(NPP instance, 1.1170 + const nsIntRect& aRect, 1.1171 + gfxContext** aCtx) 1.1172 +{ 1.1173 + PluginInstanceParent* i = InstCast(instance); 1.1174 + if (!i) 1.1175 + return NS_ERROR_FAILURE; 1.1176 + 1.1177 + return i->BeginUpdateBackground(aRect, aCtx); 1.1178 +} 1.1179 + 1.1180 +nsresult 1.1181 +PluginModuleParent::EndUpdateBackground(NPP instance, 1.1182 + gfxContext* aCtx, 1.1183 + const nsIntRect& aRect) 1.1184 +{ 1.1185 + PluginInstanceParent* i = InstCast(instance); 1.1186 + if (!i) 1.1187 + return NS_ERROR_FAILURE; 1.1188 + 1.1189 + return i->EndUpdateBackground(aCtx, aRect); 1.1190 +} 1.1191 + 1.1192 +#if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK) 1.1193 +nsresult 1.1194 +PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error) 1.1195 +{ 1.1196 + PLUGIN_LOG_DEBUG_METHOD; 1.1197 + 1.1198 + mNPNIface = bFuncs; 1.1199 + 1.1200 + if (mShutdown) { 1.1201 + *error = NPERR_GENERIC_ERROR; 1.1202 + return NS_ERROR_FAILURE; 1.1203 + } 1.1204 + 1.1205 + uint32_t flags = 0; 1.1206 + 1.1207 + if (!CallNP_Initialize(flags, error)) { 1.1208 + Close(); 1.1209 + return NS_ERROR_FAILURE; 1.1210 + } 1.1211 + else if (*error != NPERR_NO_ERROR) { 1.1212 + Close(); 1.1213 + return NS_OK; 1.1214 + } 1.1215 + 1.1216 + SetPluginFuncs(pFuncs); 1.1217 + 1.1218 + return NS_OK; 1.1219 +} 1.1220 +#else 1.1221 +nsresult 1.1222 +PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error) 1.1223 +{ 1.1224 + PLUGIN_LOG_DEBUG_METHOD; 1.1225 + 1.1226 + mNPNIface = bFuncs; 1.1227 + 1.1228 + if (mShutdown) { 1.1229 + *error = NPERR_GENERIC_ERROR; 1.1230 + return NS_ERROR_FAILURE; 1.1231 + } 1.1232 + 1.1233 + uint32_t flags = 0; 1.1234 +#ifdef XP_WIN 1.1235 + flags |= kAllowAsyncDrawing; 1.1236 +#endif 1.1237 + 1.1238 + if (!CallNP_Initialize(flags, error)) { 1.1239 + Close(); 1.1240 + return NS_ERROR_FAILURE; 1.1241 + } 1.1242 + if (*error != NPERR_NO_ERROR) { 1.1243 + Close(); 1.1244 + return NS_OK; 1.1245 + } 1.1246 + 1.1247 +#if defined XP_WIN 1.1248 + // Send the info needed to join the chrome process's audio session to the 1.1249 + // plugin process 1.1250 + nsID id; 1.1251 + nsString sessionName; 1.1252 + nsString iconPath; 1.1253 + 1.1254 + if (NS_SUCCEEDED(mozilla::widget::GetAudioSessionData(id, sessionName, 1.1255 + iconPath))) 1.1256 + unused << SendSetAudioSessionData(id, sessionName, iconPath); 1.1257 +#endif 1.1258 + 1.1259 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.1260 + InitializeInjector(); 1.1261 +#endif 1.1262 + 1.1263 + return NS_OK; 1.1264 +} 1.1265 +#endif 1.1266 + 1.1267 +nsresult 1.1268 +PluginModuleParent::NP_Shutdown(NPError* error) 1.1269 +{ 1.1270 + PLUGIN_LOG_DEBUG_METHOD; 1.1271 + 1.1272 + if (mShutdown) { 1.1273 + *error = NPERR_GENERIC_ERROR; 1.1274 + return NS_ERROR_FAILURE; 1.1275 + } 1.1276 + 1.1277 + bool ok = CallNP_Shutdown(error); 1.1278 + 1.1279 + // if NP_Shutdown() is nested within another interrupt call, this will 1.1280 + // break things. but lord help us if we're doing that anyway; the 1.1281 + // plugin dso will have been unloaded on the other side by the 1.1282 + // CallNP_Shutdown() message 1.1283 + Close(); 1.1284 + 1.1285 + return ok ? NS_OK : NS_ERROR_FAILURE; 1.1286 +} 1.1287 + 1.1288 +nsresult 1.1289 +PluginModuleParent::NP_GetMIMEDescription(const char** mimeDesc) 1.1290 +{ 1.1291 + PLUGIN_LOG_DEBUG_METHOD; 1.1292 + 1.1293 + *mimeDesc = "application/x-foobar"; 1.1294 + return NS_OK; 1.1295 +} 1.1296 + 1.1297 +nsresult 1.1298 +PluginModuleParent::NP_GetValue(void *future, NPPVariable aVariable, 1.1299 + void *aValue, NPError* error) 1.1300 +{ 1.1301 + PR_LOG(GetPluginLog(), PR_LOG_WARNING, ("%s Not implemented, requested variable %i", __FUNCTION__, 1.1302 + (int) aVariable)); 1.1303 + 1.1304 + //TODO: implement this correctly 1.1305 + *error = NPERR_GENERIC_ERROR; 1.1306 + return NS_OK; 1.1307 +} 1.1308 + 1.1309 +#if defined(XP_WIN) || defined(XP_MACOSX) 1.1310 +nsresult 1.1311 +PluginModuleParent::NP_GetEntryPoints(NPPluginFuncs* pFuncs, NPError* error) 1.1312 +{ 1.1313 + NS_ASSERTION(pFuncs, "Null pointer!"); 1.1314 + 1.1315 + // We need to have the child process update its function table 1.1316 + // here by actually calling NP_GetEntryPoints since the parent's 1.1317 + // function table can reflect nullptr entries in the child's table. 1.1318 + if (!CallNP_GetEntryPoints(error)) { 1.1319 + return NS_ERROR_FAILURE; 1.1320 + } 1.1321 + else if (*error != NPERR_NO_ERROR) { 1.1322 + return NS_OK; 1.1323 + } 1.1324 + 1.1325 + SetPluginFuncs(pFuncs); 1.1326 + 1.1327 + return NS_OK; 1.1328 +} 1.1329 +#endif 1.1330 + 1.1331 +nsresult 1.1332 +PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance, 1.1333 + uint16_t mode, int16_t argc, char* argn[], 1.1334 + char* argv[], NPSavedData* saved, 1.1335 + NPError* error) 1.1336 +{ 1.1337 + PLUGIN_LOG_DEBUG_METHOD; 1.1338 + 1.1339 + if (mShutdown) { 1.1340 + *error = NPERR_GENERIC_ERROR; 1.1341 + return NS_ERROR_FAILURE; 1.1342 + } 1.1343 + 1.1344 + // create the instance on the other side 1.1345 + InfallibleTArray<nsCString> names; 1.1346 + InfallibleTArray<nsCString> values; 1.1347 + 1.1348 + for (int i = 0; i < argc; ++i) { 1.1349 + names.AppendElement(NullableString(argn[i])); 1.1350 + values.AppendElement(NullableString(argv[i])); 1.1351 + } 1.1352 + 1.1353 + PluginInstanceParent* parentInstance = 1.1354 + new PluginInstanceParent(this, instance, 1.1355 + nsDependentCString(pluginType), mNPNIface); 1.1356 + 1.1357 + if (!parentInstance->Init()) { 1.1358 + delete parentInstance; 1.1359 + return NS_ERROR_FAILURE; 1.1360 + } 1.1361 + 1.1362 + instance->pdata = parentInstance; 1.1363 + 1.1364 + if (!CallPPluginInstanceConstructor(parentInstance, 1.1365 + nsDependentCString(pluginType), mode, 1.1366 + names, values, error)) { 1.1367 + // |parentInstance| is automatically deleted. 1.1368 + instance->pdata = nullptr; 1.1369 + // if IPC is down, we'll get an immediate "failed" return, but 1.1370 + // without *error being set. So make sure that the error 1.1371 + // condition is signaled to nsNPAPIPluginInstance 1.1372 + if (NPERR_NO_ERROR == *error) 1.1373 + *error = NPERR_GENERIC_ERROR; 1.1374 + return NS_ERROR_FAILURE; 1.1375 + } 1.1376 + 1.1377 + if (*error != NPERR_NO_ERROR) { 1.1378 + NPP_Destroy(instance, 0); 1.1379 + return NS_ERROR_FAILURE; 1.1380 + } 1.1381 + 1.1382 + TimeoutChanged(kParentTimeoutPref, this); 1.1383 + 1.1384 + return NS_OK; 1.1385 +} 1.1386 + 1.1387 +nsresult 1.1388 +PluginModuleParent::NPP_ClearSiteData(const char* site, uint64_t flags, 1.1389 + uint64_t maxAge) 1.1390 +{ 1.1391 + if (!mClearSiteDataSupported) 1.1392 + return NS_ERROR_NOT_AVAILABLE; 1.1393 + 1.1394 + NPError result; 1.1395 + if (!CallNPP_ClearSiteData(NullableString(site), flags, maxAge, &result)) 1.1396 + return NS_ERROR_FAILURE; 1.1397 + 1.1398 + switch (result) { 1.1399 + case NPERR_NO_ERROR: 1.1400 + return NS_OK; 1.1401 + case NPERR_TIME_RANGE_NOT_SUPPORTED: 1.1402 + return NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED; 1.1403 + case NPERR_MALFORMED_SITE: 1.1404 + return NS_ERROR_INVALID_ARG; 1.1405 + default: 1.1406 + return NS_ERROR_FAILURE; 1.1407 + } 1.1408 +} 1.1409 + 1.1410 +nsresult 1.1411 +PluginModuleParent::NPP_GetSitesWithData(InfallibleTArray<nsCString>& result) 1.1412 +{ 1.1413 + if (!mGetSitesWithDataSupported) 1.1414 + return NS_ERROR_NOT_AVAILABLE; 1.1415 + 1.1416 + if (!CallNPP_GetSitesWithData(&result)) 1.1417 + return NS_ERROR_FAILURE; 1.1418 + 1.1419 + return NS_OK; 1.1420 +} 1.1421 + 1.1422 +#if defined(XP_MACOSX) 1.1423 +nsresult 1.1424 +PluginModuleParent::IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing) 1.1425 +{ 1.1426 + PluginInstanceParent* i = InstCast(instance); 1.1427 + if (!i) 1.1428 + return NS_ERROR_FAILURE; 1.1429 + 1.1430 + return i->IsRemoteDrawingCoreAnimation(aDrawing); 1.1431 +} 1.1432 + 1.1433 +nsresult 1.1434 +PluginModuleParent::ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor) 1.1435 +{ 1.1436 + PluginInstanceParent* i = InstCast(instance); 1.1437 + if (!i) 1.1438 + return NS_ERROR_FAILURE; 1.1439 + 1.1440 + return i->ContentsScaleFactorChanged(aContentsScaleFactor); 1.1441 +} 1.1442 +#endif // #if defined(XP_MACOSX) 1.1443 + 1.1444 +bool 1.1445 +PluginModuleParent::AnswerNPN_GetValue_WithBoolReturn(const NPNVariable& aVariable, 1.1446 + NPError* aError, 1.1447 + bool* aBoolVal) 1.1448 +{ 1.1449 + NPBool boolVal = false; 1.1450 + *aError = mozilla::plugins::parent::_getvalue(nullptr, aVariable, &boolVal); 1.1451 + *aBoolVal = boolVal ? true : false; 1.1452 + return true; 1.1453 +} 1.1454 + 1.1455 +#if defined(MOZ_WIDGET_QT) 1.1456 +static const int kMaxtimeToProcessEvents = 30; 1.1457 +bool 1.1458 +PluginModuleParent::AnswerProcessSomeEvents() 1.1459 +{ 1.1460 + PLUGIN_LOG_DEBUG(("Spinning mini nested loop ...")); 1.1461 + QCoreApplication::processEvents(QEventLoop::AllEvents, kMaxtimeToProcessEvents); 1.1462 + 1.1463 + PLUGIN_LOG_DEBUG(("... quitting mini nested loop")); 1.1464 + 1.1465 + return true; 1.1466 +} 1.1467 + 1.1468 +#elif defined(XP_MACOSX) 1.1469 +bool 1.1470 +PluginModuleParent::AnswerProcessSomeEvents() 1.1471 +{ 1.1472 + mozilla::plugins::PluginUtilsOSX::InvokeNativeEventLoop(); 1.1473 + return true; 1.1474 +} 1.1475 + 1.1476 +#elif !defined(MOZ_WIDGET_GTK) 1.1477 +bool 1.1478 +PluginModuleParent::AnswerProcessSomeEvents() 1.1479 +{ 1.1480 + NS_RUNTIMEABORT("unreached"); 1.1481 + return false; 1.1482 +} 1.1483 + 1.1484 +#else 1.1485 +static const int kMaxChancesToProcessEvents = 20; 1.1486 + 1.1487 +bool 1.1488 +PluginModuleParent::AnswerProcessSomeEvents() 1.1489 +{ 1.1490 + PLUGIN_LOG_DEBUG(("Spinning mini nested loop ...")); 1.1491 + 1.1492 + int i = 0; 1.1493 + for (; i < kMaxChancesToProcessEvents; ++i) 1.1494 + if (!g_main_context_iteration(nullptr, FALSE)) 1.1495 + break; 1.1496 + 1.1497 + PLUGIN_LOG_DEBUG(("... quitting mini nested loop; processed %i tasks", i)); 1.1498 + 1.1499 + return true; 1.1500 +} 1.1501 +#endif 1.1502 + 1.1503 +bool 1.1504 +PluginModuleParent::RecvProcessNativeEventsInInterruptCall() 1.1505 +{ 1.1506 + PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION)); 1.1507 +#if defined(OS_WIN) 1.1508 + ProcessNativeEventsInInterruptCall(); 1.1509 + return true; 1.1510 +#else 1.1511 + NS_NOTREACHED( 1.1512 + "PluginModuleParent::RecvProcessNativeEventsInInterruptCall not implemented!"); 1.1513 + return false; 1.1514 +#endif 1.1515 +} 1.1516 + 1.1517 +void 1.1518 +PluginModuleParent::ProcessRemoteNativeEventsInInterruptCall() 1.1519 +{ 1.1520 +#if defined(OS_WIN) 1.1521 + unused << SendProcessNativeEventsInInterruptCall(); 1.1522 + return; 1.1523 +#endif 1.1524 + NS_NOTREACHED( 1.1525 + "PluginModuleParent::ProcessRemoteNativeEventsInInterruptCall not implemented!"); 1.1526 +} 1.1527 + 1.1528 +bool 1.1529 +PluginModuleParent::RecvPluginShowWindow(const uint32_t& aWindowId, const bool& aModal, 1.1530 + const int32_t& aX, const int32_t& aY, 1.1531 + const size_t& aWidth, const size_t& aHeight) 1.1532 +{ 1.1533 + PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION)); 1.1534 +#if defined(XP_MACOSX) 1.1535 + CGRect windowBound = ::CGRectMake(aX, aY, aWidth, aHeight); 1.1536 + mac_plugin_interposing::parent::OnPluginShowWindow(aWindowId, windowBound, aModal); 1.1537 + return true; 1.1538 +#else 1.1539 + NS_NOTREACHED( 1.1540 + "PluginInstanceParent::RecvPluginShowWindow not implemented!"); 1.1541 + return false; 1.1542 +#endif 1.1543 +} 1.1544 + 1.1545 +bool 1.1546 +PluginModuleParent::RecvPluginHideWindow(const uint32_t& aWindowId) 1.1547 +{ 1.1548 + PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION)); 1.1549 +#if defined(XP_MACOSX) 1.1550 + mac_plugin_interposing::parent::OnPluginHideWindow(aWindowId, OtherSidePID()); 1.1551 + return true; 1.1552 +#else 1.1553 + NS_NOTREACHED( 1.1554 + "PluginInstanceParent::RecvPluginHideWindow not implemented!"); 1.1555 + return false; 1.1556 +#endif 1.1557 +} 1.1558 + 1.1559 +PCrashReporterParent* 1.1560 +PluginModuleParent::AllocPCrashReporterParent(mozilla::dom::NativeThreadId* id, 1.1561 + uint32_t* processType) 1.1562 +{ 1.1563 +#ifdef MOZ_CRASHREPORTER 1.1564 + return new CrashReporterParent(); 1.1565 +#else 1.1566 + return nullptr; 1.1567 +#endif 1.1568 +} 1.1569 + 1.1570 +bool 1.1571 +PluginModuleParent::DeallocPCrashReporterParent(PCrashReporterParent* actor) 1.1572 +{ 1.1573 +#ifdef MOZ_CRASHREPORTER 1.1574 +#ifdef XP_WIN 1.1575 + mozilla::MutexAutoLock lock(mCrashReporterMutex); 1.1576 + if (actor == static_cast<PCrashReporterParent*>(mCrashReporter)) { 1.1577 + mCrashReporter = nullptr; 1.1578 + } 1.1579 +#endif 1.1580 +#endif 1.1581 + delete actor; 1.1582 + return true; 1.1583 +} 1.1584 + 1.1585 +bool 1.1586 +PluginModuleParent::RecvSetCursor(const NSCursorInfo& aCursorInfo) 1.1587 +{ 1.1588 + PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION)); 1.1589 +#if defined(XP_MACOSX) 1.1590 + mac_plugin_interposing::parent::OnSetCursor(aCursorInfo); 1.1591 + return true; 1.1592 +#else 1.1593 + NS_NOTREACHED( 1.1594 + "PluginInstanceParent::RecvSetCursor not implemented!"); 1.1595 + return false; 1.1596 +#endif 1.1597 +} 1.1598 + 1.1599 +bool 1.1600 +PluginModuleParent::RecvShowCursor(const bool& aShow) 1.1601 +{ 1.1602 + PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION)); 1.1603 +#if defined(XP_MACOSX) 1.1604 + mac_plugin_interposing::parent::OnShowCursor(aShow); 1.1605 + return true; 1.1606 +#else 1.1607 + NS_NOTREACHED( 1.1608 + "PluginInstanceParent::RecvShowCursor not implemented!"); 1.1609 + return false; 1.1610 +#endif 1.1611 +} 1.1612 + 1.1613 +bool 1.1614 +PluginModuleParent::RecvPushCursor(const NSCursorInfo& aCursorInfo) 1.1615 +{ 1.1616 + PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION)); 1.1617 +#if defined(XP_MACOSX) 1.1618 + mac_plugin_interposing::parent::OnPushCursor(aCursorInfo); 1.1619 + return true; 1.1620 +#else 1.1621 + NS_NOTREACHED( 1.1622 + "PluginInstanceParent::RecvPushCursor not implemented!"); 1.1623 + return false; 1.1624 +#endif 1.1625 +} 1.1626 + 1.1627 +bool 1.1628 +PluginModuleParent::RecvPopCursor() 1.1629 +{ 1.1630 + PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION)); 1.1631 +#if defined(XP_MACOSX) 1.1632 + mac_plugin_interposing::parent::OnPopCursor(); 1.1633 + return true; 1.1634 +#else 1.1635 + NS_NOTREACHED( 1.1636 + "PluginInstanceParent::RecvPopCursor not implemented!"); 1.1637 + return false; 1.1638 +#endif 1.1639 +} 1.1640 + 1.1641 +bool 1.1642 +PluginModuleParent::RecvGetNativeCursorsSupported(bool* supported) 1.1643 +{ 1.1644 + PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION)); 1.1645 +#if defined(XP_MACOSX) 1.1646 + *supported = 1.1647 + Preferences::GetBool("dom.ipc.plugins.nativeCursorSupport", false); 1.1648 + return true; 1.1649 +#else 1.1650 + NS_NOTREACHED( 1.1651 + "PluginInstanceParent::RecvGetNativeCursorSupportLevel not implemented!"); 1.1652 + return false; 1.1653 +#endif 1.1654 +} 1.1655 + 1.1656 +bool 1.1657 +PluginModuleParent::RecvNPN_SetException(PPluginScriptableObjectParent* aActor, 1.1658 + const nsCString& aMessage) 1.1659 +{ 1.1660 + PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION)); 1.1661 + 1.1662 + NPObject* aNPObj = nullptr; 1.1663 + if (aActor) { 1.1664 + aNPObj = static_cast<PluginScriptableObjectParent*>(aActor)->GetObject(true); 1.1665 + if (!aNPObj) { 1.1666 + NS_ERROR("Failed to get object!"); 1.1667 + return false; 1.1668 + } 1.1669 + } 1.1670 + mozilla::plugins::parent::_setexception(aNPObj, NullableStringGet(aMessage)); 1.1671 + return true; 1.1672 +} 1.1673 + 1.1674 +bool 1.1675 +PluginModuleParent::RecvNPN_ReloadPlugins(const bool& aReloadPages) 1.1676 +{ 1.1677 + PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION)); 1.1678 + 1.1679 + mozilla::plugins::parent::_reloadplugins(aReloadPages); 1.1680 + return true; 1.1681 +} 1.1682 + 1.1683 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.1684 + 1.1685 +// We only add the crash reporter to subprocess which have the filename 1.1686 +// FlashPlayerPlugin* 1.1687 +#define FLASH_PROCESS_PREFIX "FLASHPLAYERPLUGIN" 1.1688 + 1.1689 +static DWORD 1.1690 +GetFlashChildOfPID(DWORD pid, HANDLE snapshot) 1.1691 +{ 1.1692 + PROCESSENTRY32 entry = { 1.1693 + sizeof(entry) 1.1694 + }; 1.1695 + for (BOOL ok = Process32First(snapshot, &entry); 1.1696 + ok; 1.1697 + ok = Process32Next(snapshot, &entry)) { 1.1698 + if (entry.th32ParentProcessID == pid) { 1.1699 + nsString name(entry.szExeFile); 1.1700 + ToUpperCase(name); 1.1701 + if (StringBeginsWith(name, NS_LITERAL_STRING(FLASH_PROCESS_PREFIX))) { 1.1702 + return entry.th32ProcessID; 1.1703 + } 1.1704 + } 1.1705 + } 1.1706 + return 0; 1.1707 +} 1.1708 + 1.1709 +// We only look for child processes of the Flash plugin, NPSWF* 1.1710 +#define FLASH_PLUGIN_PREFIX "NPSWF" 1.1711 + 1.1712 +void 1.1713 +PluginModuleParent::InitializeInjector() 1.1714 +{ 1.1715 + if (!Preferences::GetBool("dom.ipc.plugins.flash.subprocess.crashreporter.enabled", false)) 1.1716 + return; 1.1717 + 1.1718 + nsCString path(Process()->GetPluginFilePath().c_str()); 1.1719 + ToUpperCase(path); 1.1720 + int32_t lastSlash = path.RFindCharInSet("\\/"); 1.1721 + if (kNotFound == lastSlash) 1.1722 + return; 1.1723 + 1.1724 + if (!StringBeginsWith(Substring(path, lastSlash + 1), 1.1725 + NS_LITERAL_CSTRING(FLASH_PLUGIN_PREFIX))) 1.1726 + return; 1.1727 + 1.1728 + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 1.1729 + if (INVALID_HANDLE_VALUE == snapshot) 1.1730 + return; 1.1731 + 1.1732 + DWORD pluginProcessPID = GetProcessId(Process()->GetChildProcessHandle()); 1.1733 + mFlashProcess1 = GetFlashChildOfPID(pluginProcessPID, snapshot); 1.1734 + if (mFlashProcess1) { 1.1735 + InjectCrashReporterIntoProcess(mFlashProcess1, this); 1.1736 + 1.1737 + mFlashProcess2 = GetFlashChildOfPID(mFlashProcess1, snapshot); 1.1738 + if (mFlashProcess2) { 1.1739 + InjectCrashReporterIntoProcess(mFlashProcess2, this); 1.1740 + } 1.1741 + } 1.1742 +} 1.1743 + 1.1744 +void 1.1745 +PluginModuleParent::OnCrash(DWORD processID) 1.1746 +{ 1.1747 + if (!mShutdown) { 1.1748 + GetIPCChannel()->CloseWithError(); 1.1749 + KillProcess(OtherProcess(), 1, false); 1.1750 + } 1.1751 +} 1.1752 + 1.1753 +#endif // MOZ_CRASHREPORTER_INJECTOR 1.1754 + 1.1755 +#ifdef MOZ_ENABLE_PROFILER_SPS 1.1756 +class PluginProfilerObserver MOZ_FINAL : public nsIObserver, 1.1757 + public nsSupportsWeakReference 1.1758 +{ 1.1759 +public: 1.1760 + NS_DECL_ISUPPORTS 1.1761 + NS_DECL_NSIOBSERVER 1.1762 + 1.1763 + explicit PluginProfilerObserver(PluginModuleParent* pmp) 1.1764 + : mPmp(pmp) 1.1765 + {} 1.1766 + 1.1767 +private: 1.1768 + PluginModuleParent* mPmp; 1.1769 +}; 1.1770 + 1.1771 +NS_IMPL_ISUPPORTS(PluginProfilerObserver, nsIObserver, nsISupportsWeakReference) 1.1772 + 1.1773 +NS_IMETHODIMP 1.1774 +PluginProfilerObserver::Observe(nsISupports *aSubject, 1.1775 + const char *aTopic, 1.1776 + const char16_t *aData) 1.1777 +{ 1.1778 + nsCOMPtr<nsIProfileSaveEvent> pse = do_QueryInterface(aSubject); 1.1779 + if (pse) { 1.1780 + nsCString result; 1.1781 + bool success = mPmp->CallGeckoGetProfile(&result); 1.1782 + if (success && !result.IsEmpty()) { 1.1783 + pse->AddSubProfile(result.get()); 1.1784 + } 1.1785 + } 1.1786 + return NS_OK; 1.1787 +} 1.1788 + 1.1789 +void 1.1790 +PluginModuleParent::InitPluginProfiling() 1.1791 +{ 1.1792 + nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); 1.1793 + if (observerService) { 1.1794 + mProfilerObserver = new PluginProfilerObserver(this); 1.1795 + observerService->AddObserver(mProfilerObserver, "profiler-subprocess", false); 1.1796 + } 1.1797 +} 1.1798 + 1.1799 +void 1.1800 +PluginModuleParent::ShutdownPluginProfiling() 1.1801 +{ 1.1802 + nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); 1.1803 + if (observerService) { 1.1804 + observerService->RemoveObserver(mProfilerObserver, "profiler-subprocess"); 1.1805 + } 1.1806 +} 1.1807 +#endif