GMPChild.cpp (26038B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "GMPChild.h" 7 8 #include "ChildProfilerController.h" 9 #include "ChromiumCDMAdapter.h" 10 #include "GeckoProfiler.h" 11 #include "base/command_line.h" 12 #include "base/task.h" 13 #ifdef XP_LINUX 14 # include "dlfcn.h" 15 # if defined(MOZ_SANDBOX) 16 # include "mozilla/Sandbox.h" 17 # endif // defined(MOZ_SANDBOX) 18 #endif // defined (XP_LINUX) 19 #include "GMPContentChild.h" 20 #include "GMPLoader.h" 21 #include "GMPLog.h" 22 #include "GMPPlatform.h" 23 #include "GMPProcessChild.h" 24 #include "GMPProcessParent.h" 25 #include "GMPUtils.h" 26 #include "GMPVideoDecoderChild.h" 27 #include "GMPVideoEncoderChild.h" 28 #include "GMPVideoHost.h" 29 #include "gmp-video-decode.h" 30 #include "gmp-video-encode.h" 31 #include "mozilla/Algorithm.h" 32 #include "mozilla/BackgroundHangMonitor.h" 33 #include "mozilla/FOGIPC.h" 34 #include "mozilla/TextUtils.h" 35 #include "mozilla/glean/GleanTestsTestMetrics.h" 36 #include "mozilla/ipc/CrashReporterClient.h" 37 #include "mozilla/ipc/Endpoint.h" 38 #include "mozilla/ipc/ProcessChild.h" 39 #include "nsDebugImpl.h" 40 #include "nsExceptionHandler.h" 41 #include "nsIFile.h" 42 #include "nsIXULRuntime.h" 43 #include "nsReadableUtils.h" 44 #include "nsThreadManager.h" 45 #include "nsXPCOM.h" 46 #include "nsXPCOMPrivate.h" // for XUL_DLL 47 #include "nsXULAppAPI.h" 48 #include "prio.h" 49 #ifdef XP_WIN 50 # include <stdlib.h> // for _exit() 51 52 # include "WinUtils.h" 53 # include "mozilla/Services.h" 54 # include "mozilla/WinDllServices.h" 55 # include "nsIObserverService.h" 56 #else 57 # include <unistd.h> // for _exit() 58 #endif 59 60 using namespace mozilla::ipc; 61 62 namespace mozilla { 63 namespace gmp { 64 65 #define GMP_CHILD_LOG(loglevel, x, ...) \ 66 MOZ_LOG( \ 67 GetGMPLog(), (loglevel), \ 68 ("GMPChild[pid=%d] " x, (int)base::GetCurrentProcId(), ##__VA_ARGS__)) 69 70 #define GMP_CHILD_LOG_DEBUG(x, ...) \ 71 GMP_CHILD_LOG(LogLevel::Debug, x, ##__VA_ARGS__) 72 73 GMPChild::GMPChild() 74 : mGMPMessageLoop(MessageLoop::current()), mGMPLoader(nullptr) { 75 GMP_CHILD_LOG_DEBUG("GMPChild ctor"); 76 nsDebugImpl::SetMultiprocessMode("GMP"); 77 } 78 79 GMPChild::~GMPChild() { 80 GMP_CHILD_LOG_DEBUG("GMPChild dtor"); 81 #ifdef XP_LINUX 82 for (auto& libHandle : mLibHandles) { 83 dlclose(libHandle); 84 } 85 #endif 86 } 87 88 bool GMPChild::Init(const nsAString& aPluginPath, const char* aParentBuildID, 89 mozilla::ipc::UntypedEndpoint&& aEndpoint) { 90 GMP_CHILD_LOG_DEBUG("%s pluginPath=%s useXpcom=%d, useNativeEvent=%d", 91 __FUNCTION__, NS_ConvertUTF16toUTF8(aPluginPath).get(), 92 GMPProcessChild::UseXPCOM(), 93 GMPProcessChild::UseNativeEventProcessing()); 94 95 // GMPChild needs nsThreadManager to create the ProfilerChild thread. 96 // It is also used on debug builds for the sandbox tests. 97 if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) { 98 return false; 99 } 100 101 if (NS_WARN_IF(!aEndpoint.Bind(this))) { 102 return false; 103 } 104 105 // This must be checked before any IPDL message, which may hit sentinel 106 // errors due to parent and content processes having different 107 // versions. 108 MessageChannel* channel = GetIPCChannel(); 109 if (channel && !channel->SendBuildIDsMatchMessage(aParentBuildID)) { 110 // We need to quit this process if the buildID doesn't match the parent's. 111 // This can occur when an update occurred in the background. 112 ipc::ProcessChild::QuickExit(); 113 } 114 115 CrashReporterClient::InitSingleton(this); 116 117 if (GMPProcessChild::UseXPCOM()) { 118 if (NS_WARN_IF(NS_FAILED(NS_InitMinimalXPCOM()))) { 119 return false; 120 } 121 } else { 122 BackgroundHangMonitor::Startup(); 123 } 124 125 mPluginPath = aPluginPath; 126 127 nsAutoCString processName("GMPlugin Process"); 128 129 nsAutoCString pluginName; 130 if (GetPluginName(pluginName)) { 131 processName.AppendLiteral(" ("); 132 processName.Append(pluginName); 133 processName.AppendLiteral(")"); 134 } 135 136 profiler_set_process_name(processName); 137 138 return true; 139 } 140 141 void GMPChild::Shutdown() { 142 if (GMPProcessChild::UseXPCOM()) { 143 NS_ShutdownXPCOM(nullptr); 144 } else { 145 BackgroundHangMonitor::Shutdown(); 146 } 147 } 148 149 mozilla::ipc::IPCResult GMPChild::RecvProvideStorageId( 150 const nsCString& aStorageId) { 151 GMP_CHILD_LOG_DEBUG("%s", __FUNCTION__); 152 mStorageId = aStorageId; 153 return IPC_OK(); 154 } 155 156 GMPErr GMPChild::GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI, 157 const nsACString& aKeySystem) { 158 if (!mGMPLoader) { 159 return GMPGenericErr; 160 } 161 return mGMPLoader->GetAPI(aAPIName, aHostAPI, aPluginAPI, aKeySystem); 162 } 163 164 mozilla::ipc::IPCResult GMPChild::RecvPreloadLibs(const nsCString& aLibs) { 165 // Pre-load libraries that may need to be used by the EME plugin but that 166 // can't be loaded after the sandbox has started. 167 #ifdef XP_WIN 168 // Items in this must be lowercase! 169 constexpr static const char16_t* whitelist[] = { 170 u"dxva2.dll", // Get monitor information 171 u"evr.dll", // MFGetStrideForBitmapInfoHeader 172 u"freebl3.dll", // NSS for clearkey CDM 173 u"mfplat.dll", // MFCreateSample, MFCreateAlignedMemoryBuffer, 174 // MFCreateMediaType 175 u"msmpeg2vdec.dll", // H.264 decoder 176 u"nss3.dll", // NSS for clearkey CDM 177 u"ole32.dll", // required for OPM 178 u"oleaut32.dll", // For _bstr_t use in libwebrtc, see bug 1788592 179 u"psapi.dll", // For GetMappedFileNameW, see bug 1383611 180 u"shell32.dll", // Dependency for widevine 181 u"softokn3.dll", // NSS for clearkey CDM 182 u"winmm.dll", // Dependency for widevine 183 }; 184 constexpr static bool (*IsASCII)(const char16_t*) = 185 IsAsciiNullTerminated<char16_t>; 186 static_assert(AllOf(std::begin(whitelist), std::end(whitelist), IsASCII), 187 "Items in the whitelist must not contain non-ASCII " 188 "characters!"); 189 190 nsTArray<nsCString> libs; 191 SplitAt(", ", aLibs, libs); 192 for (nsCString lib : libs) { 193 ToLowerCase(lib); 194 for (const char16_t* whiteListedLib : whitelist) { 195 if (nsDependentString(whiteListedLib) 196 .EqualsASCII(lib.Data(), lib.Length())) { 197 LoadLibraryW(char16ptr_t(whiteListedLib)); 198 break; 199 } 200 } 201 } 202 #elif defined(XP_LINUX) 203 constexpr static const char* whitelist[] = { 204 // NSS libraries used by clearkey. 205 "libfreeblpriv3.so", 206 "libsoftokn3.so", 207 // glibc libraries merged into libc.so.6; see bug 1725828 and 208 // the corresponding code in GMPParent.cpp. 209 "libdl.so.2", 210 "libpthread.so.0", 211 "librt.so.1", 212 }; 213 214 nsTArray<nsCString> libs; 215 SplitAt(", ", aLibs, libs); 216 for (const nsCString& lib : libs) { 217 for (const char* whiteListedLib : whitelist) { 218 if (lib.EqualsASCII(whiteListedLib)) { 219 auto libHandle = dlopen(whiteListedLib, RTLD_NOW | RTLD_GLOBAL); 220 if (libHandle) { 221 mLibHandles.AppendElement(libHandle); 222 } else { 223 // TODO(bug 1698718): remove the logging once we've identified 224 // the cause of the load failure. 225 const char* error = dlerror(); 226 if (error) { 227 // We should always have an error, but gracefully handle just in 228 // case. 229 nsAutoCString nsError{error}; 230 CrashReporter::AppendAppNotesToCrashReport(nsError); 231 } 232 // End bug 1698718 logging. 233 234 MOZ_CRASH("Couldn't load lib needed by media plugin"); 235 } 236 } 237 } 238 } 239 #endif 240 return IPC_OK(); 241 } 242 243 bool GMPChild::GetUTF8LibPath(nsACString& aOutLibPath) { 244 #ifdef MOZ_WIDGET_ANDROID 245 aOutLibPath = "lib"_ns + NS_ConvertUTF16toUTF8(mPluginPath) + ".so"_ns; 246 #else 247 nsCOMPtr<nsIFile> libFile; 248 249 # define GMP_PATH_CRASH(explain) \ 250 do { \ 251 nsAutoString path; \ 252 if (!libFile || NS_FAILED(libFile->GetPath(path))) { \ 253 path = mPluginPath; \ 254 } \ 255 CrashReporter::RecordAnnotationNSString( \ 256 CrashReporter::Annotation::GMPLibraryPath, path); \ 257 MOZ_CRASH(explain); \ 258 } while (false) 259 260 nsresult rv = NS_NewLocalFile(mPluginPath, getter_AddRefs(libFile)); 261 if (NS_WARN_IF(NS_FAILED(rv))) { 262 GMP_PATH_CRASH("Failed to create file for plugin path"); 263 return false; 264 } 265 266 nsCOMPtr<nsIFile> parent; 267 rv = libFile->GetParent(getter_AddRefs(parent)); 268 if (NS_WARN_IF(NS_FAILED(rv))) { 269 GMP_PATH_CRASH("Failed to get parent file for plugin file"); 270 return false; 271 } 272 273 nsAutoString parentLeafName; 274 rv = parent->GetLeafName(parentLeafName); 275 if (NS_WARN_IF(NS_FAILED(rv))) { 276 GMP_PATH_CRASH("Failed to get leaf for plugin file"); 277 return false; 278 } 279 280 nsAutoString baseName; 281 baseName = Substring(parentLeafName, 4, parentLeafName.Length() - 1); 282 283 # if defined(XP_MACOSX) 284 nsAutoString binaryName = u"lib"_ns + baseName + u".dylib"_ns; 285 # elif defined(XP_UNIX) 286 nsAutoString binaryName = u"lib"_ns + baseName + u".so"_ns; 287 # elif defined(XP_WIN) 288 nsAutoString binaryName = baseName + u".dll"_ns; 289 # else 290 # error not defined 291 # endif 292 rv = libFile->AppendRelativePath(binaryName); 293 if (NS_WARN_IF(NS_FAILED(rv))) { 294 GMP_PATH_CRASH("Failed to append lib to plugin file"); 295 return false; 296 } 297 298 if (NS_WARN_IF(!FileExists(libFile))) { 299 GMP_PATH_CRASH("Plugin file does not exist"); 300 return false; 301 } 302 303 nsAutoString path; 304 rv = libFile->GetPath(path); 305 if (NS_WARN_IF(NS_FAILED(rv))) { 306 GMP_PATH_CRASH("Failed to get path for plugin file"); 307 return false; 308 } 309 310 CopyUTF16toUTF8(path, aOutLibPath); 311 #endif 312 return true; 313 } 314 315 bool GMPChild::GetPluginName(nsACString& aPluginName) const { 316 #ifdef MOZ_WIDGET_ANDROID 317 aPluginName = NS_ConvertUTF16toUTF8(mPluginPath); 318 #else 319 // Extract the plugin directory name if possible. 320 nsCOMPtr<nsIFile> libFile; 321 nsresult rv = NS_NewLocalFile(mPluginPath, getter_AddRefs(libFile)); 322 NS_ENSURE_SUCCESS(rv, false); 323 324 nsCOMPtr<nsIFile> parent; 325 rv = libFile->GetParent(getter_AddRefs(parent)); 326 NS_ENSURE_SUCCESS(rv, false); 327 328 nsAutoString parentLeafName; 329 rv = parent->GetLeafName(parentLeafName); 330 NS_ENSURE_SUCCESS(rv, false); 331 332 aPluginName.Assign(NS_ConvertUTF16toUTF8(parentLeafName)); 333 #endif 334 return true; 335 } 336 337 static nsCOMPtr<nsIFile> AppendFile(nsCOMPtr<nsIFile>&& aFile, 338 const nsString& aStr) { 339 return (aFile && NS_SUCCEEDED(aFile->Append(aStr))) ? aFile : nullptr; 340 } 341 342 static nsCOMPtr<nsIFile> CloneFile(const nsCOMPtr<nsIFile>& aFile) { 343 nsCOMPtr<nsIFile> clone; 344 return (aFile && NS_SUCCEEDED(aFile->Clone(getter_AddRefs(clone)))) ? clone 345 : nullptr; 346 } 347 348 static nsCOMPtr<nsIFile> GetParentFile(const nsCOMPtr<nsIFile>& aFile) { 349 nsCOMPtr<nsIFile> parent; 350 return (aFile && NS_SUCCEEDED(aFile->GetParent(getter_AddRefs(parent)))) 351 ? parent 352 : nullptr; 353 } 354 355 #if defined(XP_WIN) 356 static bool IsFileLeafEqualToASCII(const nsCOMPtr<nsIFile>& aFile, 357 const char* aStr) { 358 nsAutoString leafName; 359 return aFile && NS_SUCCEEDED(aFile->GetLeafName(leafName)) && 360 leafName.EqualsASCII(aStr); 361 } 362 #endif 363 364 #if defined(XP_WIN) 365 # define FIREFOX_FILE MOZ_APP_NAME u".exe"_ns 366 #else 367 # define FIREFOX_FILE MOZ_APP_NAME u""_ns 368 #endif 369 #define XUL_LIB_FILE XUL_DLL u""_ns 370 371 static nsCOMPtr<nsIFile> GetFirefoxAppPath( 372 nsCOMPtr<nsIFile> aPluginContainerPath) { 373 MOZ_ASSERT(aPluginContainerPath); 374 #if defined(XP_MACOSX) 375 // On MacOS the firefox binary is a few parent directories up from 376 // plugin-container. 377 // aPluginContainerPath will end with something like: 378 // xxxx/NightlyDebug.app/Contents/MacOS/plugin-container.app/Contents/MacOS/plugin-container 379 nsCOMPtr<nsIFile> path = aPluginContainerPath; 380 for (int i = 0; i < 4; i++) { 381 path = GetParentFile(path); 382 } 383 return path; 384 #else 385 nsCOMPtr<nsIFile> parent = GetParentFile(aPluginContainerPath); 386 # if XP_WIN 387 if (IsFileLeafEqualToASCII(parent, "i686")) { 388 // We must be on Windows on ARM64, where the plugin-container path will 389 // be in the 'i686' subdir. The firefox.exe is in the parent directory. 390 parent = GetParentFile(parent); 391 } 392 # endif 393 return parent; 394 #endif 395 } 396 397 #if defined(XP_MACOSX) 398 static bool GetSigPath(const int aRelativeLayers, 399 const nsString& aTargetSigFileName, 400 nsCOMPtr<nsIFile> aExecutablePath, 401 nsCOMPtr<nsIFile>& aOutSigPath) { 402 // The sig file will be located in 403 // xxxx/NightlyDebug.app/Contents/Resources/XUL.sig 404 // xxxx/NightlyDebug.app/Contents/Resources/firefox.sig 405 // xxxx/NightlyDebug.app/Contents/MacOS/plugin-container.app/Contents/Resources/plugin-container.sig 406 // On MacOS the sig file is a few parent directories up from 407 // its executable file. 408 // Start to search the path from the path of the executable file we provided. 409 MOZ_ASSERT(aExecutablePath); 410 nsCOMPtr<nsIFile> path = aExecutablePath; 411 for (int i = 0; i < aRelativeLayers; i++) { 412 nsCOMPtr<nsIFile> parent; 413 if (NS_WARN_IF(NS_FAILED(path->GetParent(getter_AddRefs(parent))))) { 414 return false; 415 } 416 path = parent; 417 } 418 MOZ_ASSERT(path); 419 aOutSigPath = path; 420 return NS_SUCCEEDED(path->Append(u"Resources"_ns)) && 421 NS_SUCCEEDED(path->Append(aTargetSigFileName)); 422 } 423 #endif 424 425 static bool AppendHostPath(nsCOMPtr<nsIFile>& aFile, 426 nsTArray<std::pair<nsCString, nsCString>>& aPaths) { 427 nsString str; 428 if (!FileExists(aFile) || NS_FAILED(aFile->GetPath(str))) { 429 return false; 430 } 431 432 nsCString filePath = NS_ConvertUTF16toUTF8(str); 433 nsCString sigFilePath; 434 #if defined(XP_MACOSX) 435 nsAutoString binary; 436 if (NS_FAILED(aFile->GetLeafName(binary))) { 437 return false; 438 } 439 binary.Append(u".sig"_ns); 440 nsCOMPtr<nsIFile> sigFile; 441 if (GetSigPath(2, binary, aFile, sigFile) && 442 NS_SUCCEEDED(sigFile->GetPath(str))) { 443 CopyUTF16toUTF8(str, sigFilePath); 444 } else { 445 // Cannot successfully get the sig file path. 446 // Assume it is located at the same place as plugin-container 447 // alternatively. 448 sigFilePath = nsCString(NS_ConvertUTF16toUTF8(str) + ".sig"_ns); 449 } 450 #else 451 sigFilePath = nsCString(NS_ConvertUTF16toUTF8(str) + ".sig"_ns); 452 #endif 453 aPaths.AppendElement( 454 std::make_pair(std::move(filePath), std::move(sigFilePath))); 455 return true; 456 } 457 458 nsTArray<std::pair<nsCString, nsCString>> 459 GMPChild::MakeCDMHostVerificationPaths(const nsACString& aPluginLibPath) { 460 // Record the file path and its sig file path. 461 nsTArray<std::pair<nsCString, nsCString>> paths; 462 // Plugin binary path. 463 paths.AppendElement( 464 std::make_pair(nsCString(aPluginLibPath), aPluginLibPath + ".sig"_ns)); 465 466 // Plugin-container binary path. 467 // Note: clang won't let us initialize an nsString from a wstring, so we 468 // need to go through UTF8 to get to an nsString. 469 const std::string pluginContainer = 470 WideToUTF8(CommandLine::ForCurrentProcess()->program()); 471 nsString str; 472 473 CopyUTF8toUTF16(nsDependentCString(pluginContainer.c_str()), str); 474 nsCOMPtr<nsIFile> path; 475 if (NS_FAILED(NS_NewLocalFile(str, getter_AddRefs(path))) || 476 !AppendHostPath(path, paths)) { 477 // Without successfully determining plugin-container's path, we can't 478 // determine libxul's or Firefox's. So give up. 479 return paths; 480 } 481 482 #if defined(XP_WIN) 483 // On Windows on ARM64, we should also append the x86 plugin-container's 484 // xul.dll. 485 const bool isWindowsOnARM64 = 486 IsFileLeafEqualToASCII(GetParentFile(path), "i686"); 487 if (isWindowsOnARM64) { 488 nsCOMPtr<nsIFile> x86XulPath = 489 AppendFile(GetParentFile(path), XUL_LIB_FILE); 490 if (!AppendHostPath(x86XulPath, paths)) { 491 return paths; 492 } 493 } 494 #endif 495 496 // Firefox application binary path. 497 nsCOMPtr<nsIFile> appDir = GetFirefoxAppPath(path); 498 path = AppendFile(CloneFile(appDir), FIREFOX_FILE); 499 if (!AppendHostPath(path, paths)) { 500 return paths; 501 } 502 503 // Libxul path. Note: re-using 'appDir' var here, as we assume libxul is in 504 // the same directory as Firefox executable. 505 appDir->GetPath(str); 506 path = AppendFile(CloneFile(appDir), XUL_LIB_FILE); 507 if (!AppendHostPath(path, paths)) { 508 return paths; 509 } 510 511 return paths; 512 } 513 514 static auto ToCString(const nsTArray<std::pair<nsCString, nsCString>>& aPairs) { 515 return StringJoin(","_ns, aPairs, [](nsACString& dest, const auto& p) { 516 dest.AppendPrintf("(%s,%s)", p.first.get(), p.second.get()); 517 }); 518 } 519 520 mozilla::ipc::IPCResult GMPChild::RecvStartPlugin(const nsString& aAdapter) { 521 GMP_CHILD_LOG_DEBUG("%s", __FUNCTION__); 522 523 nsAutoCString libPath; 524 if (!GetUTF8LibPath(libPath)) { 525 CrashReporter::RecordAnnotationNSCString( 526 CrashReporter::Annotation::GMPLibraryPath, 527 NS_ConvertUTF16toUTF8(mPluginPath)); 528 529 #ifdef XP_WIN 530 GMP_CHILD_LOG(LogLevel::Error, "Failed to get lib path with error(%lu).", 531 GetLastError()); 532 #endif 533 return IPC_FAIL(this, "Failed to get lib path."); 534 } 535 536 auto platformAPI = new GMPPlatformAPI(); 537 InitPlatformAPI(*platformAPI, this); 538 539 mGMPLoader = MakeUnique<GMPLoader>(); 540 #if defined(MOZ_SANDBOX) && !defined(XP_MACOSX) 541 if (!mGMPLoader->CanSandbox()) { 542 GMP_CHILD_LOG_DEBUG("%s Can't sandbox GMP, failing", __FUNCTION__); 543 delete platformAPI; 544 return IPC_FAIL(this, "Can't sandbox GMP."); 545 } 546 #endif 547 548 GMPAdapter* adapter = nullptr; 549 if (aAdapter.EqualsLiteral("chromium")) { 550 auto&& paths = MakeCDMHostVerificationPaths(libPath); 551 GMP_CHILD_LOG_DEBUG("%s CDM host paths=%s", __func__, 552 ToCString(paths).get()); 553 adapter = new ChromiumCDMAdapter(std::move(paths)); 554 } 555 556 if (!mGMPLoader->Load(libPath.get(), libPath.Length(), platformAPI, 557 adapter)) { 558 #ifdef XP_WIN 559 560 NS_WARNING( 561 nsPrintfCString("Failed to load GMP with error(%lu).", GetLastError()) 562 .get()); 563 #else 564 NS_WARNING("Failed to load GMP"); 565 #endif 566 delete platformAPI; 567 CrashReporter::RecordAnnotationNSCString( 568 CrashReporter::Annotation::GMPLibraryPath, 569 NS_ConvertUTF16toUTF8(mPluginPath)); 570 571 return IPC_FAIL(this, "Failed to load GMP."); 572 } 573 574 return IPC_OK(); 575 } 576 577 MessageLoop* GMPChild::GMPMessageLoop() { return mGMPMessageLoop; } 578 579 void GMPChild::ActorDestroy(ActorDestroyReason aWhy) { 580 GMP_CHILD_LOG_DEBUG("%s reason=%d", __FUNCTION__, aWhy); 581 582 #if defined(XP_LINUX) && defined(MOZ_SANDBOX) 583 DestroySandboxProfiler(); 584 #endif 585 586 for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) { 587 MOZ_ASSERT_IF(aWhy == NormalShutdown, 588 !mGMPContentChildren[i - 1]->IsUsed()); 589 mGMPContentChildren[i - 1]->Close(); 590 } 591 592 if (mGMPLoader) { 593 mGMPLoader->Shutdown(); 594 } 595 596 ShutdownPlatformAPI(); 597 598 if (AbnormalShutdown == aWhy) { 599 NS_WARNING("Abnormal shutdown of GMP process!"); 600 ProcessChild::QuickExit(); 601 } 602 603 // Send the last bits of Glean data over to the main process. 604 glean::FlushFOGData( 605 [](ByteBuf&& aBuf) { glean::SendFOGData(std::move(aBuf)); }); 606 607 if (mProfilerController) { 608 mProfilerController->Shutdown(); 609 mProfilerController = nullptr; 610 } 611 612 CrashReporterClient::DestroySingleton(); 613 614 XRE_ShutdownChildProcess(); 615 } 616 617 void GMPChild::ProcessingError(Result aCode, const char* aReason) { 618 switch (aCode) { 619 case MsgDropped: 620 NS_WARNING("MsgDropped in GMPChild"); 621 return; 622 case MsgNotKnown: 623 MOZ_CRASH("aborting because of MsgNotKnown"); 624 case MsgNotAllowed: 625 MOZ_CRASH("aborting because of MsgNotAllowed"); 626 case MsgPayloadError: 627 MOZ_CRASH("aborting because of MsgPayloadError"); 628 case MsgProcessingError: 629 MOZ_CRASH("aborting because of MsgProcessingError"); 630 case MsgValueError: 631 MOZ_CRASH("aborting because of MsgValueError"); 632 default: 633 MOZ_CRASH("not reached"); 634 } 635 } 636 637 PGMPTimerChild* GMPChild::AllocPGMPTimerChild() { 638 return new GMPTimerChild(this); 639 } 640 641 bool GMPChild::DeallocPGMPTimerChild(PGMPTimerChild* aActor) { 642 MOZ_ASSERT(mTimerChild == static_cast<GMPTimerChild*>(aActor)); 643 mTimerChild = nullptr; 644 return true; 645 } 646 647 GMPTimerChild* GMPChild::GetGMPTimers() { 648 if (!mTimerChild) { 649 PGMPTimerChild* sc = SendPGMPTimerConstructor(); 650 if (!sc) { 651 return nullptr; 652 } 653 mTimerChild = static_cast<GMPTimerChild*>(sc); 654 } 655 return mTimerChild; 656 } 657 658 PGMPStorageChild* GMPChild::AllocPGMPStorageChild() { 659 return new GMPStorageChild(this); 660 } 661 662 bool GMPChild::DeallocPGMPStorageChild(PGMPStorageChild* aActor) { 663 mStorage = nullptr; 664 return true; 665 } 666 667 GMPStorageChild* GMPChild::GetGMPStorage() { 668 if (!mStorage) { 669 PGMPStorageChild* sc = SendPGMPStorageConstructor(); 670 if (!sc) { 671 return nullptr; 672 } 673 mStorage = static_cast<GMPStorageChild*>(sc); 674 } 675 return mStorage; 676 } 677 678 mozilla::ipc::IPCResult GMPChild::RecvCrashPluginNow() { 679 MOZ_CRASH(); 680 return IPC_OK(); 681 } 682 683 mozilla::ipc::IPCResult GMPChild::RecvCloseActive() { 684 for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) { 685 mGMPContentChildren[i - 1]->CloseActive(); 686 } 687 return IPC_OK(); 688 } 689 690 mozilla::ipc::IPCResult GMPChild::RecvInitGMPContentChild( 691 Endpoint<PGMPContentChild>&& aEndpoint) { 692 GMPContentChild* child = 693 mGMPContentChildren.AppendElement(new GMPContentChild(this))->get(); 694 aEndpoint.Bind(child); 695 return IPC_OK(); 696 } 697 698 mozilla::ipc::IPCResult GMPChild::RecvFlushFOGData( 699 FlushFOGDataResolver&& aResolver) { 700 GMP_CHILD_LOG_DEBUG("GMPChild RecvFlushFOGData"); 701 glean::FlushFOGData(std::move(aResolver)); 702 return IPC_OK(); 703 } 704 705 mozilla::ipc::IPCResult GMPChild::RecvTestTriggerMetrics( 706 TestTriggerMetricsResolver&& aResolve) { 707 GMP_CHILD_LOG_DEBUG("GMPChild RecvTestTriggerMetrics"); 708 mozilla::glean::test_only_ipc::a_counter.Add( 709 nsIXULRuntime::PROCESS_TYPE_GMPLUGIN); 710 aResolve(true); 711 return IPC_OK(); 712 } 713 714 void GMPChild::GMPContentChildActorDestroy(GMPContentChild* aGMPContentChild) { 715 for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) { 716 RefPtr<GMPContentChild>& destroyedActor = mGMPContentChildren[i - 1]; 717 if (destroyedActor.get() == aGMPContentChild) { 718 SendPGMPContentChildDestroyed(); 719 mGMPContentChildren.RemoveElementAt(i - 1); 720 break; 721 } 722 } 723 } 724 725 mozilla::ipc::IPCResult GMPChild::RecvInitProfiler( 726 Endpoint<PProfilerChild>&& aEndpoint) { 727 mProfilerController = 728 mozilla::ChildProfilerController::Create(std::move(aEndpoint)); 729 return IPC_OK(); 730 } 731 732 mozilla::ipc::IPCResult GMPChild::RecvPreferenceUpdate(const Pref& aPref) { 733 Preferences::SetPreference(aPref); 734 return IPC_OK(); 735 } 736 737 mozilla::ipc::IPCResult GMPChild::RecvShutdown(ShutdownResolver&& aResolver) { 738 if (!mProfilerController) { 739 aResolver(""_ns); 740 return IPC_OK(); 741 } 742 743 const bool isProfiling = profiler_is_active(); 744 CrashReporter::RecordAnnotationCString( 745 CrashReporter::Annotation::ProfilerChildShutdownPhase, 746 isProfiling ? "Profiling - GrabShutdownProfileAndShutdown" 747 : "Not profiling - GrabShutdownProfileAndShutdown"); 748 ProfileAndAdditionalInformation shutdownProfileAndAdditionalInformation = 749 mProfilerController->GrabShutdownProfileAndShutdown(); 750 CrashReporter::RecordAnnotationCString( 751 CrashReporter::Annotation::ProfilerChildShutdownPhase, 752 isProfiling ? "Profiling - Destroying ChildProfilerController" 753 : "Not profiling - Destroying ChildProfilerController"); 754 mProfilerController = nullptr; 755 CrashReporter::RecordAnnotationCString( 756 CrashReporter::Annotation::ProfilerChildShutdownPhase, 757 isProfiling ? "Profiling - SendShutdownProfile (resovling)" 758 : "Not profiling - SendShutdownProfile (resolving)"); 759 if (const size_t len = shutdownProfileAndAdditionalInformation.SizeOf(); 760 len >= size_t(IPC::Channel::kMaximumMessageSize)) { 761 shutdownProfileAndAdditionalInformation.mProfile = 762 nsPrintfCString("*Profile from pid %u bigger (%zu) than IPC max (%zu)", 763 unsigned(profiler_current_process_id().ToNumber()), len, 764 size_t(IPC::Channel::kMaximumMessageSize)); 765 } 766 // Send the shutdown profile to the parent process through our own 767 // message channel, which we know will survive for long enough. 768 aResolver(shutdownProfileAndAdditionalInformation.mProfile); 769 CrashReporter::RecordAnnotationCString( 770 CrashReporter::Annotation::ProfilerChildShutdownPhase, 771 isProfiling ? "Profiling - SendShutdownProfile (resolved)" 772 : "Not profiling - SendShutdownProfile (resolved)"); 773 return IPC_OK(); 774 } 775 776 #if defined(XP_WIN) 777 mozilla::ipc::IPCResult GMPChild::RecvInitDllServices( 778 const bool& aCanRecordReleaseTelemetry, 779 const bool& aIsReadyForBackgroundProcessing) { 780 if (aCanRecordReleaseTelemetry) { 781 RefPtr<DllServices> dllSvc(DllServices::Get()); 782 dllSvc->StartUntrustedModulesProcessor(aIsReadyForBackgroundProcessing); 783 } 784 return IPC_OK(); 785 } 786 787 mozilla::ipc::IPCResult GMPChild::RecvGetUntrustedModulesData( 788 GetUntrustedModulesDataResolver&& aResolver) { 789 RefPtr<DllServices> dllSvc(DllServices::Get()); 790 dllSvc->GetUntrustedModulesData()->Then( 791 GetMainThreadSerialEventTarget(), __func__, 792 [aResolver](Maybe<UntrustedModulesData>&& aData) { 793 aResolver(std::move(aData)); 794 }, 795 [aResolver](nsresult aReason) { aResolver(Nothing()); }); 796 return IPC_OK(); 797 } 798 799 mozilla::ipc::IPCResult GMPChild::RecvUnblockUntrustedModulesThread() { 800 if (nsCOMPtr<nsIObserverService> obs = 801 mozilla::services::GetObserverService()) { 802 obs->NotifyObservers(nullptr, "unblock-untrusted-modules-thread", nullptr); 803 } 804 return IPC_OK(); 805 } 806 #endif // defined(XP_WIN) 807 808 } // namespace gmp 809 } // namespace mozilla 810 811 #undef GMP_CHILD_LOG_DEBUG 812 #undef __CLASS__