summaryrefslogtreecommitdiffstats
path: root/dom/media/gmp/GMPChild.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /dom/media/gmp/GMPChild.cpp
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/media/gmp/GMPChild.cpp')
-rw-r--r--dom/media/gmp/GMPChild.cpp726
1 files changed, 726 insertions, 0 deletions
diff --git a/dom/media/gmp/GMPChild.cpp b/dom/media/gmp/GMPChild.cpp
new file mode 100644
index 0000000000..47f98ae7c1
--- /dev/null
+++ b/dom/media/gmp/GMPChild.cpp
@@ -0,0 +1,726 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GMPChild.h"
+
+#include "base/command_line.h"
+#include "base/task.h"
+#include "ChildProfilerController.h"
+#include "ChromiumCDMAdapter.h"
+#ifdef XP_LINUX
+# include "dlfcn.h"
+#endif
+#include "gmp-video-decode.h"
+#include "gmp-video-encode.h"
+#include "GMPContentChild.h"
+#include "GMPLoader.h"
+#include "GMPLog.h"
+#include "GMPPlatform.h"
+#include "GMPProcessChild.h"
+#include "GMPProcessParent.h"
+#include "GMPUtils.h"
+#include "GMPVideoDecoderChild.h"
+#include "GMPVideoEncoderChild.h"
+#include "GMPVideoHost.h"
+#include "mozilla/Algorithm.h"
+#include "mozilla/FOGIPC.h"
+#include "mozilla/glean/GleanMetrics.h"
+#include "mozilla/ipc/CrashReporterClient.h"
+#include "mozilla/ipc/Endpoint.h"
+#include "mozilla/ipc/ProcessChild.h"
+#include "mozilla/TextUtils.h"
+#include "nsDebugImpl.h"
+#include "nsExceptionHandler.h"
+#include "nsIFile.h"
+#include "nsReadableUtils.h"
+#include "nsThreadManager.h"
+#include "nsXULAppAPI.h"
+#include "nsIXULRuntime.h"
+#include "prio.h"
+#ifdef XP_WIN
+# include <stdlib.h> // for _exit()
+# include "WinUtils.h"
+#else
+# include <unistd.h> // for _exit()
+#endif
+
+using namespace mozilla::ipc;
+
+namespace mozilla {
+
+#define GMP_CHILD_LOG_DEBUG(x, ...) \
+ GMP_LOG_DEBUG("GMPChild[pid=%d] " x, (int)base::GetCurrentProcId(), \
+ ##__VA_ARGS__)
+
+namespace gmp {
+
+GMPChild::GMPChild()
+ : mGMPMessageLoop(MessageLoop::current()), mGMPLoader(nullptr) {
+ GMP_CHILD_LOG_DEBUG("GMPChild ctor");
+ nsDebugImpl::SetMultiprocessMode("GMP");
+}
+
+GMPChild::~GMPChild() {
+ GMP_CHILD_LOG_DEBUG("GMPChild dtor");
+#ifdef XP_LINUX
+ for (auto& libHandle : mLibHandles) {
+ dlclose(libHandle);
+ }
+#endif
+}
+
+static bool GetFileBase(const nsAString& aPluginPath,
+ nsCOMPtr<nsIFile>& aLibDirectory,
+ nsCOMPtr<nsIFile>& aFileBase, nsAutoString& aBaseName) {
+ nsresult rv = NS_NewLocalFile(aPluginPath, true, getter_AddRefs(aFileBase));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return false;
+ }
+
+ if (NS_WARN_IF(NS_FAILED(aFileBase->Clone(getter_AddRefs(aLibDirectory))))) {
+ return false;
+ }
+
+ nsCOMPtr<nsIFile> parent;
+ rv = aFileBase->GetParent(getter_AddRefs(parent));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return false;
+ }
+
+ nsAutoString parentLeafName;
+ rv = parent->GetLeafName(parentLeafName);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return false;
+ }
+
+ aBaseName = Substring(parentLeafName, 4, parentLeafName.Length() - 1);
+ return true;
+}
+
+static bool GetPluginFile(const nsAString& aPluginPath,
+ nsCOMPtr<nsIFile>& aLibDirectory,
+ nsCOMPtr<nsIFile>& aLibFile) {
+ nsAutoString baseName;
+ GetFileBase(aPluginPath, aLibDirectory, aLibFile, baseName);
+
+#if defined(XP_MACOSX)
+ nsAutoString binaryName = u"lib"_ns + baseName + u".dylib"_ns;
+#elif defined(OS_POSIX)
+ nsAutoString binaryName = u"lib"_ns + baseName + u".so"_ns;
+#elif defined(XP_WIN)
+ nsAutoString binaryName = baseName + u".dll"_ns;
+#else
+# error not defined
+#endif
+ aLibFile->AppendRelativePath(binaryName);
+ return true;
+}
+
+static bool GetPluginFile(const nsAString& aPluginPath,
+ nsCOMPtr<nsIFile>& aLibFile) {
+ nsCOMPtr<nsIFile> unusedlibDir;
+ return GetPluginFile(aPluginPath, unusedlibDir, aLibFile);
+}
+
+#if defined(XP_MACOSX)
+static nsCString GetNativeTarget(nsIFile* aFile) {
+ bool isLink;
+ nsCString path;
+ aFile->IsSymlink(&isLink);
+ if (isLink) {
+ aFile->GetNativeTarget(path);
+ } else {
+ aFile->GetNativePath(path);
+ }
+ return path;
+}
+
+# if defined(MOZ_SANDBOX)
+static bool GetPluginPaths(const nsAString& aPluginPath,
+ nsCString& aPluginDirectoryPath,
+ nsCString& aPluginFilePath) {
+ nsCOMPtr<nsIFile> libDirectory, libFile;
+ if (!GetPluginFile(aPluginPath, libDirectory, libFile)) {
+ return false;
+ }
+
+ // Mac sandbox rules expect paths to actual files and directories -- not
+ // soft links.
+ libDirectory->Normalize();
+ aPluginDirectoryPath = GetNativeTarget(libDirectory);
+
+ libFile->Normalize();
+ aPluginFilePath = GetNativeTarget(libFile);
+
+ return true;
+}
+# endif // MOZ_SANDBOX
+#endif // XP_MACOSX
+
+bool GMPChild::Init(const nsAString& aPluginPath,
+ mozilla::ipc::UntypedEndpoint&& aEndpoint) {
+ GMP_CHILD_LOG_DEBUG("%s pluginPath=%s", __FUNCTION__,
+ NS_ConvertUTF16toUTF8(aPluginPath).get());
+
+ // GMPChild needs nsThreadManager to create the ProfilerChild thread.
+ // It is also used on debug builds for the sandbox tests.
+ if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) {
+ return false;
+ }
+
+ if (NS_WARN_IF(!aEndpoint.Bind(this))) {
+ return false;
+ }
+
+ CrashReporterClient::InitSingleton(this);
+
+ mPluginPath = aPluginPath;
+
+ return true;
+}
+
+mozilla::ipc::IPCResult GMPChild::RecvProvideStorageId(
+ const nsCString& aStorageId) {
+ GMP_CHILD_LOG_DEBUG("%s", __FUNCTION__);
+ mStorageId = aStorageId;
+ return IPC_OK();
+}
+
+GMPErr GMPChild::GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI,
+ const nsACString& aKeySystem) {
+ if (!mGMPLoader) {
+ return GMPGenericErr;
+ }
+ return mGMPLoader->GetAPI(aAPIName, aHostAPI, aPluginAPI, aKeySystem);
+}
+
+mozilla::ipc::IPCResult GMPChild::RecvPreloadLibs(const nsCString& aLibs) {
+ // Pre-load libraries that may need to be used by the EME plugin but that
+ // can't be loaded after the sandbox has started.
+#ifdef XP_WIN
+ // Items in this must be lowercase!
+ constexpr static const char16_t* whitelist[] = {
+ u"dxva2.dll", // Get monitor information
+ u"evr.dll", // MFGetStrideForBitmapInfoHeader
+ u"freebl3.dll", // NSS for clearkey CDM
+ u"mfplat.dll", // MFCreateSample, MFCreateAlignedMemoryBuffer,
+ // MFCreateMediaType
+ u"msmpeg2vdec.dll", // H.264 decoder
+ u"nss3.dll", // NSS for clearkey CDM
+ u"ole32.dll", // required for OPM
+ u"oleaut32.dll", // For _bstr_t use in libwebrtc, see bug 1788592
+ u"psapi.dll", // For GetMappedFileNameW, see bug 1383611
+ u"softokn3.dll", // NSS for clearkey CDM
+ u"winmm.dll", // Dependency for widevine
+ };
+ constexpr static bool (*IsASCII)(const char16_t*) =
+ IsAsciiNullTerminated<char16_t>;
+ static_assert(AllOf(std::begin(whitelist), std::end(whitelist), IsASCII),
+ "Items in the whitelist must not contain non-ASCII "
+ "characters!");
+
+ nsTArray<nsCString> libs;
+ SplitAt(", ", aLibs, libs);
+ for (nsCString lib : libs) {
+ ToLowerCase(lib);
+ for (const char16_t* whiteListedLib : whitelist) {
+ if (nsDependentString(whiteListedLib)
+ .EqualsASCII(lib.Data(), lib.Length())) {
+ LoadLibraryW(char16ptr_t(whiteListedLib));
+ break;
+ }
+ }
+ }
+#elif defined(XP_LINUX)
+ constexpr static const char* whitelist[] = {
+ // NSS libraries used by clearkey.
+ "libfreeblpriv3.so",
+ "libsoftokn3.so",
+ // glibc libraries merged into libc.so.6; see bug 1725828 and
+ // the corresponding code in GMPParent.cpp.
+ "libdl.so.2",
+ "libpthread.so.0",
+ "librt.so.1",
+ };
+
+ nsTArray<nsCString> libs;
+ SplitAt(", ", aLibs, libs);
+ for (const nsCString& lib : libs) {
+ for (const char* whiteListedLib : whitelist) {
+ if (lib.EqualsASCII(whiteListedLib)) {
+ auto libHandle = dlopen(whiteListedLib, RTLD_NOW | RTLD_GLOBAL);
+ if (libHandle) {
+ mLibHandles.AppendElement(libHandle);
+ } else {
+ // TODO(bug 1698718): remove the logging once we've identified
+ // the cause of the load failure.
+ const char* error = dlerror();
+ if (error) {
+ // We should always have an error, but gracefully handle just in
+ // case.
+ nsAutoCString nsError{error};
+ CrashReporter::AppendAppNotesToCrashReport(nsError);
+ }
+ // End bug 1698718 logging.
+
+ MOZ_CRASH("Couldn't load lib needed by media plugin");
+ }
+ }
+ }
+ }
+#endif
+ return IPC_OK();
+}
+
+static bool ResolveLinks(nsCOMPtr<nsIFile>& aPath) {
+#if defined(XP_WIN)
+ return widget::WinUtils::ResolveJunctionPointsAndSymLinks(aPath);
+#elif defined(XP_MACOSX)
+ nsCString targetPath = GetNativeTarget(aPath);
+ nsCOMPtr<nsIFile> newFile;
+ if (NS_WARN_IF(NS_FAILED(
+ NS_NewNativeLocalFile(targetPath, true, getter_AddRefs(newFile))))) {
+ return false;
+ }
+ aPath = newFile;
+ return true;
+#else
+ return true;
+#endif
+}
+
+bool GMPChild::GetUTF8LibPath(nsACString& aOutLibPath) {
+#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+ nsAutoCString pluginDirectoryPath, pluginFilePath;
+ if (!GetPluginPaths(mPluginPath, pluginDirectoryPath, pluginFilePath)) {
+ MOZ_CRASH("Error scanning plugin path");
+ }
+ aOutLibPath.Assign(pluginFilePath);
+ return true;
+#else
+ nsCOMPtr<nsIFile> libFile;
+ if (!GetPluginFile(mPluginPath, libFile)) {
+ return false;
+ }
+
+ if (!FileExists(libFile)) {
+ NS_WARNING("Can't find GMP library file!");
+ return false;
+ }
+
+ nsAutoString path;
+ libFile->GetPath(path);
+ CopyUTF16toUTF8(path, aOutLibPath);
+
+ return true;
+#endif
+}
+
+static nsCOMPtr<nsIFile> AppendFile(nsCOMPtr<nsIFile>&& aFile,
+ const nsString& aStr) {
+ return (aFile && NS_SUCCEEDED(aFile->Append(aStr))) ? aFile : nullptr;
+}
+
+static nsCOMPtr<nsIFile> CloneFile(const nsCOMPtr<nsIFile>& aFile) {
+ nsCOMPtr<nsIFile> clone;
+ return (aFile && NS_SUCCEEDED(aFile->Clone(getter_AddRefs(clone)))) ? clone
+ : nullptr;
+}
+
+static nsCOMPtr<nsIFile> GetParentFile(const nsCOMPtr<nsIFile>& aFile) {
+ nsCOMPtr<nsIFile> parent;
+ return (aFile && NS_SUCCEEDED(aFile->GetParent(getter_AddRefs(parent))))
+ ? parent
+ : nullptr;
+}
+
+#if defined(XP_WIN)
+static bool IsFileLeafEqualToASCII(const nsCOMPtr<nsIFile>& aFile,
+ const char* aStr) {
+ nsAutoString leafName;
+ return aFile && NS_SUCCEEDED(aFile->GetLeafName(leafName)) &&
+ leafName.EqualsASCII(aStr);
+}
+#endif
+
+#if defined(XP_WIN)
+# define FIREFOX_FILE u"firefox.exe"_ns
+# define XUL_LIB_FILE u"xul.dll"_ns
+#elif defined(XP_MACOSX)
+# define FIREFOX_FILE u"firefox"_ns
+# define XUL_LIB_FILE u"XUL"_ns
+#else
+# define FIREFOX_FILE u"firefox"_ns
+# define XUL_LIB_FILE u"libxul.so"_ns
+#endif
+
+static nsCOMPtr<nsIFile> GetFirefoxAppPath(
+ nsCOMPtr<nsIFile> aPluginContainerPath) {
+ MOZ_ASSERT(aPluginContainerPath);
+#if defined(XP_MACOSX)
+ // On MacOS the firefox binary is a few parent directories up from
+ // plugin-container.
+ // aPluginContainerPath will end with something like:
+ // xxxx/NightlyDebug.app/Contents/MacOS/plugin-container.app/Contents/MacOS/plugin-container
+ nsCOMPtr<nsIFile> path = aPluginContainerPath;
+ for (int i = 0; i < 4; i++) {
+ path = GetParentFile(path);
+ }
+ return path;
+#else
+ nsCOMPtr<nsIFile> parent = GetParentFile(aPluginContainerPath);
+# if XP_WIN
+ if (IsFileLeafEqualToASCII(parent, "i686")) {
+ // We must be on Windows on ARM64, where the plugin-container path will
+ // be in the 'i686' subdir. The firefox.exe is in the parent directory.
+ parent = GetParentFile(parent);
+ }
+# endif
+ return parent;
+#endif
+}
+
+#if defined(XP_MACOSX)
+static bool GetSigPath(const int aRelativeLayers,
+ const nsString& aTargetSigFileName,
+ nsCOMPtr<nsIFile> aExecutablePath,
+ nsCOMPtr<nsIFile>& aOutSigPath) {
+ // The sig file will be located in
+ // xxxx/NightlyDebug.app/Contents/Resources/XUL.sig
+ // xxxx/NightlyDebug.app/Contents/Resources/firefox.sig
+ // xxxx/NightlyDebug.app/Contents/MacOS/plugin-container.app/Contents/Resources/plugin-container.sig
+ // On MacOS the sig file is a few parent directories up from
+ // its executable file.
+ // Start to search the path from the path of the executable file we provided.
+ MOZ_ASSERT(aExecutablePath);
+ nsCOMPtr<nsIFile> path = aExecutablePath;
+ for (int i = 0; i < aRelativeLayers; i++) {
+ nsCOMPtr<nsIFile> parent;
+ if (NS_WARN_IF(NS_FAILED(path->GetParent(getter_AddRefs(parent))))) {
+ return false;
+ }
+ path = parent;
+ }
+ MOZ_ASSERT(path);
+ aOutSigPath = path;
+ return NS_SUCCEEDED(path->Append(u"Resources"_ns)) &&
+ NS_SUCCEEDED(path->Append(aTargetSigFileName));
+}
+#endif
+
+static bool AppendHostPath(nsCOMPtr<nsIFile>& aFile,
+ nsTArray<std::pair<nsCString, nsCString>>& aPaths) {
+ nsString str;
+ if (!FileExists(aFile) || !ResolveLinks(aFile) ||
+ NS_FAILED(aFile->GetPath(str))) {
+ return false;
+ }
+
+ nsCString filePath = NS_ConvertUTF16toUTF8(str);
+ nsCString sigFilePath;
+#if defined(XP_MACOSX)
+ nsAutoString binary;
+ if (NS_FAILED(aFile->GetLeafName(binary))) {
+ return false;
+ }
+ binary.Append(u".sig"_ns);
+ nsCOMPtr<nsIFile> sigFile;
+ if (GetSigPath(2, binary, aFile, sigFile) &&
+ NS_SUCCEEDED(sigFile->GetPath(str))) {
+ CopyUTF16toUTF8(str, sigFilePath);
+ } else {
+ // Cannot successfully get the sig file path.
+ // Assume it is located at the same place as plugin-container
+ // alternatively.
+ sigFilePath = nsCString(NS_ConvertUTF16toUTF8(str) + ".sig"_ns);
+ }
+#else
+ sigFilePath = nsCString(NS_ConvertUTF16toUTF8(str) + ".sig"_ns);
+#endif
+ aPaths.AppendElement(
+ std::make_pair(std::move(filePath), std::move(sigFilePath)));
+ return true;
+}
+
+nsTArray<std::pair<nsCString, nsCString>>
+GMPChild::MakeCDMHostVerificationPaths() {
+ // Record the file path and its sig file path.
+ nsTArray<std::pair<nsCString, nsCString>> paths;
+ // Plugin binary path.
+ nsCOMPtr<nsIFile> path;
+ nsString str;
+ if (GetPluginFile(mPluginPath, path) && FileExists(path) &&
+ ResolveLinks(path) && NS_SUCCEEDED(path->GetPath(str))) {
+ paths.AppendElement(
+ std::make_pair(nsCString(NS_ConvertUTF16toUTF8(str)),
+ nsCString(NS_ConvertUTF16toUTF8(str) + ".sig"_ns)));
+ }
+
+ // Plugin-container binary path.
+ // Note: clang won't let us initialize an nsString from a wstring, so we
+ // need to go through UTF8 to get to an nsString.
+ const std::string pluginContainer =
+ WideToUTF8(CommandLine::ForCurrentProcess()->program());
+ path = nullptr;
+ CopyUTF8toUTF16(nsDependentCString(pluginContainer.c_str()), str);
+ if (NS_FAILED(NS_NewLocalFile(str, true, /* aFollowLinks */
+ getter_AddRefs(path))) ||
+ !AppendHostPath(path, paths)) {
+ // Without successfully determining plugin-container's path, we can't
+ // determine libxul's or Firefox's. So give up.
+ return paths;
+ }
+
+#if defined(XP_WIN)
+ // On Windows on ARM64, we should also append the x86 plugin-container's
+ // xul.dll.
+ const bool isWindowsOnARM64 =
+ IsFileLeafEqualToASCII(GetParentFile(path), "i686");
+ if (isWindowsOnARM64) {
+ nsCOMPtr<nsIFile> x86XulPath =
+ AppendFile(GetParentFile(path), XUL_LIB_FILE);
+ if (!AppendHostPath(x86XulPath, paths)) {
+ return paths;
+ }
+ }
+#endif
+
+ // Firefox application binary path.
+ nsCOMPtr<nsIFile> appDir = GetFirefoxAppPath(path);
+ path = AppendFile(CloneFile(appDir), FIREFOX_FILE);
+ if (!AppendHostPath(path, paths)) {
+ return paths;
+ }
+
+ // Libxul path. Note: re-using 'appDir' var here, as we assume libxul is in
+ // the same directory as Firefox executable.
+ appDir->GetPath(str);
+ path = AppendFile(CloneFile(appDir), XUL_LIB_FILE);
+ if (!AppendHostPath(path, paths)) {
+ return paths;
+ }
+
+ return paths;
+}
+
+static auto ToCString(const nsTArray<std::pair<nsCString, nsCString>>& aPairs) {
+ return StringJoin(","_ns, aPairs, [](nsACString& dest, const auto& p) {
+ dest.AppendPrintf("(%s,%s)", p.first.get(), p.second.get());
+ });
+}
+
+mozilla::ipc::IPCResult GMPChild::RecvStartPlugin(const nsString& aAdapter) {
+ GMP_CHILD_LOG_DEBUG("%s", __FUNCTION__);
+
+ nsCString libPath;
+ if (!GetUTF8LibPath(libPath)) {
+ CrashReporter::AnnotateCrashReport(
+ CrashReporter::Annotation::GMPLibraryPath,
+ NS_ConvertUTF16toUTF8(mPluginPath));
+
+#ifdef XP_WIN
+ return IPC_FAIL(this,
+ nsPrintfCString("Failed to get lib path with error(%lu).",
+ GetLastError())
+ .get());
+#else
+ return IPC_FAIL(this, "Failed to get lib path.");
+#endif
+ }
+
+ auto platformAPI = new GMPPlatformAPI();
+ InitPlatformAPI(*platformAPI, this);
+
+ mGMPLoader = MakeUnique<GMPLoader>();
+#if defined(MOZ_SANDBOX) && !defined(XP_MACOSX)
+ if (!mGMPLoader->CanSandbox()) {
+ GMP_CHILD_LOG_DEBUG("%s Can't sandbox GMP, failing", __FUNCTION__);
+ delete platformAPI;
+ return IPC_FAIL(this, "Can't sandbox GMP.");
+ }
+#endif
+
+ GMPAdapter* adapter = nullptr;
+ if (aAdapter.EqualsLiteral("chromium")) {
+ auto&& paths = MakeCDMHostVerificationPaths();
+ GMP_CHILD_LOG_DEBUG("%s CDM host paths=%s", __func__,
+ ToCString(paths).get());
+ adapter = new ChromiumCDMAdapter(std::move(paths));
+ }
+
+ if (!mGMPLoader->Load(libPath.get(), libPath.Length(), platformAPI,
+ adapter)) {
+ NS_WARNING("Failed to load GMP");
+ delete platformAPI;
+ CrashReporter::AnnotateCrashReport(
+ CrashReporter::Annotation::GMPLibraryPath,
+ NS_ConvertUTF16toUTF8(mPluginPath));
+
+#ifdef XP_WIN
+ return IPC_FAIL(this, nsPrintfCString("Failed to load GMP with error(%lu).",
+ GetLastError())
+ .get());
+#else
+ return IPC_FAIL(this, "Failed to load GMP.");
+#endif
+ }
+
+ return IPC_OK();
+}
+
+MessageLoop* GMPChild::GMPMessageLoop() { return mGMPMessageLoop; }
+
+void GMPChild::ActorDestroy(ActorDestroyReason aWhy) {
+ GMP_CHILD_LOG_DEBUG("%s reason=%d", __FUNCTION__, aWhy);
+
+ for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) {
+ MOZ_ASSERT_IF(aWhy == NormalShutdown,
+ !mGMPContentChildren[i - 1]->IsUsed());
+ mGMPContentChildren[i - 1]->Close();
+ }
+
+ if (mGMPLoader) {
+ mGMPLoader->Shutdown();
+ }
+ if (AbnormalShutdown == aWhy) {
+ NS_WARNING("Abnormal shutdown of GMP process!");
+ ProcessChild::QuickExit();
+ }
+
+ // Send the last bits of Glean data over to the main process.
+ glean::FlushFOGData(
+ [](ByteBuf&& aBuf) { glean::SendFOGData(std::move(aBuf)); });
+
+ if (mProfilerController) {
+ mProfilerController->Shutdown();
+ mProfilerController = nullptr;
+ }
+
+ CrashReporterClient::DestroySingleton();
+
+ XRE_ShutdownChildProcess();
+}
+
+void GMPChild::ProcessingError(Result aCode, const char* aReason) {
+ switch (aCode) {
+ case MsgDropped:
+ _exit(0); // Don't trigger a crash report.
+ case MsgNotKnown:
+ MOZ_CRASH("aborting because of MsgNotKnown");
+ case MsgNotAllowed:
+ MOZ_CRASH("aborting because of MsgNotAllowed");
+ case MsgPayloadError:
+ MOZ_CRASH("aborting because of MsgPayloadError");
+ case MsgProcessingError:
+ MOZ_CRASH("aborting because of MsgProcessingError");
+ case MsgRouteError:
+ MOZ_CRASH("aborting because of MsgRouteError");
+ case MsgValueError:
+ MOZ_CRASH("aborting because of MsgValueError");
+ default:
+ MOZ_CRASH("not reached");
+ }
+}
+
+PGMPTimerChild* GMPChild::AllocPGMPTimerChild() {
+ return new GMPTimerChild(this);
+}
+
+bool GMPChild::DeallocPGMPTimerChild(PGMPTimerChild* aActor) {
+ MOZ_ASSERT(mTimerChild == static_cast<GMPTimerChild*>(aActor));
+ mTimerChild = nullptr;
+ return true;
+}
+
+GMPTimerChild* GMPChild::GetGMPTimers() {
+ if (!mTimerChild) {
+ PGMPTimerChild* sc = SendPGMPTimerConstructor();
+ if (!sc) {
+ return nullptr;
+ }
+ mTimerChild = static_cast<GMPTimerChild*>(sc);
+ }
+ return mTimerChild;
+}
+
+PGMPStorageChild* GMPChild::AllocPGMPStorageChild() {
+ return new GMPStorageChild(this);
+}
+
+bool GMPChild::DeallocPGMPStorageChild(PGMPStorageChild* aActor) {
+ mStorage = nullptr;
+ return true;
+}
+
+GMPStorageChild* GMPChild::GetGMPStorage() {
+ if (!mStorage) {
+ PGMPStorageChild* sc = SendPGMPStorageConstructor();
+ if (!sc) {
+ return nullptr;
+ }
+ mStorage = static_cast<GMPStorageChild*>(sc);
+ }
+ return mStorage;
+}
+
+mozilla::ipc::IPCResult GMPChild::RecvCrashPluginNow() {
+ MOZ_CRASH();
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult GMPChild::RecvCloseActive() {
+ for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) {
+ mGMPContentChildren[i - 1]->CloseActive();
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult GMPChild::RecvInitGMPContentChild(
+ Endpoint<PGMPContentChild>&& aEndpoint) {
+ GMPContentChild* child =
+ mGMPContentChildren.AppendElement(new GMPContentChild(this))->get();
+ aEndpoint.Bind(child);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult GMPChild::RecvFlushFOGData(
+ FlushFOGDataResolver&& aResolver) {
+ GMP_CHILD_LOG_DEBUG("GMPChild RecvFlushFOGData");
+ glean::FlushFOGData(std::move(aResolver));
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult GMPChild::RecvTestTriggerMetrics(
+ TestTriggerMetricsResolver&& aResolve) {
+ GMP_CHILD_LOG_DEBUG("GMPChild RecvTestTriggerMetrics");
+ mozilla::glean::test_only_ipc::a_counter.Add(
+ nsIXULRuntime::PROCESS_TYPE_GMPLUGIN);
+ aResolve(true);
+ return IPC_OK();
+}
+
+void GMPChild::GMPContentChildActorDestroy(GMPContentChild* aGMPContentChild) {
+ for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) {
+ RefPtr<GMPContentChild>& destroyedActor = mGMPContentChildren[i - 1];
+ if (destroyedActor.get() == aGMPContentChild) {
+ SendPGMPContentChildDestroyed();
+ mGMPContentChildren.RemoveElementAt(i - 1);
+ break;
+ }
+ }
+}
+
+mozilla::ipc::IPCResult GMPChild::RecvInitProfiler(
+ Endpoint<PProfilerChild>&& aEndpoint) {
+ mProfilerController =
+ mozilla::ChildProfilerController::Create(std::move(aEndpoint));
+ return IPC_OK();
+}
+
+} // namespace gmp
+} // namespace mozilla
+
+#undef GMP_CHILD_LOG_DEBUG
+#undef __CLASS__