Bug 1088488 - Add GMPLoader interface to encapsulate loading GMPs, pass that to XRE_InitChildProcess. r=jesup,r=bsmedberg,r=glandium

This commit is contained in:
Chris Pearce 2014-11-14 21:26:24 +13:00
Родитель a05d3eba03
Коммит f3af16c459
10 изменённых файлов: 303 добавлений и 7 удалений

124
dom/media/gmp/GMPLoader.cpp Normal file
Просмотреть файл

@ -0,0 +1,124 @@
/* -*- 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 "mozilla/NullPtr.h"
#include "gmp-entrypoints.h"
#include "prlink.h"
#include <string>
namespace mozilla {
namespace gmp {
class GMPLoaderImpl : public GMPLoader {
public:
explicit GMPLoaderImpl(SandboxStarter* aStarter)
: mSandboxStarter(aStarter)
{}
virtual ~GMPLoaderImpl() {}
virtual bool Load(const char* aLibPath,
uint32_t aLibPathLen,
char* aOriginSalt,
uint32_t aOriginSaltLen,
const GMPPlatformAPI* aPlatformAPI) MOZ_OVERRIDE;
virtual GMPErr GetAPI(const char* aAPIName,
void* aHostAPI,
void** aPluginAPI) MOZ_OVERRIDE;
virtual void Shutdown() MOZ_OVERRIDE;
#ifdef SANDBOX_NOT_STATICALLY_LINKED_INTO_PLUGIN_CONTAINER
virtual void SetStartSandboxStarter(SandboxStarter* aStarter) MOZ_OVERRIDE {
mSandboxStarter = aStarter;
}
#endif
private:
PRLibrary* mLib;
GMPGetAPIFunc mGetAPIFunc;
SandboxStarter* mSandboxStarter;
};
GMPLoader* CreateGMPLoader(SandboxStarter* aStarter) {
return static_cast<GMPLoader*>(new GMPLoaderImpl(aStarter));
}
bool
GMPLoaderImpl::Load(const char* aLibPath,
uint32_t aLibPathLen,
char* aOriginSalt,
uint32_t aOriginSaltLen,
const GMPPlatformAPI* aPlatformAPI)
{
std::string nodeId(aOriginSalt, aOriginSalt + aOriginSaltLen);
// TODO (subsequent patch): Hash node id with device id, send to GMP.
#if defined(MOZ_GMP_SANDBOX)
// 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();
}
#endif
// Load the GMP.
PRLibSpec libSpec;
libSpec.value.pathname = aLibPath;
libSpec.type = PR_LibSpec_Pathname;
mLib = PR_LoadLibraryWithFlags(libSpec, 0);
if (!mLib) {
return false;
}
GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit"));
if (!initFunc) {
return false;
}
if (initFunc(aPlatformAPI) != GMPNoErr) {
return false;
}
mGetAPIFunc = reinterpret_cast<GMPGetAPIFunc>(PR_FindFunctionSymbol(mLib, "GMPGetAPI"));
if (!mGetAPIFunc) {
return false;
}
return true;
}
GMPErr
GMPLoaderImpl::GetAPI(const char* aAPIName,
void* aHostAPI,
void** aPluginAPI)
{
return mGetAPIFunc ? mGetAPIFunc(aAPIName, aHostAPI, aPluginAPI)
: GMPGenericErr;
}
void
GMPLoaderImpl::Shutdown()
{
if (mLib) {
GMPShutdownFunc shutdownFunc = reinterpret_cast<GMPShutdownFunc>(PR_FindFunctionSymbol(mLib, "GMPShutdown"));
if (shutdownFunc) {
shutdownFunc();
}
PR_UnloadLibrary(mLib);
mLib = nullptr;
}
}
} // namespace gmp
} // namespace mozilla

76
dom/media/gmp/GMPLoader.h Normal file
Просмотреть файл

@ -0,0 +1,76 @@
/* -*- 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/. */
#ifndef GMP_LOADER_H__
#define GMP_LOADER_H__
#include <stdint.h>
#include "gmp-entrypoints.h"
namespace mozilla {
namespace gmp {
class SandboxStarter {
public:
virtual ~SandboxStarter() {}
virtual void Start() = 0;
};
#if (defined(XP_LINUX) || defined(XP_MACOSX))
#define SANDBOX_NOT_STATICALLY_LINKED_INTO_PLUGIN_CONTAINER 1
#endif
// Encapsulates generating the device-bound node id, activating the sandbox,
// loading the GMP, and passing the node id to the GMP (in that order).
//
// In Desktop Gecko, the implementation of this lives in plugin-container,
// and is passed into XUL code from on startup. The GMP IPC child protocol actor
// uses this interface to load and retrieve interfaces from the GMPs.
//
// In Desktop Gecko the implementation lives in the plugin-container so that
// it can be covered by DRM vendor's voucher.
//
// On Android the GMPLoader implementation lives in libxul (because for the time
// being GMPLoader relies upon NSPR, which we can't use in plugin-container
// on Android).
//
// There is exactly one GMPLoader per GMP child process, and only one GMP
// per child process (so the GMPLoader only loads one GMP).
class GMPLoader {
public:
virtual ~GMPLoader() {}
// Calculates the device-bound node id, then activates the sandbox,
// then loads the GMP library and (if applicable) passes the bound node id
// to the GMP.
virtual bool Load(const char* aLibPath,
uint32_t aLibPathLen,
char* aOriginSalt,
uint32_t aOriginSaltLen,
const GMPPlatformAPI* aPlatformAPI) = 0;
// Retrieves an interface pointer from the GMP.
virtual GMPErr GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI) = 0;
// Calls the GMPShutdown function exported by the GMP lib, and unloads the
// plugin library.
virtual void Shutdown() = 0;
#ifdef SANDBOX_NOT_STATICALLY_LINKED_INTO_PLUGIN_CONTAINER
// Encapsulates starting the sandbox on Linux and MacOSX.
// TODO: Remove this, and put sandbox in plugin-container on all platforms.
virtual void SetStartSandboxStarter(SandboxStarter* aStarter) = 0;
#endif
};
// On Desktop, this function resides in plugin-container.
// On Mobile, this function resides in XUL.
GMPLoader* CreateGMPLoader(SandboxStarter* aStarter);
} // namespace gmp
} // namespace mozilla
#endif // GMP_LOADER_H__

Просмотреть файл

@ -59,5 +59,21 @@ GMPProcessChild::CleanUp()
BackgroundHangMonitor::Shutdown();
}
GMPLoader* GMPProcessChild::mLoader = nullptr;
/* static */
void
GMPProcessChild::SetGMPLoader(GMPLoader* aLoader)
{
mLoader = aLoader;
}
/* static */
GMPLoader*
GMPProcessChild::GetGMPLoader()
{
return mLoader;
}
} // namespace gmp
} // namespace mozilla

Просмотреть файл

@ -12,6 +12,8 @@
namespace mozilla {
namespace gmp {
class GMPLoader;
class GMPProcessChild MOZ_FINAL : public mozilla::ipc::ProcessChild {
protected:
typedef mozilla::ipc::ProcessChild ProcessChild;
@ -23,9 +25,15 @@ public:
virtual bool Init() MOZ_OVERRIDE;
virtual void CleanUp() MOZ_OVERRIDE;
// Set/get the GMPLoader singleton for this child process.
// Note: The GMPLoader is not deleted by this object, the caller of
// SetGMPLoader() must manage the GMPLoader's lifecycle.
static void SetGMPLoader(GMPLoader* aHost);
static GMPLoader* GetGMPLoader();
private:
GMPChild mPlugin;
static GMPLoader* mLoader;
DISALLOW_COPY_AND_ASSIGN(GMPProcessChild);
};

Просмотреть файл

@ -39,6 +39,7 @@ EXPORTS += [
'GMPDecryptorParent.h',
'GMPDecryptorProxy.h',
'GMPEncryptedBufferDataImpl.h',
'GMPLoader.h',
'GMPMessageUtils.h',
'GMPParent.h',
'GMPPlatform.h',
@ -62,6 +63,13 @@ EXPORTS += [
'GMPVideoPlaneImpl.h',
]
# We link GMPLoader into xul on B2G/Fennec as its code does not need to be
# covered by a DRM vendor's voucher.
if CONFIG['OS_TARGET'] == 'Android':
SOURCES += [
'GMPLoader.cpp',
]
UNIFIED_SOURCES += [
'GMPAudioDecoderChild.cpp',
'GMPAudioDecoderParent.cpp',

Просмотреть файл

@ -33,6 +33,13 @@ LOCAL_INCLUDES += [
'/xpcom/base',
]
# We link GMPLoader into plugin-container on desktop so that its code is
# covered by the desktop DRM vendor's voucher.
if CONFIG['OS_TARGET'] != 'Android':
SOURCES += [
'../../dom/media/gmp/GMPLoader.cpp',
]
if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
# For sandbox includes and the include dependencies those have
LOCAL_INCLUDES += [

Просмотреть файл

@ -6,6 +6,7 @@
#include "nsXPCOM.h"
#include "nsXULAppAPI.h"
#include "nsAutoPtr.h"
// FIXME/cjones testing
#if !defined(OS_WIN)
@ -21,6 +22,8 @@
#include "nsSetDllDirectory.h"
#endif
#include "GMPLoader.h"
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
#include "sandbox/chromium/base/basictypes.h"
#include "sandbox/win/src/sandbox.h"
@ -82,8 +85,29 @@ void StartSandboxCallback()
target_service->LowerToken();
}
}
class WinSandboxStarter : public mozilla::gmp::SandboxStarter {
public:
virtual void Start() MOZ_OVERRIDE {
StartSandboxCallback();
}
};
#endif
mozilla::gmp::SandboxStarter*
MakeSandboxStarter()
{
// Note: Linux and MacOSX create their SandboxStarters inside xul code,
// they need to change to statically link their sandbox code into
// plugin-container. Once they do that, we can create SandboxStarters for
// them here.
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
return new WinSandboxStarter();
#else
return nullptr;
#endif
}
int
content_process_main(int argc, char* argv[])
{
@ -154,8 +178,16 @@ content_process_main(int argc, char* argv[])
}
#endif
#endif
nsresult rv = XRE_InitChildProcess(argc, argv);
nsAutoPtr<mozilla::gmp::GMPLoader> loader;
#if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_GONK)
// On desktop, the GMPLoader lives in plugin-container, so that its
// code can be covered by an EME/GMP vendor's voucher.
nsAutoPtr<mozilla::gmp::SandboxStarter> starter(MakeSandboxStarter());
if (XRE_GetProcessType() == GeckoProcessType_GMPlugin) {
loader = mozilla::gmp::CreateGMPLoader(starter);
}
#endif
nsresult rv = XRE_InitChildProcess(argc, argv, loader);
NS_ENSURE_SUCCESS(rv, 1);
return 0;

Просмотреть файл

@ -445,11 +445,11 @@ ChildProcessInit(int argc, char* argv[])
void (*fXRE_SetProcessType)(char*);
xul_dlsym("XRE_SetProcessType", &fXRE_SetProcessType);
mozglueresult (*fXRE_InitChildProcess)(int, char**);
mozglueresult (*fXRE_InitChildProcess)(int, char**, void*);
xul_dlsym("XRE_InitChildProcess", &fXRE_InitChildProcess);
fXRE_SetProcessType(argv[--argc]);
return fXRE_InitChildProcess(argc, argv);
return fXRE_InitChildProcess(argc, argv, nullptr);
}

Просмотреть файл

@ -71,6 +71,7 @@
#include "mozilla/ipc/XPCShellEnvironment.h"
#include "GMPProcessChild.h"
#include "GMPLoader.h"
#include "GeckoProfiler.h"
@ -104,6 +105,10 @@ using mozilla::dom::ContentProcess;
using mozilla::dom::ContentParent;
using mozilla::dom::ContentChild;
using mozilla::gmp::GMPLoader;
using mozilla::gmp::CreateGMPLoader;
using mozilla::gmp::GMPProcessChild;
using mozilla::ipc::TestShellParent;
using mozilla::ipc::TestShellCommandParent;
using mozilla::ipc::XPCShellEnvironment;
@ -288,12 +293,25 @@ SetTaskbarGroupId(const nsString& aId)
nsresult
XRE_InitChildProcess(int aArgc,
char* aArgv[])
char* aArgv[],
GMPLoader* aGMPLoader)
{
NS_ENSURE_ARG_MIN(aArgc, 2);
NS_ENSURE_ARG_POINTER(aArgv);
NS_ENSURE_ARG_POINTER(aArgv[0]);
#if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_GONK)
// On non-Fennec Gecko, the GMPLoader code resides in plugin-container,
// and we must forward it through to the GMP code here.
GMPProcessChild::SetGMPLoader(aGMPLoader);
#else
// On Fennec, the GMPLoader's code resides inside XUL (because for the time
// being GMPLoader relies upon NSPR, which we can't use in plugin-container
// on Android), so we create it here inside XUL and pass it to the GMP code.
nsAutoPtr<GMPLoader> loader(CreateGMPLoader(nullptr));
GMPProcessChild::SetGMPLoader(loader);
#endif
#if defined(XP_WIN)
// From the --attach-console support in nsNativeAppSupportWin.cpp, but
// here we are a content child process, so we always attempt to attach

Просмотреть файл

@ -393,9 +393,16 @@ XRE_API(bool,
XRE_SetRemoteExceptionHandler, (const char* aPipe))
#endif
namespace mozilla {
namespace gmp {
class GMPLoader;
} // namespace gmp
} // namepsace mozilla
XRE_API(nsresult,
XRE_InitChildProcess, (int aArgc,
char* aArgv[]))
char* aArgv[],
mozilla::gmp::GMPLoader* aGMPLoader))
XRE_API(GeckoProcessType,
XRE_GetProcessType, ())