tor-browser

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

GMPParent.cpp (49742B)


      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 "GMPParent.h"
      7 
      8 #include "CDMStorageIdProvider.h"
      9 #include "ChromiumCDMAdapter.h"
     10 #include "GMPContentParent.h"
     11 #include "GMPLog.h"
     12 #include "GMPTimerParent.h"
     13 #include "GeckoProfiler.h"
     14 #include "MediaResult.h"
     15 #include "mozIGeckoMediaPluginService.h"
     16 #include "mozilla/Casting.h"
     17 #include "mozilla/FOGIPC.h"
     18 #include "mozilla/dom/KeySystemNames.h"
     19 #include "mozilla/dom/WidevineCDMManifestBinding.h"
     20 #include "mozilla/ipc/CrashReporterHost.h"
     21 #include "mozilla/ipc/Endpoint.h"
     22 #include "mozilla/ipc/GeckoChildProcessHost.h"
     23 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
     24 #  include "mozilla/SandboxInfo.h"
     25 #  include "mozilla/ipc/SharedMemoryHandle.h"
     26 #endif
     27 #include "ProfilerParent.h"
     28 #include "mozilla/SSE.h"
     29 #include "mozilla/Services.h"
     30 #include "mozilla/StaticPrefs_media.h"
     31 #include "mozilla/SyncRunnable.h"
     32 #include "mozilla/Telemetry.h"
     33 #include "mozilla/glean/IpcMetrics.h"
     34 #include "nsComponentManagerUtils.h"
     35 #include "nsIObserverService.h"
     36 #include "nsIRunnable.h"
     37 #include "nsIWritablePropertyBag2.h"
     38 #include "nsPrintfCString.h"
     39 #include "nsThreadUtils.h"
     40 #include "runnable_utils.h"
     41 #ifdef XP_WIN
     42 #  include "PDMFactory.h"
     43 #  include "WMFDecoderModule.h"
     44 #  include "mozilla/FileUtilsWin.h"
     45 #  include "mozilla/WinDllServices.h"
     46 #endif
     47 #if defined(MOZ_WIDGET_ANDROID)
     48 #  include "mozilla/java/GeckoProcessManagerWrappers.h"
     49 #  include "mozilla/java/GeckoProcessTypeWrappers.h"
     50 #endif  // defined(MOZ_WIDGET_ANDROID)
     51 #if defined(XP_MACOSX)
     52 #  include "base/process_util.h"
     53 #  include "nsMacUtilsImpl.h"
     54 #endif  // defined(XP_MACOSX)
     55 
     56 using mozilla::ipc::GeckoChildProcessHost;
     57 
     58 using CrashReporter::AnnotationTable;
     59 
     60 namespace mozilla::gmp {
     61 
     62 #define GMP_PARENT_LOG_DEBUG(x, ...) \
     63  GMP_LOG_DEBUG("GMPParent[%p|childPid=%d] " x, this, mChildPid, ##__VA_ARGS__)
     64 
     65 #ifdef __CLASS__
     66 #  undef __CLASS__
     67 #endif
     68 #define __CLASS__ "GMPParent"
     69 
     70 GMPParent::GMPParent()
     71    : mState(GMPState::NotLoaded),
     72      mPluginId(GeckoChildProcessHost::GetUniqueID()),
     73      mProcess(nullptr),
     74      mDeleteProcessOnlyOnUnload(false),
     75      mAbnormalShutdownInProgress(false),
     76      mIsBlockingDeletion(false),
     77      mCanDecrypt(false),
     78      mGMPContentChildCount(0),
     79      mChildPid(0),
     80 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
     81      mChildLaunchArch(base::PROCESS_ARCH_INVALID),
     82 #endif
     83      mMainThread(GetMainThreadSerialEventTarget()) {
     84  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
     85  GMP_PARENT_LOG_DEBUG("GMPParent ctor id=%u", mPluginId);
     86 }
     87 
     88 GMPParent::~GMPParent() {
     89  // This method is not restricted to a specific thread.
     90  GMP_PARENT_LOG_DEBUG("GMPParent dtor id=%u", mPluginId);
     91  MOZ_ASSERT(!mProcess);
     92 }
     93 
     94 void GMPParent::CloneFrom(const GMPParent* aOther) {
     95  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
     96  MOZ_ASSERT(aOther->mService);
     97 
     98  mService = aOther->mService;
     99  mDirectory = aOther->mDirectory;
    100  mName = aOther->mName;
    101  mVersion = aOther->mVersion;
    102  mDescription = aOther->mDescription;
    103  mDisplayName = aOther->mDisplayName;
    104  mPluginType = aOther->mPluginType;
    105 #if defined(XP_WIN) || defined(XP_LINUX)
    106  mLibs = aOther->mLibs;
    107 #endif
    108  for (const GMPCapability& cap : aOther->mCapabilities) {
    109    mCapabilities.AppendElement(cap);
    110  }
    111  mAdapter = aOther->mAdapter;
    112 
    113 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
    114  mChildLaunchArch = aOther->mChildLaunchArch;
    115 #endif
    116 }
    117 
    118 #if defined(XP_WIN) || defined(XP_MACOSX)
    119 nsresult GMPParent::GetPluginFileArch(nsIFile* aPluginDir,
    120                                      const nsString& aBaseName,
    121                                      uint32_t& aArchSet) {
    122  // Build up the plugin filename
    123 #  if defined(XP_MACOSX)
    124  nsAutoString pluginFileName = u"lib"_ns + aBaseName + u".dylib"_ns;
    125 #  elif defined(XP_WIN)
    126  nsAutoString pluginFileName = aBaseName + u".dll"_ns;
    127 #  endif
    128  GMP_PARENT_LOG_DEBUG("%s: pluginFileName: %s", __FUNCTION__,
    129                       NS_LossyConvertUTF16toASCII(pluginFileName).get());
    130 
    131  // Create an nsIFile representing the plugin
    132  nsCOMPtr<nsIFile> pluginFile;
    133  nsresult rv = aPluginDir->Clone(getter_AddRefs(pluginFile));
    134  NS_ENSURE_SUCCESS(rv, rv);
    135  pluginFile->AppendRelativePath(pluginFileName);
    136 
    137 #  if defined(XP_MACOSX)
    138  // Get the full plugin path
    139  nsAutoCString pluginPath;
    140  rv = pluginFile->GetNativePath(pluginPath);
    141  NS_ENSURE_SUCCESS(rv, rv);
    142  GMP_PARENT_LOG_DEBUG("%s: pluginPath: %s", __FUNCTION__, pluginPath.get());
    143 
    144  rv = nsMacUtilsImpl::GetArchitecturesForBinary(pluginPath.get(), &aArchSet);
    145  NS_ENSURE_SUCCESS(rv, rv);
    146 
    147 #    if defined(__aarch64__)
    148  mPluginFilePath = pluginPath;
    149 #    endif
    150 #  elif defined(XP_WIN)
    151  // Get the full plugin path
    152  nsAutoString pluginPath;
    153  rv = pluginFile->GetTarget(pluginPath);
    154  NS_ENSURE_SUCCESS(rv, rv);
    155  GMP_PARENT_LOG_DEBUG("%s: pluginPath: %s", __FUNCTION__,
    156                       NS_LossyConvertUTF16toASCII(pluginPath).get());
    157 
    158  aArchSet = GetExecutableArchitecture(pluginPath.get());
    159  if (aArchSet == base::PROCESS_ARCH_INVALID) {
    160    return NS_ERROR_FAILURE;
    161  }
    162 #  endif
    163 
    164  return NS_OK;
    165 }
    166 #endif  // defined(XP_WIN) || defined(XP_MACOSX)
    167 
    168 #ifdef MOZ_WIDGET_ANDROID
    169 void GMPParent::InitForClearkey(GeckoMediaPluginServiceParent* aService) {
    170  MOZ_ASSERT(aService);
    171  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
    172 
    173  mService = aService;
    174  mName = u"clearkey"_ns;
    175  mDisplayName = "clearkey"_ns;
    176  mVersion = "0.1"_ns;
    177  mDescription = "ClearKey Gecko Media Plugin"_ns;
    178  mPluginType = GMPPluginType::Clearkey;
    179  mAdapter = u"chromium"_ns;
    180 
    181  mCapabilities.SetCapacity(1);
    182  auto& video = *mCapabilities.AppendElement();
    183  video.mAPIName = nsLiteralCString(CHROMIUM_CDM_API);
    184  video.mAPITags.SetCapacity(2);
    185  video.mAPITags.AppendElement(nsCString{kClearKeyKeySystemName});
    186  video.mAPITags.AppendElement(
    187      nsCString{kClearKeyWithProtectionQueryKeySystemName});
    188 }
    189 #endif
    190 
    191 RefPtr<GenericPromise> GMPParent::Init(GeckoMediaPluginServiceParent* aService,
    192                                       nsIFile* aPluginDir) {
    193  MOZ_ASSERT(aPluginDir);
    194  MOZ_ASSERT(aService);
    195  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
    196 
    197  mService = aService;
    198  mDirectory = aPluginDir;
    199 
    200  // aPluginDir is <profile-dir>/<gmp-plugin-id>/<version>
    201  // where <gmp-plugin-id> should be gmp-gmpopenh264
    202  nsCOMPtr<nsIFile> parent;
    203  nsresult rv = aPluginDir->GetParent(getter_AddRefs(parent));
    204  if (NS_WARN_IF(NS_FAILED(rv))) {
    205    return GenericPromise::CreateAndReject(rv, __func__);
    206  }
    207  nsAutoString parentLeafName;
    208  rv = parent->GetLeafName(parentLeafName);
    209  if (NS_WARN_IF(NS_FAILED(rv))) {
    210    return GenericPromise::CreateAndReject(rv, __func__);
    211  }
    212  GMP_PARENT_LOG_DEBUG("%s: for %s", __FUNCTION__,
    213                       NS_LossyConvertUTF16toASCII(parentLeafName).get());
    214 
    215  MOZ_ASSERT(parentLeafName.Length() > 4);
    216  mName = Substring(parentLeafName, 4);
    217 
    218 #if defined(XP_WIN) || defined(XP_MACOSX)
    219  uint32_t pluginArch = base::PROCESS_ARCH_INVALID;
    220  rv = GetPluginFileArch(
    221      aPluginDir,
    222 #  ifdef MOZ_WMF_CDM
    223      mName.Equals(u"widevinecdm-l1"_ns) ? u"Google.Widevine.CDM"_ns : mName,
    224 #  else
    225      mName,
    226 #  endif
    227      pluginArch);
    228  if (NS_FAILED(rv)) {
    229    GMP_PARENT_LOG_DEBUG("%s: Plugin arch error: %d", __FUNCTION__,
    230                         uint32_t(rv));
    231  } else {
    232    GMP_PARENT_LOG_DEBUG("%s: Plugin arch: 0x%x", __FUNCTION__, pluginArch);
    233  }
    234 
    235  const uint32_t x86 = base::PROCESS_ARCH_X86_64 | base::PROCESS_ARCH_I386;
    236 #  ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
    237  const uint32_t arm64 = base::PROCESS_ARCH_ARM_64;
    238 
    239  mChildLaunchArch = pluginArch;
    240  // When executing in an ARM64 process, if the library is x86 or x64,
    241  // set |mChildLaunchArch| to x64 and allow the library to be used as long
    242  // as this process is a universal binary.
    243  if (!(pluginArch & arm64) && (pluginArch & x86)) {
    244    bool isWidevine = parentLeafName.Find(u"widevine") != kNotFound;
    245    bool isWidevineAllowed =
    246        StaticPrefs::media_gmp_widevinecdm_allow_x64_plugin_on_arm64();
    247    bool isH264 = parentLeafName.Find(u"openh264") != kNotFound;
    248    bool isH264Allowed =
    249        StaticPrefs::media_gmp_gmpopenh264_allow_x64_plugin_on_arm64();
    250    bool isClearkey = parentLeafName.Find(u"clearkey") != kNotFound;
    251    bool isClearkeyAllowed =
    252        StaticPrefs::media_gmp_gmpclearkey_allow_x64_plugin_on_arm64();
    253 
    254    // Only allow x64 child GMP processes for Widevine, OpenH264 and Clearkey
    255    if (!isWidevine && !isH264 && !isClearkey) {
    256      return GenericPromise::CreateAndReject(NS_ERROR_NOT_IMPLEMENTED,
    257                                             __func__);
    258    }
    259    // And only if prefs permit it.
    260    if ((isWidevine && !isWidevineAllowed) || (isH264 && !isH264Allowed) ||
    261        (isClearkey && !isClearkeyAllowed)) {
    262      return GenericPromise::CreateAndReject(NS_ERROR_PLUGIN_DISABLED,
    263                                             __func__);
    264    }
    265 
    266 #    ifdef XP_MACOSX
    267    // We have an x64 library. Get the bundle architecture to determine
    268    // if we are a universal binary and hence if we can launch an x64
    269    // child process to host this plugin.
    270    uint32_t bundleArch = base::PROCESS_ARCH_INVALID;
    271    rv = nsMacUtilsImpl::GetArchitecturesForBundle(&bundleArch);
    272    if (NS_FAILED(rv)) {
    273      // If we fail here, continue as if this is not a univeral binary.
    274      GMP_PARENT_LOG_DEBUG("%s: Bundle arch error: %d", __FUNCTION__,
    275                           uint32_t(rv));
    276    } else {
    277      GMP_PARENT_LOG_DEBUG("%s: Bundle arch: 0x%x", __FUNCTION__, bundleArch);
    278    }
    279 
    280    bool isUniversalBinary = (bundleArch & base::PROCESS_ARCH_X86_64) &&
    281                             (bundleArch & base::PROCESS_ARCH_ARM_64);
    282    if (isUniversalBinary) {
    283      mChildLaunchArch = base::PROCESS_ARCH_X86_64;
    284      PreTranslateBins();
    285    } else {
    286      return GenericPromise::CreateAndReject(NS_ERROR_NOT_IMPLEMENTED,
    287                                             __func__);
    288    }
    289 #    endif
    290  }
    291 #  else
    292  // When executing in a non-ARM process, if the library is not x86 or x64,
    293  // remove it and return an error. This prevents a child process crash due
    294  // to loading an incompatible library and forces a new plugin version to be
    295  // downloaded when the check is next performed. This could occur if a profile
    296  // is moved from an ARM64 system to an x64 system.
    297  if ((pluginArch & x86) == 0) {
    298    GMP_PARENT_LOG_DEBUG("%s: Removing plugin directory", __FUNCTION__);
    299    aPluginDir->Remove(true);
    300    return GenericPromise::CreateAndReject(NS_ERROR_NOT_IMPLEMENTED, __func__);
    301  }
    302 #  endif  // defined(ALLOW_GECKO_CHILD_PROCESS_ARCH)
    303 #endif    // defined(XP_WIN) || defined(XP_MACOSX)
    304 
    305  return ReadGMPMetaData();
    306 }
    307 
    308 void GMPParent::Crash() {
    309  if (mState != GMPState::NotLoaded) {
    310    (void)SendCrashPluginNow();
    311  }
    312 }
    313 
    314 class NotifyGMPProcessLoadedTask : public Runnable {
    315 public:
    316  explicit NotifyGMPProcessLoadedTask(const ::base::ProcessId aProcessId,
    317                                      GMPParent* aGMPParent)
    318      : Runnable("NotifyGMPProcessLoadedTask"),
    319        mProcessId(aProcessId),
    320        mGMPParent(aGMPParent) {}
    321 
    322  NS_IMETHOD Run() override {
    323    MOZ_ASSERT(NS_IsMainThread());
    324 
    325    bool canProfile = true;
    326 
    327 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
    328    if (SandboxInfo::Get().Test(SandboxInfo::kEnabledForMedia) &&
    329        ipc::shared_memory::UsingPosixShm()) {
    330      canProfile = false;
    331    }
    332 #endif
    333 
    334    nsCOMPtr<nsISerialEventTarget> gmpEventTarget =
    335        mGMPParent->GMPEventTarget();
    336    if (NS_WARN_IF(!gmpEventTarget)) {
    337      return NS_ERROR_FAILURE;
    338    }
    339 
    340 #if defined(XP_WIN)
    341    RefPtr<DllServices> dllSvc(DllServices::Get());
    342    bool isReadyForBackgroundProcessing =
    343        dllSvc->IsReadyForBackgroundProcessing();
    344    gmpEventTarget->Dispatch(NewRunnableMethod<bool, bool>(
    345        "GMPParent::SendInitDllServices", mGMPParent,
    346        &GMPParent::SendInitDllServices, isReadyForBackgroundProcessing,
    347        Telemetry::CanRecordReleaseData()));
    348 #endif
    349 
    350    if (canProfile) {
    351      ipc::Endpoint<PProfilerChild> profilerParent(
    352          ProfilerParent::CreateForProcess(mProcessId));
    353 
    354      gmpEventTarget->Dispatch(
    355          NewRunnableMethod<ipc::Endpoint<mozilla::PProfilerChild>&&>(
    356              "GMPParent::SendInitProfiler", mGMPParent,
    357              &GMPParent::SendInitProfiler, std::move(profilerParent)));
    358    }
    359 
    360    return NS_OK;
    361  }
    362 
    363  ::base::ProcessId mProcessId;
    364  const RefPtr<GMPParent> mGMPParent;
    365 };
    366 
    367 nsresult GMPParent::LoadProcess() {
    368  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
    369  MOZ_ASSERT(mState == GMPState::NotLoaded);
    370 
    371  if (NS_WARN_IF(mPluginType == GMPPluginType::WidevineL1)) {
    372    GMP_PARENT_LOG_DEBUG("%s: cannot load process for WidevineL1",
    373                         __FUNCTION__);
    374    return NS_ERROR_NOT_IMPLEMENTED;
    375  }
    376 
    377  nsAutoString path;
    378 #ifdef MOZ_WIDGET_ANDROID
    379  // We need to bundle any CDMs with the APK, so we can just supply the library
    380  // name to the child process.
    381  path = mName;
    382 #else
    383  if (NS_WARN_IF(!mDirectory) ||
    384      NS_WARN_IF(NS_FAILED(mDirectory->GetPath(path)))) {
    385    return NS_ERROR_FAILURE;
    386  }
    387 #endif
    388  GMP_PARENT_LOG_DEBUG("%s: for %s", __FUNCTION__,
    389                       NS_ConvertUTF16toUTF8(path).get());
    390 
    391  if (!mProcess) {
    392    mProcess = new GMPProcessParent(NS_ConvertUTF16toUTF8(path).get());
    393 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
    394    mProcess->SetRequiresWindowServer(mAdapter.EqualsLiteral("chromium"));
    395 #endif
    396 
    397 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
    398    mProcess->SetLaunchArchitecture(mChildLaunchArch);
    399 #endif
    400 
    401    if (!mProcess->Launch(30 * 1000)) {
    402      GMP_PARENT_LOG_DEBUG("%s: Failed to launch new child process",
    403                           __FUNCTION__);
    404      mProcess->Delete();
    405      mProcess = nullptr;
    406      return NS_ERROR_FAILURE;
    407    }
    408 
    409    mChildPid = mProcess->GetChildProcessId();
    410    GMP_PARENT_LOG_DEBUG("%s: Launched new child process", __FUNCTION__);
    411 
    412    bool opened = mProcess->TakeInitialEndpoint().Bind(this);
    413    if (!opened) {
    414      GMP_PARENT_LOG_DEBUG("%s: Failed to open channel to new child process",
    415                           __FUNCTION__);
    416      mProcess->Delete();
    417      mProcess = nullptr;
    418      return NS_ERROR_FAILURE;
    419    }
    420    GMP_PARENT_LOG_DEBUG("%s: Opened channel to new child process",
    421                         __FUNCTION__);
    422 
    423    // ComputeStorageId may return empty string, we leave the error handling to
    424    // CDM. The CDM will reject the promise once we provide a empty string of
    425    // storage id.
    426    bool ok =
    427        SendProvideStorageId(CDMStorageIdProvider::ComputeStorageId(mNodeId));
    428    if (!ok) {
    429      GMP_PARENT_LOG_DEBUG("%s: Failed to send storage id to child process",
    430                           __FUNCTION__);
    431      return NS_ERROR_FAILURE;
    432    }
    433    GMP_PARENT_LOG_DEBUG("%s: Sent storage id to child process", __FUNCTION__);
    434 
    435 #if defined(XP_WIN) || defined(XP_LINUX)
    436    if (!mLibs.IsEmpty()) {
    437      bool ok = SendPreloadLibs(mLibs);
    438      if (!ok) {
    439        GMP_PARENT_LOG_DEBUG("%s: Failed to send preload-libs to child process",
    440                             __FUNCTION__);
    441        return NS_ERROR_FAILURE;
    442      }
    443      GMP_PARENT_LOG_DEBUG("%s: Sent preload-libs ('%s') to child process",
    444                           __FUNCTION__, mLibs.get());
    445    }
    446 #endif
    447 
    448    NS_DispatchToMainThread(new NotifyGMPProcessLoadedTask(OtherPid(), this));
    449 
    450    // Intr call to block initialization on plugin load.
    451    if (!SendStartPlugin(mAdapter)) {
    452      GMP_PARENT_LOG_DEBUG("%s: Failed to send start to child process",
    453                           __FUNCTION__);
    454      return NS_ERROR_FAILURE;
    455    }
    456    GMP_PARENT_LOG_DEBUG("%s: Sent StartPlugin to child process", __FUNCTION__);
    457  }
    458 
    459  mState = GMPState::Loaded;
    460 
    461  return NS_OK;
    462 }
    463 
    464 void GMPParent::OnPreferenceChange(const mozilla::dom::Pref& aPref) {
    465  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
    466  GMP_PARENT_LOG_DEBUG("%s", __FUNCTION__);
    467 
    468  if (!mProcess || !mProcess->UseXPCOM()) {
    469    return;
    470  }
    471 
    472  (void)SendPreferenceUpdate(aPref);
    473 }
    474 
    475 mozilla::ipc::IPCResult GMPParent::RecvPGMPContentChildDestroyed() {
    476  --mGMPContentChildCount;
    477  if (!IsUsed()) {
    478    CloseIfUnused();
    479  }
    480  return IPC_OK();
    481 }
    482 
    483 mozilla::ipc::IPCResult GMPParent::RecvFOGData(ByteBuf&& aBuf) {
    484  GMP_PARENT_LOG_DEBUG("GMPParent RecvFOGData");
    485  glean::FOGData(std::move(aBuf));
    486  return IPC_OK();
    487 }
    488 
    489 #if defined(XP_WIN)
    490 mozilla::ipc::IPCResult GMPParent::RecvGetModulesTrust(
    491    ModulePaths&& aModPaths, bool aRunAtNormalPriority,
    492    GetModulesTrustResolver&& aResolver) {
    493  class ModulesTrustRunnable final : public Runnable {
    494   public:
    495    ModulesTrustRunnable(ModulePaths&& aModPaths, bool aRunAtNormalPriority,
    496                         GetModulesTrustResolver&& aResolver)
    497        : Runnable("GMPParent::RecvGetModulesTrust::ModulesTrustRunnable"),
    498          mModPaths(std::move(aModPaths)),
    499          mResolver(std::move(aResolver)),
    500          mEventTarget(GetCurrentSerialEventTarget()),
    501          mRunAtNormalPriority(aRunAtNormalPriority) {}
    502 
    503    NS_IMETHOD Run() override {
    504      RefPtr<DllServices> dllSvc(DllServices::Get());
    505      dllSvc->GetModulesTrust(std::move(mModPaths), mRunAtNormalPriority)
    506          ->Then(
    507              mEventTarget, __func__,
    508              [self = RefPtr{this}](ModulesMapResult&& aResult) {
    509                self->mResolver(Some(ModulesMapResult(std::move(aResult))));
    510              },
    511              [self = RefPtr{this}](nsresult aRv) {
    512                self->mResolver(Nothing());
    513              });
    514      return NS_OK;
    515    }
    516 
    517   private:
    518    ~ModulesTrustRunnable() override = default;
    519 
    520    ModulePaths mModPaths;
    521    GetModulesTrustResolver mResolver;
    522    nsCOMPtr<nsISerialEventTarget> mEventTarget;
    523    bool mRunAtNormalPriority;
    524  };
    525 
    526  NS_DispatchToMainThread(MakeAndAddRef<ModulesTrustRunnable>(
    527      std::move(aModPaths), aRunAtNormalPriority, std::move(aResolver)));
    528  return IPC_OK();
    529 }
    530 #endif  // defined(XP_WIN)
    531 
    532 void GMPParent::CloseIfUnused() {
    533  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
    534  GMP_PARENT_LOG_DEBUG("%s", __FUNCTION__);
    535 
    536  if ((mDeleteProcessOnlyOnUnload || mState == GMPState::Loaded ||
    537       mState == GMPState::Unloading) &&
    538      !IsUsed()) {
    539    // Ensure all timers are killed.
    540    for (uint32_t i = mTimers.Length(); i > 0; i--) {
    541      mTimers[i - 1]->Shutdown();
    542    }
    543 
    544    // Shutdown GMPStorage. Given that all protocol actors must be shutdown
    545    // (!Used() is true), all storage operations should be complete.
    546    GMP_PARENT_LOG_DEBUG("%p shutdown storage (sz=%zu)", this,
    547                         mStorage.Length());
    548    for (size_t i = mStorage.Length(); i > 0; i--) {
    549      mStorage[i - 1]->Shutdown();
    550    }
    551    Shutdown();
    552  }
    553 }
    554 
    555 void GMPParent::CloseActive(bool aDieWhenUnloaded) {
    556  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
    557  GMP_PARENT_LOG_DEBUG("%s: state %u", __FUNCTION__,
    558                       uint32_t(GMPState(mState)));
    559 
    560  if (aDieWhenUnloaded) {
    561    mDeleteProcessOnlyOnUnload = true;  // don't allow this to go back...
    562  }
    563  if (mState == GMPState::Loaded) {
    564    mState = GMPState::Unloading;
    565  }
    566  if (mState != GMPState::NotLoaded && IsUsed()) {
    567    (void)SendCloseActive();
    568    CloseIfUnused();
    569  }
    570 }
    571 
    572 void GMPParent::MarkForDeletion() {
    573  mDeleteProcessOnlyOnUnload = true;
    574  mIsBlockingDeletion = true;
    575 }
    576 
    577 bool GMPParent::IsMarkedForDeletion() { return mIsBlockingDeletion; }
    578 
    579 void GMPParent::Shutdown() {
    580  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
    581  GMP_PARENT_LOG_DEBUG("%s", __FUNCTION__);
    582 
    583  if (mAbnormalShutdownInProgress) {
    584    return;
    585  }
    586 
    587  MOZ_ASSERT(!IsUsed());
    588  switch (mState) {
    589    case GMPState::NotLoaded:
    590    case GMPState::Closing:
    591    case GMPState::Closed:
    592      return;
    593    default:
    594      break;
    595  }
    596 
    597  RefPtr<GMPParent> self(this);
    598  DeleteProcess();
    599 
    600  // XXX Get rid of mDeleteProcessOnlyOnUnload and this code when
    601  // Bug 1043671 is fixed
    602  if (!mDeleteProcessOnlyOnUnload) {
    603    // Destroy ourselves and rise from the fire to save memory
    604    mService->ReAddOnGMPThread(self);
    605  }  // else we've been asked to die and stay dead
    606  MOZ_ASSERT(mState == GMPState::NotLoaded || mState == GMPState::Closing);
    607 }
    608 
    609 class NotifyGMPShutdownTask : public Runnable {
    610 public:
    611  explicit NotifyGMPShutdownTask(const nsAString& aNodeId)
    612      : Runnable("NotifyGMPShutdownTask"), mNodeId(aNodeId) {}
    613  NS_IMETHOD Run() override {
    614    MOZ_ASSERT(NS_IsMainThread());
    615    nsCOMPtr<nsIObserverService> obsService =
    616        mozilla::services::GetObserverService();
    617    MOZ_ASSERT(obsService);
    618    if (obsService) {
    619      obsService->NotifyObservers(nullptr, "gmp-shutdown", mNodeId.get());
    620    }
    621    return NS_OK;
    622  }
    623  nsString mNodeId;
    624 };
    625 
    626 void GMPParent::ChildTerminated() {
    627  RefPtr<GMPParent> self(this);
    628  nsCOMPtr<nsISerialEventTarget> gmpEventTarget = GMPEventTarget();
    629 
    630  if (!gmpEventTarget) {
    631    // Bug 1163239 - this can happen on shutdown.
    632    // PluginTerminated removes the GMP from the GMPService.
    633    // On shutdown we can have this case where it is already been
    634    // removed so there is no harm in not trying to remove it again.
    635    GMP_PARENT_LOG_DEBUG("%s::%s: GMPEventTarget() returned nullptr.",
    636                         __CLASS__, __FUNCTION__);
    637  } else {
    638    gmpEventTarget->Dispatch(
    639        NewRunnableMethod<RefPtr<GMPParent>>(
    640            "gmp::GeckoMediaPluginServiceParent::PluginTerminated", mService,
    641            &GeckoMediaPluginServiceParent::PluginTerminated, self),
    642        NS_DISPATCH_NORMAL);
    643  }
    644 }
    645 
    646 void GMPParent::DeleteProcess() {
    647  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
    648 
    649  switch (mState) {
    650    case GMPState::Closed:
    651      // Closing has finished, we can proceed to destroy the process.
    652      break;
    653    case GMPState::Closing:
    654      // Closing in progress, just waiting for the shutdown response.
    655      GMP_PARENT_LOG_DEBUG("%s: Shutdown handshake in progress.", __FUNCTION__);
    656      return;
    657    default: {
    658      // Don't Close() twice!
    659      // Probably remove when bug 1043671 is resolved
    660      GMP_PARENT_LOG_DEBUG("%s: Shutdown handshake starting.", __FUNCTION__);
    661 
    662      RefPtr<GMPParent> self = this;
    663      nsCOMPtr<nsISerialEventTarget> gmpEventTarget = GMPEventTarget();
    664      mState = GMPState::Closing;
    665      // Let's attempt to get the profile from the child process if we can
    666      // before we destroy it. This is particularly important for the GMP
    667      // process because we aggressively shut it down when not in active use, so
    668      // it is easy to miss the recordings during profiling.
    669      SendShutdown()->Then(
    670          gmpEventTarget, __func__,
    671          [self](nsCString&& aProfile) {
    672            GMP_LOG_DEBUG(
    673                "GMPParent[%p|childPid=%d] DeleteProcess: Shutdown handshake "
    674                "success, profileLen=%zu.",
    675                self.get(), self->mChildPid, aProfile.Length());
    676            if (!aProfile.IsEmpty()) {
    677              NS_DispatchToMainThread(NS_NewRunnableFunction(
    678                  "GMPParent::DeleteProcess",
    679                  [profile = std::move(aProfile)]() {
    680                    profiler_received_exit_profile(profile);
    681                  }));
    682            }
    683            self->mState = GMPState::Closed;
    684            self->Close();
    685            self->DeleteProcess();
    686          },
    687          [self](const ipc::ResponseRejectReason&) {
    688            // We crashed during shutdown, ActorDestroy will perform cleanup.
    689            GMP_LOG_DEBUG(
    690                "GMPParent[%p|childPid=%d] DeleteProcess: Shutdown handshake "
    691                "error.",
    692                self.get(), self->mChildPid);
    693          });
    694      return;
    695    }
    696  }
    697 
    698  GMP_PARENT_LOG_DEBUG("%s: Shutting down process.", __FUNCTION__);
    699  mProcess->Delete(NewRunnableMethod("gmp::GMPParent::ChildTerminated", this,
    700                                     &GMPParent::ChildTerminated));
    701  GMP_PARENT_LOG_DEBUG("%s: Shut down process", __FUNCTION__);
    702  mProcess = nullptr;
    703 
    704 #if defined(MOZ_WIDGET_ANDROID)
    705  if (mState != GMPState::NotLoaded) {
    706    nsCOMPtr<nsIEventTarget> launcherThread(ipc::GetIPCLauncher());
    707    MOZ_ASSERT(launcherThread);
    708 
    709    auto procType = java::GeckoProcessType::GMPLUGIN();
    710    auto selector =
    711        java::GeckoProcessManager::Selector::New(procType, OtherPid());
    712 
    713    launcherThread->Dispatch(NS_NewRunnableFunction(
    714        "GMPParent::DeleteProcess",
    715        [selector =
    716             java::GeckoProcessManager::Selector::GlobalRef(selector)]() {
    717          java::GeckoProcessManager::ShutdownProcess(selector);
    718        }));
    719  }
    720 #endif  // defined(MOZ_WIDGET_ANDROID)
    721 
    722  mState = GMPState::NotLoaded;
    723 
    724  nsCOMPtr<nsIRunnable> r =
    725      new NotifyGMPShutdownTask(NS_ConvertUTF8toUTF16(mNodeId));
    726  mMainThread->Dispatch(r.forget());
    727 }
    728 
    729 GMPState GMPParent::State() const { return mState; }
    730 
    731 nsCOMPtr<nsISerialEventTarget> GMPParent::GMPEventTarget() {
    732  nsCOMPtr<mozIGeckoMediaPluginService> mps =
    733      do_GetService("@mozilla.org/gecko-media-plugin-service;1");
    734  MOZ_ASSERT(mps);
    735  if (!mps) {
    736    return nullptr;
    737  }
    738  // Note: GeckoMediaPluginService::GetThread() is threadsafe, and returns
    739  // nullptr if the GeckoMediaPluginService has started shutdown.
    740  nsCOMPtr<nsIThread> gmpThread;
    741  mps->GetThread(getter_AddRefs(gmpThread));
    742  return gmpThread;
    743 }
    744 
    745 /* static */
    746 bool GMPCapability::Supports(const nsTArray<GMPCapability>& aCapabilities,
    747                             const nsACString& aAPI,
    748                             const nsTArray<nsCString>& aTags) {
    749  for (const nsCString& tag : aTags) {
    750    if (!GMPCapability::Supports(aCapabilities, aAPI, tag)) {
    751      return false;
    752    }
    753  }
    754  return true;
    755 }
    756 
    757 /* static */
    758 bool GMPCapability::Supports(const nsTArray<GMPCapability>& aCapabilities,
    759                             const nsACString& aAPI, const nsCString& aTag) {
    760  for (const GMPCapability& capabilities : aCapabilities) {
    761    if (!capabilities.mAPIName.Equals(aAPI)) {
    762      continue;
    763    }
    764    for (const nsCString& tag : capabilities.mAPITags) {
    765      if (tag.Equals(aTag)) {
    766 #ifdef XP_WIN
    767        // Clearkey on Windows advertises that it can decode in its GMP info
    768        // file, but uses Windows Media Foundation to decode. That's not present
    769        // on Windows XP, and on some Vista, Windows N, and KN variants without
    770        // certain services packs.
    771        if (tag.EqualsLiteral(kClearKeyKeySystemName)) {
    772          if (capabilities.mAPIName.EqualsLiteral(GMP_API_VIDEO_DECODER)) {
    773            auto pdmFactory = MakeRefPtr<PDMFactory>();
    774            if (pdmFactory->SupportsMimeType("video/avc"_ns).isEmpty()) {
    775              continue;
    776            }
    777          }
    778        }
    779 #endif
    780        return true;
    781      }
    782    }
    783  }
    784  return false;
    785 }
    786 
    787 bool GMPParent::EnsureProcessLoaded() {
    788  switch (mState) {
    789    case GMPState::NotLoaded:
    790      return NS_SUCCEEDED(LoadProcess());
    791    case GMPState::Loaded:
    792      return true;
    793    case GMPState::Unloading:
    794    case GMPState::Closing:
    795    case GMPState::Closed:
    796      return false;
    797  }
    798 
    799  MOZ_ASSERT_UNREACHABLE("Unhandled GMPState!");
    800  return false;
    801 }
    802 
    803 void GMPParent::AddCrashAnnotations() {
    804  if (mCrashReporter) {
    805    mCrashReporter->AddAnnotationBool(CrashReporter::Annotation::GMPPlugin,
    806                                      true);
    807    mCrashReporter->AddAnnotationNSCString(
    808        CrashReporter::Annotation::PluginFilename,
    809        NS_ConvertUTF16toUTF8(mName));
    810    mCrashReporter->AddAnnotationNSCString(
    811        CrashReporter::Annotation::PluginName, mDisplayName);
    812    mCrashReporter->AddAnnotationNSCString(
    813        CrashReporter::Annotation::PluginVersion, mVersion);
    814  }
    815 }
    816 
    817 void GMPParent::GetCrashID(nsString& aResult) {
    818  AddCrashAnnotations();
    819  GenerateCrashReport(&aResult);
    820 }
    821 
    822 static void GMPNotifyObservers(const uint32_t aPluginID,
    823                               const nsACString& aPluginName,
    824                               const nsAString& aPluginDumpID) {
    825  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
    826  nsCOMPtr<nsIWritablePropertyBag2> propbag =
    827      do_CreateInstance("@mozilla.org/hash-property-bag;1");
    828  if (obs && propbag) {
    829    propbag->SetPropertyAsUint32(u"pluginID"_ns, aPluginID);
    830    propbag->SetPropertyAsACString(u"pluginName"_ns, aPluginName);
    831    propbag->SetPropertyAsAString(u"pluginDumpID"_ns, aPluginDumpID);
    832    obs->NotifyObservers(propbag, "gmp-plugin-crash", nullptr);
    833  }
    834 
    835  RefPtr<gmp::GeckoMediaPluginService> service =
    836      gmp::GeckoMediaPluginService::GetGeckoMediaPluginService();
    837  if (service) {
    838    service->RunPluginCrashCallbacks(aPluginID, aPluginName);
    839  }
    840 }
    841 
    842 void GMPParent::ActorDestroy(ActorDestroyReason aWhy) {
    843  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
    844  GMP_PARENT_LOG_DEBUG("%s: (%d), state=%u", __FUNCTION__, (int)aWhy,
    845                       uint32_t(GMPState(mState)));
    846 
    847  if (AbnormalShutdown == aWhy) {
    848    glean::subprocess::abnormal_abort.Get("gmplugin"_ns).Add(1);
    849    nsString dumpID;
    850    GetCrashID(dumpID);
    851    if (dumpID.IsEmpty()) {
    852      NS_WARNING("GMP crash without crash report");
    853      dumpID = mName;
    854      dumpID += '-';
    855      AppendUTF8toUTF16(mVersion, dumpID);
    856    }
    857 
    858    // NotifyObservers is mainthread-only
    859    nsCOMPtr<nsIRunnable> r =
    860        WrapRunnableNM(&GMPNotifyObservers, mPluginId, mDisplayName, dumpID);
    861    mMainThread->Dispatch(r.forget());
    862  }
    863 
    864  // warn us off trying to close again
    865  mState = GMPState::Closed;
    866  mAbnormalShutdownInProgress = true;
    867  CloseActive(false);
    868 
    869  // Normal Shutdown() will delete the process on unwind. GMPProcessParent
    870  // blocks shutdown to avoid races.
    871  if (AbnormalShutdown == aWhy) {
    872    RefPtr<GMPParent> self(this);
    873    // Must not call Close() again in DeleteProcess(), as we'll recurse
    874    // infinitely if we do.
    875    MOZ_ASSERT(mState == GMPState::Closed);
    876    DeleteProcess();
    877    // Note: final destruction will be Dispatched to ourself
    878    mService->ReAddOnGMPThread(self);
    879  }
    880 }
    881 
    882 PGMPStorageParent* GMPParent::AllocPGMPStorageParent() {
    883  GMPStorageParent* p = new GMPStorageParent(mNodeId, this);
    884  mStorage.AppendElement(p);  // Addrefs, released in DeallocPGMPStorageParent.
    885  return p;
    886 }
    887 
    888 bool GMPParent::DeallocPGMPStorageParent(PGMPStorageParent* aActor) {
    889  GMPStorageParent* p = static_cast<GMPStorageParent*>(aActor);
    890  p->Shutdown();
    891  mStorage.RemoveElement(p);
    892  return true;
    893 }
    894 
    895 mozilla::ipc::IPCResult GMPParent::RecvPGMPStorageConstructor(
    896    PGMPStorageParent* aActor) {
    897  GMPStorageParent* p = (GMPStorageParent*)aActor;
    898  if (NS_FAILED(p->Init())) {
    899    // TODO: Verify if this is really a good reason to IPC_FAIL.
    900    // There might be shutdown edge cases here.
    901    return IPC_FAIL(this,
    902                    "GMPParent::RecvPGMPStorageConstructor: p->Init() failed.");
    903  }
    904  return IPC_OK();
    905 }
    906 
    907 mozilla::ipc::IPCResult GMPParent::RecvPGMPTimerConstructor(
    908    PGMPTimerParent* actor) {
    909  return IPC_OK();
    910 }
    911 
    912 PGMPTimerParent* GMPParent::AllocPGMPTimerParent() {
    913  nsCOMPtr<nsISerialEventTarget> target = GMPEventTarget();
    914  GMPTimerParent* p = new GMPTimerParent(target);
    915  mTimers.AppendElement(
    916      p);  // Released in DeallocPGMPTimerParent, or on shutdown.
    917  return p;
    918 }
    919 
    920 bool GMPParent::DeallocPGMPTimerParent(PGMPTimerParent* aActor) {
    921  GMPTimerParent* p = static_cast<GMPTimerParent*>(aActor);
    922  p->Shutdown();
    923  mTimers.RemoveElement(p);
    924  return true;
    925 }
    926 
    927 bool ReadInfoField(GMPInfoFileParser& aParser, const nsCString& aKey,
    928                   nsACString& aOutValue) {
    929  if (!aParser.Contains(aKey) || aParser.Get(aKey).IsEmpty()) {
    930    return false;
    931  }
    932  aOutValue = aParser.Get(aKey);
    933  return true;
    934 }
    935 
    936 RefPtr<GenericPromise> GMPParent::ReadGMPMetaData() {
    937  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
    938  MOZ_ASSERT(mDirectory, "Plugin directory cannot be NULL!");
    939  MOZ_ASSERT(!mName.IsEmpty(), "Plugin mName cannot be empty!");
    940 
    941  nsCOMPtr<nsIFile> infoFile;
    942  nsresult rv = mDirectory->Clone(getter_AddRefs(infoFile));
    943  if (NS_WARN_IF(NS_FAILED(rv))) {
    944    return GenericPromise::CreateAndReject(rv, __func__);
    945  }
    946  infoFile->AppendRelativePath(mName + u".info"_ns);
    947 
    948  if (FileExists(infoFile)) {
    949    return ReadGMPInfoFile(infoFile);
    950  }
    951 
    952  // Maybe this is the Widevine adapted plugin?
    953  nsCOMPtr<nsIFile> manifestFile;
    954  rv = mDirectory->Clone(getter_AddRefs(manifestFile));
    955  if (NS_WARN_IF(NS_FAILED(rv))) {
    956    return GenericPromise::CreateAndReject(rv, __func__);
    957  }
    958  manifestFile->AppendRelativePath(u"manifest.json"_ns);
    959  return ReadChromiumManifestFile(manifestFile);
    960 }
    961 
    962 #if defined(XP_LINUX)
    963 static void ApplyGlibcWorkaround(nsCString& aLibs) {
    964  // These glibc libraries were merged into libc.so.6 as of glibc
    965  // 2.34; they now exist only as stub libraries for compatibility and
    966  // newly linked code won't depend on them, so we need to ensure
    967  // they're loaded for plugins that may have been linked against a
    968  // different version of glibc.  (See also bug 1725828.)
    969  if (!aLibs.IsEmpty()) {
    970    aLibs.AppendLiteral(", ");
    971  }
    972  aLibs.AppendLiteral("libdl.so.2, libpthread.so.0, librt.so.1");
    973 }
    974 #endif
    975 
    976 #if defined(XP_WIN)
    977 static void ApplyOleaut32(nsCString& aLibs) {
    978  // In the libwebrtc update in bug 1766646 an include of comdef.h for using
    979  // _bstr_t was introduced. This resulted in a dependency on comsupp.lib which
    980  // contains a `_variant_t vtMissing` that would get cleared in an exit
    981  // handler. VariantClear is defined in oleaut32.dll, and so we'd try to load
    982  // oleaut32.dll on exit but get denied by the sandbox.
    983  // Note that we had includes of comdef.h before bug 1766646 but it is the use
    984  // of _bstr_t that triggers the vtMissing exit handler.
    985  // See bug 1788592 for details.
    986  if (!aLibs.IsEmpty()) {
    987    aLibs.AppendLiteral(", ");
    988  }
    989  aLibs.AppendLiteral("oleaut32.dll");
    990 }
    991 #endif
    992 
    993 static constexpr uint64_t MakeVersion(uint16_t aA, uint16_t aB, uint16_t aC,
    994                                      uint16_t aD) {
    995  return (static_cast<uint64_t>(aA) << 48) | (static_cast<uint64_t>(aB) << 32) |
    996         (static_cast<uint64_t>(aC) << 16) | aD;
    997 }
    998 
    999 static nsresult ParseVersion(const nsACString& aVersion,
   1000                             uint64_t* aParsedVersion) {
   1001  MOZ_ASSERT(aParsedVersion);
   1002 
   1003  uint64_t version = 0;
   1004  uint32_t fragmentCount = 0;
   1005  nsresult rv = NS_OK;
   1006 
   1007  for (const auto& fragment : aVersion.Split('.')) {
   1008    ++fragmentCount;
   1009    if (NS_WARN_IF(fragmentCount >= 5)) {
   1010      return NS_ERROR_FAILURE;
   1011    }
   1012 
   1013    uint32_t fragmentInt = fragment.ToUnsignedInteger(&rv, /* aRadix */ 10);
   1014    if (NS_WARN_IF(NS_FAILED(rv))) {
   1015      return rv;
   1016    }
   1017 
   1018    version = (version << 16) | SaturatingCast<uint16_t>(fragmentInt);
   1019  }
   1020 
   1021  *aParsedVersion = version << (4 - fragmentCount) * 16;
   1022  return NS_OK;
   1023 }
   1024 
   1025 RefPtr<GenericPromise> GMPParent::ReadGMPInfoFile(nsIFile* aFile) {
   1026  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
   1027  GMPInfoFileParser parser;
   1028  if (!parser.Init(aFile)) {
   1029    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   1030  }
   1031 
   1032  nsAutoCString apis;
   1033  if (!ReadInfoField(parser, "name"_ns, mDisplayName) ||
   1034      !ReadInfoField(parser, "description"_ns, mDescription) ||
   1035      !ReadInfoField(parser, "version"_ns, mVersion) ||
   1036      !ReadInfoField(parser, "apis"_ns, apis)) {
   1037    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   1038  }
   1039 
   1040 #if defined(XP_WIN) || defined(XP_LINUX)
   1041  // "Libraries" field is optional.
   1042  ReadInfoField(parser, "libraries"_ns, mLibs);
   1043 #endif
   1044 
   1045  UpdatePluginType();
   1046 
   1047  // We check the version for OpenH264 because we may need to add additional API
   1048  // tags to indicate we support more advanced modes for newer versions of the
   1049  // plugin.
   1050  bool addMozSupportsH264Advanced = false;
   1051  bool addMozSupportsH264TemporalSVC = false;
   1052  if (mPluginType == GMPPluginType::OpenH264) {
   1053    uint64_t parsedVersion = 0;
   1054    nsresult rv = ParseVersion(mVersion, &parsedVersion);
   1055    if (NS_WARN_IF(NS_FAILED(rv))) {
   1056      return GenericPromise::CreateAndReject(rv, __func__);
   1057    }
   1058 
   1059    // Earlier versions only supported decoding/encoding constrained baseline.
   1060    addMozSupportsH264Advanced = parsedVersion >= MakeVersion(2, 3, 2, 0);
   1061 
   1062    // Earlier versions did not expose the encoded SVC temporal layer ID.
   1063    addMozSupportsH264TemporalSVC = parsedVersion > MakeVersion(2, 5, 0, 0);
   1064  }
   1065 
   1066 #ifdef XP_LINUX
   1067  // The glibc workaround (see above) isn't needed for clearkey
   1068  // because it's built along with the browser.
   1069  if (mPluginType != GMPPluginType::Clearkey) {
   1070    ApplyGlibcWorkaround(mLibs);
   1071  }
   1072 #endif
   1073 
   1074 #ifdef XP_WIN
   1075  ApplyOleaut32(mLibs);
   1076 #endif
   1077 
   1078  nsTArray<nsCString> apiTokens;
   1079  SplitAt(", ", apis, apiTokens);
   1080  for (nsCString api : apiTokens) {
   1081    int32_t tagsStart = api.FindChar('[');
   1082    if (tagsStart == 0) {
   1083      // Not allowed to be the first character.
   1084      // API name must be at least one character.
   1085      continue;
   1086    }
   1087 
   1088    GMPCapability cap;
   1089    if (tagsStart == -1) {
   1090      // No tags.
   1091      cap.mAPIName.Assign(api);
   1092    } else {
   1093      auto tagsEnd = api.FindChar(']');
   1094      if (tagsEnd == -1 || tagsEnd < tagsStart) {
   1095        // Invalid syntax, skip whole capability.
   1096        continue;
   1097      }
   1098 
   1099      cap.mAPIName.Assign(Substring(api, 0, tagsStart));
   1100 
   1101      if ((tagsEnd - tagsStart) > 1) {
   1102        const nsDependentCSubstring ts(
   1103            Substring(api, tagsStart + 1, tagsEnd - tagsStart - 1));
   1104        nsTArray<nsCString> tagTokens;
   1105        SplitAt(":", ts, tagTokens);
   1106        for (nsCString tag : tagTokens) {
   1107          cap.mAPITags.AppendElement(tag);
   1108        }
   1109      }
   1110    }
   1111 
   1112    if (mPluginType == GMPPluginType::OpenH264) {
   1113      if (addMozSupportsH264Advanced &&
   1114          !cap.mAPITags.Contains("moz-h264-advanced"_ns)) {
   1115        cap.mAPITags.AppendElement("moz-h264-advanced"_ns);
   1116      }
   1117      if (addMozSupportsH264TemporalSVC &&
   1118          !cap.mAPITags.Contains("moz-h264-temporal-svc"_ns)) {
   1119        cap.mAPITags.AppendElement("moz-h264-temporal-svc"_ns);
   1120      }
   1121    }
   1122 
   1123    mCapabilities.AppendElement(std::move(cap));
   1124  }
   1125 
   1126  if (mCapabilities.IsEmpty()) {
   1127    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   1128  }
   1129 
   1130  return GenericPromise::CreateAndResolve(true, __func__);
   1131 }
   1132 
   1133 RefPtr<GenericPromise> GMPParent::ReadChromiumManifestFile(nsIFile* aFile) {
   1134  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
   1135  nsAutoCString json;
   1136  if (!ReadIntoString(aFile, json, 5 * 1024)) {
   1137    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   1138  }
   1139 
   1140  // DOM JSON parsing needs to run on the main thread.
   1141  return InvokeAsync(mMainThread, this, __func__,
   1142                     &GMPParent::ParseChromiumManifest,
   1143                     NS_ConvertUTF8toUTF16(json));
   1144 }
   1145 
   1146 static bool IsCDMAPISupported(
   1147    const mozilla::dom::WidevineCDMManifest& aManifest) {
   1148  if (!aManifest.mX_cdm_module_versions.WasPassed() ||
   1149      !aManifest.mX_cdm_interface_versions.WasPassed() ||
   1150      !aManifest.mX_cdm_host_versions.WasPassed()) {
   1151    return false;
   1152  }
   1153 
   1154  nsresult ignored;  // Note: ToInteger returns 0 on failure.
   1155  int32_t moduleVersion =
   1156      aManifest.mX_cdm_module_versions.Value().ToInteger(&ignored);
   1157  int32_t interfaceVersion =
   1158      aManifest.mX_cdm_interface_versions.Value().ToInteger(&ignored);
   1159  int32_t hostVersion =
   1160      aManifest.mX_cdm_host_versions.Value().ToInteger(&ignored);
   1161  return ChromiumCDMAdapter::Supports(moduleVersion, interfaceVersion,
   1162                                      hostVersion);
   1163 }
   1164 
   1165 RefPtr<GenericPromise> GMPParent::ParseChromiumManifest(
   1166    const nsAString& aJSON) {
   1167  GMP_PARENT_LOG_DEBUG("%s: for '%s'", __FUNCTION__,
   1168                       NS_LossyConvertUTF16toASCII(aJSON).get());
   1169 
   1170  MOZ_ASSERT(NS_IsMainThread());
   1171  mozilla::dom::WidevineCDMManifest m;
   1172  if (!m.Init(aJSON)) {
   1173    GMP_PARENT_LOG_DEBUG("%s: Failed to initialize json parser, failing.",
   1174                         __FUNCTION__);
   1175    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   1176  }
   1177 
   1178  CopyUTF16toUTF8(m.mName, mDisplayName);
   1179  CopyUTF16toUTF8(m.mVersion, mVersion);
   1180 
   1181  if (m.mDescription.WasPassed()) {
   1182    CopyUTF16toUTF8(m.mDescription.Value(), mDescription);
   1183  }
   1184 
   1185 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
   1186  if (!mozilla::SandboxInfo::Get().CanSandboxMedia()) {
   1187    nsPrintfCString msg(
   1188        "GMPParent::ParseChromiumManifest: Plugin \"%s\" is an EME CDM"
   1189        " but this system can't sandbox it; not loading.",
   1190        mDisplayName.get());
   1191    printf_stderr("%s\n", msg.get());
   1192    GMP_PARENT_LOG_DEBUG("%s", msg.get());
   1193    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   1194  }
   1195 #endif
   1196 
   1197  UpdatePluginType();
   1198 
   1199  GMPCapability video;
   1200 
   1201  if (IsCDMAPISupported(m)) {
   1202    video.mAPIName = nsLiteralCString(CHROMIUM_CDM_API);
   1203    mAdapter = u"chromium"_ns;
   1204 #ifdef MOZ_WMF_CDM
   1205  } else if (mPluginType == GMPPluginType::WidevineL1) {
   1206    video.mAPIName = nsCString(kWidevineExperimentAPIName);
   1207    mAdapter = NS_ConvertUTF8toUTF16(kWidevineExperimentAPIName);
   1208 #endif
   1209  } else {
   1210    GMP_PARENT_LOG_DEBUG("%s: CDM API not supported, failing.", __FUNCTION__);
   1211    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   1212  }
   1213 
   1214  // We hard code a few of the settings because they can't be stored in the
   1215  // widevine manifest without making our API different to widevine's.
   1216  switch (mPluginType) {
   1217    case GMPPluginType::Clearkey:
   1218      video.mAPITags.AppendElement(nsCString{kClearKeyKeySystemName});
   1219      video.mAPITags.AppendElement(
   1220          nsCString{kClearKeyWithProtectionQueryKeySystemName});
   1221 #if XP_WIN
   1222      mLibs = nsLiteralCString(
   1223          "dxva2.dll, evr.dll, freebl3.dll, mfh264dec.dll, mfplat.dll, "
   1224          "msmpeg2vdec.dll, nss3.dll, softokn3.dll");
   1225 #elif XP_LINUX
   1226      mLibs = "libfreeblpriv3.so, libsoftokn3.so"_ns;
   1227 #endif
   1228      break;
   1229    case GMPPluginType::Widevine:
   1230      video.mAPITags.AppendElement(nsCString{kWidevineKeySystemName});
   1231 #if XP_WIN
   1232      // psapi.dll added for GetMappedFileNameW, which could possibly be avoided
   1233      // in future versions, see bug 1383611 for details.
   1234      mLibs = "dxva2.dll, ole32.dll, psapi.dll, shell32.dll, winmm.dll"_ns;
   1235 #endif
   1236      break;
   1237 #ifdef MOZ_WMF_CDM
   1238    case GMPPluginType::WidevineL1:
   1239      video.mAPITags.AppendElement(nsCString{kWidevineExperimentKeySystemName});
   1240      video.mAPITags.AppendElement(
   1241          nsCString{kWidevineExperiment2KeySystemName});
   1242      break;
   1243 #endif
   1244    case GMPPluginType::Fake:
   1245      // The fake CDM just exposes a key system with id "fake".
   1246      video.mAPITags.AppendElement(nsCString{"fake"});
   1247 #if XP_WIN
   1248      mLibs = "dxva2.dll, ole32.dll"_ns;
   1249 #endif
   1250      break;
   1251    default:
   1252      GMP_PARENT_LOG_DEBUG("%s: Unrecognized key system: %s, failing.",
   1253                           __FUNCTION__, mDisplayName.get());
   1254      return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   1255  }
   1256 
   1257 #ifdef XP_LINUX
   1258  ApplyGlibcWorkaround(mLibs);
   1259 #endif
   1260 
   1261 #ifdef XP_WIN
   1262  ApplyOleaut32(mLibs);
   1263 #endif
   1264 
   1265  nsTArray<nsCString> codecs;
   1266 
   1267  if (m.mX_cdm_codecs.WasPassed()) {
   1268    nsCString codecsString;
   1269    codecsString = NS_ConvertUTF16toUTF8(m.mX_cdm_codecs.Value());
   1270    SplitAt(",", codecsString, codecs);
   1271  }
   1272 
   1273  // Parse the codec strings in the manifest and map them to strings used
   1274  // internally by Gecko for capability recognition.
   1275  //
   1276  // Google's code to parse manifests can be used as a reference for strings
   1277  // the manifest may contain
   1278  // https://source.chromium.org/chromium/chromium/src/+/master:components/cdm/common/cdm_manifest.cc;l=74;drc=775880ced8a989191281e93854c7f2201f25068f
   1279  //
   1280  // Gecko's internal strings can be found at
   1281  // https://searchfox.org/mozilla-central/rev/ea63a0888d406fae720cf24f4727d87569a8cab5/dom/media/eme/MediaKeySystemAccess.cpp#149-155
   1282  for (const nsCString& chromiumCodec : codecs) {
   1283    nsCString codec;
   1284    if (chromiumCodec.EqualsASCII("vp8")) {
   1285      codec = "vp8"_ns;
   1286    } else if (chromiumCodec.EqualsASCII("vp9.0") ||  // Legacy string.
   1287               chromiumCodec.EqualsASCII("vp09")) {
   1288      codec = "vp9"_ns;
   1289    } else if (chromiumCodec.EqualsASCII("avc1")) {
   1290      codec = "h264"_ns;
   1291    } else if (chromiumCodec.EqualsASCII("av01")) {
   1292      codec = "av1"_ns;
   1293    } else {
   1294      GMP_PARENT_LOG_DEBUG("%s: Unrecognized codec: %s.", __FUNCTION__,
   1295                           chromiumCodec.get());
   1296      MOZ_ASSERT_UNREACHABLE(
   1297          "Unhandled codec string! Need to add it to the parser.");
   1298      continue;
   1299    }
   1300 
   1301    video.mAPITags.AppendElement(codec);
   1302  }
   1303 
   1304  mCapabilities.AppendElement(std::move(video));
   1305 
   1306  GMP_PARENT_LOG_DEBUG("%s: Successfully parsed manifest.", __FUNCTION__);
   1307  return GenericPromise::CreateAndResolve(true, __func__);
   1308 }
   1309 
   1310 bool GMPParent::CanBeSharedCrossNodeIds() const {
   1311  return mNodeId.IsEmpty() &&
   1312         // XXX bug 1159300 hack -- maybe remove after openh264 1.4
   1313         // We don't want to use CDM decoders for non-encrypted playback
   1314         // just yet; especially not for WebRTC. Don't allow CDMs to be used
   1315         // without a node ID.
   1316         !mCanDecrypt;
   1317 }
   1318 
   1319 bool GMPParent::CanBeUsedFrom(const nsACString& aNodeId) const {
   1320  return mNodeId == aNodeId;
   1321 }
   1322 
   1323 void GMPParent::SetNodeId(const nsACString& aNodeId) {
   1324  MOZ_ASSERT(!aNodeId.IsEmpty());
   1325  mNodeId = aNodeId;
   1326 }
   1327 
   1328 void GMPParent::UpdatePluginType() {
   1329  if (mDisplayName.EqualsLiteral("WidevineCdm")) {
   1330    mPluginType = GMPPluginType::Widevine;
   1331 #ifdef MOZ_WMF_CDM
   1332  } else if (mDisplayName.EqualsLiteral(kWidevineExperimentAPIName)) {
   1333    mPluginType = GMPPluginType::WidevineL1;
   1334 #endif
   1335  } else if (mDisplayName.EqualsLiteral("gmpopenh264")) {
   1336    mPluginType = GMPPluginType::OpenH264;
   1337  } else if (mDisplayName.EqualsLiteral("clearkey")) {
   1338    mPluginType = GMPPluginType::Clearkey;
   1339  } else if (mDisplayName.EqualsLiteral("fake")) {
   1340    mPluginType = GMPPluginType::Fake;
   1341  } else {
   1342    mPluginType = GMPPluginType::Unknown;
   1343  }
   1344 }
   1345 
   1346 const nsCString& GMPParent::GetDisplayName() const { return mDisplayName; }
   1347 
   1348 const nsCString& GMPParent::GetVersion() const { return mVersion; }
   1349 
   1350 uint32_t GMPParent::GetPluginId() const { return mPluginId; }
   1351 
   1352 void GMPParent::ResolveGetContentParentPromises() {
   1353  nsTArray<UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>>> promises =
   1354      std::move(mGetContentParentPromises);
   1355  MOZ_ASSERT(mGetContentParentPromises.IsEmpty());
   1356  RefPtr<GMPContentParentCloseBlocker> blocker(
   1357      new GMPContentParentCloseBlocker(mGMPContentParent));
   1358  for (auto& holder : promises) {
   1359    holder->Resolve(blocker, __func__);
   1360  }
   1361 }
   1362 
   1363 bool GMPParent::OpenPGMPContent() {
   1364  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
   1365  MOZ_ASSERT(!mGMPContentParent);
   1366 
   1367  Endpoint<PGMPContentParent> parent;
   1368  Endpoint<PGMPContentChild> child;
   1369  if (NS_WARN_IF(NS_FAILED(PGMPContent::CreateEndpoints(
   1370          mozilla::ipc::EndpointProcInfo::Current(), OtherEndpointProcInfo(),
   1371          &parent, &child)))) {
   1372    return false;
   1373  }
   1374 
   1375  mGMPContentParent = new GMPContentParent(this);
   1376 
   1377  if (!parent.Bind(mGMPContentParent)) {
   1378    return false;
   1379  }
   1380 
   1381  if (!SendInitGMPContentChild(std::move(child))) {
   1382    return false;
   1383  }
   1384 
   1385  ResolveGetContentParentPromises();
   1386 
   1387  return true;
   1388 }
   1389 
   1390 void GMPParent::RejectGetContentParentPromises() {
   1391  nsTArray<UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>>> promises =
   1392      std::move(mGetContentParentPromises);
   1393  MOZ_ASSERT(mGetContentParentPromises.IsEmpty());
   1394  for (auto& holder : promises) {
   1395    holder->Reject(NS_ERROR_FAILURE, __func__);
   1396  }
   1397 }
   1398 
   1399 void GMPParent::GetGMPContentParent(
   1400    UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>>&& aPromiseHolder) {
   1401  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
   1402  GMP_PARENT_LOG_DEBUG("%s %p", __FUNCTION__, this);
   1403 
   1404  if (mGMPContentParent) {
   1405    RefPtr<GMPContentParentCloseBlocker> blocker(
   1406        new GMPContentParentCloseBlocker(mGMPContentParent));
   1407    aPromiseHolder->Resolve(blocker, __func__);
   1408  } else {
   1409    mGetContentParentPromises.AppendElement(std::move(aPromiseHolder));
   1410    // If we don't have a GMPContentParent and we try to get one for the first
   1411    // time (mGetContentParentPromises.Length() == 1) then call
   1412    // PGMPContent::Open. If more calls to GetGMPContentParent happen before
   1413    // mGMPContentParent has been set then we should just store them, so that
   1414    // they get called when we set mGMPContentParent as a result of the
   1415    // PGMPContent::Open call.
   1416    if (mGetContentParentPromises.Length() == 1) {
   1417      if (!EnsureProcessLoaded() || !OpenPGMPContent()) {
   1418        RejectGetContentParentPromises();
   1419        return;
   1420      }
   1421      // We want to increment this as soon as possible, to avoid that we'd try
   1422      // to shut down the GMP process while we're still trying to get a
   1423      // PGMPContentParent actor.
   1424      ++mGMPContentChildCount;
   1425    }
   1426  }
   1427 }
   1428 
   1429 already_AddRefed<GMPContentParent> GMPParent::ForgetGMPContentParent() {
   1430  MOZ_ASSERT(mGetContentParentPromises.IsEmpty());
   1431  return mGMPContentParent.forget();
   1432 }
   1433 
   1434 bool GMPParent::EnsureProcessLoaded(base::ProcessId* aID) {
   1435  if (!EnsureProcessLoaded()) {
   1436    return false;
   1437  }
   1438  *aID = OtherPid();
   1439  return true;
   1440 }
   1441 
   1442 void GMPParent::IncrementGMPContentChildCount() { ++mGMPContentChildCount; }
   1443 
   1444 nsString GMPParent::GetPluginBaseName() const { return u"gmp-"_ns + mName; }
   1445 
   1446 #if defined(XP_MACOSX) && defined(__aarch64__)
   1447 void GMPParent::PreTranslateBins() {
   1448  nsCOMPtr<nsIRunnable> event = mozilla::NewRunnableMethod(
   1449      "RosettaTranslation", this, &GMPParent::PreTranslateBinsWorker);
   1450 
   1451  DebugOnly<nsresult> rv =
   1452      NS_DispatchBackgroundTask(event.forget(), NS_DISPATCH_EVENT_MAY_BLOCK);
   1453 
   1454  MOZ_ASSERT(NS_SUCCEEDED(rv));
   1455 }
   1456 
   1457 void GMPParent::PreTranslateBinsWorker() {
   1458  int rv = nsMacUtilsImpl::PreTranslateXUL();
   1459  GMP_PARENT_LOG_DEBUG("%s: XUL translation result: %d", __FUNCTION__, rv);
   1460 
   1461  rv = nsMacUtilsImpl::PreTranslateBinary(mPluginFilePath);
   1462  GMP_PARENT_LOG_DEBUG("%s: %s translation result: %d", __FUNCTION__,
   1463                       mPluginFilePath.get(), rv);
   1464 }
   1465 #endif
   1466 
   1467 }  // namespace mozilla::gmp
   1468 
   1469 #undef GMP_PARENT_LOG_DEBUG
   1470 #undef __CLASS__