summaryrefslogtreecommitdiffstats
path: root/dom/media/gmp/GMPLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/gmp/GMPLoader.cpp')
-rw-r--r--dom/media/gmp/GMPLoader.cpp222
1 files changed, 222 insertions, 0 deletions
diff --git a/dom/media/gmp/GMPLoader.cpp b/dom/media/gmp/GMPLoader.cpp
new file mode 100644
index 000000000..c10208a49
--- /dev/null
+++ b/dom/media/gmp/GMPLoader.cpp
@@ -0,0 +1,222 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ * 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 "GMPLoader.h"
+#include <stdio.h>
+#include "mozilla/Attributes.h"
+#include "gmp-entrypoints.h"
+#include "prlink.h"
+#include "prenv.h"
+
+#include <string>
+
+#ifdef XP_WIN
+#include "windows.h"
+#endif
+
+#include "GMPDeviceBinding.h"
+
+namespace mozilla {
+namespace gmp {
+
+class GMPLoaderImpl : public GMPLoader {
+public:
+ explicit GMPLoaderImpl(SandboxStarter* aStarter)
+ : mSandboxStarter(aStarter)
+ , mAdapter(nullptr)
+ {}
+ virtual ~GMPLoaderImpl() {}
+
+ bool Load(const char* aUTF8LibPath,
+ uint32_t aUTF8LibPathLen,
+ char* aOriginSalt,
+ uint32_t aOriginSaltLen,
+ const GMPPlatformAPI* aPlatformAPI,
+ GMPAdapter* aAdapter) override;
+
+ GMPErr GetAPI(const char* aAPIName,
+ void* aHostAPI,
+ void** aPluginAPI,
+ uint32_t aDecryptorId) override;
+
+ void Shutdown() override;
+
+#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
+ void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) override;
+#endif
+
+private:
+ SandboxStarter* mSandboxStarter;
+ UniquePtr<GMPAdapter> mAdapter;
+};
+
+UniquePtr<GMPLoader> CreateGMPLoader(SandboxStarter* aStarter) {
+ return MakeUnique<GMPLoaderImpl>(aStarter);
+}
+
+class PassThroughGMPAdapter : public GMPAdapter {
+public:
+ ~PassThroughGMPAdapter() {
+ // Ensure we're always shutdown, even if caller forgets to call GMPShutdown().
+ GMPShutdown();
+ }
+
+ void SetAdaptee(PRLibrary* aLib) override
+ {
+ mLib = aLib;
+ }
+
+ GMPErr GMPInit(const GMPPlatformAPI* aPlatformAPI) override
+ {
+ if (!mLib) {
+ return GMPGenericErr;
+ }
+ GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit"));
+ if (!initFunc) {
+ return GMPNotImplementedErr;
+ }
+ return initFunc(aPlatformAPI);
+ }
+
+ GMPErr GMPGetAPI(const char* aAPIName,
+ void* aHostAPI,
+ void** aPluginAPI,
+ uint32_t aDecryptorId) override
+ {
+ if (!mLib) {
+ return GMPGenericErr;
+ }
+ GMPGetAPIFunc getapiFunc = reinterpret_cast<GMPGetAPIFunc>(PR_FindFunctionSymbol(mLib, "GMPGetAPI"));
+ if (!getapiFunc) {
+ return GMPNotImplementedErr;
+ }
+ return getapiFunc(aAPIName, aHostAPI, aPluginAPI);
+ }
+
+ void GMPShutdown() override
+ {
+ if (mLib) {
+ GMPShutdownFunc shutdownFunc = reinterpret_cast<GMPShutdownFunc>(PR_FindFunctionSymbol(mLib, "GMPShutdown"));
+ if (shutdownFunc) {
+ shutdownFunc();
+ }
+ PR_UnloadLibrary(mLib);
+ mLib = nullptr;
+ }
+ }
+
+ void GMPSetNodeId(const char* aNodeId, uint32_t aLength) override
+ {
+ if (!mLib) {
+ return;
+ }
+ GMPSetNodeIdFunc setNodeIdFunc = reinterpret_cast<GMPSetNodeIdFunc>(PR_FindFunctionSymbol(mLib, "GMPSetNodeId"));
+ if (setNodeIdFunc) {
+ setNodeIdFunc(aNodeId, aLength);
+ }
+ }
+
+private:
+ PRLibrary* mLib = nullptr;
+};
+
+bool
+GMPLoaderImpl::Load(const char* aUTF8LibPath,
+ uint32_t aUTF8LibPathLen,
+ char* aOriginSalt,
+ uint32_t aOriginSaltLen,
+ const GMPPlatformAPI* aPlatformAPI,
+ GMPAdapter* aAdapter)
+{
+ std::string nodeId;
+ if (!CalculateGMPDeviceId(aOriginSalt, aOriginSaltLen, nodeId)) {
+ return false;
+ }
+
+ // Start the sandbox now that we've generated the device bound node id.
+ // This must happen after the node id is bound to the device id, as
+ // generating the device id requires privileges.
+ if (mSandboxStarter && !mSandboxStarter->Start(aUTF8LibPath)) {
+ return false;
+ }
+
+ // Load the GMP.
+ PRLibSpec libSpec;
+#ifdef XP_WIN
+ int pathLen = MultiByteToWideChar(CP_UTF8, 0, aUTF8LibPath, -1, nullptr, 0);
+ if (pathLen == 0) {
+ return false;
+ }
+
+ auto widePath = MakeUnique<wchar_t[]>(pathLen);
+ if (MultiByteToWideChar(CP_UTF8, 0, aUTF8LibPath, -1, widePath.get(), pathLen) == 0) {
+ return false;
+ }
+
+ libSpec.value.pathname_u = widePath.get();
+ libSpec.type = PR_LibSpec_PathnameU;
+#else
+ libSpec.value.pathname = aUTF8LibPath;
+ libSpec.type = PR_LibSpec_Pathname;
+#endif
+ PRLibrary* lib = PR_LoadLibraryWithFlags(libSpec, 0);
+ if (!lib) {
+ return false;
+ }
+
+ GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(lib, "GMPInit"));
+ if ((initFunc && aAdapter) ||
+ (!initFunc && !aAdapter)) {
+ // Ensure that if we're dealing with a GMP we do *not* use an adapter
+ // provided from the outside world. This is important as it means we
+ // don't call code not covered by Adobe's plugin-container voucher
+ // before we pass the node Id to Adobe's GMP.
+ return false;
+ }
+
+ // Note: PassThroughGMPAdapter's code must remain in this file so that it's
+ // covered by Adobe's plugin-container voucher.
+ mAdapter.reset((!aAdapter) ? new PassThroughGMPAdapter() : aAdapter);
+ mAdapter->SetAdaptee(lib);
+
+ if (mAdapter->GMPInit(aPlatformAPI) != GMPNoErr) {
+ return false;
+ }
+
+ mAdapter->GMPSetNodeId(nodeId.c_str(), nodeId.size());
+
+ return true;
+}
+
+GMPErr
+GMPLoaderImpl::GetAPI(const char* aAPIName,
+ void* aHostAPI,
+ void** aPluginAPI,
+ uint32_t aDecryptorId)
+{
+ return mAdapter->GMPGetAPI(aAPIName, aHostAPI, aPluginAPI, aDecryptorId);
+}
+
+void
+GMPLoaderImpl::Shutdown()
+{
+ if (mAdapter) {
+ mAdapter->GMPShutdown();
+ }
+}
+
+#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
+void
+GMPLoaderImpl::SetSandboxInfo(MacSandboxInfo* aSandboxInfo)
+{
+ if (mSandboxStarter) {
+ mSandboxStarter->SetSandboxInfo(aSandboxInfo);
+ }
+}
+#endif
+} // namespace gmp
+} // namespace mozilla
+