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