tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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__