Backed out changeset 935617a393ae (bug 1917548) for causing a top crash as in bug...
[gecko.git] / dom / media / gmp / GMPLoader.cpp
blob0a684d6452246279f0746a33e66eab49a54290c5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=4 et :
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "GMPLoader.h"
8 #include <stdio.h>
9 #include "mozilla/Attributes.h"
10 #include "nsExceptionHandler.h"
11 #include "gmp-entrypoints.h"
12 #include "prlink.h"
13 #include "prenv.h"
14 #include "prerror.h"
15 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
16 # include "mozilla/sandboxTarget.h"
17 # include "mozilla/sandboxing/SandboxInitialization.h"
18 # include "mozilla/sandboxing/sandboxLogging.h"
19 #endif
20 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
21 # include "mozilla/Sandbox.h"
22 # include "mozilla/SandboxInfo.h"
23 # include "mozilla/SandboxProfilerObserver.h"
24 #endif
26 #include <string>
28 #ifdef XP_WIN
29 # include <windows.h>
30 #endif
32 namespace mozilla::gmp {
33 class PassThroughGMPAdapter : public GMPAdapter {
34 public:
35 ~PassThroughGMPAdapter() override {
36 // Ensure we're always shutdown, even if caller forgets to call
37 // GMPShutdown().
38 GMPShutdown();
41 void SetAdaptee(PRLibrary* aLib) override { mLib = aLib; }
43 GMPErr GMPInit(const GMPPlatformAPI* aPlatformAPI) override {
44 if (NS_WARN_IF(!mLib)) {
45 MOZ_CRASH("Missing library!");
46 return GMPGenericErr;
48 GMPInitFunc initFunc =
49 reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit"));
50 if (!initFunc) {
51 MOZ_CRASH("Missing init method!");
52 return GMPNotImplementedErr;
54 return initFunc(aPlatformAPI);
57 GMPErr GMPGetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI,
58 const nsACString& /* aKeySystem */) override {
59 if (!mLib) {
60 return GMPGenericErr;
62 GMPGetAPIFunc getapiFunc = reinterpret_cast<GMPGetAPIFunc>(
63 PR_FindFunctionSymbol(mLib, "GMPGetAPI"));
64 if (!getapiFunc) {
65 return GMPNotImplementedErr;
67 return getapiFunc(aAPIName, aHostAPI, aPluginAPI);
70 void GMPShutdown() override {
71 if (mLib) {
72 GMPShutdownFunc shutdownFunc = reinterpret_cast<GMPShutdownFunc>(
73 PR_FindFunctionSymbol(mLib, "GMPShutdown"));
74 if (shutdownFunc) {
75 shutdownFunc();
77 PR_UnloadLibrary(mLib);
78 mLib = nullptr;
82 private:
83 PRLibrary* mLib = nullptr;
86 bool GMPLoader::Load(const char* aUTF8LibPath, uint32_t aUTF8LibPathLen,
87 const GMPPlatformAPI* aPlatformAPI, GMPAdapter* aAdapter) {
88 CrashReporter::AutoRecordAnnotation autoLibPath(
89 CrashReporter::Annotation::GMPLibraryPath,
90 nsDependentCString(aUTF8LibPath));
92 if (!getenv("MOZ_DISABLE_GMP_SANDBOX") && mSandboxStarter &&
93 !mSandboxStarter->Start(aUTF8LibPath)) {
94 MOZ_CRASH("Cannot start sandbox!");
95 return false;
98 // Load the GMP.
99 PRLibSpec libSpec;
100 #ifdef XP_WIN
101 int pathLen = MultiByteToWideChar(CP_UTF8, 0, aUTF8LibPath, -1, nullptr, 0);
102 if (pathLen == 0) {
103 MOZ_CRASH("Cannot get path length as wide char!");
104 return false;
107 auto widePath = MakeUnique<wchar_t[]>(pathLen);
108 if (MultiByteToWideChar(CP_UTF8, 0, aUTF8LibPath, -1, widePath.get(),
109 pathLen) == 0) {
110 MOZ_CRASH("Cannot convert path to wide char!");
111 return false;
114 libSpec.value.pathname_u = widePath.get();
115 libSpec.type = PR_LibSpec_PathnameU;
116 #else
117 libSpec.value.pathname = aUTF8LibPath;
118 libSpec.type = PR_LibSpec_Pathname;
119 #endif
120 PRLibrary* lib = PR_LoadLibraryWithFlags(libSpec, 0);
121 if (!lib) {
122 MOZ_CRASH_UNSAFE_PRINTF("Cannot load plugin as library %d %d",
123 PR_GetError(), PR_GetOSError());
124 return false;
127 mAdapter.reset((!aAdapter) ? new PassThroughGMPAdapter() : aAdapter);
128 mAdapter->SetAdaptee(lib);
130 if (mAdapter->GMPInit(aPlatformAPI) != GMPNoErr) {
131 MOZ_CRASH("Cannot initialize plugin adapter!");
132 return false;
135 return true;
138 GMPErr GMPLoader::GetAPI(const char* aAPIName, void* aHostAPI,
139 void** aPluginAPI, const nsACString& aKeySystem) {
140 return mAdapter->GMPGetAPI(aAPIName, aHostAPI, aPluginAPI, aKeySystem);
143 void GMPLoader::Shutdown() {
144 if (mAdapter) {
145 mAdapter->GMPShutdown();
149 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
150 class WinSandboxStarter : public mozilla::gmp::SandboxStarter {
151 public:
152 bool Start(const char* aLibPath) override {
153 // Cause advapi32 to load before the sandbox is turned on, as
154 // Widevine version 970 and later require it and the sandbox
155 // blocks it on Win7.
156 unsigned int dummy_rand;
157 rand_s(&dummy_rand);
159 mozilla::SandboxTarget::Instance()->StartSandbox();
160 return true;
163 #endif
165 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
166 namespace {
167 class LinuxSandboxStarter : public mozilla::gmp::SandboxStarter {
168 private:
169 LinuxSandboxStarter() = default;
170 friend mozilla::detail::UniqueSelector<LinuxSandboxStarter>::SingleObject
171 mozilla::MakeUnique<LinuxSandboxStarter>();
173 public:
174 static UniquePtr<SandboxStarter> Make() {
175 if (mozilla::SandboxInfo::Get().CanSandboxMedia()) {
176 return MakeUnique<LinuxSandboxStarter>();
178 // Sandboxing isn't possible, but the parent has already
179 // checked that this plugin doesn't require it. (Bug 1074561)
180 return nullptr;
182 bool Start(const char* aLibPath) override {
183 RegisterProfilerObserversForSandboxProfiler();
184 mozilla::SetMediaPluginSandbox(aLibPath);
185 return true;
188 } // anonymous namespace
189 #endif // XP_LINUX && MOZ_SANDBOX
191 static UniquePtr<SandboxStarter> MakeSandboxStarter() {
192 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
193 return mozilla::MakeUnique<WinSandboxStarter>();
194 #elif defined(XP_LINUX) && defined(MOZ_SANDBOX)
195 return LinuxSandboxStarter::Make();
196 #else
197 return nullptr;
198 #endif
201 GMPLoader::GMPLoader() : mSandboxStarter(MakeSandboxStarter()) {}
203 bool GMPLoader::CanSandbox() const { return !!mSandboxStarter; }
205 } // namespace mozilla::gmp