Bug 1315850 - Handle sending and receiving key session messages. r=gerald

MozReview-Commit-ID: 6hLPFLFRD5I

--HG--
extra : rebase_source : 0931d65116bf0c499933efc58cae97b275b0ba85
This commit is contained in:
Chris Pearce 2017-03-08 16:41:06 +13:00
Родитель a987efe1ed
Коммит 0c935efca9
3 изменённых файлов: 299 добавлений и 1 удалений

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

@ -8,6 +8,8 @@
#include "GMPContentChild.h"
#include "mozilla/Unused.h"
#include "ChromiumCDMProxy.h"
#include "mozilla/dom/MediaKeyMessageEventBinding.h"
#include "content_decryption_module.h"
namespace mozilla {
namespace gmp {
@ -28,6 +30,55 @@ ChromiumCDMParent::Init(ChromiumCDMProxy* aProxy,
return SendInit(aAllowDistinctiveIdentifier, aAllowPersistentState);
}
void
ChromiumCDMParent::SetServerCertificate(uint32_t aPromiseId,
const nsTArray<uint8_t>& aCert)
{
if (!SendSetServerCertificate(aPromiseId, aCert)) {
RejectPromise(
aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Failed to send setServerCertificate to CDM process"));
}
}
void
ChromiumCDMParent::UpdateSession(const nsCString& aSessionId,
uint32_t aPromiseId,
const nsTArray<uint8_t>& aResponse)
{
if (!SendUpdateSession(aPromiseId, aSessionId, aResponse)) {
RejectPromise(
aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Failed to send updateSession to CDM process"));
}
}
void
ChromiumCDMParent::CloseSession(const nsCString& aSessionId,
uint32_t aPromiseId)
{
if (!SendCloseSession(aPromiseId, aSessionId)) {
RejectPromise(
aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Failed to send closeSession to CDM process"));
}
}
void
ChromiumCDMParent::RemoveSession(const nsCString& aSessionId,
uint32_t aPromiseId)
{
if (!SendRemoveSession(aPromiseId, aSessionId)) {
RejectPromise(
aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Failed to send removeSession to CDM process"));
}
}
ipc::IPCResult
ChromiumCDMParent::Recv__delete__()
{
@ -44,31 +95,149 @@ ChromiumCDMParent::RecvOnResolveNewSessionPromise(const uint32_t& aPromiseId,
ipc::IPCResult
ChromiumCDMParent::RecvOnResolvePromise(const uint32_t& aPromiseId)
{
if (!mProxy) {
return IPC_OK();
}
NS_DispatchToMainThread(NewRunnableMethod<uint32_t>(
mProxy, &ChromiumCDMProxy::ResolvePromise, aPromiseId));
return IPC_OK();
}
static nsresult
ToNsresult(uint32_t aError)
{
switch (static_cast<cdm::Error>(aError)) {
case cdm::kNotSupportedError:
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
case cdm::kInvalidStateError:
return NS_ERROR_DOM_INVALID_STATE_ERR;
case cdm::kInvalidAccessError:
// Note: Chrome converts kInvalidAccessError to TypeError, since the
// Chromium CDM API doesn't have a type error enum value. The EME spec
// requires TypeError in some places, so we do the same conversion.
// See bug 1313202.
return NS_ERROR_DOM_TYPE_ERR;
case cdm::kQuotaExceededError:
return NS_ERROR_DOM_QUOTA_EXCEEDED_ERR;
case cdm::kUnknownError:
return NS_ERROR_DOM_UNKNOWN_ERR; // Note: Unique placeholder.
case cdm::kClientError:
return NS_ERROR_DOM_ABORT_ERR; // Note: Unique placeholder.
case cdm::kOutputError:
return NS_ERROR_DOM_SECURITY_ERR; // Note: Unique placeholder.
};
MOZ_ASSERT_UNREACHABLE("Invalid cdm::Error enum value.");
return NS_ERROR_DOM_TIMEOUT_ERR; // Note: Unique placeholder.
}
void
ChromiumCDMParent::RejectPromise(uint32_t aPromiseId,
nsresult aError,
const nsCString& aErrorMessage)
{
if (!mProxy) {
return;
}
NS_DispatchToMainThread(NewRunnableMethod<uint32_t, nsresult, nsCString>(
mProxy,
&ChromiumCDMProxy::RejectPromise,
aPromiseId,
aError,
aErrorMessage));
}
ipc::IPCResult
ChromiumCDMParent::RecvOnRejectPromise(const uint32_t& aPromiseId,
const uint32_t& aError,
const uint32_t& aSystemCode,
const nsCString& aErrorMessage)
{
RejectPromise(aPromiseId, ToNsresult(aError), aErrorMessage);
return IPC_OK();
}
static dom::MediaKeyMessageType
ToDOMMessageType(uint32_t aMessageType)
{
switch (static_cast<cdm::MessageType>(aMessageType)) {
case cdm::kLicenseRequest:
return dom::MediaKeyMessageType::License_request;
case cdm::kLicenseRenewal:
return dom::MediaKeyMessageType::License_renewal;
case cdm::kLicenseRelease:
return dom::MediaKeyMessageType::License_release;
}
MOZ_ASSERT_UNREACHABLE("Invalid cdm::MessageType enum value.");
return dom::MediaKeyMessageType::License_request;
}
ipc::IPCResult
ChromiumCDMParent::RecvOnSessionMessage(const nsCString& aSessionId,
const uint32_t& aMessageType,
nsTArray<uint8_t>&& aMessage)
{
if (!mProxy) {
return IPC_OK();
}
RefPtr<CDMProxy> proxy = mProxy;
nsString sid = NS_ConvertUTF8toUTF16(aSessionId);
dom::MediaKeyMessageType messageType = ToDOMMessageType(aMessageType);
nsTArray<uint8_t> msg(Move(aMessage));
NS_DispatchToMainThread(
NS_NewRunnableFunction([proxy, sid, messageType, msg]() mutable {
proxy->OnSessionMessage(sid, messageType, msg);
}));
return IPC_OK();
}
static dom::MediaKeyStatus
ToDOMMediaKeyStatus(uint32_t aStatus)
{
switch (static_cast<cdm::KeyStatus>(aStatus)) {
case cdm::kUsable:
return dom::MediaKeyStatus::Usable;
case cdm::kInternalError:
return dom::MediaKeyStatus::Internal_error;
case cdm::kExpired:
return dom::MediaKeyStatus::Expired;
case cdm::kOutputRestricted:
return dom::MediaKeyStatus::Output_restricted;
case cdm::kOutputDownscaled:
return dom::MediaKeyStatus::Output_downscaled;
case cdm::kStatusPending:
return dom::MediaKeyStatus::Status_pending;
case cdm::kReleased:
return dom::MediaKeyStatus::Released;
}
MOZ_ASSERT_UNREACHABLE("Invalid cdm::KeyStatus enum value.");
return dom::MediaKeyStatus::Internal_error;
}
ipc::IPCResult
ChromiumCDMParent::RecvOnSessionKeysChange(
const nsCString& aSessionId,
nsTArray<CDMKeyInformation>&& aKeysInfo)
{
if (!mProxy) {
return IPC_OK();
}
bool keyStatusesChange = false;
{
CDMCaps::AutoLock caps(mProxy->Capabilites());
for (size_t i = 0; i < aKeysInfo.Length(); i++) {
keyStatusesChange |=
caps.SetKeyStatus(aKeysInfo[i].mKeyId(),
NS_ConvertUTF8toUTF16(aSessionId),
dom::Optional<dom::MediaKeyStatus>(
ToDOMMediaKeyStatus(aKeysInfo[i].mStatus())));
}
}
if (keyStatusesChange) {
NS_DispatchToMainThread(
NewRunnableMethod<nsString>(mProxy,
&ChromiumCDMProxy::OnKeyStatusesChange,
NS_ConvertUTF8toUTF16(aSessionId)));
}
return IPC_OK();
}
@ -76,12 +245,27 @@ ipc::IPCResult
ChromiumCDMParent::RecvOnExpirationChange(const nsCString& aSessionId,
const double& aSecondsSinceEpoch)
{
if (!mProxy) {
return IPC_OK();
}
NS_DispatchToMainThread(NewRunnableMethod<nsString, UnixTime>(
mProxy,
&ChromiumCDMProxy::OnExpirationChange,
NS_ConvertUTF8toUTF16(aSessionId),
GMPTimestamp(aSecondsSinceEpoch * 1000)));
return IPC_OK();
}
ipc::IPCResult
ChromiumCDMParent::RecvOnSessionClosed(const nsCString& aSessionId)
{
if (!mProxy) {
return IPC_OK();
}
NS_DispatchToMainThread(
NewRunnableMethod<nsString>(mProxy,
&ChromiumCDMProxy::OnSessionClosed,
NS_ConvertUTF8toUTF16(aSessionId)));
return IPC_OK();
}
@ -91,6 +275,17 @@ ChromiumCDMParent::RecvOnLegacySessionError(const nsCString& aSessionId,
const uint32_t& aSystemCode,
const nsCString& aMessage)
{
if (!mProxy) {
return IPC_OK();
}
NS_DispatchToMainThread(
NewRunnableMethod<nsString, nsresult, uint32_t, nsString>(
mProxy,
&ChromiumCDMProxy::OnSessionError,
NS_ConvertUTF8toUTF16(aSessionId),
ToNsresult(aError),
aSystemCode,
NS_ConvertUTF8toUTF16(aMessage)));
return IPC_OK();
}

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

@ -35,7 +35,17 @@ public:
bool aAllowDistinctiveIdentifier,
bool aAllowPersistentState);
// TODO: Add functions for clients to send data to CDM, and
void SetServerCertificate(uint32_t aPromiseId,
const nsTArray<uint8_t>& aCert);
void UpdateSession(const nsCString& aSessionId,
uint32_t aPromiseId,
const nsTArray<uint8_t>& aResponse);
void CloseSession(const nsCString& aSessionId, uint32_t aPromiseId);
void RemoveSession(const nsCString& aSessionId, uint32_t aPromiseId);
// a Close() function.
protected:
@ -71,6 +81,10 @@ protected:
ipc::IPCResult RecvShutdown() override;
void ActorDestroy(ActorDestroyReason aWhy) override;
void RejectPromise(uint32_t aPromiseId,
nsresult aError,
const nsCString& aErrorMessage);
const uint32_t mPluginId;
GMPContentParent* mContentParent;
// Note: this pointer is a weak reference because otherwise it would cause

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

@ -8,6 +8,7 @@
#include "GMPUtils.h"
#include "nsPrintfCString.h"
#include "GMPService.h"
#include "mozilla/dom/MediaKeySession.h"
namespace mozilla {
@ -152,12 +153,24 @@ ChromiumCDMProxy::CreateSession(uint32_t aCreateSessionToken,
void
ChromiumCDMProxy::LoadSession(PromiseId aPromiseId, const nsAString& aSessionId)
{
MOZ_ASSERT(NS_IsMainThread());
RejectPromise(aPromiseId,
NS_ERROR_DOM_NOT_SUPPORTED_ERR,
NS_LITERAL_CSTRING("loadSession is not supported"));
}
void
ChromiumCDMProxy::SetServerCertificate(PromiseId aPromiseId,
nsTArray<uint8_t>& aCert)
{
MOZ_ASSERT(NS_IsMainThread());
mGMPThread->Dispatch(NewRunnableMethod<uint32_t, nsTArray<uint8_t>>(
mCDM,
&gmp::ChromiumCDMParent::SetServerCertificate,
aPromiseId,
Move(aCert)));
}
void
@ -165,18 +178,36 @@ ChromiumCDMProxy::UpdateSession(const nsAString& aSessionId,
PromiseId aPromiseId,
nsTArray<uint8_t>& aResponse)
{
MOZ_ASSERT(NS_IsMainThread());
mGMPThread->Dispatch(NewRunnableMethod<nsCString, uint32_t, nsTArray<uint8_t>>(
mCDM,
&gmp::ChromiumCDMParent::UpdateSession,
NS_ConvertUTF16toUTF8(aSessionId),
aPromiseId,
Move(aResponse)));
}
void
ChromiumCDMProxy::CloseSession(const nsAString& aSessionId,
PromiseId aPromiseId)
{
mGMPThread->Dispatch(NewRunnableMethod<nsCString, uint32_t>(
mCDM,
&gmp::ChromiumCDMParent::CloseSession,
NS_ConvertUTF16toUTF8(aSessionId),
aPromiseId));
}
void
ChromiumCDMProxy::RemoveSession(const nsAString& aSessionId,
PromiseId aPromiseId)
{
mGMPThread->Dispatch(NewRunnableMethod<nsCString, uint32_t>(
mCDM,
&gmp::ChromiumCDMParent::RemoveSession,
NS_ConvertUTF16toUTF8(aSessionId),
aPromiseId));
}
void
@ -242,22 +273,66 @@ ChromiumCDMProxy::OnSessionMessage(const nsAString& aSessionId,
dom::MediaKeyMessageType aMessageType,
nsTArray<uint8_t>& aMessage)
{
MOZ_ASSERT(NS_IsMainThread());
if (mKeys.IsNull()) {
return;
}
RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
if (session) {
session->DispatchKeyMessage(aMessageType, aMessage);
}
}
void
ChromiumCDMProxy::OnKeyStatusesChange(const nsAString& aSessionId)
{
MOZ_ASSERT(NS_IsMainThread());
if (mKeys.IsNull()) {
return;
}
RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
if (session) {
session->DispatchKeyStatusesChange();
}
}
void
ChromiumCDMProxy::OnExpirationChange(const nsAString& aSessionId,
GMPTimestamp aExpiryTime)
{
MOZ_ASSERT(NS_IsMainThread());
if (mKeys.IsNull()) {
return;
}
RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
if (session) {
// Expiry of 0 is interpreted as "never expire". See bug 1345341.
double t = (aExpiryTime == 0) ? std::numeric_limits<double>::quiet_NaN()
: static_cast<double>(aExpiryTime);
session->SetExpiration(t);
}
}
void
ChromiumCDMProxy::OnSessionClosed(const nsAString& aSessionId)
{
MOZ_ASSERT(NS_IsMainThread());
bool keyStatusesChange = false;
{
CDMCaps::AutoLock caps(Capabilites());
keyStatusesChange = caps.RemoveKeysForSession(nsString(aSessionId));
}
if (keyStatusesChange) {
OnKeyStatusesChange(aSessionId);
}
if (mKeys.IsNull()) {
return;
}
RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
if (session) {
session->OnClosed();
}
}
void
@ -273,6 +348,15 @@ ChromiumCDMProxy::OnSessionError(const nsAString& aSessionId,
uint32_t aSystemCode,
const nsAString& aMsg)
{
MOZ_ASSERT(NS_IsMainThread());
if (mKeys.IsNull()) {
return;
}
RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
if (session) {
session->DispatchKeyError(aSystemCode);
}
LogToConsole(aMsg);
}
void
@ -307,11 +391,16 @@ void
ChromiumCDMProxy::GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
nsTArray<nsCString>& aSessionIds)
{
CDMCaps::AutoLock caps(Capabilites());
caps.GetSessionIdsForKeyId(aKeyId, aSessionIds);
}
void
ChromiumCDMProxy::Terminated()
{
if (!mKeys.IsNull()) {
mKeys->Terminated();
}
}
} // namespace mozilla