Fix native fault in WVMMediaSource::DecryptCallback
This change resolves a lifetime issue between the media extractor and media sources. The extractor was being passed as a context object to a callout in the WV libs. In some cases, a pointer to the extractor would be delivered to the callout after the extractor had been released. This change assigns the responsibility of the lifetime of the context object to the media source, to ensure that a ref is always held on the context object during the lifetime of the media source. Change-Id: Ic7a57a1c8496a4798fe590ec356b8a19a4f69967 related-to-bug: 6502322
This commit is contained in:
@@ -93,13 +93,12 @@ bool IsWidevineMedia(const sp<DataSource>& dataSource) {
|
|||||||
WVMExtractorImpl::WVMExtractorImpl(sp<DataSource> dataSource)
|
WVMExtractorImpl::WVMExtractorImpl(sp<DataSource> dataSource)
|
||||||
: mFileMetaData(new MetaData()),
|
: mFileMetaData(new MetaData()),
|
||||||
mDataSource(dataSource),
|
mDataSource(dataSource),
|
||||||
|
mClientContext(new ClientContext()),
|
||||||
mHaveMetaData(false),
|
mHaveMetaData(false),
|
||||||
mUseAdaptiveStreaming(false),
|
mUseAdaptiveStreaming(false),
|
||||||
mIsLiveStream(false),
|
mIsLiveStream(false),
|
||||||
mSession(NULL),
|
mSession(NULL),
|
||||||
mSetupStatus(OK),
|
mSetupStatus(OK)
|
||||||
mUIDIsSet(false),
|
|
||||||
mCryptoPluginMode(false)
|
|
||||||
{
|
{
|
||||||
dataSource->getDrmInfo(sDecryptHandle, &sDrmManagerClient);
|
dataSource->getDrmInfo(sDecryptHandle, &sDrmManagerClient);
|
||||||
|
|
||||||
@@ -161,13 +160,13 @@ void WVMExtractorImpl::Initialize()
|
|||||||
// Use the URI - streaming case, only for widevine:// protocol
|
// Use the URI - streaming case, only for widevine:// protocol
|
||||||
result = WV_Setup(mSession, mDataSource->getUri().string(),
|
result = WV_Setup(mSession, mDataSource->getUri().string(),
|
||||||
"RAW/RAW/RAW;destination=getdata", credentials,
|
"RAW/RAW/RAW;destination=getdata", credentials,
|
||||||
WV_OutputFormat_ES, kStreamCacheSize, this);
|
WV_OutputFormat_ES, kStreamCacheSize, mClientContext.get());
|
||||||
} else {
|
} else {
|
||||||
// No URI supplied or not adaptive, pull data from the stagefright data source.
|
// No URI supplied or not adaptive, pull data from the stagefright data source.
|
||||||
mFileSource = new WVMFileSource(mDataSource);
|
mFileSource = new WVMFileSource(mDataSource);
|
||||||
result = WV_Setup(mSession, mFileSource.get(),
|
result = WV_Setup(mSession, mFileSource.get(),
|
||||||
"RAW/RAW/RAW;destination=getdata", credentials,
|
"RAW/RAW/RAW;destination=getdata", credentials,
|
||||||
WV_OutputFormat_ES, kStreamCacheSize, this);
|
WV_OutputFormat_ES, kStreamCacheSize, mClientContext.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != WV_Status_OK) {
|
if (result != WV_Status_OK) {
|
||||||
@@ -198,21 +197,21 @@ void WVMExtractorImpl::SocketInfoCallback(int fd, int closing, void *context)
|
|||||||
{
|
{
|
||||||
//ALOGD("WVMExtractorImpl::SocketInfoCallback(%d, %d, %p)", fd, closing, context);
|
//ALOGD("WVMExtractorImpl::SocketInfoCallback(%d, %d, %p)", fd, closing, context);
|
||||||
|
|
||||||
WVMExtractorImpl *obj = (WVMExtractorImpl *)context;
|
ClientContext *obj = (ClientContext *)context;
|
||||||
|
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
ALOGW("SocketInfoCallback: missing context!");
|
// Not an error, there are some cases where this is expected
|
||||||
return;
|
return;
|
||||||
} else if (!obj->mUIDIsSet) {
|
} else if (!obj->haveUID()) {
|
||||||
ALOGW("SocketInfoCallback: UID not set!");
|
ALOGW("SocketInfoCallback: UID not set!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!closing) {
|
if (!closing) {
|
||||||
uint32_t kTag = *(uint32_t *)"WVEX";
|
uint32_t kTag = *(uint32_t *)"WVEX";
|
||||||
int res = qtaguid_tagSocket(fd, kTag, obj->mUID);
|
int res = qtaguid_tagSocket(fd, kTag, obj->getUID());
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
ALOGE("Failed tagging socket %d for uid %d (My UID=%d)", fd, obj->mUID, geteuid());
|
ALOGE("Failed tagging socket %d for uid %d (My UID=%d)", fd, obj->getUID(), geteuid());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int res = qtaguid_untagSocket(fd);
|
int res = qtaguid_untagSocket(fd);
|
||||||
@@ -339,10 +338,12 @@ status_t WVMExtractorImpl::readMetaData()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cryptoPluginMode = mClientContext->getCryptoPluginMode();
|
||||||
|
|
||||||
mAudioSource = new WVMMediaSource(mSession, WV_EsSelector_Audio, audioMetaData,
|
mAudioSource = new WVMMediaSource(mSession, WV_EsSelector_Audio, audioMetaData,
|
||||||
mIsLiveStream, mCryptoPluginMode);
|
mIsLiveStream, cryptoPluginMode);
|
||||||
mVideoSource = new WVMMediaSource(mSession, WV_EsSelector_Video, videoMetaData,
|
mVideoSource = new WVMMediaSource(mSession, WV_EsSelector_Video, videoMetaData,
|
||||||
mIsLiveStream, mCryptoPluginMode);
|
mIsLiveStream, cryptoPluginMode);
|
||||||
|
|
||||||
// Since the WVExtractor goes away soon after this, we delegate ownership of some resources
|
// Since the WVExtractor goes away soon after this, we delegate ownership of some resources
|
||||||
// to the constructed media source
|
// to the constructed media source
|
||||||
@@ -351,13 +352,17 @@ status_t WVMExtractorImpl::readMetaData()
|
|||||||
|
|
||||||
mVideoSource->delegateDataSource(mDataSource);
|
mVideoSource->delegateDataSource(mDataSource);
|
||||||
|
|
||||||
|
mClientContext->setAudioSource(mAudioSource);
|
||||||
|
mClientContext->setVideoSource(mVideoSource);
|
||||||
|
mVideoSource->delegateClientContext(mClientContext);
|
||||||
|
|
||||||
mFileMetaData->setCString(kKeyMIMEType, "video/wvm");
|
mFileMetaData->setCString(kKeyMIMEType, "video/wvm");
|
||||||
|
|
||||||
mHaveMetaData = true;
|
mHaveMetaData = true;
|
||||||
|
|
||||||
mInfoListener->configureHeartbeat();
|
mInfoListener->configureHeartbeat();
|
||||||
|
|
||||||
if (mCryptoPluginMode) {
|
if (cryptoPluginMode) {
|
||||||
// In crypto plugin mode, need to trigger the drm plugin to begin
|
// In crypto plugin mode, need to trigger the drm plugin to begin
|
||||||
// license use on playback since the media player isn't involved.
|
// license use on playback since the media player isn't involved.
|
||||||
sDrmManagerClient->setPlaybackStatus(sDecryptHandle, Playback::START, 0);
|
sDrmManagerClient->setPlaybackStatus(sDecryptHandle, Playback::START, 0);
|
||||||
@@ -534,20 +539,13 @@ bool WVMExtractorImpl::getAdaptiveStreamingMode() const
|
|||||||
void WVMExtractorImpl::setCryptoPluginMode(bool cryptoPluginMode)
|
void WVMExtractorImpl::setCryptoPluginMode(bool cryptoPluginMode)
|
||||||
{
|
{
|
||||||
//ALOGD("WVMExtractorImpl::setCryptoPluginMode(%d)", cryptoPluginMode);
|
//ALOGD("WVMExtractorImpl::setCryptoPluginMode(%d)", cryptoPluginMode);
|
||||||
mCryptoPluginMode = cryptoPluginMode;
|
mClientContext->setCryptoPluginMode(cryptoPluginMode);
|
||||||
}
|
|
||||||
|
|
||||||
bool WVMExtractorImpl::getCryptoPluginMode() const
|
|
||||||
{
|
|
||||||
//ALOGD("WVMExtractorImpl::getCryptoPluginMode - %d", mCryptoPluginMode);
|
|
||||||
return mCryptoPluginMode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WVMExtractorImpl::setUID(uid_t uid)
|
void WVMExtractorImpl::setUID(uid_t uid)
|
||||||
{
|
{
|
||||||
//ALOGD("WVMExtractorImpl::setUID(%d)", (uint32_t)uid);
|
//ALOGD("WVMExtractorImpl::setUID(%d)", (uint32_t)uid);
|
||||||
mUID = uid;
|
mClientContext->setUID(uid);
|
||||||
mUIDIsSet = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "WVMMediaSource.h"
|
#include "WVMMediaSource.h"
|
||||||
#include "WVMFileSource.h"
|
#include "WVMFileSource.h"
|
||||||
#include "WVMExtractorImpl.h"
|
#include "WVMExtractorImpl.h"
|
||||||
|
#include "ClientContext.h"
|
||||||
#include "media/stagefright/foundation/ADebug.h"
|
#include "media/stagefright/foundation/ADebug.h"
|
||||||
#include "media/stagefright/MediaErrors.h"
|
#include "media/stagefright/MediaErrors.h"
|
||||||
#include "media/stagefright/MediaDefs.h"
|
#include "media/stagefright/MediaDefs.h"
|
||||||
@@ -66,6 +67,11 @@ void WVMMediaSource::delegateDataSource(sp<DataSource> dataSource)
|
|||||||
mDataSource = dataSource;
|
mDataSource = dataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WVMMediaSource::delegateClientContext(sp<ClientContext> context)
|
||||||
|
{
|
||||||
|
mClientContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
void WVMMediaSource::allocBufferGroup()
|
void WVMMediaSource::allocBufferGroup()
|
||||||
{
|
{
|
||||||
if (mGroup)
|
if (mGroup)
|
||||||
@@ -422,24 +428,25 @@ void WVMMediaSource::DecryptCallback(WVEsSelector esType, void* input, void* out
|
|||||||
//ALOGD("DecryptCallback(type=%d, in=%p, out=%p, len=%d, key=%d\n",
|
//ALOGD("DecryptCallback(type=%d, in=%p, out=%p, len=%d, key=%d\n",
|
||||||
// (int)esType, input, output, length, key);
|
// (int)esType, input, output, length, key);
|
||||||
|
|
||||||
WVMExtractorImpl *extractor = (WVMExtractorImpl *)obj;
|
ClientContext *clientContext = (ClientContext *)obj;
|
||||||
if (!extractor) {
|
if (!clientContext) {
|
||||||
ALOGE("WVMMediaSource::DecryptCallback - no extractor!");
|
ALOGE("WVMMediaSource::DecryptCallback - no client context!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sp<WVMMediaSource> source;
|
sp<WVMMediaSource> source;
|
||||||
if (esType == WV_EsSelector_Video)
|
if (esType == WV_EsSelector_Video)
|
||||||
source = extractor->getVideoSource();
|
source = clientContext->getVideoSource();
|
||||||
else
|
else
|
||||||
source = extractor->getAudioSource();
|
source = clientContext->getAudioSource();
|
||||||
|
|
||||||
DecryptContext &context = source->getDecryptContext();
|
DecryptContext &context = source->getDecryptContext();
|
||||||
|
|
||||||
OEMCrypto_UINT32 copied = length;
|
OEMCrypto_UINT32 copied = length;
|
||||||
OEMCryptoResult result;
|
OEMCryptoResult result;
|
||||||
unsigned char *iv = NULL;
|
unsigned char *iv = NULL;
|
||||||
|
|
||||||
if (extractor->getCryptoPluginMode()) {
|
if (clientContext->getCryptoPluginMode()) {
|
||||||
// just determine crypto unit boundaries
|
// just determine crypto unit boundaries
|
||||||
if (key) {
|
if (key) {
|
||||||
source->addEncryptedSize(length);
|
source->addEncryptedSize(length);
|
||||||
|
|||||||
46
proprietary/wvm/include/ClientContext.h
Normal file
46
proprietary/wvm/include/ClientContext.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 Google, Inc. All Rights Reserved
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CLIENTCONTEXT_H_
|
||||||
|
#define CLIENTCONTEXT_H_
|
||||||
|
|
||||||
|
#include <utils/RefBase.h>
|
||||||
|
#include <media/stagefright/foundation/ABase.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
class WVMMediaSource;
|
||||||
|
|
||||||
|
class ClientContext : public RefBase {
|
||||||
|
public:
|
||||||
|
ClientContext() : mUIDIsSet(false), mCryptoPluginMode(false) {}
|
||||||
|
|
||||||
|
void setUID(uid_t uid) { mUID = uid; mUIDIsSet = true; }
|
||||||
|
uid_t getUID() const { return mUID; }
|
||||||
|
bool haveUID() const { return mUIDIsSet; }
|
||||||
|
|
||||||
|
void setCryptoPluginMode(bool cryptoPluginMode) { mCryptoPluginMode = cryptoPluginMode; }
|
||||||
|
bool getCryptoPluginMode() const { return mCryptoPluginMode; }
|
||||||
|
|
||||||
|
void setAudioSource(sp<WVMMediaSource> const &audioSource) { mAudioSource = audioSource; }
|
||||||
|
void setVideoSource(sp<WVMMediaSource> const &videoSource) { mVideoSource = videoSource; }
|
||||||
|
|
||||||
|
sp<WVMMediaSource> getAudioSource() const { return mAudioSource.promote(); }
|
||||||
|
sp<WVMMediaSource> getVideoSource() const { return mVideoSource.promote(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mUIDIsSet;;
|
||||||
|
uid_t mUID;
|
||||||
|
|
||||||
|
bool mCryptoPluginMode;
|
||||||
|
|
||||||
|
wp<WVMMediaSource> mAudioSource;
|
||||||
|
wp<WVMMediaSource> mVideoSource;
|
||||||
|
|
||||||
|
DISALLOW_EVIL_CONSTRUCTORS(ClientContext);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -38,14 +38,16 @@ public:
|
|||||||
virtual void setAdaptiveStreamingMode(bool adaptive);
|
virtual void setAdaptiveStreamingMode(bool adaptive);
|
||||||
bool getAdaptiveStreamingMode() const;
|
bool getAdaptiveStreamingMode() const;
|
||||||
|
|
||||||
|
//
|
||||||
|
// if in CryptoPlugin mode, the extractor doesn't decrypt,
|
||||||
|
// it just accumulates the ranges of data requiring decryption
|
||||||
|
// into the MediaBuffer's metadata, the decryption happens
|
||||||
|
// later via the CryptoPlugin
|
||||||
|
//
|
||||||
virtual void setCryptoPluginMode(bool cryptoPluginMode);
|
virtual void setCryptoPluginMode(bool cryptoPluginMode);
|
||||||
bool getCryptoPluginMode() const;
|
|
||||||
|
|
||||||
virtual void setUID(uid_t uid);
|
virtual void setUID(uid_t uid);
|
||||||
|
|
||||||
sp<WVMMediaSource> getAudioSource() const { return mAudioSource; }
|
|
||||||
sp<WVMMediaSource> getVideoSource() const { return mVideoSource; }
|
|
||||||
|
|
||||||
static void SocketInfoCallback(int fd, int op, void *context);
|
static void SocketInfoCallback(int fd, int op, void *context);
|
||||||
static void cleanup();
|
static void cleanup();
|
||||||
|
|
||||||
@@ -63,6 +65,7 @@ private:
|
|||||||
sp<WVMFileSource> mFileSource;
|
sp<WVMFileSource> mFileSource;
|
||||||
sp<DataSource> mDataSource;
|
sp<DataSource> mDataSource;
|
||||||
sp<WVMInfoListener> mInfoListener;
|
sp<WVMInfoListener> mInfoListener;
|
||||||
|
sp<ClientContext> mClientContext;
|
||||||
|
|
||||||
bool mHaveMetaData;
|
bool mHaveMetaData;
|
||||||
bool mUseAdaptiveStreaming;
|
bool mUseAdaptiveStreaming;
|
||||||
@@ -73,17 +76,6 @@ private:
|
|||||||
|
|
||||||
status_t mSetupStatus;
|
status_t mSetupStatus;
|
||||||
|
|
||||||
bool mUIDIsSet;
|
|
||||||
uid_t mUID;
|
|
||||||
|
|
||||||
//
|
|
||||||
// if in CryptoPlugin mode, the extractor doesn't decrypt,
|
|
||||||
// it just accumulates the ranges of data requiring decryption
|
|
||||||
// into the MediaBuffer's metadata, the decryption happens
|
|
||||||
// later via the CryptoPlugin
|
|
||||||
//
|
|
||||||
bool mCryptoPluginMode;
|
|
||||||
|
|
||||||
status_t readMetaData();
|
status_t readMetaData();
|
||||||
|
|
||||||
const static size_t kStreamCacheSize = 10 * 1024 * 1024;
|
const static size_t kStreamCacheSize = 10 * 1024 * 1024;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <media/stagefright/MetaData.h>
|
#include <media/stagefright/MetaData.h>
|
||||||
#include <media/stagefright/MediaBufferGroup.h>
|
#include <media/stagefright/MediaBufferGroup.h>
|
||||||
#include <utils/RefBase.h>
|
#include <utils/RefBase.h>
|
||||||
|
#include "ClientContext.h"
|
||||||
#ifdef REQUIRE_SECURE_BUFFERS
|
#ifdef REQUIRE_SECURE_BUFFERS
|
||||||
#include "OEMCrypto_L1.h"
|
#include "OEMCrypto_L1.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -29,6 +30,7 @@ public:
|
|||||||
|
|
||||||
void delegateFileSource(sp<WVMFileSource> fileSource);
|
void delegateFileSource(sp<WVMFileSource> fileSource);
|
||||||
void delegateDataSource(sp<DataSource> dataSource);
|
void delegateDataSource(sp<DataSource> dataSource);
|
||||||
|
void delegateClientContext(sp<ClientContext> context);
|
||||||
|
|
||||||
virtual status_t start(MetaData *params = NULL);
|
virtual status_t start(MetaData *params = NULL);
|
||||||
virtual status_t stop();
|
virtual status_t stop();
|
||||||
@@ -87,6 +89,7 @@ private:
|
|||||||
|
|
||||||
sp<WVMFileSource> mFileSource;
|
sp<WVMFileSource> mFileSource;
|
||||||
sp<DataSource> mDataSource;
|
sp<DataSource> mDataSource;
|
||||||
|
sp<ClientContext> mClientContext;
|
||||||
|
|
||||||
Vector<size_t> mEncryptedSizes;
|
Vector<size_t> mEncryptedSizes;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user