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