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 "base/command_line.h"
9 #include "base/task.h"
10 #include "ChildProfilerController.h"
11 #include "ChromiumCDMAdapter.h"
12 #ifdef XP_LINUX
13 #  include "dlfcn.h"
14 #endif
15 #include "gmp-video-decode.h"
16 #include "gmp-video-encode.h"
17 #include "GMPContentChild.h"
18 #include "GMPLoader.h"
19 #include "GMPLog.h"
20 #include "GMPPlatform.h"
21 #include "GMPProcessChild.h"
22 #include "GMPProcessParent.h"
23 #include "GMPUtils.h"
24 #include "GMPVideoDecoderChild.h"
25 #include "GMPVideoEncoderChild.h"
26 #include "GMPVideoHost.h"
27 #include "mozilla/Algorithm.h"
28 #include "mozilla/FOGIPC.h"
29 #include "mozilla/glean/GleanMetrics.h"
30 #include "mozilla/ipc/CrashReporterClient.h"
31 #include "mozilla/ipc/Endpoint.h"
32 #include "mozilla/ipc/ProcessChild.h"
33 #include "mozilla/TextUtils.h"
34 #include "nsDebugImpl.h"
35 #include "nsExceptionHandler.h"
36 #include "nsIFile.h"
37 #include "nsReadableUtils.h"
38 #include "nsThreadManager.h"
39 #include "nsXULAppAPI.h"
40 #include "nsIXULRuntime.h"
41 #include "prio.h"
42 #ifdef XP_WIN
43 #  include <stdlib.h>  // for _exit()
44 #  include "WinUtils.h"
45 #else
46 #  include <unistd.h>  // for _exit()
47 #endif
48 
49 using namespace mozilla::ipc;
50 
51 namespace mozilla {
52 
53 #define GMP_CHILD_LOG_DEBUG(x, ...)                                   \
54   GMP_LOG_DEBUG("GMPChild[pid=%d] " x, (int)base::GetCurrentProcId(), \
55                 ##__VA_ARGS__)
56 
57 namespace gmp {
58 
GMPChild()59 GMPChild::GMPChild()
60     : mGMPMessageLoop(MessageLoop::current()), mGMPLoader(nullptr) {
61   GMP_CHILD_LOG_DEBUG("GMPChild ctor");
62   nsDebugImpl::SetMultiprocessMode("GMP");
63 }
64 
~GMPChild()65 GMPChild::~GMPChild() {
66   GMP_CHILD_LOG_DEBUG("GMPChild dtor");
67 #ifdef XP_LINUX
68   for (auto& libHandle : mLibHandles) {
69     dlclose(libHandle);
70   }
71 #endif
72 }
73 
GetFileBase(const nsAString & aPluginPath,nsCOMPtr<nsIFile> & aLibDirectory,nsCOMPtr<nsIFile> & aFileBase,nsAutoString & aBaseName)74 static bool GetFileBase(const nsAString& aPluginPath,
75                         nsCOMPtr<nsIFile>& aLibDirectory,
76                         nsCOMPtr<nsIFile>& aFileBase, nsAutoString& aBaseName) {
77   nsresult rv = NS_NewLocalFile(aPluginPath, true, getter_AddRefs(aFileBase));
78   if (NS_WARN_IF(NS_FAILED(rv))) {
79     return false;
80   }
81 
82   if (NS_WARN_IF(NS_FAILED(aFileBase->Clone(getter_AddRefs(aLibDirectory))))) {
83     return false;
84   }
85 
86   nsCOMPtr<nsIFile> parent;
87   rv = aFileBase->GetParent(getter_AddRefs(parent));
88   if (NS_WARN_IF(NS_FAILED(rv))) {
89     return false;
90   }
91 
92   nsAutoString parentLeafName;
93   rv = parent->GetLeafName(parentLeafName);
94   if (NS_WARN_IF(NS_FAILED(rv))) {
95     return false;
96   }
97 
98   aBaseName = Substring(parentLeafName, 4, parentLeafName.Length() - 1);
99   return true;
100 }
101 
GetPluginFile(const nsAString & aPluginPath,nsCOMPtr<nsIFile> & aLibDirectory,nsCOMPtr<nsIFile> & aLibFile)102 static bool GetPluginFile(const nsAString& aPluginPath,
103                           nsCOMPtr<nsIFile>& aLibDirectory,
104                           nsCOMPtr<nsIFile>& aLibFile) {
105   nsAutoString baseName;
106   GetFileBase(aPluginPath, aLibDirectory, aLibFile, baseName);
107 
108 #if defined(XP_MACOSX)
109   nsAutoString binaryName = u"lib"_ns + baseName + u".dylib"_ns;
110 #elif defined(OS_POSIX)
111   nsAutoString binaryName = u"lib"_ns + baseName + u".so"_ns;
112 #elif defined(XP_WIN)
113   nsAutoString binaryName = baseName + u".dll"_ns;
114 #else
115 #  error not defined
116 #endif
117   aLibFile->AppendRelativePath(binaryName);
118   return true;
119 }
120 
GetPluginFile(const nsAString & aPluginPath,nsCOMPtr<nsIFile> & aLibFile)121 static bool GetPluginFile(const nsAString& aPluginPath,
122                           nsCOMPtr<nsIFile>& aLibFile) {
123   nsCOMPtr<nsIFile> unusedlibDir;
124   return GetPluginFile(aPluginPath, unusedlibDir, aLibFile);
125 }
126 
127 #if defined(XP_MACOSX)
GetNativeTarget(nsIFile * aFile)128 static nsCString GetNativeTarget(nsIFile* aFile) {
129   bool isLink;
130   nsCString path;
131   aFile->IsSymlink(&isLink);
132   if (isLink) {
133     aFile->GetNativeTarget(path);
134   } else {
135     aFile->GetNativePath(path);
136   }
137   return path;
138 }
139 
140 #  if defined(MOZ_SANDBOX)
GetPluginPaths(const nsAString & aPluginPath,nsCString & aPluginDirectoryPath,nsCString & aPluginFilePath)141 static bool GetPluginPaths(const nsAString& aPluginPath,
142                            nsCString& aPluginDirectoryPath,
143                            nsCString& aPluginFilePath) {
144   nsCOMPtr<nsIFile> libDirectory, libFile;
145   if (!GetPluginFile(aPluginPath, libDirectory, libFile)) {
146     return false;
147   }
148 
149   // Mac sandbox rules expect paths to actual files and directories -- not
150   // soft links.
151   libDirectory->Normalize();
152   aPluginDirectoryPath = GetNativeTarget(libDirectory);
153 
154   libFile->Normalize();
155   aPluginFilePath = GetNativeTarget(libFile);
156 
157   return true;
158 }
159 #  endif  // MOZ_SANDBOX
160 #endif    // XP_MACOSX
161 
Init(const nsAString & aPluginPath,base::ProcessId aParentPid,mozilla::ipc::ScopedPort aPort)162 bool GMPChild::Init(const nsAString& aPluginPath, base::ProcessId aParentPid,
163                     mozilla::ipc::ScopedPort aPort) {
164   GMP_CHILD_LOG_DEBUG("%s pluginPath=%s", __FUNCTION__,
165                       NS_ConvertUTF16toUTF8(aPluginPath).get());
166 
167   // GMPChild needs nsThreadManager to create the ProfilerChild thread.
168   // It is also used on debug builds for the sandbox tests.
169   if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) {
170     return false;
171   }
172 
173   if (NS_WARN_IF(!Open(std::move(aPort), aParentPid))) {
174     return false;
175   }
176 
177   CrashReporterClient::InitSingleton(this);
178 
179   mPluginPath = aPluginPath;
180 
181   return true;
182 }
183 
RecvProvideStorageId(const nsCString & aStorageId)184 mozilla::ipc::IPCResult GMPChild::RecvProvideStorageId(
185     const nsCString& aStorageId) {
186   GMP_CHILD_LOG_DEBUG("%s", __FUNCTION__);
187   mStorageId = aStorageId;
188   return IPC_OK();
189 }
190 
GetAPI(const char * aAPIName,void * aHostAPI,void ** aPluginAPI,const nsCString aKeySystem)191 GMPErr GMPChild::GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI,
192                         const nsCString aKeySystem) {
193   if (!mGMPLoader) {
194     return GMPGenericErr;
195   }
196   return mGMPLoader->GetAPI(aAPIName, aHostAPI, aPluginAPI, aKeySystem);
197 }
198 
RecvPreloadLibs(const nsCString & aLibs)199 mozilla::ipc::IPCResult GMPChild::RecvPreloadLibs(const nsCString& aLibs) {
200   // Pre-load libraries that may need to be used by the EME plugin but that
201   // can't be loaded after the sandbox has started.
202 #ifdef XP_WIN
203   // Items in this must be lowercase!
204   constexpr static const char16_t* whitelist[] = {
205       u"dxva2.dll",        // Get monitor information
206       u"evr.dll",          // MFGetStrideForBitmapInfoHeader
207       u"freebl3.dll",      // NSS for clearkey CDM
208       u"mfplat.dll",       // MFCreateSample, MFCreateAlignedMemoryBuffer,
209                            // MFCreateMediaType
210       u"msmpeg2vdec.dll",  // H.264 decoder
211       u"nss3.dll",         // NSS for clearkey CDM
212       u"ole32.dll",        // required for OPM
213       u"psapi.dll",        // For GetMappedFileNameW, see bug 1383611
214       u"softokn3.dll",     // NSS for clearkey CDM
215       u"winmm.dll",        // Dependency for widevine
216   };
217   constexpr static bool (*IsASCII)(const char16_t*) =
218       IsAsciiNullTerminated<char16_t>;
219   static_assert(AllOf(std::begin(whitelist), std::end(whitelist), IsASCII),
220                 "Items in the whitelist must not contain non-ASCII "
221                 "characters!");
222 
223   nsTArray<nsCString> libs;
224   SplitAt(", ", aLibs, libs);
225   for (nsCString lib : libs) {
226     ToLowerCase(lib);
227     for (const char16_t* whiteListedLib : whitelist) {
228       if (nsDependentString(whiteListedLib)
229               .EqualsASCII(lib.Data(), lib.Length())) {
230         LoadLibraryW(char16ptr_t(whiteListedLib));
231         break;
232       }
233     }
234   }
235 #elif defined(XP_LINUX)
236   constexpr static const char* whitelist[] = {
237       // NSS libraries used by clearkey.
238       "libfreeblpriv3.so",
239       "libsoftokn3.so",
240       // glibc libraries merged into libc.so.6; see bug 1725828 and
241       // the corresponding code in GMPParent.cpp.
242       "libdl.so.2",
243       "libpthread.so.0",
244       "librt.so.1",
245   };
246 
247   nsTArray<nsCString> libs;
248   SplitAt(", ", aLibs, libs);
249   for (const nsCString& lib : libs) {
250     for (const char* whiteListedLib : whitelist) {
251       if (lib.EqualsASCII(whiteListedLib)) {
252         auto libHandle = dlopen(whiteListedLib, RTLD_NOW | RTLD_GLOBAL);
253         if (libHandle) {
254           mLibHandles.AppendElement(libHandle);
255         } else {
256           // TODO(bug 1698718): remove the logging once we've identified
257           // the cause of the load failure.
258           const char* error = dlerror();
259           if (error) {
260             // We should always have an error, but gracefully handle just in
261             // case.
262             nsAutoCString nsError{error};
263             CrashReporter::AppendAppNotesToCrashReport(nsError);
264           }
265           // End bug 1698718 logging.
266 
267           MOZ_CRASH("Couldn't load lib needed by media plugin");
268         }
269       }
270     }
271   }
272 #endif
273   return IPC_OK();
274 }
275 
ResolveLinks(nsCOMPtr<nsIFile> & aPath)276 static bool ResolveLinks(nsCOMPtr<nsIFile>& aPath) {
277 #if defined(XP_WIN)
278   return widget::WinUtils::ResolveJunctionPointsAndSymLinks(aPath);
279 #elif defined(XP_MACOSX)
280   nsCString targetPath = GetNativeTarget(aPath);
281   nsCOMPtr<nsIFile> newFile;
282   if (NS_WARN_IF(NS_FAILED(
283           NS_NewNativeLocalFile(targetPath, true, getter_AddRefs(newFile))))) {
284     return false;
285   }
286   aPath = newFile;
287   return true;
288 #else
289   return true;
290 #endif
291 }
292 
GetUTF8LibPath(nsACString & aOutLibPath)293 bool GMPChild::GetUTF8LibPath(nsACString& aOutLibPath) {
294 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
295   nsAutoCString pluginDirectoryPath, pluginFilePath;
296   if (!GetPluginPaths(mPluginPath, pluginDirectoryPath, pluginFilePath)) {
297     MOZ_CRASH("Error scanning plugin path");
298   }
299   aOutLibPath.Assign(pluginFilePath);
300   return true;
301 #else
302   nsCOMPtr<nsIFile> libFile;
303   if (!GetPluginFile(mPluginPath, libFile)) {
304     return false;
305   }
306 
307   if (!FileExists(libFile)) {
308     NS_WARNING("Can't find GMP library file!");
309     return false;
310   }
311 
312   nsAutoString path;
313   libFile->GetPath(path);
314   CopyUTF16toUTF8(path, aOutLibPath);
315 
316   return true;
317 #endif
318 }
319 
AppendFile(nsCOMPtr<nsIFile> && aFile,const nsString & aStr)320 static nsCOMPtr<nsIFile> AppendFile(nsCOMPtr<nsIFile>&& aFile,
321                                     const nsString& aStr) {
322   return (aFile && NS_SUCCEEDED(aFile->Append(aStr))) ? aFile : nullptr;
323 }
324 
CloneFile(const nsCOMPtr<nsIFile> & aFile)325 static nsCOMPtr<nsIFile> CloneFile(const nsCOMPtr<nsIFile>& aFile) {
326   nsCOMPtr<nsIFile> clone;
327   return (aFile && NS_SUCCEEDED(aFile->Clone(getter_AddRefs(clone)))) ? clone
328                                                                       : nullptr;
329 }
330 
GetParentFile(const nsCOMPtr<nsIFile> & aFile)331 static nsCOMPtr<nsIFile> GetParentFile(const nsCOMPtr<nsIFile>& aFile) {
332   nsCOMPtr<nsIFile> parent;
333   return (aFile && NS_SUCCEEDED(aFile->GetParent(getter_AddRefs(parent))))
334              ? parent
335              : nullptr;
336 }
337 
338 #if defined(XP_WIN)
IsFileLeafEqualToASCII(const nsCOMPtr<nsIFile> & aFile,const char * aStr)339 static bool IsFileLeafEqualToASCII(const nsCOMPtr<nsIFile>& aFile,
340                                    const char* aStr) {
341   nsAutoString leafName;
342   return aFile && NS_SUCCEEDED(aFile->GetLeafName(leafName)) &&
343          leafName.EqualsASCII(aStr);
344 }
345 #endif
346 
347 #if defined(XP_WIN)
348 #  define FIREFOX_FILE u"firefox.exe"_ns
349 #  define XUL_LIB_FILE u"xul.dll"_ns
350 #elif defined(XP_MACOSX)
351 #  define FIREFOX_FILE u"firefox"_ns
352 #  define XUL_LIB_FILE u"XUL"_ns
353 #else
354 #  define FIREFOX_FILE u"firefox"_ns
355 #  define XUL_LIB_FILE u"libxul.so"_ns
356 #endif
357 
GetFirefoxAppPath(nsCOMPtr<nsIFile> aPluginContainerPath)358 static nsCOMPtr<nsIFile> GetFirefoxAppPath(
359     nsCOMPtr<nsIFile> aPluginContainerPath) {
360   MOZ_ASSERT(aPluginContainerPath);
361 #if defined(XP_MACOSX)
362   // On MacOS the firefox binary is a few parent directories up from
363   // plugin-container.
364   // aPluginContainerPath will end with something like:
365   // xxxx/NightlyDebug.app/Contents/MacOS/plugin-container.app/Contents/MacOS/plugin-container
366   nsCOMPtr<nsIFile> path = aPluginContainerPath;
367   for (int i = 0; i < 4; i++) {
368     path = GetParentFile(path);
369   }
370   return path;
371 #else
372   nsCOMPtr<nsIFile> parent = GetParentFile(aPluginContainerPath);
373 #  if XP_WIN
374   if (IsFileLeafEqualToASCII(parent, "i686")) {
375     // We must be on Windows on ARM64, where the plugin-container path will
376     // be in the 'i686' subdir. The firefox.exe is in the parent directory.
377     parent = GetParentFile(parent);
378   }
379 #  endif
380   return parent;
381 #endif
382 }
383 
384 #if defined(XP_MACOSX)
GetSigPath(const int aRelativeLayers,const nsString & aTargetSigFileName,nsCOMPtr<nsIFile> aExecutablePath,nsCOMPtr<nsIFile> & aOutSigPath)385 static bool GetSigPath(const int aRelativeLayers,
386                        const nsString& aTargetSigFileName,
387                        nsCOMPtr<nsIFile> aExecutablePath,
388                        nsCOMPtr<nsIFile>& aOutSigPath) {
389   // The sig file will be located in
390   // xxxx/NightlyDebug.app/Contents/Resources/XUL.sig
391   // xxxx/NightlyDebug.app/Contents/Resources/firefox.sig
392   // xxxx/NightlyDebug.app/Contents/MacOS/plugin-container.app/Contents/Resources/plugin-container.sig
393   // On MacOS the sig file is a few parent directories up from
394   // its executable file.
395   // Start to search the path from the path of the executable file we provided.
396   MOZ_ASSERT(aExecutablePath);
397   nsCOMPtr<nsIFile> path = aExecutablePath;
398   for (int i = 0; i < aRelativeLayers; i++) {
399     nsCOMPtr<nsIFile> parent;
400     if (NS_WARN_IF(NS_FAILED(path->GetParent(getter_AddRefs(parent))))) {
401       return false;
402     }
403     path = parent;
404   }
405   MOZ_ASSERT(path);
406   aOutSigPath = path;
407   return NS_SUCCEEDED(path->Append(u"Resources"_ns)) &&
408          NS_SUCCEEDED(path->Append(aTargetSigFileName));
409 }
410 #endif
411 
AppendHostPath(nsCOMPtr<nsIFile> & aFile,nsTArray<std::pair<nsCString,nsCString>> & aPaths)412 static bool AppendHostPath(nsCOMPtr<nsIFile>& aFile,
413                            nsTArray<std::pair<nsCString, nsCString>>& aPaths) {
414   nsString str;
415   if (!FileExists(aFile) || !ResolveLinks(aFile) ||
416       NS_FAILED(aFile->GetPath(str))) {
417     return false;
418   }
419 
420   nsCString filePath = NS_ConvertUTF16toUTF8(str);
421   nsCString sigFilePath;
422 #if defined(XP_MACOSX)
423   nsAutoString binary;
424   if (NS_FAILED(aFile->GetLeafName(binary))) {
425     return false;
426   }
427   binary.Append(u".sig"_ns);
428   nsCOMPtr<nsIFile> sigFile;
429   if (GetSigPath(2, binary, aFile, sigFile) &&
430       NS_SUCCEEDED(sigFile->GetPath(str))) {
431     CopyUTF16toUTF8(str, sigFilePath);
432   } else {
433     // Cannot successfully get the sig file path.
434     // Assume it is located at the same place as plugin-container
435     // alternatively.
436     sigFilePath = nsCString(NS_ConvertUTF16toUTF8(str) + ".sig"_ns);
437   }
438 #else
439   sigFilePath = nsCString(NS_ConvertUTF16toUTF8(str) + ".sig"_ns);
440 #endif
441   aPaths.AppendElement(
442       std::make_pair(std::move(filePath), std::move(sigFilePath)));
443   return true;
444 }
445 
446 nsTArray<std::pair<nsCString, nsCString>>
MakeCDMHostVerificationPaths()447 GMPChild::MakeCDMHostVerificationPaths() {
448   // Record the file path and its sig file path.
449   nsTArray<std::pair<nsCString, nsCString>> paths;
450   // Plugin binary path.
451   nsCOMPtr<nsIFile> path;
452   nsString str;
453   if (GetPluginFile(mPluginPath, path) && FileExists(path) &&
454       ResolveLinks(path) && NS_SUCCEEDED(path->GetPath(str))) {
455     paths.AppendElement(
456         std::make_pair(nsCString(NS_ConvertUTF16toUTF8(str)),
457                        nsCString(NS_ConvertUTF16toUTF8(str) + ".sig"_ns)));
458   }
459 
460   // Plugin-container binary path.
461   // Note: clang won't let us initialize an nsString from a wstring, so we
462   // need to go through UTF8 to get to an nsString.
463   const std::string pluginContainer =
464       WideToUTF8(CommandLine::ForCurrentProcess()->program());
465   path = nullptr;
466   CopyUTF8toUTF16(nsDependentCString(pluginContainer.c_str()), str);
467   if (NS_FAILED(NS_NewLocalFile(str, true, /* aFollowLinks */
468                                 getter_AddRefs(path))) ||
469       !AppendHostPath(path, paths)) {
470     // Without successfully determining plugin-container's path, we can't
471     // determine libxul's or Firefox's. So give up.
472     return paths;
473   }
474 
475 #if defined(XP_WIN)
476   // On Windows on ARM64, we should also append the x86 plugin-container's
477   // xul.dll.
478   const bool isWindowsOnARM64 =
479       IsFileLeafEqualToASCII(GetParentFile(path), "i686");
480   if (isWindowsOnARM64) {
481     nsCOMPtr<nsIFile> x86XulPath =
482         AppendFile(GetParentFile(path), XUL_LIB_FILE);
483     if (!AppendHostPath(x86XulPath, paths)) {
484       return paths;
485     }
486   }
487 #endif
488 
489   // Firefox application binary path.
490   nsCOMPtr<nsIFile> appDir = GetFirefoxAppPath(path);
491   path = AppendFile(CloneFile(appDir), FIREFOX_FILE);
492   if (!AppendHostPath(path, paths)) {
493     return paths;
494   }
495 
496   // Libxul path. Note: re-using 'appDir' var here, as we assume libxul is in
497   // the same directory as Firefox executable.
498   appDir->GetPath(str);
499   path = AppendFile(CloneFile(appDir), XUL_LIB_FILE);
500   if (!AppendHostPath(path, paths)) {
501     return paths;
502   }
503 
504   return paths;
505 }
506 
ToCString(const nsTArray<std::pair<nsCString,nsCString>> & aPairs)507 static auto ToCString(const nsTArray<std::pair<nsCString, nsCString>>& aPairs) {
508   return StringJoin(","_ns, aPairs, [](nsACString& dest, const auto& p) {
509     dest.AppendPrintf("(%s,%s)", p.first.get(), p.second.get());
510   });
511 }
512 
RecvStartPlugin(const nsString & aAdapter)513 mozilla::ipc::IPCResult GMPChild::RecvStartPlugin(const nsString& aAdapter) {
514   GMP_CHILD_LOG_DEBUG("%s", __FUNCTION__);
515 
516   nsCString libPath;
517   if (!GetUTF8LibPath(libPath)) {
518     CrashReporter::AnnotateCrashReport(
519         CrashReporter::Annotation::GMPLibraryPath,
520         NS_ConvertUTF16toUTF8(mPluginPath));
521 
522 #ifdef XP_WIN
523     return IPC_FAIL(this,
524                     nsPrintfCString("Failed to get lib path with error(%d).",
525                                     GetLastError())
526                         .get());
527 #else
528     return IPC_FAIL(this, "Failed to get lib path.");
529 #endif
530   }
531 
532   auto platformAPI = new GMPPlatformAPI();
533   InitPlatformAPI(*platformAPI, this);
534 
535   mGMPLoader = MakeUnique<GMPLoader>();
536 #if defined(MOZ_SANDBOX) && !defined(XP_MACOSX)
537   if (!mGMPLoader->CanSandbox()) {
538     GMP_CHILD_LOG_DEBUG("%s Can't sandbox GMP, failing", __FUNCTION__);
539     delete platformAPI;
540     return IPC_FAIL(this, "Can't sandbox GMP.");
541   }
542 #endif
543 
544   GMPAdapter* adapter = nullptr;
545   if (aAdapter.EqualsLiteral("chromium")) {
546     auto&& paths = MakeCDMHostVerificationPaths();
547     GMP_CHILD_LOG_DEBUG("%s CDM host paths=%s", __func__,
548                         ToCString(paths).get());
549     adapter = new ChromiumCDMAdapter(std::move(paths));
550   }
551 
552   if (!mGMPLoader->Load(libPath.get(), libPath.Length(), platformAPI,
553                         adapter)) {
554     NS_WARNING("Failed to load GMP");
555     delete platformAPI;
556     CrashReporter::AnnotateCrashReport(
557         CrashReporter::Annotation::GMPLibraryPath,
558         NS_ConvertUTF16toUTF8(mPluginPath));
559 
560 #ifdef XP_WIN
561     return IPC_FAIL(this, nsPrintfCString("Failed to load GMP with error(%d).",
562                                           GetLastError())
563                               .get());
564 #else
565     return IPC_FAIL(this, "Failed to load GMP.");
566 #endif
567   }
568 
569   return IPC_OK();
570 }
571 
GMPMessageLoop()572 MessageLoop* GMPChild::GMPMessageLoop() { return mGMPMessageLoop; }
573 
ActorDestroy(ActorDestroyReason aWhy)574 void GMPChild::ActorDestroy(ActorDestroyReason aWhy) {
575   GMP_CHILD_LOG_DEBUG("%s reason=%d", __FUNCTION__, aWhy);
576 
577   for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) {
578     MOZ_ASSERT_IF(aWhy == NormalShutdown,
579                   !mGMPContentChildren[i - 1]->IsUsed());
580     mGMPContentChildren[i - 1]->Close();
581   }
582 
583   if (mGMPLoader) {
584     mGMPLoader->Shutdown();
585   }
586   if (AbnormalShutdown == aWhy) {
587     NS_WARNING("Abnormal shutdown of GMP process!");
588     ProcessChild::QuickExit();
589   }
590 
591   // Send the last bits of Glean data over to the main process.
592   glean::FlushFOGData(
593       [](ByteBuf&& aBuf) { glean::SendFOGData(std::move(aBuf)); });
594 
595   if (mProfilerController) {
596     mProfilerController->Shutdown();
597     mProfilerController = nullptr;
598   }
599 
600   CrashReporterClient::DestroySingleton();
601 
602   XRE_ShutdownChildProcess();
603 }
604 
ProcessingError(Result aCode,const char * aReason)605 void GMPChild::ProcessingError(Result aCode, const char* aReason) {
606   switch (aCode) {
607     case MsgDropped:
608       _exit(0);  // Don't trigger a crash report.
609     case MsgNotKnown:
610       MOZ_CRASH("aborting because of MsgNotKnown");
611     case MsgNotAllowed:
612       MOZ_CRASH("aborting because of MsgNotAllowed");
613     case MsgPayloadError:
614       MOZ_CRASH("aborting because of MsgPayloadError");
615     case MsgProcessingError:
616       MOZ_CRASH("aborting because of MsgProcessingError");
617     case MsgRouteError:
618       MOZ_CRASH("aborting because of MsgRouteError");
619     case MsgValueError:
620       MOZ_CRASH("aborting because of MsgValueError");
621     default:
622       MOZ_CRASH("not reached");
623   }
624 }
625 
AllocPGMPTimerChild()626 PGMPTimerChild* GMPChild::AllocPGMPTimerChild() {
627   return new GMPTimerChild(this);
628 }
629 
DeallocPGMPTimerChild(PGMPTimerChild * aActor)630 bool GMPChild::DeallocPGMPTimerChild(PGMPTimerChild* aActor) {
631   MOZ_ASSERT(mTimerChild == static_cast<GMPTimerChild*>(aActor));
632   mTimerChild = nullptr;
633   return true;
634 }
635 
GetGMPTimers()636 GMPTimerChild* GMPChild::GetGMPTimers() {
637   if (!mTimerChild) {
638     PGMPTimerChild* sc = SendPGMPTimerConstructor();
639     if (!sc) {
640       return nullptr;
641     }
642     mTimerChild = static_cast<GMPTimerChild*>(sc);
643   }
644   return mTimerChild;
645 }
646 
AllocPGMPStorageChild()647 PGMPStorageChild* GMPChild::AllocPGMPStorageChild() {
648   return new GMPStorageChild(this);
649 }
650 
DeallocPGMPStorageChild(PGMPStorageChild * aActor)651 bool GMPChild::DeallocPGMPStorageChild(PGMPStorageChild* aActor) {
652   mStorage = nullptr;
653   return true;
654 }
655 
GetGMPStorage()656 GMPStorageChild* GMPChild::GetGMPStorage() {
657   if (!mStorage) {
658     PGMPStorageChild* sc = SendPGMPStorageConstructor();
659     if (!sc) {
660       return nullptr;
661     }
662     mStorage = static_cast<GMPStorageChild*>(sc);
663   }
664   return mStorage;
665 }
666 
RecvCrashPluginNow()667 mozilla::ipc::IPCResult GMPChild::RecvCrashPluginNow() {
668   MOZ_CRASH();
669   return IPC_OK();
670 }
671 
RecvCloseActive()672 mozilla::ipc::IPCResult GMPChild::RecvCloseActive() {
673   for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) {
674     mGMPContentChildren[i - 1]->CloseActive();
675   }
676   return IPC_OK();
677 }
678 
RecvInitGMPContentChild(Endpoint<PGMPContentChild> && aEndpoint)679 mozilla::ipc::IPCResult GMPChild::RecvInitGMPContentChild(
680     Endpoint<PGMPContentChild>&& aEndpoint) {
681   GMPContentChild* child =
682       mGMPContentChildren.AppendElement(new GMPContentChild(this))->get();
683   aEndpoint.Bind(child);
684   return IPC_OK();
685 }
686 
RecvFlushFOGData(FlushFOGDataResolver && aResolver)687 mozilla::ipc::IPCResult GMPChild::RecvFlushFOGData(
688     FlushFOGDataResolver&& aResolver) {
689   GMP_CHILD_LOG_DEBUG("GMPChild RecvFlushFOGData");
690   glean::FlushFOGData(std::move(aResolver));
691   return IPC_OK();
692 }
693 
RecvTestTriggerMetrics(TestTriggerMetricsResolver && aResolve)694 mozilla::ipc::IPCResult GMPChild::RecvTestTriggerMetrics(
695     TestTriggerMetricsResolver&& aResolve) {
696   GMP_CHILD_LOG_DEBUG("GMPChild RecvTestTriggerMetrics");
697   mozilla::glean::test_only_ipc::a_counter.Add(
698       nsIXULRuntime::PROCESS_TYPE_GMPLUGIN);
699   aResolve(true);
700   return IPC_OK();
701 }
702 
GMPContentChildActorDestroy(GMPContentChild * aGMPContentChild)703 void GMPChild::GMPContentChildActorDestroy(GMPContentChild* aGMPContentChild) {
704   for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) {
705     RefPtr<GMPContentChild>& destroyedActor = mGMPContentChildren[i - 1];
706     if (destroyedActor.get() == aGMPContentChild) {
707       SendPGMPContentChildDestroyed();
708       mGMPContentChildren.RemoveElementAt(i - 1);
709       break;
710     }
711   }
712 }
713 
RecvInitProfiler(Endpoint<PProfilerChild> && aEndpoint)714 mozilla::ipc::IPCResult GMPChild::RecvInitProfiler(
715     Endpoint<PProfilerChild>&& aEndpoint) {
716   mProfilerController =
717       mozilla::ChildProfilerController::Create(std::move(aEndpoint));
718   return IPC_OK();
719 }
720 
721 }  // namespace gmp
722 }  // namespace mozilla
723 
724 #undef GMP_CHILD_LOG_DEBUG
725 #undef __CLASS__
726