Bug 1315850 - Shutdown ChromiumCDMParent. r=gerald

MozReview-Commit-ID: E82ETFS90eH

--HG--
extra : rebase_source : 6f0d72f76e313b55f7c905d5878c63b8d7292b1b
This commit is contained in:
Chris Pearce 2017-03-09 17:34:18 +13:00
Родитель 4c421503a8
Коммит bf0e67458a
3 изменённых файлов: 227 добавлений и 12 удалений

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

@ -6,6 +6,7 @@
#include "ChromiumCDMParent.h"
#include "mozilla/gmp/GMPTypes.h"
#include "GMPContentChild.h"
#include "GMPContentParent.h"
#include "mozilla/Unused.h"
#include "ChromiumCDMProxy.h"
#include "mozilla/dom/MediaKeyMessageEventBinding.h"
@ -33,6 +34,9 @@ ChromiumCDMParent::Init(ChromiumCDMProxy* aProxy,
bool aAllowPersistentState)
{
GMP_LOG("ChromiumCDMParent::Init(this=%p)", this);
if (!aProxy) {
return false;
}
mProxy = aProxy;
return SendInit(aAllowDistinctiveIdentifier, aAllowPersistentState);
}
@ -45,6 +49,12 @@ ChromiumCDMParent::CreateSession(uint32_t aCreateSessionToken,
const nsTArray<uint8_t>& aInitData)
{
GMP_LOG("ChromiumCDMParent::CreateSession(this=%p)", this);
if (mIsShutdown) {
RejectPromise(aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("CDM is shutdown."));
return;
}
if (!SendCreateSessionAndGenerateRequest(
aPromiseId, aSessionType, aInitDataType, aInitData)) {
RejectPromise(
@ -61,6 +71,12 @@ ChromiumCDMParent::SetServerCertificate(uint32_t aPromiseId,
const nsTArray<uint8_t>& aCert)
{
GMP_LOG("ChromiumCDMParent::SetServerCertificate(this=%p)", this);
if (mIsShutdown) {
RejectPromise(aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("CDM is shutdown."));
return;
}
if (!SendSetServerCertificate(aPromiseId, aCert)) {
RejectPromise(
aPromiseId,
@ -75,6 +91,12 @@ ChromiumCDMParent::UpdateSession(const nsCString& aSessionId,
const nsTArray<uint8_t>& aResponse)
{
GMP_LOG("ChromiumCDMParent::UpdateSession(this=%p)", this);
if (mIsShutdown) {
RejectPromise(aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("CDM is shutdown."));
return;
}
if (!SendUpdateSession(aPromiseId, aSessionId, aResponse)) {
RejectPromise(
aPromiseId,
@ -88,6 +110,12 @@ ChromiumCDMParent::CloseSession(const nsCString& aSessionId,
uint32_t aPromiseId)
{
GMP_LOG("ChromiumCDMParent::CloseSession(this=%p)", this);
if (mIsShutdown) {
RejectPromise(aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("CDM is shutdown."));
return;
}
if (!SendCloseSession(aPromiseId, aSessionId)) {
RejectPromise(
aPromiseId,
@ -101,6 +129,12 @@ ChromiumCDMParent::RemoveSession(const nsCString& aSessionId,
uint32_t aPromiseId)
{
GMP_LOG("ChromiumCDMParent::RemoveSession(this=%p)", this);
if (mIsShutdown) {
RejectPromise(aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("CDM is shutdown."));
return;
}
if (!SendRemoveSession(aPromiseId, aSessionId)) {
RejectPromise(
aPromiseId,
@ -135,6 +169,10 @@ InitCDMInputBuffer(gmp::CDMInputBuffer& aBuffer, MediaRawData* aSample)
RefPtr<DecryptPromise>
ChromiumCDMParent::Decrypt(MediaRawData* aSample)
{
if (mIsShutdown) {
return DecryptPromise::CreateAndReject(DecryptResult(GenericErr, aSample),
__func__);
}
CDMInputBuffer buffer;
if (!InitCDMInputBuffer(buffer, aSample)) {
return DecryptPromise::CreateAndReject(DecryptResult(GenericErr, aSample),
@ -156,7 +194,12 @@ ChromiumCDMParent::Decrypt(MediaRawData* aSample)
ipc::IPCResult
ChromiumCDMParent::Recv__delete__()
{
MOZ_ASSERT(mIsShutdown);
GMP_LOG("ChromiumCDMParent::Recv__delete__(this=%p)", this);
if (mContentParent) {
mContentParent->ChromiumCDMDestroyed(this);
mContentParent = nullptr;
}
return IPC_OK();
}
@ -169,7 +212,7 @@ ChromiumCDMParent::RecvOnResolveNewSessionPromise(const uint32_t& aPromiseId,
this,
aPromiseId,
aSessionId.get());
if (!mProxy) {
if (!mProxy || mIsShutdown) {
return IPC_OK();
}
@ -199,7 +242,9 @@ ChromiumCDMParent::ResolvePromise(uint32_t aPromiseId)
GMP_LOG(
"ChromiumCDMParent::ResolvePromise(this=%p, pid=%u)", this, aPromiseId);
if (!mProxy) {
// Note: The MediaKeys rejects all pending DOM promises when it
// initiates shutdown.
if (!mProxy || mIsShutdown) {
return;
}
NS_DispatchToMainThread(NewRunnableMethod<uint32_t>(
@ -247,7 +292,9 @@ ChromiumCDMParent::RejectPromise(uint32_t aPromiseId,
{
GMP_LOG(
"ChromiumCDMParent::RejectPromise(this=%p, pid=%u)", this, aPromiseId);
if (!mProxy) {
// Note: The MediaKeys rejects all pending DOM promises when it
// initiates shutdown.
if (!mProxy || mIsShutdown) {
return;
}
NS_DispatchToMainThread(NewRunnableMethod<uint32_t, nsresult, nsCString>(
@ -291,7 +338,7 @@ ChromiumCDMParent::RecvOnSessionMessage(const nsCString& aSessionId,
GMP_LOG("ChromiumCDMParent::RecvOnSessionMessage(this=%p, sid=%s)",
this,
aSessionId.get());
if (!mProxy) {
if (!mProxy || mIsShutdown) {
return IPC_OK();
}
RefPtr<CDMProxy> proxy = mProxy;
@ -334,7 +381,7 @@ ChromiumCDMParent::RecvOnSessionKeysChange(
nsTArray<CDMKeyInformation>&& aKeysInfo)
{
GMP_LOG("ChromiumCDMParent::RecvOnSessionKeysChange(this=%p)", this);
if (!mProxy) {
if (!mProxy || mIsShutdown) {
return IPC_OK();
}
bool keyStatusesChange = false;
@ -364,7 +411,7 @@ ChromiumCDMParent::RecvOnExpirationChange(const nsCString& aSessionId,
GMP_LOG("ChromiumCDMParent::RecvOnExpirationChange(this=%p) time=%lf",
this,
aSecondsSinceEpoch);
if (!mProxy) {
if (!mProxy || mIsShutdown) {
return IPC_OK();
}
NS_DispatchToMainThread(NewRunnableMethod<nsString, UnixTime>(
@ -379,7 +426,7 @@ ipc::IPCResult
ChromiumCDMParent::RecvOnSessionClosed(const nsCString& aSessionId)
{
GMP_LOG("ChromiumCDMParent::RecvOnSessionClosed(this=%p)", this);
if (!mProxy) {
if (!mProxy || mIsShutdown) {
return IPC_OK();
}
NS_DispatchToMainThread(
@ -396,7 +443,7 @@ ChromiumCDMParent::RecvOnLegacySessionError(const nsCString& aSessionId,
const nsCString& aMessage)
{
GMP_LOG("ChromiumCDMParent::RecvOnLegacySessionError(this=%p)", this);
if (!mProxy) {
if (!mProxy || mIsShutdown) {
return IPC_OK();
}
NS_DispatchToMainThread(
@ -432,6 +479,10 @@ ChromiumCDMParent::RecvDecrypted(const uint32_t& aId,
this,
aId,
aStatus);
if (mIsShutdown) {
MOZ_ASSERT(mDecrypts.IsEmpty());
return IPC_OK();
}
for (size_t i = 0; i < mDecrypts.Length(); i++) {
if (mDecrypts[i]->mId == aId) {
mDecrypts[i]->PostResult(ToDecryptStatus(aStatus), aData);
@ -445,7 +496,7 @@ ChromiumCDMParent::RecvDecrypted(const uint32_t& aId,
ipc::IPCResult
ChromiumCDMParent::RecvDecoded(const CDMVideoFrame& aFrame)
{
if (mDecodePromise.IsEmpty()) {
if (mIsShutdown || mDecodePromise.IsEmpty()) {
return IPC_OK();
}
VideoData::YCbCrBuffer b;
@ -505,6 +556,10 @@ ChromiumCDMParent::RecvDecoded(const CDMVideoFrame& aFrame)
ipc::IPCResult
ChromiumCDMParent::RecvDecodeFailed(const uint32_t& aStatus)
{
if (mIsShutdown) {
MOZ_ASSERT(mDecodePromise.IsEmpty());
return IPC_OK();
}
mDecodePromise.RejectIfExists(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("ChromiumCDMParent::RecvDecodeFailed")),
@ -516,7 +571,7 @@ ipc::IPCResult
ChromiumCDMParent::RecvShutdown()
{
GMP_LOG("ChromiumCDMParent::RecvShutdown(this=%p)", this);
// TODO: SendDestroy(), call Terminated.
Shutdown();
return IPC_OK();
}
@ -524,6 +579,26 @@ void
ChromiumCDMParent::ActorDestroy(ActorDestroyReason aWhy)
{
GMP_LOG("ChromiumCDMParent::ActorDestroy(this=%p, reason=%d)", this, aWhy);
MOZ_ASSERT(!mActorDestroyed);
mActorDestroyed = true;
if (!mIsShutdown) {
// Plugin crash.
MOZ_ASSERT(aWhy == AbnormalShutdown);
Shutdown();
}
MOZ_ASSERT(mIsShutdown);
RefPtr<ChromiumCDMParent> kungFuDeathGrip(this);
if (mContentParent) {
mContentParent->ChromiumCDMDestroyed(this);
mContentParent = nullptr;
}
bool abnormalShutdown = (aWhy == AbnormalShutdown);
if (abnormalShutdown && mProxy) {
RefPtr<Runnable> task =
NewRunnableMethod(mProxy, &ChromiumCDMProxy::Terminated);
NS_DispatchToMainThread(task);
}
MaybeDisconnect(abnormalShutdown);
}
RefPtr<MediaDataDecoder::InitPromise>
@ -532,6 +607,13 @@ ChromiumCDMParent::InitializeVideoDecoder(
const VideoInfo& aInfo,
RefPtr<layers::ImageContainer> aImageContainer)
{
if (mIsShutdown) {
return MediaDataDecoder::InitPromise::CreateAndReject(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("ChromiumCDMParent is shutdown")),
__func__);
}
if (!SendInitializeVideoDecoder(aConfig)) {
return MediaDataDecoder::InitPromise::CreateAndReject(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
@ -539,6 +621,7 @@ ChromiumCDMParent::InitializeVideoDecoder(
__func__);
}
mVideoDecoderInitialized = true;
mImageContainer = aImageContainer;
mVideoInfo = aInfo;
@ -551,9 +634,14 @@ ChromiumCDMParent::RecvOnDecoderInitDone(const uint32_t& aStatus)
GMP_LOG("ChromiumCDMParent::RecvOnDecoderInitDone(this=%p, status=%u)",
this,
aStatus);
if (mIsShutdown) {
MOZ_ASSERT(mInitVideoDecoderPromise.IsEmpty());
return IPC_OK();
}
if (aStatus == static_cast<uint32_t>(cdm::kSuccess)) {
mInitVideoDecoderPromise.ResolveIfExists(TrackInfo::kVideoTrack, __func__);
} else {
mVideoDecoderInitialized = false;
mInitVideoDecoderPromise.RejectIfExists(
MediaResult(
NS_ERROR_DOM_MEDIA_FATAL_ERR,
@ -566,6 +654,13 @@ ChromiumCDMParent::RecvOnDecoderInitDone(const uint32_t& aStatus)
RefPtr<MediaDataDecoder::DecodePromise>
ChromiumCDMParent::DecryptAndDecodeFrame(MediaRawData* aSample)
{
if (mIsShutdown) {
return MediaDataDecoder::DecodePromise::CreateAndReject(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("ChromiumCDMParent is shutdown")),
__func__);
}
CDMInputBuffer buffer;
if (!InitCDMInputBuffer(buffer, aSample)) {
@ -592,6 +687,13 @@ ChromiumCDMParent::DecryptAndDecodeFrame(MediaRawData* aSample)
RefPtr<MediaDataDecoder::FlushPromise>
ChromiumCDMParent::FlushVideoDecoder()
{
if (mIsShutdown) {
return MediaDataDecoder::FlushPromise::CreateAndReject(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("ChromiumCDMParent is shutdown")),
__func__);
}
mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
if (!SendResetVideoDecoder()) {
return MediaDataDecoder::FlushPromise::CreateAndReject(
@ -604,7 +706,11 @@ ChromiumCDMParent::FlushVideoDecoder()
ipc::IPCResult
ChromiumCDMParent::RecvResetVideoDecoderComplete()
{
mFlushDecoderPromise.Resolve(true, __func__);
if (mIsShutdown) {
MOZ_ASSERT(mFlushDecoderPromise.IsEmpty());
return IPC_OK();
}
mFlushDecoderPromise.ResolveIfExists(true, __func__);
return IPC_OK();
}
@ -612,6 +718,12 @@ RefPtr<MediaDataDecoder::DecodePromise>
ChromiumCDMParent::Drain()
{
MOZ_ASSERT(mDecodePromise.IsEmpty(), "Must wait for decoding to complete");
if (mIsShutdown) {
return MediaDataDecoder::DecodePromise::CreateAndReject(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("ChromiumCDMParent is shutdown")),
__func__);
}
RefPtr<MediaDataDecoder::DecodePromise> p = mDecodePromise.Ensure(__func__);
if (!SendDrain()) {
@ -623,21 +735,70 @@ ChromiumCDMParent::Drain()
ipc::IPCResult
ChromiumCDMParent::RecvDrainComplete()
{
if (mIsShutdown) {
MOZ_ASSERT(mDecodePromise.IsEmpty());
return IPC_OK();
}
mDecodePromise.ResolveIfExists(MediaDataDecoder::DecodedData(), __func__);
return IPC_OK();
}
RefPtr<ShutdownPromise>
ChromiumCDMParent::ShutdownVideoDecoder()
{
if (mIsShutdown || !mVideoDecoderInitialized) {
return ShutdownPromise::CreateAndResolve(true, __func__);
}
mInitVideoDecoderPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED,
__func__);
MOZ_ASSERT(mDecodePromise.IsEmpty());
mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
MOZ_ASSERT(mFlushDecoderPromise.IsEmpty());
if (!SendDeinitializeVideoDecoder()) {
return ShutdownPromise::CreateAndResolve(true, __func__);
}
mVideoDecoderInitialized = false;
return ShutdownPromise::CreateAndResolve(true, __func__);
}
void
ChromiumCDMParent::Shutdown()
{
GMP_LOG("ChromiumCDMParent::Shutdown(this=%p)", this);
if (mIsShutdown) {
return;
}
mIsShutdown = true;
for (RefPtr<DecryptJob>& decrypt : mDecrypts) {
decrypt->PostResult(AbortedErr);
}
mDecrypts.Clear();
if (mVideoDecoderInitialized && !mActorDestroyed) {
Unused << SendDeinitializeVideoDecoder();
mVideoDecoderInitialized = false;
}
// Note: MediaKeys rejects all outstanding promises when it initiates shutdown.
mPromiseToCreateSessionToken.Clear();
mInitVideoDecoderPromise.RejectIfExists(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("ChromiumCDMParent is shutdown")),
__func__);
mDecodePromise.RejectIfExists(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("ChromiumCDMParent is shutdown")),
__func__);
mFlushDecoderPromise.RejectIfExists(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("ChromiumCDMParent is shutdown")),
__func__);
if (!mActorDestroyed) {
Unused << SendDestroy();
}
}
} // namespace gmp
} // namespace mozilla

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

@ -75,6 +75,8 @@ public:
RefPtr<ShutdownPromise> ShutdownVideoDecoder();
void Shutdown();
protected:
~ChromiumCDMParent() {}
@ -135,6 +137,10 @@ protected:
uint64_t mLastStreamOffset = 0;
MozPromiseHolder<MediaDataDecoder::FlushPromise> mFlushDecoderPromise;
bool mIsShutdown = false;
bool mVideoDecoderInitialized = false;
bool mActorDestroyed = false;
};
} // namespace gmp

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

@ -202,6 +202,13 @@ ChromiumCDMProxy::CreateSession(uint32_t aCreateSessionToken,
uint32_t initDataType = ToCDMInitDataType(aInitDataType);
RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
if (!cdm) {
RejectPromise(aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Null CDM in CreateSession"));
return;
}
mGMPThread->Dispatch(
NewRunnableMethod<uint32_t,
uint32_t,
@ -236,6 +243,13 @@ ChromiumCDMProxy::SetServerCertificate(PromiseId aPromiseId,
aCert.Length());
RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
if (!cdm) {
RejectPromise(aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Null CDM in SetServerCertificate"));
return;
}
mGMPThread->Dispatch(NewRunnableMethod<uint32_t, nsTArray<uint8_t>>(
cdm,
&gmp::ChromiumCDMParent::SetServerCertificate,
@ -255,6 +269,12 @@ ChromiumCDMProxy::UpdateSession(const nsAString& aSessionId,
aResponse.Length());
RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
if (!cdm) {
RejectPromise(aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Null CDM in UpdateSession"));
return;
}
mGMPThread->Dispatch(
NewRunnableMethod<nsCString, uint32_t, nsTArray<uint8_t>>(
cdm,
@ -274,6 +294,12 @@ ChromiumCDMProxy::CloseSession(const nsAString& aSessionId,
aPromiseId);
RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
if (!cdm) {
RejectPromise(aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Null CDM in CloseSession"));
return;
}
mGMPThread->Dispatch(NewRunnableMethod<nsCString, uint32_t>(
cdm,
&gmp::ChromiumCDMParent::CloseSession,
@ -291,6 +317,12 @@ ChromiumCDMProxy::RemoveSession(const nsAString& aSessionId,
aPromiseId);
RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
if (!cdm) {
RejectPromise(aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Null CDM in RemoveSession"));
return;
}
mGMPThread->Dispatch(NewRunnableMethod<nsCString, uint32_t>(
cdm,
&gmp::ChromiumCDMParent::RemoveSession,
@ -301,7 +333,19 @@ ChromiumCDMProxy::RemoveSession(const nsAString& aSessionId,
void
ChromiumCDMProxy::Shutdown()
{
MOZ_ASSERT(NS_IsMainThread());
EME_LOG("ChromiumCDMProxy::Shutdown()");
mKeys.Clear();
RefPtr<gmp::ChromiumCDMParent> cdm;
{
MutexAutoLock lock(mCDMMutex);
cdm.swap(mCDM);
}
if (cdm) {
nsCOMPtr<nsIRunnable> task =
NewRunnableMethod(mCDM, &gmp::ChromiumCDMParent::Shutdown);
mGMPThread->Dispatch(task.forget());
}
}
void
@ -491,6 +535,10 @@ RefPtr<DecryptPromise>
ChromiumCDMProxy::Decrypt(MediaRawData* aSample)
{
RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
if (!cdm) {
return DecryptPromise::CreateAndReject(DecryptResult(AbortedErr, aSample),
__func__);
}
RefPtr<MediaRawData> sample = aSample;
return InvokeAsync(
mGMPThread, __func__, [cdm, sample]() { return cdm->Decrypt(sample); });