dom/plugins/ipc/PluginModuleParent.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rwxr-xr-x

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial