From 41233600a82d286f723e37f2f9199f3791a3012c Mon Sep 17 00:00:00 2001 From: Vaibhav Deshu Venkatesh Date: Tue, 15 Nov 2016 12:12:39 -0800 Subject: [PATCH 01/93] NuPlayer: Uninitialized bool variable in fetchInputData dropAccessUnit is uninitialized. The do-while loop which checks for this variable has a continue and hence this variable was being used without initialization. The change initializes this variable to default value. CRs-Fixed: 1087183 Change-Id: I301eb165b51f773b5062283041d6749ccaff9e3e --- media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index c24078790..034693018 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -731,7 +731,7 @@ bool NuPlayer::Decoder::isStaleReply(const sp &msg) { status_t NuPlayer::Decoder::fetchInputData(sp &reply) { sp accessUnit; - bool dropAccessUnit; + bool dropAccessUnit = true; do { status_t err = mSource->dequeueAccessUnit(mIsAudio, &accessUnit); From 8e59f1a88a80a86c8a531714e68b9279670d7fb3 Mon Sep 17 00:00:00 2001 From: Preetam Singh Ranawat Date: Fri, 25 Nov 2016 17:00:13 +0530 Subject: [PATCH 02/93] libmedia : Fix for AudioRecord CTS test case -if sample rate is not specificed during construction of audio record it updates sampling rate with default value based on the source. but divide by zero execption is happeing since it uses same unspeficied sampling rate to calculate latency. -Use updated default sample rate to calcuate latency vaulue. CRs-Fixed: 1090804 Change-Id: Icb1e717d869de7bcd4b52194f3ee4e8b0b318da4 --- media/libmedia/AudioRecord.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 92cf9f9b3..b61a4645c 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -274,9 +274,9 @@ status_t AudioRecord::set( // TODO: add audio hardware input latency here if (mTransfer == TRANSFER_CALLBACK || mTransfer == TRANSFER_SYNC) { - mLatency = (1000 * mNotificationFramesAct) / sampleRate; + mLatency = (1000 * mNotificationFramesAct) / mSampleRate; } else { - mLatency = (1000 * mFrameCount) / sampleRate; + mLatency = (1000 * mFrameCount) / mSampleRate; } mMarkerPosition = 0; mMarkerReached = false; From 5e24b9ca37a93299da4690a372818fcb45ebd604 Mon Sep 17 00:00:00 2001 From: Uma Mehta Date: Wed, 30 Nov 2016 13:18:32 +0530 Subject: [PATCH 03/93] frameworks/av: Set Protected flag only for secure Changes to set protected flag only for secure contents. Change-Id: I18812ae216c30031fb0ffa42f63ce89b1cd6ab4d --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 90ce5cb39..5e486aeb5 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -450,7 +450,7 @@ void NuPlayer::GenericSource::onPrepareAsync() { notifyFlagsChanged( (mIsSecure ? FLAG_SECURE : 0) - | (mDecryptHandle != NULL ? FLAG_PROTECTED : 0) + | ((mIsSecure && (mDecryptHandle != NULL)) ? FLAG_PROTECTED : 0) | FLAG_CAN_PAUSE | FLAG_CAN_SEEK_BACKWARD | FLAG_CAN_SEEK_FORWARD From b6edd955fa242e6757e669957f488625506e3a8f Mon Sep 17 00:00:00 2001 From: Uma Mehta Date: Tue, 15 Nov 2016 09:12:25 +0530 Subject: [PATCH 04/93] frameworks/av: Changes to enable DRM flag Changes to enable isDrm flag for DRM playback so as to enable setPlaybackStatus. Change-Id: I824f59471286e5454fab7630a45bdbc2430711ac --- media/libmedia/IMediaExtractor.cpp | 18 ++++++++++++++++-- media/libstagefright/MediaExtractor.cpp | 8 +++++++- 2 files changed, 23 insertions(+), 3 deletions(-) mode change 100644 => 100755 media/libmedia/IMediaExtractor.cpp diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp old mode 100644 new mode 100755 index e8ad75b09..ce718d259 --- a/media/libmedia/IMediaExtractor.cpp +++ b/media/libmedia/IMediaExtractor.cpp @@ -105,8 +105,15 @@ class BpMediaExtractor : public BpInterface { ALOGV("setDrmFlag NOT IMPLEMENTED"); } virtual bool getDrmFlag() { - ALOGV("getDrmFlag NOT IMPLEMENTED"); - return false; + ALOGV("getDrmFlag"); + Parcel data, reply; + data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); + status_t ret = remote()->transact(GETDRMFLAG, data, &reply); + bool isDrm = 0; + if (ret == NO_ERROR) { + isDrm = reply.readUint32(); + } + return isDrm; } virtual char* getDrmTrackInfo(size_t trackID __unused, int *len __unused) { ALOGV("getDrmTrackInfo NOT IMPLEMENTED"); @@ -175,6 +182,13 @@ status_t BnMediaExtractor::onTransact( } return UNKNOWN_ERROR; } + case GETDRMFLAG: { + ALOGV("getDrmFlag"); + CHECK_INTERFACE(IMediaExtractor, data, reply); + bool isDrm = getDrmFlag(); + reply->writeUint32(uint32_t(isDrm)); + return NO_ERROR; + } default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp index fd051e4a5..92f8b291f 100644 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -264,7 +264,13 @@ sp MediaExtractor::CreateFromService( } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) { ret = new MidiExtractor(source); } - + if (ret != NULL) { + if (isDrm) { + ret->setDrmFlag(true); + } else { + ret->setDrmFlag(false); + } + } return ret; } From 557bd7bfe6c4895faee09e46fc9b5304a956c8b7 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Tue, 18 Oct 2016 17:13:09 -0700 Subject: [PATCH 05/93] Visualizer: Check capture size and latency parameters Bug: 31781965 Change-Id: I1c439a0d0f6aa0057b3c651499f28426e1e1f5e4 (cherry picked from commit 9a2732ba0a8d609ab040d2c1ddee28577ead9772) --- .../visualizer/EffectVisualizer.cpp | 43 ++++++++++++++----- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp index 21fddb1db..b7d27d6cc 100644 --- a/media/libeffects/visualizer/EffectVisualizer.cpp +++ b/media/libeffects/visualizer/EffectVisualizer.cpp @@ -59,6 +59,8 @@ enum visualizer_state_e { #define DISCARD_MEASUREMENTS_TIME_MS 2000 // discard measurements older than this number of ms +#define MAX_LATENCY_MS 3000 // 3 seconds of latency for audio pipeline + // maximum number of buffers for which we keep track of the measurements #define MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS 25 // note: buffer index is stored in uint8_t @@ -521,18 +523,29 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, break; } switch (*(uint32_t *)p->data) { - case VISUALIZER_PARAM_CAPTURE_SIZE: - pContext->mCaptureSize = *((uint32_t *)p->data + 1); - ALOGV("set mCaptureSize = %" PRIu32, pContext->mCaptureSize); - break; + case VISUALIZER_PARAM_CAPTURE_SIZE: { + const uint32_t captureSize = *((uint32_t *)p->data + 1); + if (captureSize > VISUALIZER_CAPTURE_SIZE_MAX) { + android_errorWriteLog(0x534e4554, "31781965"); + *(int32_t *)pReplyData = -EINVAL; + ALOGW("set mCaptureSize = %u > %u", captureSize, VISUALIZER_CAPTURE_SIZE_MAX); + } else { + pContext->mCaptureSize = captureSize; + ALOGV("set mCaptureSize = %u", captureSize); + } + } break; case VISUALIZER_PARAM_SCALING_MODE: pContext->mScalingMode = *((uint32_t *)p->data + 1); ALOGV("set mScalingMode = %" PRIu32, pContext->mScalingMode); break; - case VISUALIZER_PARAM_LATENCY: - pContext->mLatency = *((uint32_t *)p->data + 1); - ALOGV("set mLatency = %" PRIu32, pContext->mLatency); - break; + case VISUALIZER_PARAM_LATENCY: { + uint32_t latency = *((uint32_t *)p->data + 1); + if (latency > MAX_LATENCY_MS) { + latency = MAX_LATENCY_MS; // clamp latency b/31781965 + } + pContext->mLatency = latency; + ALOGV("set mLatency = %u", latency); + } break; case VISUALIZER_PARAM_MEASUREMENT_MODE: pContext->mMeasurementMode = *((uint32_t *)p->data + 1); ALOGV("set mMeasurementMode = %" PRIu32, pContext->mMeasurementMode); @@ -571,10 +584,18 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, if (latencyMs < 0) { latencyMs = 0; } - const uint32_t deltaSmpl = - pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000; - int32_t capturePoint = pContext->mCaptureIdx - captureSize - deltaSmpl; + uint32_t deltaSmpl = captureSize + + pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000; + + // large sample rate, latency, or capture size, could cause overflow. + // do not offset more than the size of buffer. + if (deltaSmpl > CAPTURE_BUF_SIZE) { + android_errorWriteLog(0x534e4554, "31781965"); + deltaSmpl = CAPTURE_BUF_SIZE; + } + int32_t capturePoint = pContext->mCaptureIdx - deltaSmpl; + // a negative capturePoint means we wrap the buffer. if (capturePoint < 0) { uint32_t size = -capturePoint; if (size > captureSize) { From 781bd819f22229725d7b9e9d2e81997cb36d745d Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 26 Oct 2016 17:41:56 -0700 Subject: [PATCH 06/93] stagefright: remove allottedSize equality check in IOMX::useBuffer This was meant for buffers shared cross-process, but we are not gaining anything from this check even if it was at the correct place. Bug: 32436178 Change-Id: I6919e8ac6e35092273e171f49f6711ba577ba2e6 (cherry picked from commit 58388aa7be1c6963eb4b8464d46938ba9b0a04b0) --- media/libstagefright/omx/OMXNodeInstance.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index 5f903a9f0..43a50ae0c 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -805,13 +805,6 @@ status_t OMXNodeInstance::useBuffer( } memset(data, 0, allottedSize); - // if we are not connecting the buffers, the sizes must match - if (allottedSize != params->size()) { - CLOG_ERROR(useBuffer, BAD_VALUE, SIMPLE_BUFFER(portIndex, (size_t)allottedSize, data)); - delete[] data; - return BAD_VALUE; - } - buffer_meta = new BufferMeta( params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, data); } else { From c66c43ad571ed2590dcd55a762c73c90d9744bac Mon Sep 17 00:00:00 2001 From: rago Date: Mon, 31 Oct 2016 12:50:20 -0700 Subject: [PATCH 07/93] Fix security vulnerability: Equalizer command might allow negative indexes Bug: 32247948 Bug: 32438598 Bug: 32436341 Test: use POC on bug or cts security test Change-Id: I91bd6aadb6c7410163e03101f365db767f4cd2a3 (cherry picked from commit 0872b65cff9129633471945431b9a5a28418049c) (cherry picked from commit e981cca9fff3608af22bdf8fc1acef5470e25663) --- .../lvm/wrapper/Bundle/EffectBundle.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index a1892e44a..5f18c9747 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -2357,8 +2357,12 @@ int Equalizer_getParameter(EffectContext *pContext, case EQ_PARAM_BAND_LEVEL: param2 = *pParamTemp; - if (param2 >= FIVEBAND_NUMBANDS) { + if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) { status = -EINVAL; + if (param2 < 0) { + android_errorWriteLog(0x534e4554, "32438598"); + ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_LEVEL band %d", param2); + } break; } *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, param2); @@ -2368,8 +2372,12 @@ int Equalizer_getParameter(EffectContext *pContext, case EQ_PARAM_CENTER_FREQ: param2 = *pParamTemp; - if (param2 >= FIVEBAND_NUMBANDS) { + if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) { status = -EINVAL; + if (param2 < 0) { + android_errorWriteLog(0x534e4554, "32436341"); + ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_CENTER_FREQ band %d", param2); + } break; } *(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, param2); @@ -2379,8 +2387,12 @@ int Equalizer_getParameter(EffectContext *pContext, case EQ_PARAM_BAND_FREQ_RANGE: param2 = *pParamTemp; - if (param2 >= FIVEBAND_NUMBANDS) { + if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) { status = -EINVAL; + if (param2 < 0) { + android_errorWriteLog(0x534e4554, "32247948"); + ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d", param2); + } break; } EqualizerGetBandFreqRange(pContext, param2, (uint32_t *)pValue, ((uint32_t *)pValue + 1)); From 7a3246b870ddd11861eda2ab458b11d723c7f62c Mon Sep 17 00:00:00 2001 From: Ray Essick Date: Wed, 2 Nov 2016 14:17:57 -0700 Subject: [PATCH 08/93] DO NOT MERGE: defensive parsing of mp3 album art information several points in stagefrights mp3 album art code used strlen() to parse user-supplied strings that may be unterminated, resulting in reading beyond the end of a buffer. This changes the code to use strnlen() for 8-bit encodings and strengthens the parsing of 16-bit encodings similarly. It also reworks how we watch for the end-of-buffer to avoid all over-reads. Bug: 32377688 Test: crafted mp3's w/ good/bad cover art. See what showed in play music Change-Id: Ia9f526d71b21ef6a61acacf616b573753cd21df6 (cherry picked from commit fa0806b594e98f1aed3ebcfc6a801b4c0056f9eb) --- media/libstagefright/id3/ID3.cpp | 56 ++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp index 394215812..33f79fdb5 100644 --- a/media/libstagefright/id3/ID3.cpp +++ b/media/libstagefright/id3/ID3.cpp @@ -836,20 +836,21 @@ void ID3::Iterator::findFrame() { } } -static size_t StringSize(const uint8_t *start, uint8_t encoding) { +// return includes terminator; if unterminated, returns > limit +static size_t StringSize(const uint8_t *start, size_t limit, uint8_t encoding) { + if (encoding == 0x00 || encoding == 0x03) { // ISO 8859-1 or UTF-8 - return strlen((const char *)start) + 1; + return strnlen((const char *)start, limit) + 1; } // UCS-2 size_t n = 0; - while (start[n] != '\0' || start[n + 1] != '\0') { + while ((n+1 < limit) && (start[n] != '\0' || start[n + 1] != '\0')) { n += 2; } - - // Add size of null termination. - return n + 2; + n += 2; + return n; } const void * @@ -870,11 +871,19 @@ ID3::getAlbumArt(size_t *length, String8 *mime) const { if (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) { uint8_t encoding = data[0]; - mime->setTo((const char *)&data[1]); - size_t mimeLen = strlen((const char *)&data[1]) + 1; + size_t consumed = 1; + + // *always* in an 8-bit encoding + size_t mimeLen = StringSize(&data[consumed], size - consumed, 0x00); + if (mimeLen > size - consumed) { + ALOGW("bogus album art size: mime"); + return NULL; + } + mime->setTo((const char *)&data[consumed]); + consumed += mimeLen; #if 0 - uint8_t picType = data[1 + mimeLen]; + uint8_t picType = data[consumed]; if (picType != 0x03) { // Front Cover Art it.next(); @@ -882,20 +891,30 @@ ID3::getAlbumArt(size_t *length, String8 *mime) const { } #endif - size_t descLen = StringSize(&data[2 + mimeLen], encoding); + consumed++; + if (consumed >= size) { + ALOGW("bogus album art size: pic type"); + return NULL; + } + + size_t descLen = StringSize(&data[consumed], size - consumed, encoding); + consumed += descLen; - if (size < 2 || - size - 2 < mimeLen || - size - 2 - mimeLen < descLen) { - ALOGW("bogus album art sizes"); + if (consumed >= size) { + ALOGW("bogus album art size: description"); return NULL; } - *length = size - 2 - mimeLen - descLen; - return &data[2 + mimeLen + descLen]; + *length = size - consumed; + + return &data[consumed]; } else { uint8_t encoding = data[0]; + if (size <= 5) { + return NULL; + } + if (!memcmp(&data[1], "PNG", 3)) { mime->setTo("image/png"); } else if (!memcmp(&data[1], "JPG", 3)) { @@ -915,7 +934,10 @@ ID3::getAlbumArt(size_t *length, String8 *mime) const { } #endif - size_t descLen = StringSize(&data[5], encoding); + size_t descLen = StringSize(&data[5], size - 5, encoding); + if (descLen > size - 5) { + return NULL; + } *length = size - 5 - descLen; From 26965db50a617f69bdefca0d7533796c80374f2c Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Fri, 4 Nov 2016 19:40:53 -0700 Subject: [PATCH 09/93] Effects: Check get parameter command size Test: Custom test. Bug: 32438594 Bug: 32624850 Bug: 32635664 Change-Id: I9b1315e2c02f11bea395bfdcf5c1ccddccbad8a6 (cherry picked from commit 3d34cc76e315dfa8c3b1edf78835b0dab4980505) --- services/audioflinger/Effects.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index 9711f2dec..bb3067f27 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -600,6 +600,13 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode, android_errorWriteLog(0x534e4554, "29251553"); return -EINVAL; } + if (cmdCode == EFFECT_CMD_GET_PARAM && + (sizeof(effect_param_t) > cmdSize || + ((effect_param_t *)pCmdData)->psize > cmdSize + - sizeof(effect_param_t))) { + android_errorWriteLog(0x534e4554, "32438594"); + return -EINVAL; + } if ((cmdCode == EFFECT_CMD_SET_PARAM || cmdCode == EFFECT_CMD_SET_PARAM_DEFERRED) && // DEFERRED not generally used (sizeof(effect_param_t) > cmdSize From 453b351ac5bd2b6619925dc966da60adf6b3126c Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 11 Nov 2016 09:20:00 -0800 Subject: [PATCH 10/93] Make VBRISeeker more robust Bug: 32577290 Change-Id: I9bcc9422ae7dd3ae4a38df330c9dcd7ac4941ec8 (cherry picked from commit 7fdd36418e945cf6a500018632dfb0ed8cb1a343) --- media/libstagefright/VBRISeeker.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp index 58f2c6065..5b8f23a77 100644 --- a/media/libstagefright/VBRISeeker.cpp +++ b/media/libstagefright/VBRISeeker.cpp @@ -83,8 +83,23 @@ sp VBRISeeker::CreateFromSource( scale, entrySize); + if (entrySize > 4) { + ALOGE("invalid VBRI entry size: %zu", entrySize); + return NULL; + } + + sp seeker = new (std::nothrow) VBRISeeker; + if (seeker == NULL) { + ALOGW("Couldn't allocate VBRISeeker"); + return NULL; + } + size_t totalEntrySize = numEntries * entrySize; - uint8_t *buffer = new uint8_t[totalEntrySize]; + uint8_t *buffer = new (std::nothrow) uint8_t[totalEntrySize]; + if (!buffer) { + ALOGW("Couldn't allocate %zu bytes", totalEntrySize); + return NULL; + } n = source->readAt(pos + sizeof(vbriHeader), buffer, totalEntrySize); if (n < (ssize_t)totalEntrySize) { @@ -94,7 +109,6 @@ sp VBRISeeker::CreateFromSource( return NULL; } - sp seeker = new VBRISeeker; seeker->mBasePos = post_id3_pos + frameSize; // only update mDurationUs if the calculated duration is valid (non zero) // otherwise, leave duration at -1 so that getDuration() and getOffsetForTime() From 321ea5257e37c8edb26e66fe4ee78cca4cd915fe Mon Sep 17 00:00:00 2001 From: rago Date: Mon, 14 Nov 2016 14:58:34 -0800 Subject: [PATCH 11/93] Fix security vulnerability: Effect command might allow negative indexes Bug: 32448258 Bug: 32095626 Test: Use POC bug or cts security test Change-Id: I69f24eac5866f8d9090fc4c0ebe58c2c297b63df (cherry picked from commit 01183402d757f0c28bfd5e3b127b3809dfd67459) --- .../libeffects/lvm/wrapper/Bundle/EffectBundle.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index 5f18c9747..ed38584d9 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -2419,9 +2419,13 @@ int Equalizer_getParameter(EffectContext *pContext, case EQ_PARAM_GET_PRESET_NAME: param2 = *pParamTemp; - if (param2 >= EqualizerGetNumPresets()) { - //if (param2 >= 20) { // AGO FIX + if ((param2 < 0 && param2 != PRESET_CUSTOM) || param2 >= EqualizerGetNumPresets()) { status = -EINVAL; + if (param2 < 0) { + android_errorWriteLog(0x534e4554, "32448258"); + ALOGE("\tERROR Equalizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d", + param2); + } break; } name = (char *)pValue; @@ -2491,8 +2495,12 @@ int Equalizer_setParameter (EffectContext *pContext, void *pParam, void *pValue) band = *pParamTemp; level = (int32_t)(*(int16_t *)pValue); //ALOGV("\tEqualizer_setParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", band, level); - if (band >= FIVEBAND_NUMBANDS) { + if (band < 0 || band >= FIVEBAND_NUMBANDS) { status = -EINVAL; + if (band < 0) { + android_errorWriteLog(0x534e4554, "32095626"); + ALOGE("\tERROR Equalizer_setParameter() EQ_PARAM_BAND_LEVEL band %d", band); + } break; } EqualizerSetBandLevel(pContext, band, level); From 8fa8fd2971f5c0562eda422ac0b4e91915da504a Mon Sep 17 00:00:00 2001 From: Paramananda Pradhan Date: Thu, 10 Nov 2016 11:35:36 +0530 Subject: [PATCH 12/93] OMA DRM : Give permission to access drm service api from Oma Drm engine Uses user defined permission "com.oma.drm.permission.ACCESS_OMA_DRM" to access protected api call from Oma Drm util framework. This changes is required for DRM Image support in Android. Change-Id: I6811d97e45e2bc37356be9061e1a5a5557e19e06 CRs-Fixed: 1088307 --- drm/drmserver/DrmManagerService.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp index dad599b42..ea3fed612 100644 --- a/drm/drmserver/DrmManagerService.cpp +++ b/drm/drmserver/DrmManagerService.cpp @@ -92,6 +92,9 @@ bool DrmManagerService::isProtectedCallAllowed(drm_perm_t perm) { return selinuxIsProtectedCallAllowed(spid, perm); } } + if (checkCallingPermission(String16("com.oma.drm.permission.ACCESS_OMA_DRM")) == true) { + return true; + } return false; } From 690fff0ac46c2f9a0a972d0f60252cd68c72d4e0 Mon Sep 17 00:00:00 2001 From: Lalit Kansara Date: Tue, 6 Dec 2016 22:42:53 +0530 Subject: [PATCH 13/93] Compilation fix: N-MR1 merge. Change-Id: I7d5faf8a5ab78eaea184544472486a41a1f1e5dd --- include/media/stagefright/MPEG4Writer.h | 2 + .../MediaPlayerService.cpp | 2 +- .../nuplayer/GenericSource.cpp | 7 + media/libstagefright/ACodec.cpp | 133 +++++++++++++++++- media/libstagefright/MPEG4Writer.cpp | 58 +++++++- .../common/managerdefinitions/Android.mk | 2 +- 6 files changed, 199 insertions(+), 5 deletions(-) diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h index 7df82ebcc..5932610ca 100644 --- a/include/media/stagefright/MPEG4Writer.h +++ b/include/media/stagefright/MPEG4Writer.h @@ -65,6 +65,7 @@ class MPEG4Writer : public MediaWriter { status_t setGeoData(int latitudex10000, int longitudex10000); status_t setCaptureRate(float captureFps); + status_t setTemporalLayerCount(uint32_t layerCount); virtual void setStartTimeOffsetMs(int ms) { mStartTimeOffsetMs = ms; } virtual int32_t getStartTimeOffsetMs() const { return mStartTimeOffsetMs; } @@ -196,6 +197,7 @@ class MPEG4Writer : public MediaWriter { protected: static void StripStartcode(MediaBuffer *buffer); virtual off64_t addLengthPrefixedSample_l(MediaBuffer *buffer); + off64_t addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer); private: bool exceedsFileSizeLimit(); diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 30de64861..c954b1ec0 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1974,7 +1974,7 @@ status_t MediaPlayerService::AudioOutput::updateTrack() { } } #ifdef DOLBY_ENABLE - updateTrackOnAudioProcessed(t, false); + updateTrackOnAudioProcessed(mTrack, false); #endif // DOLBY_END ALOGV("updateTrack() DONE status %d", res); return res; diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index caeab0667..e20b26e16 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -1305,6 +1305,13 @@ sp NuPlayer::GenericSource::mediaBufferToABuffer( } #endif + if (trackType == MEDIA_TRACK_TYPE_VIDEO) { + int32_t layerId; + if (mb->meta_data()->findInt32(kKeyTemporalLayerId, &layerId)) { + meta->setInt32("temporal-layer-id", layerId); + } + } + if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) { const char *mime; CHECK(mTimedTextTrack.mSource != NULL diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 8477db60d..23eee299a 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -2519,6 +2519,109 @@ status_t ACodec::setIntraRefreshPeriod(uint32_t intraRefreshPeriod, bool inConfi return OK; } +status_t ACodec::configureTemporalLayers( + const sp &msg, bool inConfigure, sp &outputFormat) { + if (!mIsVideo || !mIsEncoder) { + return INVALID_OPERATION; + } + + AString tsSchema; + if (!msg->findString("ts-schema", &tsSchema)) { + return OK; + } + + unsigned int numLayers = 0; + unsigned int numBLayers = 0; + int tags; + char dummy; + OMX_VIDEO_ANDROID_TEMPORALLAYERINGPATTERNTYPE pattern = + OMX_VIDEO_AndroidTemporalLayeringPatternNone; + if (sscanf(tsSchema.c_str(), "webrtc.vp8.%u-layer%c", &numLayers, &dummy) == 1 + && numLayers > 0) { + pattern = OMX_VIDEO_AndroidTemporalLayeringPatternWebRTC; + } else if ((tags = sscanf(tsSchema.c_str(), "android.generic.%u%c%u%c", + &numLayers, &dummy, &numBLayers, &dummy)) + && (tags == 1 || (tags == 3 && dummy == '+')) + && numLayers > 0 && numLayers < UINT32_MAX - numBLayers) { + numLayers += numBLayers; + pattern = OMX_VIDEO_AndroidTemporalLayeringPatternAndroid; + } else { + ALOGI("Ignoring unsupported ts-schema [%s]", tsSchema.c_str()); + return BAD_VALUE; + } + + OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE layerParams; + InitOMXParams(&layerParams); + layerParams.nPortIndex = kPortIndexOutput; + + status_t err = mOMX->getParameter( + mNode, (OMX_INDEXTYPE)OMX_IndexParamAndroidVideoTemporalLayering, + &layerParams, sizeof(layerParams)); + + if (err != OK) { + return err; + } else if (!(layerParams.eSupportedPatterns & pattern)) { + return BAD_VALUE; + } + + numLayers = min(numLayers, layerParams.nLayerCountMax); + numBLayers = min(numBLayers, layerParams.nBLayerCountMax); + + if (!inConfigure) { + OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE layerConfig; + InitOMXParams(&layerConfig); + layerConfig.nPortIndex = kPortIndexOutput; + layerConfig.ePattern = pattern; + layerConfig.nPLayerCountActual = numLayers - numBLayers; + layerConfig.nBLayerCountActual = numBLayers; + layerConfig.bBitrateRatiosSpecified = OMX_FALSE; + + err = mOMX->setConfig( + mNode, (OMX_INDEXTYPE)OMX_IndexConfigAndroidVideoTemporalLayering, + &layerConfig, sizeof(layerConfig)); + } else { + layerParams.ePattern = pattern; + layerParams.nPLayerCountActual = numLayers - numBLayers; + layerParams.nBLayerCountActual = numBLayers; + layerParams.bBitrateRatiosSpecified = OMX_FALSE; + + err = mOMX->setParameter( + mNode, (OMX_INDEXTYPE)OMX_IndexParamAndroidVideoTemporalLayering, + &layerParams, sizeof(layerParams)); + } + + AString configSchema; + if (pattern == OMX_VIDEO_AndroidTemporalLayeringPatternAndroid) { + configSchema = AStringPrintf("android.generic.%u+%u", numLayers - numBLayers, numBLayers); + } else if (pattern == OMX_VIDEO_AndroidTemporalLayeringPatternWebRTC) { + configSchema = AStringPrintf("webrtc.vp8.%u", numLayers); + } + + if (err != OK) { + ALOGW("Failed to set temporal layers to %s (requested %s)", + configSchema.c_str(), tsSchema.c_str()); + return err; + } + + err = mOMX->getParameter( + mNode, (OMX_INDEXTYPE)OMX_IndexParamAndroidVideoTemporalLayering, + &layerParams, sizeof(layerParams)); + + if (err == OK) { + ALOGD("Temporal layers requested:%s configured:%s got:%s(%u: P=%u, B=%u)", + tsSchema.c_str(), configSchema.c_str(), + asString(layerParams.ePattern), layerParams.ePattern, + layerParams.nPLayerCountActual, layerParams.nBLayerCountActual); + + if (outputFormat.get() == mOutputFormat.get()) { + mOutputFormat = mOutputFormat->dup(); // trigger an output format change event + } + // assume we got what we configured + outputFormat->setString("ts-schema", configSchema); + } + return err; +} + status_t ACodec::setMinBufferSize(OMX_U32 portIndex, size_t size) { OMX_PARAM_PORTDEFINITIONTYPE def; InitOMXParams(&def); @@ -3861,6 +3964,29 @@ status_t ACodec::setupVideoEncoder( err = OK; } + if (err != OK) { + return err; + } + + switch (compressionFormat) { + case OMX_VIDEO_CodingAVC: + case OMX_VIDEO_CodingHEVC: + err = configureTemporalLayers(msg, true /* inConfigure */, outputFormat); + if (err != OK) { + err = OK; // ignore failure + } + break; + + case OMX_VIDEO_CodingVP8: + case OMX_VIDEO_CodingVP9: + // TODO: do we need to support android.generic layering? webrtc layering is + // already set up in setupVPXEncoderParameters. + break; + + default: + break; + } + if (err == OK) { ALOGI("setupVideoEncoder succeeded"); } @@ -7535,7 +7661,12 @@ status_t ACodec::setParameters(const sp ¶ms) { return setDolbyParameterOnProcessedAudio(params); #endif // DOLBY_END - return OK; + status_t err = configureTemporalLayers(params, false /* inConfigure */, mOutputFormat); + if (err != OK) { + err = OK; // ignore failure + } + + return err; } void ACodec::onSignalEndOfInputStream() { diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 37147e968..bbbc86bac 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -49,6 +49,7 @@ #include "include/ESDS.h" #include "include/HevcUtils.h" #include +#include "include/avc_utils.h" #ifndef __predict_false #define __predict_false(exp) __builtin_expect((exp) != 0, 0) @@ -76,6 +77,7 @@ static const char kMetaKey_Model[] = "com.android.model"; static const char kMetaKey_Build[] = "com.android.build"; #endif static const char kMetaKey_CaptureFps[] = "com.android.capture.fps"; +static const char kMetaKey_TemporalLayerCount[] = "com.android.video.temporal_layers_count"; static const uint8_t kMandatoryHevcNalUnitTypes[3] = { kHevcNalUnitTypeVps, @@ -1195,6 +1197,37 @@ void MPEG4Writer::StripStartcode(MediaBuffer *buffer) { } } +off64_t MPEG4Writer::addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer) { + off64_t old_offset = mOffset; + + const size_t kExtensionNALSearchRange = 64; // bytes to look for non-VCL NALUs + + const uint8_t *dataStart = (const uint8_t *)buffer->data() + buffer->range_offset(); + const uint8_t *currentNalStart = dataStart; + const uint8_t *nextNalStart; + const uint8_t *data = dataStart; + size_t nextNalSize; + size_t searchSize = buffer->range_length() > kExtensionNALSearchRange ? + kExtensionNALSearchRange : buffer->range_length(); + + while (getNextNALUnit(&data, &searchSize, &nextNalStart, + &nextNalSize, true) == OK) { + size_t currentNalSize = nextNalStart - currentNalStart - 4 /* strip start-code */; + MediaBuffer *nalBuf = new MediaBuffer((void *)currentNalStart, currentNalSize); + addLengthPrefixedSample_l(nalBuf); + nalBuf->release(); + + currentNalStart = nextNalStart; + } + + size_t currentNalOffset = currentNalStart - dataStart; + buffer->set_range(buffer->range_offset() + currentNalOffset, + buffer->range_length() - currentNalOffset); + addLengthPrefixedSample_l(buffer); + + return old_offset; +} + off64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { off64_t old_offset = mOffset; @@ -1414,6 +1447,19 @@ status_t MPEG4Writer::setCaptureRate(float captureFps) { return OK; } +status_t MPEG4Writer::setTemporalLayerCount(uint32_t layerCount) { + if (layerCount > 9) { + return BAD_VALUE; + } + + if (layerCount > 0) { + mMetaKeys->setInt32(kMetaKey_TemporalLayerCount, layerCount); + mMoovExtraSize += sizeof(kMetaKey_TemporalLayerCount) + 4 + 32; + } + + return OK; +} + void MPEG4Writer::write(const void *data, size_t size) { write(data, 1, size); } @@ -1531,6 +1577,14 @@ MPEG4Writer::Track::Track( mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); + // store temporal layer count + if (!mIsAudio) { + int32_t count; + if (mMeta->findInt32(kKeyTemporalLayerCount, &count) && count > 1) { + mOwner->setTemporalLayerCount(count); + } + } + setTimeScale(); } @@ -1719,7 +1773,7 @@ void MPEG4Writer::writeChunkToFile(Chunk* chunk) { List::iterator it = chunk->mSamples.begin(); off64_t offset = (chunk->mTrack->isAvc() || chunk->mTrack->isHevc()) - ? addLengthPrefixedSample_l(*it) + ? addMultipleLengthPrefixedSamples_l(*it) : addSample_l(*it); if (isFirstSample) { @@ -2672,7 +2726,7 @@ status_t MPEG4Writer::Track::threadEntry() { trackProgressStatus(timestampUs); } if (!hasMultipleTracks) { - off64_t offset = (mIsAvc || mIsHevc) ? mOwner->addLengthPrefixedSample_l(copy) + off64_t offset = (mIsAvc || mIsHevc) ? mOwner->addMultipleLengthPrefixedSamples_l(copy) : mOwner->addSample_l(copy); uint32_t count = (mOwner->use32BitFileOffset() diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk index 3506e50e6..dea42ed79 100644 --- a/services/audiopolicy/common/managerdefinitions/Android.mk +++ b/services/audiopolicy/common/managerdefinitions/Android.mk @@ -71,7 +71,7 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := \ LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB) -LOCAL_CFLAGS := -Wall -Werror +LOCAL_CFLAGS += -Wall -Werror LOCAL_MODULE := libaudiopolicycomponents From ae893161169703e71734a7e4e3b54919ab821078 Mon Sep 17 00:00:00 2001 From: Chaithanya Krishna Bacharaju Date: Tue, 29 Nov 2016 16:01:03 +0530 Subject: [PATCH 14/93] soundtrigger: Support multiple clients attaching to a module Currently service allows only a single client to be attached to a Module. This limits only a single client can use sound trigger at a time. Add changes to attach multiple clients to a given Module through ModuleClient inteface so that multiple clients can in parallel use sound trigger on a given Module. ModuleClient class is introduced as a client interface to a Module. Service provides a unique instance of ModuleClient to each client being attached and adds this client to the module clients list. Bug:32030191 Change-Id: I0214395ed545690bb9f95365c7b8d415fcf60c9a --- .../soundtrigger/SoundTriggerHwService.cpp | 355 ++++++++++++++---- services/soundtrigger/SoundTriggerHwService.h | 87 +++-- 2 files changed, 335 insertions(+), 107 deletions(-) diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp index eebc48705..b2f269840 100644 --- a/services/soundtrigger/SoundTriggerHwService.cpp +++ b/services/soundtrigger/SoundTriggerHwService.cpp @@ -87,8 +87,7 @@ void SoundTriggerHwService::onFirstRef() ALOGI("loaded default module %s, handle %d", descriptor.properties.description, descriptor.handle); - sp client; - sp module = new Module(this, dev, descriptor, client); + sp module = new Module(this, dev, descriptor); mModules.add(descriptor.handle, module); mCallbackThread = new CallbackThread(this); } @@ -143,11 +142,13 @@ status_t SoundTriggerHwService::attach(const sound_trigger_module_handle_t handl } sp module = mModules.valueAt(index); - module->setClient(client); - IInterface::asBinder(client)->linkToDeath(module); - moduleInterface = module; + sp moduleClient = module->addClient(client); + if (moduleClient == 0) { + return NO_INIT; + } - module->setCaptureState_l(mCaptureState); + moduleClient->setCaptureState_l(mCaptureState); + moduleInterface = moduleClient; return NO_ERROR; } @@ -164,14 +165,6 @@ status_t SoundTriggerHwService::setCaptureState(bool active) } -void SoundTriggerHwService::detachModule(sp module) -{ - ALOGV("detachModule"); - AutoMutex lock(mServiceLock); - module->clearClient(); -} - - static const int kDumpLockRetries = 50; static const int kDumpLockSleep = 60000; @@ -293,8 +286,10 @@ void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognitio return; } - sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_RECOGNITION, - eventMemory, strongModule)); + sp callbackEvent = new CallbackEvent(CallbackEvent::TYPE_RECOGNITION, + eventMemory); + callbackEvent->setModule(strongModule); + sendCallbackEvent_l(callbackEvent); } // static @@ -305,6 +300,7 @@ void SoundTriggerHwService::soundModelCallback(struct sound_trigger_model_event if (module == NULL) { return; } + sp service = module->service().promote(); if (service == 0) { return; @@ -346,8 +342,10 @@ void SoundTriggerHwService::sendSoundModelEvent(struct sound_trigger_model_event if (strongModule == 0) { return; } - sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_SOUNDMODEL, - eventMemory, strongModule)); + sp callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SOUNDMODEL, + eventMemory); + callbackEvent->setModule(strongModule); + sendCallbackEvent_l(callbackEvent); } @@ -383,8 +381,24 @@ void SoundTriggerHwService::sendServiceStateEvent_l(sound_trigger_service_state_ if (strongModule == 0) { return; } - sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE, - eventMemory, strongModule)); + sp callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE, + eventMemory); + callbackEvent->setModule(strongModule); + sendCallbackEvent_l(callbackEvent); +} + +void SoundTriggerHwService::sendServiceStateEvent_l(sound_trigger_service_state_t state, + ModuleClient *moduleClient) +{ + sp eventMemory = prepareServiceStateEvent_l(state); + if (eventMemory == 0) { + return; + } + + sp callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE, + eventMemory); + callbackEvent->setModuleClient(moduleClient); + sendCallbackEvent_l(callbackEvent); } // call with mServiceLock held @@ -397,14 +411,25 @@ void SoundTriggerHwService::onCallbackEvent(const sp& event) { ALOGV("onCallbackEvent"); sp module; + sp moduleClient; { AutoMutex lock(mServiceLock); + //CallbackEvent is either for Module or ModuleClient module = event->mModule.promote(); if (module == 0) { - return; + moduleClient = event->mModuleClient.promote(); + if (moduleClient == 0) { + return; + } } } - module->onCallbackEvent(event); + if (module != 0) { + ALOGV("onCallbackEvent for module"); + module->onCallbackEvent(event); + } else if (moduleClient != 0) { + ALOGV("onCallbackEvent for moduleClient"); + moduleClient->onCallbackEvent(event); + } { AutoMutex lock(mServiceLock); // clear now to execute with mServiceLock locked @@ -474,9 +499,8 @@ void SoundTriggerHwService::CallbackThread::sendCallbackEvent( mCallbackCond.signal(); } -SoundTriggerHwService::CallbackEvent::CallbackEvent(event_type type, sp memory, - wp module) - : mType(type), mMemory(memory), mModule(module) +SoundTriggerHwService::CallbackEvent::CallbackEvent(event_type type, sp memory) + : mType(type), mMemory(memory) { } @@ -490,51 +514,74 @@ SoundTriggerHwService::CallbackEvent::~CallbackEvent() SoundTriggerHwService::Module::Module(const sp& service, sound_trigger_hw_device* hwDevice, - sound_trigger_module_descriptor descriptor, - const sp& client) + sound_trigger_module_descriptor descriptor) : mService(service), mHwDevice(hwDevice), mDescriptor(descriptor), - mClient(client), mServiceState(SOUND_TRIGGER_STATE_NO_INIT) + mServiceState(SOUND_TRIGGER_STATE_NO_INIT) { } SoundTriggerHwService::Module::~Module() { + mModuleClients.clear(); } -void SoundTriggerHwService::Module::detach() { - ALOGV("detach()"); - if (!captureHotwordAllowed()) { +sp +SoundTriggerHwService::Module::addClient(const sp& client) +{ + AutoMutex lock(mLock); + sp moduleClient; + + for (size_t i = 0; i < mModuleClients.size(); i++) { + if (mModuleClients[i]->client() == client) { + // Client already present, reject client + return moduleClient; + } + } + moduleClient = new ModuleClient(this, client); + + ALOGV("addClient() client %p", moduleClient.get()); + mModuleClients.add(moduleClient); + + return moduleClient; +} + +void SoundTriggerHwService::Module::detach(const sp& moduleClient) +{ + ALOGV("Module::detach()"); + AutoMutex lock(mLock); + ssize_t index = -1; + + for (size_t i = 0; i < mModuleClients.size(); i++) { + if (mModuleClients[i] == moduleClient) { + index = i; + break; + } + } + if (index == -1) { return; } - { - AutoMutex lock(mLock); - for (size_t i = 0; i < mModels.size(); i++) { - sp model = mModels.valueAt(i); + + ALOGV("remove client %p", moduleClient.get()); + mModuleClients.removeAt(index); + + for (size_t i = 0; i < mModels.size(); i++) { + sp model = mModels.valueAt(i); + if (moduleClient == model->mModuleClient) { + mModels.removeItemsAt(i); ALOGV("detach() unloading model %d", model->mHandle); if (model->mState == Model::STATE_ACTIVE) { mHwDevice->stop_recognition(mHwDevice, model->mHandle); } + AudioSystem::releaseSoundTriggerSession(model->mCaptureSession); mHwDevice->unload_sound_model(mHwDevice, model->mHandle); } - mModels.clear(); - } - if (mClient != 0) { - IInterface::asBinder(mClient)->unlinkToDeath(this); - } - sp service = mService.promote(); - if (service == 0) { - return; } - service->detachModule(this); } status_t SoundTriggerHwService::Module::loadSoundModel(const sp& modelMemory, - sound_model_handle_t *handle) + sp moduleClient, + sound_model_handle_t *handle) { ALOGV("loadSoundModel() handle"); - if (!captureHotwordAllowed()) { - return PERMISSION_DENIED; - } - if (modelMemory == 0 || modelMemory->pointer() == NULL) { ALOGE("loadSoundModel() modelMemory is 0 or has NULL pointer()"); return BAD_VALUE; @@ -582,7 +629,8 @@ status_t SoundTriggerHwService::Module::loadSoundModel(const sp& modelM return status; } - sp model = new Model(*handle, session, ioHandle, device, sound_model->type); + sp model = new Model(*handle, session, ioHandle, device, sound_model->type, + moduleClient); mModels.replaceValueFor(*handle, model); return status; @@ -591,10 +639,6 @@ status_t SoundTriggerHwService::Module::loadSoundModel(const sp& modelM status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t handle) { ALOGV("unloadSoundModel() model handle %d", handle); - if (!captureHotwordAllowed()) { - return PERMISSION_DENIED; - } - AutoMutex lock(mLock); return unloadSoundModel_l(handle); } @@ -619,10 +663,6 @@ status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t ha const sp& dataMemory) { ALOGV("startRecognition() model handle %d", handle); - if (!captureHotwordAllowed()) { - return PERMISSION_DENIED; - } - if (dataMemory == 0 || dataMemory->pointer() == NULL) { ALOGE("startRecognition() dataMemory is 0 or has NULL pointer()"); return BAD_VALUE; @@ -672,10 +712,6 @@ status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t ha status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle) { ALOGV("stopRecognition() model handle %d", handle); - if (!captureHotwordAllowed()) { - return PERMISSION_DENIED; - } - AutoMutex lock(mLock); sp model = getModel(handle); if (model == 0) { @@ -690,7 +726,6 @@ status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t han return NO_ERROR; } - void SoundTriggerHwService::Module::onCallbackEvent(const sp& event) { ALOGV("onCallbackEvent type %d", event->mType); @@ -700,8 +735,8 @@ void SoundTriggerHwService::Module::onCallbackEvent(const sp& eve if (eventMemory == 0 || eventMemory->pointer() == NULL) { return; } - if (mClient == 0) { - ALOGI("%s mClient == 0", __func__); + if (mModuleClients.isEmpty()) { + ALOGI("%s no clients", __func__); return; } @@ -724,7 +759,7 @@ void SoundTriggerHwService::Module::onCallbackEvent(const sp& eve recognitionEvent->capture_session = model->mCaptureSession; model->mState = Model::STATE_IDLE; - client = mClient; + client = model->mModuleClient->client(); } if (client != 0) { client->onRecognitionEvent(eventMemory); @@ -741,20 +776,24 @@ void SoundTriggerHwService::Module::onCallbackEvent(const sp& eve ALOGW("%s model == 0", __func__); return; } - client = mClient; + client = model->mModuleClient->client(); } if (client != 0) { client->onSoundModelEvent(eventMemory); } } break; case CallbackEvent::TYPE_SERVICE_STATE: { - sp client; + Vector< sp > clients; { AutoMutex lock(mLock); - client = mClient; + for (size_t i = 0; i < mModuleClients.size(); i++) { + if (mModuleClients[i] != 0) { + clients.add(mModuleClients[i]->client()); + } + } } - if (client != 0) { - client->onServiceStateChange(eventMemory); + for (size_t i = 0; i < clients.size(); i++) { + clients[i]->onServiceStateChange(eventMemory); } } break; default: @@ -773,12 +812,6 @@ sp SoundTriggerHwService::Module::getModel( return model; } -void SoundTriggerHwService::Module::binderDied( - const wp &who __unused) { - ALOGW("client binder died for module %d", mDescriptor.handle); - detach(); -} - // Called with mServiceLock held void SoundTriggerHwService::Module::setCaptureState_l(bool active) { @@ -867,8 +900,10 @@ void SoundTriggerHwService::Module::setCaptureState_l(bool active) } for (size_t i = 0; i < events.size(); i++) { - service->sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_RECOGNITION, events[i], - this)); + sp callbackEvent = new CallbackEvent(CallbackEvent::TYPE_RECOGNITION, + events[i]); + callbackEvent->setModule(this); + service->sendCallbackEvent_l(callbackEvent); } exit: @@ -878,17 +913,171 @@ void SoundTriggerHwService::Module::setCaptureState_l(bool active) SoundTriggerHwService::Model::Model(sound_model_handle_t handle, audio_session_t session, audio_io_handle_t ioHandle, audio_devices_t device, - sound_trigger_sound_model_type_t type) : + sound_trigger_sound_model_type_t type, + sp& moduleClient) : mHandle(handle), mState(STATE_IDLE), mCaptureSession(session), - mCaptureIOHandle(ioHandle), mCaptureDevice(device), mType(type) + mCaptureIOHandle(ioHandle), mCaptureDevice(device), mType(type), + mModuleClient(moduleClient) { } -status_t SoundTriggerHwService::Module::dump(int fd __unused, - const Vector& args __unused) { +#undef LOG_TAG +#define LOG_TAG "SoundTriggerHwService::ModuleClient" + +SoundTriggerHwService::ModuleClient::ModuleClient(const sp& module, + const sp& client) + : mModule(module), mClient(client) +{ +} + +void SoundTriggerHwService::ModuleClient::onFirstRef() +{ + IInterface::asBinder(mClient)->linkToDeath(this); +} + +SoundTriggerHwService::ModuleClient::~ModuleClient() +{ +} + +status_t SoundTriggerHwService::ModuleClient::dump(int fd __unused, + const Vector& args __unused) { String8 result; return NO_ERROR; } +void SoundTriggerHwService::ModuleClient::detach() { + ALOGV("detach()"); + if (!captureHotwordAllowed()) { + return; + } + + { + AutoMutex lock(mLock); + if (mClient != 0) { + IInterface::asBinder(mClient)->unlinkToDeath(this); + mClient.clear(); + } + } + + sp module = mModule.promote(); + if (module == 0) { + return; + } + module->detach(this); +} + +status_t SoundTriggerHwService::ModuleClient::loadSoundModel(const sp& modelMemory, + sound_model_handle_t *handle) +{ + ALOGV("loadSoundModel() handle"); + if (!captureHotwordAllowed()) { + return PERMISSION_DENIED; + } + + sp module = mModule.promote(); + if (module == 0) { + return NO_INIT; + } + return module->loadSoundModel(modelMemory, this, handle); +} + +status_t SoundTriggerHwService::ModuleClient::unloadSoundModel(sound_model_handle_t handle) +{ + ALOGV("unloadSoundModel() model handle %d", handle); + if (!captureHotwordAllowed()) { + return PERMISSION_DENIED; + } + + sp module = mModule.promote(); + if (module == 0) { + return NO_INIT; + } + return module->unloadSoundModel(handle); +} + +status_t SoundTriggerHwService::ModuleClient::startRecognition(sound_model_handle_t handle, + const sp& dataMemory) +{ + ALOGV("startRecognition() model handle %d", handle); + if (!captureHotwordAllowed()) { + return PERMISSION_DENIED; + } + + sp module = mModule.promote(); + if (module == 0) { + return NO_INIT; + } + return module->startRecognition(handle, dataMemory); +} + +status_t SoundTriggerHwService::ModuleClient::stopRecognition(sound_model_handle_t handle) +{ + ALOGV("stopRecognition() model handle %d", handle); + if (!captureHotwordAllowed()) { + return PERMISSION_DENIED; + } + + sp module = mModule.promote(); + if (module == 0) { + return NO_INIT; + } + return module->stopRecognition(handle); +} + +void SoundTriggerHwService::ModuleClient::setCaptureState_l(bool active) +{ + ALOGV("ModuleClient::setCaptureState_l %d", active); + sp service; + sound_trigger_service_state_t state; + + sp module = mModule.promote(); + if (module == 0) { + return; + } + { + AutoMutex lock(mLock); + state = (active && !module->isConcurrentCaptureAllowed()) ? + SOUND_TRIGGER_STATE_DISABLED : SOUND_TRIGGER_STATE_ENABLED; + + service = module->service().promote(); + if (service == 0) { + return; + } + } + service->sendServiceStateEvent_l(state, this); +} + +void SoundTriggerHwService::ModuleClient::onCallbackEvent(const sp& event) +{ + ALOGV("ModuleClient onCallbackEvent type %d", event->mType); + + sp eventMemory = event->mMemory; + + if (eventMemory == 0 || eventMemory->pointer() == NULL) { + return; + } + + switch (event->mType) { + case CallbackEvent::TYPE_SERVICE_STATE: { + sp client; + { + AutoMutex lock(mLock); + client = mClient; + } + if (client !=0 ) { + client->onServiceStateChange(eventMemory); + } + } break; + default: + LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType); + } +} + +void SoundTriggerHwService::ModuleClient::binderDied( + const wp &who __unused) { + ALOGW("client binder died for client %p", this); + detach(); +} + }; // namespace android diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h index 2619a5fb4..fcb189dd0 100644 --- a/services/soundtrigger/SoundTriggerHwService.h +++ b/services/soundtrigger/SoundTriggerHwService.h @@ -39,6 +39,7 @@ class SoundTriggerHwService : friend class BinderService; public: class Module; + class ModuleClient; static char const* getServiceName() { return "media.sound_trigger_hw"; } @@ -69,7 +70,8 @@ class SoundTriggerHwService : }; Model(sound_model_handle_t handle, audio_session_t session, audio_io_handle_t ioHandle, - audio_devices_t device, sound_trigger_sound_model_type_t type); + audio_devices_t device, sound_trigger_sound_model_type_t type, + sp& moduleClient); ~Model() {} sound_model_handle_t mHandle; @@ -79,6 +81,7 @@ class SoundTriggerHwService : audio_devices_t mCaptureDevice; sound_trigger_sound_model_type_t mType; struct sound_trigger_recognition_config mConfig; + sp mModuleClient; }; class CallbackEvent : public RefBase { @@ -88,30 +91,30 @@ class SoundTriggerHwService : TYPE_SOUNDMODEL, TYPE_SERVICE_STATE, } event_type; - CallbackEvent(event_type type, sp memory, wp module); + CallbackEvent(event_type type, sp memory); virtual ~CallbackEvent(); + void setModule(wp module) { mModule = module; } + void setModuleClient(wp moduleClient) { mModuleClient = moduleClient; } + event_type mType; sp mMemory; wp mModule; + wp mModuleClient; }; - class Module : public virtual RefBase, - public BnSoundTrigger, - public IBinder::DeathRecipient { + class Module : public RefBase { public: Module(const sp& service, sound_trigger_hw_device* hwDevice, - sound_trigger_module_descriptor descriptor, - const sp& client); + sound_trigger_module_descriptor descriptor); virtual ~Module(); - virtual void detach(); - virtual status_t loadSoundModel(const sp& modelMemory, + sp moduleClient, sound_model_handle_t *handle); virtual status_t unloadSoundModel(sound_model_handle_t handle); @@ -120,39 +123,75 @@ class SoundTriggerHwService : const sp& dataMemory); virtual status_t stopRecognition(sound_model_handle_t handle); - virtual status_t dump(int fd, const Vector& args); - - sound_trigger_hw_device *hwDevice() const { return mHwDevice; } struct sound_trigger_module_descriptor descriptor() { return mDescriptor; } - void setClient(sp client) { mClient = client; } - void clearClient() { mClient.clear(); } - sp client() const { return mClient; } wp service() const { return mService; } - - void onCallbackEvent(const sp& event); + bool isConcurrentCaptureAllowed() const { return mDescriptor.properties.concurrent_capture; } sp getModel(sound_model_handle_t handle); void setCaptureState_l(bool active); - // IBinder::DeathRecipient implementation - virtual void binderDied(const wp &who); + sp addClient(const sp& client); - private: + void detach(const sp& moduleClient); + + void onCallbackEvent(const sp& event); - status_t unloadSoundModel_l(sound_model_handle_t handle); + private: + status_t unloadSoundModel_l(sound_model_handle_t handle); Mutex mLock; wp mService; struct sound_trigger_hw_device* mHwDevice; struct sound_trigger_module_descriptor mDescriptor; - sp mClient; + Vector< sp > mModuleClients; DefaultKeyedVector< sound_model_handle_t, sp > mModels; sound_trigger_service_state_t mServiceState; }; // class Module + class ModuleClient : public virtual RefBase, + public BnSoundTrigger, + public IBinder::DeathRecipient { + public: + + ModuleClient(const sp& module, + const sp& client); + + virtual ~ModuleClient(); + + virtual void detach(); + + virtual status_t loadSoundModel(const sp& modelMemory, + sound_model_handle_t *handle); + + virtual status_t unloadSoundModel(sound_model_handle_t handle); + + virtual status_t startRecognition(sound_model_handle_t handle, + const sp& dataMemory); + virtual status_t stopRecognition(sound_model_handle_t handle); + + virtual status_t dump(int fd, const Vector& args); + + virtual void onFirstRef(); + + // IBinder::DeathRecipient implementation + virtual void binderDied(const wp &who); + + void onCallbackEvent(const sp& event); + + void setCaptureState_l(bool active); + + sp client() const { return mClient; } + + private: + + mutable Mutex mLock; + wp mModule; + sp mClient; + }; // class ModuleClient + class CallbackThread : public Thread { public: @@ -176,8 +215,6 @@ class SoundTriggerHwService : Vector< sp > mEventQueue; }; - void detachModule(sp module); - static void recognitionCallback(struct sound_trigger_recognition_event *event, void *cookie); sp prepareRecognitionEvent_l(struct sound_trigger_recognition_event *event); void sendRecognitionEvent(struct sound_trigger_recognition_event *event, Module *module); @@ -188,6 +225,8 @@ class SoundTriggerHwService : sp prepareServiceStateEvent_l(sound_trigger_service_state_t state); void sendServiceStateEvent_l(sound_trigger_service_state_t state, Module *module); + void sendServiceStateEvent_l(sound_trigger_service_state_t state, + ModuleClient *moduleClient); void sendCallbackEvent_l(const sp& event); void onCallbackEvent(const sp& event); From a155de4d70e0b9ac8fc02b2bdcbb2e8e6cca46ff Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Tue, 15 Nov 2016 17:19:58 -0800 Subject: [PATCH 15/93] Effect: Use local cached data for Effect commit Test: POC, Cts Effect, BassBoost, EnvReverb, Equalizer, Test: LoudnessEnhancer, PresetReverb, Virtualizer, Visualizer Bug: 32220769 Change-Id: Iea96ba0daf71691ee8954cca4ba1c10fe827626e (cherry picked from commit dd79ccda92c1e9b982b2d0f8877d98e5258fbb73) --- services/audioflinger/Effects.cpp | 57 ++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index bb3067f27..2f3c18379 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -1289,36 +1289,54 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode, // particular client process: no risk to block the whole media server process or mixer // threads if we are stuck here Mutex::Autolock _l(mCblk->lock); - if (mCblk->clientIndex > EFFECT_PARAM_BUFFER_SIZE || - mCblk->serverIndex > EFFECT_PARAM_BUFFER_SIZE) { + + // keep local copy of index in case of client corruption b/32220769 + const uint32_t clientIndex = mCblk->clientIndex; + const uint32_t serverIndex = mCblk->serverIndex; + if (clientIndex > EFFECT_PARAM_BUFFER_SIZE || + serverIndex > EFFECT_PARAM_BUFFER_SIZE) { mCblk->serverIndex = 0; mCblk->clientIndex = 0; return BAD_VALUE; } status_t status = NO_ERROR; - while (mCblk->serverIndex < mCblk->clientIndex) { - int reply; - uint32_t rsize = sizeof(int); - int *p = (int *)(mBuffer + mCblk->serverIndex); - int size = *p++; - if (((uint8_t *)p + size) > mBuffer + mCblk->clientIndex) { + effect_param_t *param = NULL; + for (uint32_t index = serverIndex; index < clientIndex;) { + int *p = (int *)(mBuffer + index); + const int size = *p++; + if (size < 0 + || size > EFFECT_PARAM_BUFFER_SIZE + || ((uint8_t *)p + size) > mBuffer + clientIndex) { ALOGW("command(): invalid parameter block size"); + status = BAD_VALUE; break; } - effect_param_t *param = (effect_param_t *)p; - if (param->psize == 0 || param->vsize == 0) { - ALOGW("command(): null parameter or value size"); - mCblk->serverIndex += size; - continue; + + // copy to local memory in case of client corruption b/32220769 + param = (effect_param_t *)realloc(param, size); + if (param == NULL) { + ALOGW("command(): out of memory"); + status = NO_MEMORY; + break; } - uint32_t psize = sizeof(effect_param_t) + - ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + - param->vsize; + memcpy(param, p, size); + + int reply = 0; + uint32_t rsize = sizeof(reply); status_t ret = mEffect->command(EFFECT_CMD_SET_PARAM, - psize, - p, + size, + param, &rsize, &reply); + + // verify shared memory: server index shouldn't change; client index can't go back. + if (serverIndex != mCblk->serverIndex + || clientIndex > mCblk->clientIndex) { + android_errorWriteLog(0x534e4554, "32220769"); + status = BAD_VALUE; + break; + } + // stop at first error encountered if (ret != NO_ERROR) { status = ret; @@ -1328,8 +1346,9 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode, *(int *)pReplyData = reply; break; } - mCblk->serverIndex += size; + index += size; } + free(param); mCblk->serverIndex = 0; mCblk->clientIndex = 0; return status; From b0bcddb44d992e74140a3f5eedc7177977ea8e34 Mon Sep 17 00:00:00 2001 From: rago Date: Tue, 22 Nov 2016 18:02:48 -0800 Subject: [PATCH 16/93] Fix security vulnerability: potential OOB write in audioserver Bug: 32705438 Bug: 32703959 Test: cts security test Change-Id: I8900c92fa55b56c4c2c9d721efdbabe6bfc8a4a4 (cherry picked from commit e275907e576601a3579747c3a842790bacf111e2) --- .../lvm/wrapper/Bundle/EffectBundle.cpp | 27 ++++++++++++++----- media/libmedia/IEffect.cpp | 12 +++++++++ services/audioflinger/Effects.cpp | 16 +++++++++++ 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index ed38584d9..c0d7c6c1b 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -3117,10 +3117,6 @@ int Effect_command(effect_handle_t self, //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_GET_PARAM start"); effect_param_t *p = (effect_param_t *)pCmdData; - if (SIZE_MAX - sizeof(effect_param_t) < (size_t)p->psize) { - android_errorWriteLog(0x534e4554, "26347509"); - return -EINVAL; - } if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) || cmdSize < (sizeof(effect_param_t) + p->psize) || pReplyData == NULL || replySize == NULL || @@ -3128,13 +3124,32 @@ int Effect_command(effect_handle_t self, ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: ERROR"); return -EINVAL; } + if (EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) < (size_t)p->psize) { + android_errorWriteLog(0x534e4554, "26347509"); + ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: psize too big"); + return -EINVAL; + } + uint32_t paddedParamSize = ((p->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) * + sizeof(int32_t); + if ((EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) < paddedParamSize) || + (EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) - paddedParamSize < + p->vsize)) { + ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: padded_psize or vsize too big"); + return -EINVAL; + } + uint32_t expectedReplySize = sizeof(effect_param_t) + paddedParamSize + p->vsize; + if (*replySize < expectedReplySize) { + ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: min. replySize %u, got %u bytes", + expectedReplySize, *replySize); + android_errorWriteLog(0x534e4554, "32705438"); + return -EINVAL; + } memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize); p = (effect_param_t *)pReplyData; - int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); - + uint32_t voffset = paddedParamSize; if(pContext->EffectType == LVM_BASS_BOOST){ p->status = android::BassBoost_getParameter(pContext, p->data, diff --git a/media/libmedia/IEffect.cpp b/media/libmedia/IEffect.cpp index faf579509..af6d8de85 100644 --- a/media/libmedia/IEffect.cpp +++ b/media/libmedia/IEffect.cpp @@ -25,6 +25,9 @@ namespace android { +// Maximum command/reply size expected +#define EFFECT_PARAM_SIZE_MAX 65536 + enum { ENABLE = IBinder::FIRST_CALL_TRANSACTION, DISABLE, @@ -156,6 +159,10 @@ status_t BnEffect::onTransact( uint32_t cmdSize = data.readInt32(); char *cmd = NULL; if (cmdSize) { + if (cmdSize > EFFECT_PARAM_SIZE_MAX) { + reply->writeInt32(NO_MEMORY); + return NO_ERROR; + } cmd = (char *)calloc(cmdSize, 1); if (cmd == NULL) { reply->writeInt32(NO_MEMORY); @@ -167,6 +174,11 @@ status_t BnEffect::onTransact( uint32_t replySz = replySize; char *resp = NULL; if (replySize) { + if (replySize > EFFECT_PARAM_SIZE_MAX) { + free(cmd); + reply->writeInt32(NO_MEMORY); + return NO_ERROR; + } resp = (char *)calloc(replySize, 1); if (resp == NULL) { free(cmd); diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index 2f3c18379..0d245cb04 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -607,6 +607,22 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode, android_errorWriteLog(0x534e4554, "32438594"); return -EINVAL; } + if (cmdCode == EFFECT_CMD_GET_PARAM && + (sizeof(effect_param_t) > *replySize + || ((effect_param_t *)pCmdData)->psize > *replySize + - sizeof(effect_param_t) + || ((effect_param_t *)pCmdData)->vsize > *replySize + - sizeof(effect_param_t) + - ((effect_param_t *)pCmdData)->psize + || roundUpDelta(((effect_param_t *)pCmdData)->psize, (uint32_t)sizeof(int)) > + *replySize + - sizeof(effect_param_t) + - ((effect_param_t *)pCmdData)->psize + - ((effect_param_t *)pCmdData)->vsize)) { + ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: reply size inconsistent"); + android_errorWriteLog(0x534e4554, "32705438"); + return -EINVAL; + } if ((cmdCode == EFFECT_CMD_SET_PARAM || cmdCode == EFFECT_CMD_SET_PARAM_DEFERRED) && // DEFERRED not generally used (sizeof(effect_param_t) > cmdSize From 62acd24ab04f05704474a229047aeecd8bb181a9 Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Tue, 20 Dec 2016 13:44:17 -0800 Subject: [PATCH 17/93] AudioRecord: Check object state on entering read Proceed with AudioRecord::read only if object state is active. An active AudioRecord instance can become inactive if restoreRecord fails (for example due to concurrency with other AudioRecord instances) CRs-Fixed: 1101547 Bug: 26229717 Change-Id: I2a1d0c32b29e0da3e0c457e43f006388fc7b2433 --- media/libmedia/AudioRecord.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 31c851f2a..b2153c15a 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -875,7 +875,7 @@ audio_io_handle_t AudioRecord::getInputPrivate() const ssize_t AudioRecord::read(void* buffer, size_t userSize, bool blocking) { - if (mTransfer != TRANSFER_SYNC) { + if ((mTransfer != TRANSFER_SYNC) || !mActive) { return INVALID_OPERATION; } From d2e4e5e70b3bf0e87dfca902edbae20bc2af88cd Mon Sep 17 00:00:00 2001 From: Cong Jiajia Date: Fri, 25 Nov 2016 18:26:15 +0800 Subject: [PATCH 18/93] HLS: force audio/video both to start from IDR position force audio/video both to start from video last preceding IDR position after suspend/resume or seek operation, to make playback smooth Change-Id: I868da2db100459f2971dcfa2fe9c54295f8c31ec CRs-Fixed: 1077339 --- media/libstagefright/httplive/LiveSession.cpp | 8 ++ .../httplive/PlaylistFetcher.cpp | 74 ++++++++++++++++++- .../libstagefright/httplive/PlaylistFetcher.h | 3 + 3 files changed, 81 insertions(+), 4 deletions(-) mode change 100644 => 100755 media/libstagefright/httplive/LiveSession.cpp mode change 100644 => 100755 media/libstagefright/httplive/PlaylistFetcher.cpp diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp old mode 100644 new mode 100755 index 33ad5ace9..ffc0b72b1 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -429,6 +429,14 @@ status_t LiveSession::dequeueAccessUnit( } else { mDiscontinuityAbsStartTimesUs.add(strm.mCurDiscontinuitySeq, timeUs); firstTimeUs = timeUs; + // we have adjusted a/v both start from last preceding IDR position, it's always + // before original seek position, so we need to adjust mLastSeekTimeUs to the + // actual start position + int64_t newSeekTimeUs = -1; + if ((*accessUnit)->meta()->findInt64("newSeekTimeUs", &newSeekTimeUs) + && newSeekTimeUs != -1) { + mLastSeekTimeUs = newSeekTimeUs; + } } strm.mLastDequeuedTimeUs = timeUs; diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp old mode 100644 new mode 100755 index d6bd191e7..c3d465084 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -158,6 +158,8 @@ PlaylistFetcher::PlaylistFetcher( mNumRetries(0), mStartup(true), mIDRFound(false), + mLastIDRFound(false), + mLastIDRTimeUs(-1), mSeekMode(LiveSession::kSeekModeExactPosition), mTimeChangeSignaled(false), mNextPTSTimeUs(-1ll), @@ -168,6 +170,7 @@ PlaylistFetcher::PlaylistFetcher( mFirstPTSValid(false), mFirstTimeUs(-1ll), mVideoBuffer(new AnotherPacketSource(NULL)), + mAudioBuffer(new AnotherPacketSource(NULL)), mThresholdRatio(-1.0f), mDownloadState(new DownloadState()), mHasMetadata(false) { @@ -703,7 +706,9 @@ status_t PlaylistFetcher::onStart(const sp &msg) { if (startTimeUs >= 0 || mSeekMode == LiveSession::kSeekModeNextSample) { mStartup = true; mIDRFound = false; + mLastIDRFound = false; mVideoBuffer->clear(); + mAudioBuffer->clear(); } if (startTimeUs >= 0) { @@ -1115,6 +1120,7 @@ bool PlaylistFetcher::initDownloadState( // properties in extractAndQueueAccessUnitsFromTs. sp buffer = new ABuffer(0); mSeqNumber = lastSeqNumberInPlaylist; + mLastIDRTimeUs = -1; extractAndQueueAccessUnitsFromTs(buffer); } notifyError(ERROR_END_OF_STREAM); @@ -1213,7 +1219,9 @@ bool PlaylistFetcher::initDownloadState( mStartTimeUs = 0; mFirstPTSValid = false; mIDRFound = false; + mLastIDRFound = false; mVideoBuffer->clear(); + mAudioBuffer->clear(); } } @@ -1262,6 +1270,7 @@ void PlaylistFetcher::onDownloadNext() { // block-wise download bool shouldPause = false; ssize_t bytesRead; + mLastIDRTimeUs = -1; do { int64_t startUs = ALooper::GetNowUs(); bytesRead = mHTTPDownloader->fetchBlock( @@ -1577,6 +1586,8 @@ const sp &PlaylistFetcher::setAccessUnitProperties( if (discard) { accessUnit->meta()->setInt32("discard", discard); + } else { + accessUnit->meta()->setInt64("newSeekTimeUs", mLastIDRTimeUs); } accessUnit->meta()->setInt32("discontinuitySeq", mDiscontinuitySeq); @@ -1698,6 +1709,7 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &bu mStartTimeUsNotify->setInt32("what", kWhatStartedAt); mStartTimeUsNotify->setString("uri", mURI); mIDRFound = false; + mLastIDRFound = false; mSegmentStartTimeUs = -1; return -EAGAIN; } @@ -1705,14 +1717,19 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &bu } status_t err = OK; + mLastIDRFound = false; + bool hasAvcSource = false; for (size_t i = mPacketSources.size(); i > 0;) { i--; + bool isAudio = false; sp packetSource = mPacketSources.valueAt(i); const LiveSession::StreamType stream = mPacketSources.keyAt(i); if (stream == LiveSession::STREAMTYPE_SUBTITLES) { ALOGE("MPEG2 Transport streams do not contain subtitles."); return ERROR_MALFORMED; + } else if (stream == LiveSession::STREAMTYPE_AUDIO) { + isAudio = true; } const char *key = LiveSession::getKeyForStream(stream); @@ -1732,6 +1749,10 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &bu && (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)); + if (isAvc) { + hasAvcSource = true; + } + sp accessUnit; status_t finalResult; while (source->hasBufferAvailable(&finalResult) @@ -1743,7 +1764,7 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &bu if (mStartup) { bool startTimeReached = isStartTimeReached(timeUs); - if (!startTimeReached || (isAvc && !mIDRFound)) { + if (!startTimeReached) { // buffer up to the closest preceding IDR frame in the next segement, // or the closest succeeding IDR frame after the exact position FSLOGV(stream, "timeUs(%lld)-mStartTimeUs(%lld)=%lld, mIDRFound=%d", @@ -1751,20 +1772,50 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &bu (long long)mStartTimeUs, (long long)timeUs - mStartTimeUs, mIDRFound); + // finding video last preceding IRD, caching video buffers from last + // preceding IDR to seek time if (isAvc) { if (IsIDR(accessUnit) || AVUtils::get()->IsHevcIDR(accessUnit)) { mVideoBuffer->clear(); - FSLOGV(stream, "found IDR, clear mVideoBuffer"); + FSLOGV(stream, "found IDR, clear mVideoBuffer, save IDR timestamp"); mIDRFound = true; + mLastIDRTimeUs = timeUs; } if (mIDRFound && mStartTimeUsRelative && !startTimeReached) { mVideoBuffer->queueAccessUnit(accessUnit); FSLOGV(stream, "saving AVC video AccessUnit"); } + continue; } - if (!startTimeReached || (isAvc && !mIDRFound)) { + + // only when current ts segment contains avc/hevc source, IDR frame can be found + // caching audio buffers from last video preceding IDR to seek time. If video + // last IDR is found before audio reached this IDR position, will clear audio + // buffers and start from IDR pisition (new start time). If audio reached seek + // time before last preceding IDR is found, the redundant audio buffers will be + // discared when queuing buffers to LiveSession + if (isAudio && hasAvcSource) { + if (!mLastIDRFound) { + mAudioBuffer->queueAccessUnit(accessUnit); + FSLOGV(stream, "saving audio AccessUnit"); + } else if (timeUs < mLastIDRTimeUs) { + FSLOGV(stream, "found last preceding IDR, but audio still didn't \ + reach IDR time, clear mAudioBuffer"); + mAudioBuffer->clear(); + } continue; } + } else { + if (isAvc && mIDRFound) { + mLastIDRFound = true; + // last preceding IDR found, set mStartTimeUs to this IDR time, the new + // start time will affect audio stream checking if it has reached start time + if (mStartTimeUsRelative) { + mStartTimeUs = mLastIDRTimeUs - mFirstTimeUs; + } else { + mStartTimeUs = mLastIDRTimeUs; + } + } } } @@ -1801,7 +1852,7 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &bu } if (stream == LiveSession::STREAMTYPE_VIDEO) { - const bool discard = true; + const bool discard = false; status_t status; while (mVideoBuffer->hasBufferAvailable(&status)) { sp videoBuffer; @@ -1813,6 +1864,21 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &bu FSLOGV(stream, "queueAccessUnit (saved), timeUs=%lld", (long long)bufferTimeUs); } + } else if (stream == LiveSession::STREAMTYPE_AUDIO) { + const bool discard = false; + status_t status; + while (mAudioBuffer->hasBufferAvailable(&status)) { + sp audioBuffer; + mAudioBuffer->dequeueAccessUnit(&audioBuffer); + int64_t bufferTimeUs; + CHECK(audioBuffer->meta()->findInt64("timeUs", &bufferTimeUs)); + if (bufferTimeUs >= mLastIDRTimeUs) { + setAccessUnitProperties(audioBuffer, source, discard); + packetSource->queueAccessUnit(audioBuffer); + FSLOGV(stream, "queueAccessUnit (saved), timeUs=%lld", + (long long)bufferTimeUs); + } + } } else if (stream == LiveSession::STREAMTYPE_METADATA && !mHasMetadata) { mHasMetadata = true; sp notify = mNotify->dup(); diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index 6b60b65f3..e0dd51aa4 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -145,6 +145,8 @@ struct PlaylistFetcher : public AHandler { int32_t mNumRetries; bool mStartup; bool mIDRFound; + bool mLastIDRFound; + int64_t mLastIDRTimeUs; int32_t mSeekMode; bool mTimeChangeSignaled; int64_t mNextPTSTimeUs; @@ -170,6 +172,7 @@ struct PlaylistFetcher : public AHandler { int64_t mFirstTimeUs; int64_t mSegmentFirstPTS; sp mVideoBuffer; + sp mAudioBuffer; // Stores the initialization vector to decrypt the next block of cipher text, which can // either be derived from the sequence number, read from the manifest, or copied from From d1593df8271287e86b5984a710654e503bd5bb4b Mon Sep 17 00:00:00 2001 From: Uma Mehta Date: Thu, 22 Dec 2016 15:00:38 +0530 Subject: [PATCH 19/93] Revert "frameworks/av: Set Protected flag only for secure" This reverts commit 5e24b9ca37a93299da4690a372818fcb45ebd604. Change-Id: I282ff86dacedfa3a10e81a86b3aa25e7f5da76b1 --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index b8b35f009..e20b26e16 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -449,7 +449,7 @@ void NuPlayer::GenericSource::onPrepareAsync() { notifyFlagsChanged( (mIsSecure ? FLAG_SECURE : 0) - | ((mIsSecure && (mDecryptHandle != NULL)) ? FLAG_PROTECTED : 0) + | (mDecryptHandle != NULL ? FLAG_PROTECTED : 0) | FLAG_CAN_PAUSE | FLAG_CAN_SEEK_BACKWARD | FLAG_CAN_SEEK_FORWARD From 8b288f400a70a61770bc2146b749cf0402bc7f15 Mon Sep 17 00:00:00 2001 From: Weiyin Jiang Date: Mon, 26 Dec 2016 14:12:41 +0800 Subject: [PATCH 20/93] audio: allow effect chain on direct output if it's pcm offload Allow effect chain on direct output if it's pcm offload use case. Change-Id: I62335ad16091bc6d318b4ca0c014bd6bf160c18d CRs-Fixed: 1102537 --- services/audioflinger/Threads.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 08ccc8e94..a29e81556 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -1380,6 +1380,11 @@ status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l( case DIRECT: // Reject any effect on Direct output threads for now, since the format of // mSinkBuffer is not guaranteed to be compatible with effect processing (PCM 16 stereo). + // Exception: allow effects for Direct PCM + if (mIsDirectPcm) { + // Allow effects when direct PCM enabled on Direct output + break; + } ALOGW("checkEffectCompatibility_l(): effect %s on DIRECT output thread %s", desc->name, mThreadName); return BAD_VALUE; From 53fb6f8bf9398bd55b31142dd02a4baf0d98dd7b Mon Sep 17 00:00:00 2001 From: Sharad Sangle Date: Wed, 30 Nov 2016 17:21:06 +0530 Subject: [PATCH 21/93] audio: Don't update the audio_output flag with track flags Use the AUDIO_OUTPUT_FLAG_DIRECT only for creating the track and do not add this in the audio_flags of AudioTrack Change-Id: Ic85ad5aef91e147a209d1c7a3a7ef0728f3d4207 --- media/libmedia/AudioTrack.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 28d923004..f4a74003c 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1438,6 +1438,10 @@ status_t AudioTrack::createTrack_l() } ALOG_ASSERT(track != 0); + if (mTrackOffloaded) { + flags = (audio_output_flags_t)(flags & ~AUDIO_OUTPUT_FLAG_DIRECT); + } + // AudioFlinger now owns the reference to the I/O handle, // so we are no longer responsible for releasing it. From 2aeccaaef54c98850196c330a3a53c66d8714c0d Mon Sep 17 00:00:00 2001 From: Naresh Tanniru Date: Mon, 19 Dec 2016 18:00:12 +0530 Subject: [PATCH 22/93] audio: Reduce offload pause timeout to 3 secs - On split a2dp audio is received on remote device for 10secs after triggering pause of offload session - Offload session is tear down only after 10secs which resulted silence audio stream to BT till pause timeout - Reduce pausetimeout to 3 secs to inline split & non-split a2dp behaviour Change-Id: If7698c36ad04e3ddd2da3dfbd1816be9c6c36870 --- media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 2ebf49148..11ef82f40 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -1792,10 +1792,12 @@ void NuPlayer::Renderer::onAudioTearDown(AudioTearDownReason reason) { void NuPlayer::Renderer::startAudioOffloadPauseTimeout() { if (offloadingAudio()) { + int64_t pauseTimeOutDuration = property_get_int64( + "audio.offload.pstimeout.secs",(kOffloadPauseMaxUs/1000000)/*default*/); mWakeLock->acquire(); sp msg = new AMessage(kWhatAudioOffloadPauseTimeout, this); msg->setInt32("drainGeneration", mAudioOffloadPauseTimeoutGeneration); - msg->post(kOffloadPauseMaxUs); + msg->post(pauseTimeOutDuration*1000000); } } From 32ed9b1c504aa01a55504f493c05eedf1295d200 Mon Sep 17 00:00:00 2001 From: rago Date: Mon, 14 Nov 2016 14:58:34 -0800 Subject: [PATCH 23/93] Fix security vulnerability: Effect command might allow negative indexes Bug: 32448258 Bug: 32095626 Test: Use POC bug or cts security test Change-Id: I69f24eac5866f8d9090fc4c0ebe58c2c297b63df (cherry picked from commit 01183402d757f0c28bfd5e3b127b3809dfd67459) (cherry picked from commit 20cd1eaf8094dd9745ce95bd10dfb25525fce1a4) --- .../libeffects/lvm/wrapper/Bundle/EffectBundle.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index e6126f451..cb16b6cea 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -2407,9 +2407,13 @@ int Equalizer_getParameter(EffectContext *pContext, case EQ_PARAM_GET_PRESET_NAME: param2 = *pParamTemp; - if (param2 >= EqualizerGetNumPresets()) { - //if (param2 >= 20) { // AGO FIX + if ((param2 < 0 && param2 != PRESET_CUSTOM) || param2 >= EqualizerGetNumPresets()) { status = -EINVAL; + if (param2 < 0) { + android_errorWriteLog(0x534e4554, "32448258"); + ALOGE("\tERROR Equalizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d", + param2); + } break; } name = (char *)pValue; @@ -2479,8 +2483,12 @@ int Equalizer_setParameter (EffectContext *pContext, void *pParam, void *pValue) band = *pParamTemp; level = (int32_t)(*(int16_t *)pValue); //ALOGV("\tEqualizer_setParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", band, level); - if (band >= FIVEBAND_NUMBANDS) { + if (band < 0 || band >= FIVEBAND_NUMBANDS) { status = -EINVAL; + if (band < 0) { + android_errorWriteLog(0x534e4554, "32095626"); + ALOGE("\tERROR Equalizer_setParameter() EQ_PARAM_BAND_LEVEL band %d", band); + } break; } EqualizerSetBandLevel(pContext, band, level); From eab92353fac670a740961d5c93a0f3dd5de70e85 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 11 Nov 2016 09:20:00 -0800 Subject: [PATCH 24/93] Make VBRISeeker more robust Bug: 32577290 Change-Id: I9bcc9422ae7dd3ae4a38df330c9dcd7ac4941ec8 (cherry picked from commit 7fdd36418e945cf6a500018632dfb0ed8cb1a343) (cherry picked from commit 16e7fa2883a045106deedeb837fa25ef34f4931b) --- media/libstagefright/VBRISeeker.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp index 58f2c6065..5b8f23a77 100644 --- a/media/libstagefright/VBRISeeker.cpp +++ b/media/libstagefright/VBRISeeker.cpp @@ -83,8 +83,23 @@ sp VBRISeeker::CreateFromSource( scale, entrySize); + if (entrySize > 4) { + ALOGE("invalid VBRI entry size: %zu", entrySize); + return NULL; + } + + sp seeker = new (std::nothrow) VBRISeeker; + if (seeker == NULL) { + ALOGW("Couldn't allocate VBRISeeker"); + return NULL; + } + size_t totalEntrySize = numEntries * entrySize; - uint8_t *buffer = new uint8_t[totalEntrySize]; + uint8_t *buffer = new (std::nothrow) uint8_t[totalEntrySize]; + if (!buffer) { + ALOGW("Couldn't allocate %zu bytes", totalEntrySize); + return NULL; + } n = source->readAt(pos + sizeof(vbriHeader), buffer, totalEntrySize); if (n < (ssize_t)totalEntrySize) { @@ -94,7 +109,6 @@ sp VBRISeeker::CreateFromSource( return NULL; } - sp seeker = new VBRISeeker; seeker->mBasePos = post_id3_pos + frameSize; // only update mDurationUs if the calculated duration is valid (non zero) // otherwise, leave duration at -1 so that getDuration() and getOffsetForTime() From f26d767b0724b3cf8bc910a20f81965e3f683f40 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Fri, 4 Nov 2016 19:40:53 -0700 Subject: [PATCH 25/93] Effects: Check get parameter command size Test: Custom test. Bug: 32438594 Bug: 32624850 Bug: 32635664 Change-Id: I9b1315e2c02f11bea395bfdcf5c1ccddccbad8a6 (cherry picked from commit 3d34cc76e315dfa8c3b1edf78835b0dab4980505) (cherry picked from commit a1712f7f89f2a7158669c0d5e84016297ee0ef26) --- services/audioflinger/Effects.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index 154b8a15d..a790ad41e 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -619,6 +619,13 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode, android_errorWriteLog(0x534e4554, "29251553"); return -EINVAL; } + if (cmdCode == EFFECT_CMD_GET_PARAM && + (sizeof(effect_param_t) > cmdSize || + ((effect_param_t *)pCmdData)->psize > cmdSize + - sizeof(effect_param_t))) { + android_errorWriteLog(0x534e4554, "32438594"); + return -EINVAL; + } if ((cmdCode == EFFECT_CMD_SET_PARAM || cmdCode == EFFECT_CMD_SET_PARAM_DEFERRED) && // DEFERRED not generally used (sizeof(effect_param_t) > cmdSize From e6104032b542e40093169e42d61685240af578df Mon Sep 17 00:00:00 2001 From: Ray Essick Date: Wed, 2 Nov 2016 14:17:57 -0700 Subject: [PATCH 26/93] DO NOT MERGE: defensive parsing of mp3 album art information several points in stagefrights mp3 album art code used strlen() to parse user-supplied strings that may be unterminated, resulting in reading beyond the end of a buffer. This changes the code to use strnlen() for 8-bit encodings and strengthens the parsing of 16-bit encodings similarly. It also reworks how we watch for the end-of-buffer to avoid all over-reads. Bug: 32377688 Test: crafted mp3's w/ good/bad cover art. See what showed in play music Change-Id: Ia9f526d71b21ef6a61acacf616b573753cd21df6 (cherry picked from commit fa0806b594e98f1aed3ebcfc6a801b4c0056f9eb) (cherry picked from commit cfc7e9af62c1815c8018d93316de6a788b902032) --- media/libstagefright/id3/ID3.cpp | 56 ++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp index bc561ccb0..ba8ce2a4c 100644 --- a/media/libstagefright/id3/ID3.cpp +++ b/media/libstagefright/id3/ID3.cpp @@ -837,20 +837,21 @@ void ID3::Iterator::findFrame() { } } -static size_t StringSize(const uint8_t *start, uint8_t encoding) { +// return includes terminator; if unterminated, returns > limit +static size_t StringSize(const uint8_t *start, size_t limit, uint8_t encoding) { + if (encoding == 0x00 || encoding == 0x03) { // ISO 8859-1 or UTF-8 - return strlen((const char *)start) + 1; + return strnlen((const char *)start, limit) + 1; } // UCS-2 size_t n = 0; - while (start[n] != '\0' || start[n + 1] != '\0') { + while ((n+1 < limit) && (start[n] != '\0' || start[n + 1] != '\0')) { n += 2; } - - // Add size of null termination. - return n + 2; + n += 2; + return n; } const void * @@ -871,11 +872,19 @@ ID3::getAlbumArt(size_t *length, String8 *mime) const { if (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) { uint8_t encoding = data[0]; - mime->setTo((const char *)&data[1]); - size_t mimeLen = strlen((const char *)&data[1]) + 1; + size_t consumed = 1; + + // *always* in an 8-bit encoding + size_t mimeLen = StringSize(&data[consumed], size - consumed, 0x00); + if (mimeLen > size - consumed) { + ALOGW("bogus album art size: mime"); + return NULL; + } + mime->setTo((const char *)&data[consumed]); + consumed += mimeLen; #if 0 - uint8_t picType = data[1 + mimeLen]; + uint8_t picType = data[consumed]; if (picType != 0x03) { // Front Cover Art it.next(); @@ -883,20 +892,30 @@ ID3::getAlbumArt(size_t *length, String8 *mime) const { } #endif - size_t descLen = StringSize(&data[2 + mimeLen], encoding); + consumed++; + if (consumed >= size) { + ALOGW("bogus album art size: pic type"); + return NULL; + } + + size_t descLen = StringSize(&data[consumed], size - consumed, encoding); + consumed += descLen; - if (size < 2 || - size - 2 < mimeLen || - size - 2 - mimeLen < descLen) { - ALOGW("bogus album art sizes"); + if (consumed >= size) { + ALOGW("bogus album art size: description"); return NULL; } - *length = size - 2 - mimeLen - descLen; - return &data[2 + mimeLen + descLen]; + *length = size - consumed; + + return &data[consumed]; } else { uint8_t encoding = data[0]; + if (size <= 5) { + return NULL; + } + if (!memcmp(&data[1], "PNG", 3)) { mime->setTo("image/png"); } else if (!memcmp(&data[1], "JPG", 3)) { @@ -916,7 +935,10 @@ ID3::getAlbumArt(size_t *length, String8 *mime) const { } #endif - size_t descLen = StringSize(&data[5], encoding); + size_t descLen = StringSize(&data[5], size - 5, encoding); + if (descLen > size - 5) { + return NULL; + } *length = size - 5 - descLen; From d62d387d6e1ffbe1881c03af36c0f01579ad01a8 Mon Sep 17 00:00:00 2001 From: rago Date: Mon, 31 Oct 2016 12:50:20 -0700 Subject: [PATCH 27/93] Fix security vulnerability: Equalizer command might allow negative indexes Bug: 32247948 Bug: 32438598 Bug: 32436341 Test: use POC on bug or cts security test Change-Id: I91bd6aadb6c7410163e03101f365db767f4cd2a3 (cherry picked from commit 0872b65cff9129633471945431b9a5a28418049c) (cherry picked from commit e981cca9fff3608af22bdf8fc1acef5470e25663) (cherry picked from commit b57c79b5d7ba86f3603f35b60576dbf45b8d0c7b) --- .../lvm/wrapper/Bundle/EffectBundle.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index cb16b6cea..536ce78e1 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -2357,8 +2357,12 @@ int Equalizer_getParameter(EffectContext *pContext, case EQ_PARAM_BAND_LEVEL: param2 = *pParamTemp; - if (param2 >= FIVEBAND_NUMBANDS) { + if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) { status = -EINVAL; + if (param2 < 0) { + android_errorWriteLog(0x534e4554, "32438598"); + ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_LEVEL band %d", param2); + } break; } *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, param2); @@ -2368,8 +2372,12 @@ int Equalizer_getParameter(EffectContext *pContext, case EQ_PARAM_CENTER_FREQ: param2 = *pParamTemp; - if (param2 >= FIVEBAND_NUMBANDS) { + if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) { status = -EINVAL; + if (param2 < 0) { + android_errorWriteLog(0x534e4554, "32436341"); + ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_CENTER_FREQ band %d", param2); + } break; } *(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, param2); @@ -2379,8 +2387,12 @@ int Equalizer_getParameter(EffectContext *pContext, case EQ_PARAM_BAND_FREQ_RANGE: param2 = *pParamTemp; - if (param2 >= FIVEBAND_NUMBANDS) { + if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) { status = -EINVAL; + if (param2 < 0) { + android_errorWriteLog(0x534e4554, "32247948"); + ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d", param2); + } break; } EqualizerGetBandFreqRange(pContext, param2, (uint32_t *)pValue, ((uint32_t *)pValue + 1)); From 3bc9a1e88606ee4fde92eb1728fcfcf92d02a4f5 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 26 Oct 2016 17:41:56 -0700 Subject: [PATCH 28/93] stagefright: remove allottedSize equality check in IOMX::useBuffer This was meant for buffers shared cross-process, but we are not gaining anything from this check even if it was at the correct place. Bug: 32436178 Change-Id: I6919e8ac6e35092273e171f49f6711ba577ba2e6 (cherry picked from commit 58388aa7be1c6963eb4b8464d46938ba9b0a04b0) (cherry picked from commit 12ac1ae407b29533ea05f771607ba885b3f72801) --- media/libstagefright/omx/OMXNodeInstance.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index da5a1b1f9..a692d095f 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -809,13 +809,6 @@ status_t OMXNodeInstance::useBuffer( } memset(data, 0, allottedSize); - // if we are not connecting the buffers, the sizes must match - if (allottedSize != params->size()) { - CLOG_ERROR(useBuffer, BAD_VALUE, SIMPLE_BUFFER(portIndex, (size_t)allottedSize, data)); - delete[] data; - return BAD_VALUE; - } - buffer_meta = new BufferMeta( params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, data); } else { From 2436e97712a2f39be8f0637776712e5a7aff165d Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Tue, 18 Oct 2016 17:13:09 -0700 Subject: [PATCH 29/93] Visualizer: Check capture size and latency parameters Bug: 31781965 Change-Id: I1c439a0d0f6aa0057b3c651499f28426e1e1f5e4 (cherry picked from commit 9a2732ba0a8d609ab040d2c1ddee28577ead9772) (cherry picked from commit 6e6e99247dd3349e8c23175e1ae024adb8c5ec9d) --- .../visualizer/EffectVisualizer.cpp | 43 ++++++++++++++----- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp index 21fddb1db..b7d27d6cc 100644 --- a/media/libeffects/visualizer/EffectVisualizer.cpp +++ b/media/libeffects/visualizer/EffectVisualizer.cpp @@ -59,6 +59,8 @@ enum visualizer_state_e { #define DISCARD_MEASUREMENTS_TIME_MS 2000 // discard measurements older than this number of ms +#define MAX_LATENCY_MS 3000 // 3 seconds of latency for audio pipeline + // maximum number of buffers for which we keep track of the measurements #define MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS 25 // note: buffer index is stored in uint8_t @@ -521,18 +523,29 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, break; } switch (*(uint32_t *)p->data) { - case VISUALIZER_PARAM_CAPTURE_SIZE: - pContext->mCaptureSize = *((uint32_t *)p->data + 1); - ALOGV("set mCaptureSize = %" PRIu32, pContext->mCaptureSize); - break; + case VISUALIZER_PARAM_CAPTURE_SIZE: { + const uint32_t captureSize = *((uint32_t *)p->data + 1); + if (captureSize > VISUALIZER_CAPTURE_SIZE_MAX) { + android_errorWriteLog(0x534e4554, "31781965"); + *(int32_t *)pReplyData = -EINVAL; + ALOGW("set mCaptureSize = %u > %u", captureSize, VISUALIZER_CAPTURE_SIZE_MAX); + } else { + pContext->mCaptureSize = captureSize; + ALOGV("set mCaptureSize = %u", captureSize); + } + } break; case VISUALIZER_PARAM_SCALING_MODE: pContext->mScalingMode = *((uint32_t *)p->data + 1); ALOGV("set mScalingMode = %" PRIu32, pContext->mScalingMode); break; - case VISUALIZER_PARAM_LATENCY: - pContext->mLatency = *((uint32_t *)p->data + 1); - ALOGV("set mLatency = %" PRIu32, pContext->mLatency); - break; + case VISUALIZER_PARAM_LATENCY: { + uint32_t latency = *((uint32_t *)p->data + 1); + if (latency > MAX_LATENCY_MS) { + latency = MAX_LATENCY_MS; // clamp latency b/31781965 + } + pContext->mLatency = latency; + ALOGV("set mLatency = %u", latency); + } break; case VISUALIZER_PARAM_MEASUREMENT_MODE: pContext->mMeasurementMode = *((uint32_t *)p->data + 1); ALOGV("set mMeasurementMode = %" PRIu32, pContext->mMeasurementMode); @@ -571,10 +584,18 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, if (latencyMs < 0) { latencyMs = 0; } - const uint32_t deltaSmpl = - pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000; - int32_t capturePoint = pContext->mCaptureIdx - captureSize - deltaSmpl; + uint32_t deltaSmpl = captureSize + + pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000; + + // large sample rate, latency, or capture size, could cause overflow. + // do not offset more than the size of buffer. + if (deltaSmpl > CAPTURE_BUF_SIZE) { + android_errorWriteLog(0x534e4554, "31781965"); + deltaSmpl = CAPTURE_BUF_SIZE; + } + int32_t capturePoint = pContext->mCaptureIdx - deltaSmpl; + // a negative capturePoint means we wrap the buffer. if (capturePoint < 0) { uint32_t size = -capturePoint; if (size > captureSize) { From 71957cb2db9c31fe9735e30fb1a609a55b8b91fb Mon Sep 17 00:00:00 2001 From: Garmond Leung Date: Tue, 6 Dec 2016 16:14:58 -0800 Subject: [PATCH 30/93] libstagefright: Add NULL check during memcpy for MediaCodecSource Add null check for the source buffer prior to memcpy. Change-Id: I5971e0c01fd4821078780c9623154e396f679357 CRs-Fixed: 1096369 --- media/libstagefright/MediaCodecSource.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) mode change 100755 => 100644 media/libstagefright/MediaCodecSource.cpp diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp old mode 100755 new mode 100644 index 97da8d390..904b60cd3 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -709,7 +709,9 @@ status_t MediaCodecSource::feedEncoderInputBuffers() { sp inbuf; status_t err = mEncoder->getInputBuffer(bufferIndex, &inbuf); - if (err != OK || inbuf == NULL) { + + if (err != OK || inbuf == NULL || inbuf->data() == NULL + || mbuf->data() == NULL || mbuf->size() == 0) { mbuf->release(); signalEOS(err); break; @@ -871,12 +873,20 @@ void MediaCodecSource::onMessageReceived(const sp &msg) { sp outbuf; status_t err = mEncoder->getOutputBuffer(index, &outbuf); - if (err != OK || outbuf == NULL) { + if (err != OK || outbuf == NULL || outbuf->data() == NULL + || outbuf->size() == 0) { signalEOS(err); break; } MediaBuffer *mbuf = new MediaBuffer(outbuf->size()); + if (mbuf == NULL || mbuf->data() == NULL || mbuf->size() == 0) { + if ( mbuf ) + mbuf->release(); + signalEOS(err); + break; + } + memcpy(mbuf->data(), outbuf->data(), outbuf->size()); sp meta = mbuf->meta_data(); AVUtils::get()->setDeferRelease(meta); From c69eb0ed2f7e104af21df6ccf9d06fcef5be0e62 Mon Sep 17 00:00:00 2001 From: Praveen Chavan Date: Fri, 21 Oct 2016 14:52:16 -0700 Subject: [PATCH 31/93] stagefright: MPEG4Writer: defer video stop to match last audio time Writer stops the video and audio tracks synchronously. In case video pipeline is running slow, video will be stopped first, resulting in shorter video track in the saved recording. To match durations of video and audio: [a] reverse the order of stopping tracks to stop audio first since audio source stops faster than video. [b] defer stopping video till the video frame-time reaches the time of the last processed audio frame-time. If this event does not happen within 1 second, stop video anyways CRs-Fixed: 1087319 Change-Id: I98c62f927160de10ab2e9068741bd62734ead25c --- include/media/stagefright/MPEG4Writer.h | 4 ++++ media/libstagefright/MPEG4Writer.cpp | 29 ++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h index 5932610ca..d2d9d84ab 100644 --- a/include/media/stagefright/MPEG4Writer.h +++ b/include/media/stagefright/MPEG4Writer.h @@ -225,6 +225,10 @@ class MPEG4Writer : public MediaWriter { static uint32_t getMpeg4Time(); + int64_t mLastAudioTimeStampUs; + void setLastAudioTimeStamp(int64_t ts) {mLastAudioTimeStampUs = ts;} + int64_t getLastAudioTimeStamp() {return mLastAudioTimeStampUs;} + MPEG4Writer(const MPEG4Writer &); MPEG4Writer &operator=(const MPEG4Writer &); }; diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index bbbc86bac..0fdb61e39 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -407,6 +407,10 @@ class MPEG4Writer::Track { Track(const Track &); Track &operator=(const Track &); + + bool mIsStopping; + Mutex mTrackCompletionLock; + Condition mTrackCompletionSignal; }; MPEG4Writer::MPEG4Writer(int fd) @@ -966,8 +970,9 @@ status_t MPEG4Writer::reset() { status_t err = OK; int64_t maxDurationUs = 0; int64_t minDurationUs = 0x7fffffffffffffffLL; - for (List::iterator it = mTracks.begin(); - it != mTracks.end(); ++it) { + List::iterator it = mTracks.end(); + do { + --it; status_t status = (*it)->stop(); if (err == OK && status != OK) { err = status; @@ -980,7 +985,7 @@ status_t MPEG4Writer::reset() { if (durationUs < minDurationUs) { minDurationUs = durationUs; } - } + } while (it != mTracks.begin()); if (mTracks.size() > 1) { ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", @@ -1586,6 +1591,7 @@ MPEG4Writer::Track::Track( } setTimeScale(); + mIsStopping = false; } void MPEG4Writer::Track::updateTrackSizeEstimate() { @@ -1986,6 +1992,14 @@ status_t MPEG4Writer::Track::stop() { if (mDone) { return OK; } + + if (!mIsAudio) { + Mutex::Autolock lock(mTrackCompletionLock); + mIsStopping = true; + if (mTrackCompletionSignal.waitRelative(mTrackCompletionLock, 1e9 /* 1 sec */)) { + ALOGW("Timed-out waiting for video track to reach final audio timestamp !"); + } + } mDone = true; ALOGD("%s track source stopping", mIsAudio? "Audio": "Video"); @@ -2766,6 +2780,15 @@ status_t MPEG4Writer::Track::threadEntry() { } } + if (mIsAudio) { + mOwner->setLastAudioTimeStamp(lastTimestampUs); + } else if (mIsStopping && timestampUs >= mOwner->getLastAudioTimeStamp()) { + ALOGI("Video time (%lld) reached last audio time (%lld)", (long long)timestampUs, (long long)mOwner->getLastAudioTimeStamp()); + Mutex::Autolock lock(mTrackCompletionLock); + mTrackCompletionSignal.signal(); + break; + } + } if (isTrackMalFormed()) { From d7a94300edede35f6b10675f51259a29ea41d732 Mon Sep 17 00:00:00 2001 From: Preetam Singh Ranawat Date: Wed, 4 Jan 2017 17:02:19 +0530 Subject: [PATCH 32/93] audio flinger: Fix native crash during underruns for patch track When audio flinger removes an AudioTrack from the active list in case of underrun, framecount gets reset to 0 in audio track client during obtain buffer. Server side patch track uses same frame count(0) to invoke obtain buffer during retry post restart and it lead to crash. Keep a copy of buffer frame count in patch track obtain buffer and use it during retry. CRs-Fixed: 1091467 Change-Id: I29404941aae904a8c713c40838476c30680a30e5 --- services/audioflinger/Tracks.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 95805251d..dd3fe909c 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -1462,9 +1462,11 @@ status_t AudioFlinger::PlaybackThread::PatchTrack::obtainBuffer(Proxy::Buffer* b status_t status = NO_ERROR; static const int32_t kMaxTries = 5; int32_t tryCounter = kMaxTries; + size_t frameCount = buffer->mFrameCount; do { if (status == NOT_ENOUGH_DATA) { restartIfDisabled(); + buffer->mFrameCount = frameCount; } status = mProxy->obtainBuffer(buffer, timeOut); } while ((status == NOT_ENOUGH_DATA) && (tryCounter-- > 0)); From 08156217634653d0a5c4e3fc30430357a9f27c31 Mon Sep 17 00:00:00 2001 From: Zhou Song Date: Fri, 18 Nov 2016 14:23:28 +0800 Subject: [PATCH 33/93] audioflinger: remove redundant adding to tracksToRemove There could be a corner case when direct track paused just after started before rendering anything and HAL is still in standby. So this active track can be added to tracksToRemove by two times, then it is started again before threadloop_removeTracks() called. And finally when threadloop_removeTracks() is invoked, it will trigger two times stopOutput and makes the active count of this stream to 0. Remove the redundant adding where it can also be added when track is paused and all frames are presented out. Change-Id: I9f7575a677a25a348dce750f8b338f45646d309c CRs-Fixed: 1091752 --- services/audioflinger/Threads.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index a29e81556..127fd66e0 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -5140,7 +5140,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep } } if ((track->sharedBuffer() != 0) || track->isStopped() || - track->isStopping_2() || track->isPaused()) { + track->isStopping_2()) { // We have consumed all the buffers of this track. // Remove it from the list of active tracks. size_t audioHALFrames; From 26dfb547d48eeab39594ff980c8e45940ffb44df Mon Sep 17 00:00:00 2001 From: Zhou Song Date: Mon, 28 Nov 2016 14:58:26 +0800 Subject: [PATCH 34/93] audioflinger: put fastmixer with active tracks into mix state when suspended Fastmixer will enter COLD_IDLE state after the output is suspended. If it still has active tracks and may be removed later, the state command sent to fastmixer could be blocked and thus block subsequent calls to this output. Put fastmixer into MIX state instead of COLD_IDLE when it's suspended but still has active tracks to be processed. Change-Id: I7f24f1a3e5b1651001fcef3ba3d00a8fb67e2b79 CRs-Fixed: 1093067 --- services/audioflinger/FastMixer.cpp | 8 +++- services/audioflinger/Threads.cpp | 68 ++++++++++++++++++++++++----- services/audioflinger/Threads.h | 1 + 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp index 93f7ce56b..76a03fd01 100644 --- a/services/audioflinger/FastMixer.cpp +++ b/services/audioflinger/FastMixer.cpp @@ -335,7 +335,8 @@ void FastMixer::onWork() const FastMixerState::Command command = mCommand; const size_t frameCount = current->mFrameCount; - if ((command & FastMixerState::MIX) && (mMixer != NULL) && mIsWarm) { + if ((command & FastMixerState::MIX) && (mMixer != NULL) && + (mIsWarm || command == FastMixerState::MIX)) { ALOG_ASSERT(mMixerBuffer != NULL); // AudioMixer::mState.enabledTracks is undefined if mState.hook == process__validate, @@ -423,6 +424,11 @@ void FastMixer::onWork() mMixerBufferState = UNDEFINED; } + // if mixerthread is suspended, simulate the write with period time sleep + if (command == FastMixerState::MIX) { + const struct timespec req = {0, mPeriodNs}; + nanosleep(&req, NULL); + } } else if (mMixerBufferState == MIXED) { mMixerBufferState = UNDEFINED; } diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 127fd66e0..bc1041f9f 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -3704,6 +3704,7 @@ AudioFlinger::MixerThread::MixerThread(const sp& audioFlinger, Aud // mAudioMixer below // mFastMixer below mFastMixerFutex(0), + mFastMixerIdlePending(false), mMasterMono(false) // mOutputSink below // mPipeSink below @@ -3935,16 +3936,18 @@ ssize_t AudioFlinger::MixerThread::threadLoop_write() FastMixerState *state = sq->begin(); if (state->mCommand != FastMixerState::MIX_WRITE && (kUseFastMixer != FastMixer_Dynamic || state->mTrackMask > 1)) { - if (state->mCommand == FastMixerState::COLD_IDLE) { + if (state->mCommand == FastMixerState::COLD_IDLE || mFastMixerIdlePending) { + mFastMixerIdlePending = false; // FIXME workaround for first HAL write being CPU bound on some devices ATRACE_BEGIN("write"); mOutput->write((char *)mSinkBuffer, 0); ATRACE_END(); - - int32_t old = android_atomic_inc(&mFastMixerFutex); - if (old == -1) { - (void) syscall(__NR_futex, &mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1); + if (state->mCommand == FastMixerState::COLD_IDLE) { + int32_t old = android_atomic_inc(&mFastMixerFutex); + if (old == -1) { + (void) syscall(__NR_futex, &mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1); + } } #ifdef AUDIO_WATCHDOG if (mAudioWatchdog != 0) { @@ -3976,10 +3979,20 @@ void AudioFlinger::MixerThread::threadLoop_standby() FastMixerStateQueue *sq = mFastMixer->sq(); FastMixerState *state = sq->begin(); if (!(state->mCommand & FastMixerState::IDLE)) { - state->mCommand = FastMixerState::COLD_IDLE; - state->mColdFutexAddr = &mFastMixerFutex; - state->mColdGen++; - mFastMixerFutex = 0; + // if standby is called due to output suspended, when + // 1): for dynamic usage, if there are FAST tracks OR + // 2): for none dynamic usage, if there are active tracks + // we still need to mix the data for tracks but not write to HAL + if (isSuspended () && ((kUseFastMixer == FastMixer_Dynamic && state->mTrackMask > 1) || + (kUseFastMixer != FastMixer_Dynamic && mActiveTracks.size()))) { + state->mCommand = FastMixerState::MIX; + mFastMixerIdlePending = true; + } else { + state->mCommand = FastMixerState::COLD_IDLE; + state->mColdFutexAddr = &mFastMixerFutex; + state->mColdGen++; + mFastMixerFutex = 0; + } sq->end(); // BLOCK_UNTIL_PUSHED would be insufficient, as we need it to stop doing I/O now sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED); @@ -4047,6 +4060,26 @@ void AudioFlinger::MixerThread::threadLoop_mix() { // mix buffers... mAudioMixer->process(); + // for mixerthread with fastmixer enabled, if it's already suspended, start mixing when + // 1) for dynamic usage and there are active FAST tracks + // 2) for none dynmaic usage, always enable mixing + if (mFastMixer != 0 && isSuspended()) { + FastMixerStateQueue *sq = mFastMixer->sq(); + FastMixerState *state = sq->begin(); + if (state->mCommand == FastMixerState::COLD_IDLE && (kUseFastMixer != FastMixer_Dynamic || + (kUseFastMixer == FastMixer_Dynamic && state->mTrackMask > 1))) { + int32_t old = android_atomic_inc(&mFastMixerFutex); + if (old == -1) { + (void) syscall(__NR_futex, &mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1); + } + state->mCommand = FastMixerState::MIX; + sq->end(); + sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED); + mFastMixerIdlePending = true; + } else { + sq->end(false /*didModify*/); + } + } mCurrentWriteLength = mSinkBufferSize; // increase sleep time progressively when application underrun condition clears. // Only increase sleep time if the mixer is ready for two consecutive times to avoid @@ -4632,7 +4665,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac state->mFastTracksGen++; // if the fast mixer was active, but now there are no fast tracks, then put it in cold idle if (kUseFastMixer == FastMixer_Dynamic && - state->mCommand == FastMixerState::MIX_WRITE && state->mTrackMask <= 1) { + (state->mCommand & FastMixerState::MIX_WRITE) && state->mTrackMask <= 1) { state->mCommand = FastMixerState::COLD_IDLE; state->mColdFutexAddr = &mFastMixerFutex; state->mColdGen++; @@ -4644,6 +4677,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac // so that fast mixer stops doing I/O. block = FastMixerStateQueue::BLOCK_UNTIL_ACKED; pauseAudioWatchdog = true; + if (mFastMixerIdlePending) + mFastMixerIdlePending = false; } } if (sq != NULL) { @@ -4719,6 +4754,19 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac EffectDapController::instance()->updatePregain(mType, mId, mOutput->flags, max_vol); } #endif // DOLBY_END + + // if no more ative tracks available, put the fastmixer into COLD_IDLE + if (mFastMixerIdlePending && !mActiveTracks.size()) { + state = sq->begin(); + state->mCommand = FastMixerState::COLD_IDLE; + state->mColdFutexAddr = &mFastMixerFutex; + state->mColdGen++; + mFastMixerFutex = 0; + // I/O was already stopped during standby, no need to wait for ack + sq->end(); + sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED); + mFastMixerIdlePending = false; + } return mixerStatus; } diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 85bfa9880..80388c1af 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -938,6 +938,7 @@ class MixerThread : public PlaybackThread { // accessible only within the threadLoop(), no locks required // mFastMixer->sq() // for mutating and pushing state int32_t mFastMixerFutex; // for cold idle + bool mFastMixerIdlePending; std::atomic_bool mMasterMono; public: From 735f2741275ac650306db6d15f3966ba3ae0605d Mon Sep 17 00:00:00 2001 From: Satya Krishna Pindiproli Date: Mon, 27 Jul 2015 20:01:35 -0700 Subject: [PATCH 35/93] StagefrightRecorder: avoid 30ms offset with QC AAC encoder There is a loss of a/v sync during camcorder recording with QC HW AAC encoder when pause/resume operations are done continuously. This is because the encoder does not consider the input timestamp to calculate the timestamp of an encoded frame. For each output buffer, the timestamp is just the number of frames encoded so far times the frame duration. However, as the input timestamp is used by video encoder, there is a drift between the audio and video timestamps after resume which results in a/v sync loss. Avoid the default 30ms offset in the total paused duration when QC AAC encoder is used to ensure that the timestamps of audio and video are in sync. Also, calculate the TotalPausedDuration value considering the capturerate and framerate. Change-Id: I8420e44ab96484f0d6301c366a24eefc8efeaf0f CRs-Fixed: 1070540 Change-Id: Ia201f3df011c61ce8ed47c3ccb7a2e6a457c2cef --- media/libmediaplayerservice/StagefrightRecorder.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 6b91f9de7..dbfa4e9f7 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include "WebmWriter.h" #include "StagefrightRecorder.h" @@ -1852,9 +1853,15 @@ status_t StagefrightRecorder::resume() { if (mPauseStartTimeUs < bufferStartTimeUs) { mPauseStartTimeUs = bufferStartTimeUs; } - // 30 ms buffer to avoid timestamp overlap - mTotalPausedDurationUs += (systemTime() / 1000) - mPauseStartTimeUs - 30000; + mTotalPausedDurationUs += (systemTime() / 1000) - mPauseStartTimeUs; + + bool isQCHwAACEnc = property_get_bool("qcom.hw.aac.encoder", true); + if (!isQCHwAACEnc || mAudioEncoder != AUDIO_ENCODER_AAC || mCaptureFpsEnable) { + // 30 ms buffer to avoid timestamp overlap + mTotalPausedDurationUs -= (30000*(mCaptureFpsEnable ? (mCaptureFps / mFrameRate) : 1)); + } } + double timeOffset = -mTotalPausedDurationUs; if (mCaptureFpsEnable) { timeOffset *= mCaptureFps / mFrameRate; From c119a6fa55a1e8d474934dcd6950da201f8588f8 Mon Sep 17 00:00:00 2001 From: Zhou Song Date: Fri, 16 Dec 2016 16:41:06 +0800 Subject: [PATCH 36/93] audioflinger: pause direct output when buffer timeout Direct output can be paused when track underrun is observed for the first time, so this can interrupt the playback even when there is PCM data cached in the driver. Also the track may be ready before the next prepareTracks, the playback should be continued. To avoid the unnecessary pause, only do HAL pausing when track is going to be removed due to buffer timeout. Change-Id: I3707d883d0daa4ffd2baa9bd69aebf4bf9ddef4e CRs-Fixed: 1094472 --- services/audioflinger/Threads.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index bc1041f9f..1434a56ab 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -5219,15 +5219,19 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep // indicate to client process that the track was disabled because of underrun; // it will then automatically call start() when data is available track->disable(); - } else if (last) { + // only do hw pause when track is going to be removed due to BUFFER TIMEOUT. + // unlike mixerthread, HAL can be paused for direct output, and as HAL can be + // paused at the first underrun, but track may be ready for the next loop and + // the playback is resumed, it will make the playback interrupted ALOGW("pause because of UNDERRUN, framesReady = %zu," "minFrames = %u, mFormat = %#x", track->framesReady(), minFrames, mFormat); - mixerStatus = MIXER_TRACKS_ENABLED; - if (mHwSupportsPause && !mHwPaused && !mStandby) { + if (mHwSupportsPause && last && !mHwPaused && !mStandby) { doHwPause = true; mHwPaused = true; } + } else if (last) { + mixerStatus = MIXER_TRACKS_ENABLED; } } } From 2b444237e3b8beef6ca31462b296429c89f2d8cf Mon Sep 17 00:00:00 2001 From: Karthikeyan Periasamy Date: Wed, 25 Jan 2017 14:53:12 -0800 Subject: [PATCH 37/93] libstagefright: Check trackMeta for NULL getTrackMetaData will return NULL for failure. If we pass the NULL, mediaserver application will crash. Check trackMeta and go to next index if it is NULL. CRs-Fixed: 1115425 Change-Id: I55a73cb0f327b6af31d30ed1b3d27c83578762d3 --- media/libstagefright/StagefrightMetadataRetriever.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index 0add7426f..c2e71d5dc 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -489,6 +489,10 @@ VideoFrame *StagefrightMetadataRetriever::getFrameAtTime( for (i = 0; i < n; ++i) { sp meta = mExtractor->getTrackMetaData(i); + if (meta == NULL) { + continue; + } + const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); @@ -682,6 +686,10 @@ void StagefrightMetadataRetriever::parseMetaData() { for (size_t i = 0; i < numTracks; ++i) { sp trackMeta = mExtractor->getTrackMetaData(i); + if (trackMeta == NULL) { + continue; + } + int64_t durationUs; if (trackMeta->findInt64(kKeyDuration, &durationUs)) { if (durationUs > maxDurationUs) { @@ -765,7 +773,8 @@ void StagefrightMetadataRetriever::parseMetaData() { if (!strcasecmp(fileMIME, "video/x-matroska")) { sp trackMeta = mExtractor->getTrackMetaData(0); const char *trackMIME; - CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME)); + CHECK(trackMeta != NULL + && trackMeta->findCString(kKeyMIMEType, &trackMIME)); if (!strncasecmp("audio/", trackMIME, 6)) { // The matroska file only contains a single audio track, From 7942bf3310a23d5fa9f5065f3e98da26f818c461 Mon Sep 17 00:00:00 2001 From: Mahesh Lanka Date: Thu, 10 Nov 2016 15:06:16 +0530 Subject: [PATCH 38/93] Video: add support for playback of QT clips -define mime types for QT format Change-Id: I4170a4019211a4a973ee4bcc79af80585082b34d --- include/media/stagefright/ExtendedMediaDefs.h | 2 +- media/libavextensions/stagefright/ExtendedMediaDefs.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/media/stagefright/ExtendedMediaDefs.h b/include/media/stagefright/ExtendedMediaDefs.h index 1e60fc1d4..6625795e3 100644 --- a/include/media/stagefright/ExtendedMediaDefs.h +++ b/include/media/stagefright/ExtendedMediaDefs.h @@ -66,7 +66,7 @@ extern const char *MEDIA_MIMETYPE_VIDEO_MPEG4_DP; extern const char *MEDIA_MIMETYPE_AUDIO_DSD; extern const char *MEDIA_MIMETYPE_CONTAINER_DSF; extern const char *MEDIA_MIMETYPE_CONTAINER_DFF; - +extern const char *MEDIA_MIMETYPE_CONTAINER_MOV; } // namespace android diff --git a/media/libavextensions/stagefright/ExtendedMediaDefs.cpp b/media/libavextensions/stagefright/ExtendedMediaDefs.cpp index 20437ebdf..c02867ed1 100644 --- a/media/libavextensions/stagefright/ExtendedMediaDefs.cpp +++ b/media/libavextensions/stagefright/ExtendedMediaDefs.cpp @@ -67,6 +67,6 @@ const char *MEDIA_MIMETYPE_VIDEO_MPEG4_DP = "video/mp4v-esdp"; const char *MEDIA_MIMETYPE_CONTAINER_DSF = "audio/x-dsf"; // For DSF clip const char *MEDIA_MIMETYPE_CONTAINER_DFF = "audio/x-dff"; // For DFF or DIF clip const char *MEDIA_MIMETYPE_AUDIO_DSD = "audio/dsd"; - +const char *MEDIA_MIMETYPE_CONTAINER_MOV = "video/quicktime"; //mov clip } // namespace android From 335a7df26c72f7055a5fc8eff4f04b62bdb6ee2e Mon Sep 17 00:00:00 2001 From: Praveen Chavan Date: Tue, 8 Nov 2016 15:36:33 -0800 Subject: [PATCH 39/93] stagefright: Optimize stop-delay for EIS enabled recording When EIS-3.0-enabled session is stopped, video frames worth 1 sec (up to 30 frames) have to be encoded and muxed. This operation can take up to 1 sec and increase the stop- latency for back-to-back recording. Optimize this by notifying perf-hints to video and camera. CRs-Fixed: 1087319 Change-Id: Ic05edd3e5bfd5b65fec8f48ad45a6e15cd2a437e --- include/media/stagefright/CameraSource.h | 2 ++ include/media/stagefright/MediaCodecSource.h | 2 ++ media/libmediaplayerservice/StagefrightRecorder.cpp | 11 ++++++++++- media/libmediaplayerservice/StagefrightRecorder.h | 1 + media/libstagefright/MediaCodecSource.cpp | 9 ++++++++- 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h index c2e75a61c..07d016729 100644 --- a/include/media/stagefright/CameraSource.h +++ b/include/media/stagefright/CameraSource.h @@ -127,6 +127,8 @@ class CameraSource : public MediaSource, public MediaBufferObserver { virtual void signalBufferReturned(MediaBuffer* buffer); + virtual void notifyPerformanceMode() {} + protected: /** diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h index 1044ee4d6..bd411f7d1 100644 --- a/include/media/stagefright/MediaCodecSource.h +++ b/include/media/stagefright/MediaCodecSource.h @@ -68,6 +68,8 @@ struct MediaCodecSource : public MediaSource, // for AHandlerReflector void onMessageReceived(const sp &msg); + void notifyPerformanceMode(); + protected: virtual ~MediaCodecSource(); diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index dbfa4e9f7..e92aefa02 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -1478,10 +1478,11 @@ status_t StagefrightRecorder::setupCameraSource( mTimeBetweenCaptureUs); *cameraSource = mCameraSourceTimeLapse; } else { - *cameraSource = AVFactory::get()->CreateCameraSourceFromCamera( + mCameraSource = AVFactory::get()->CreateCameraSourceFromCamera( mCamera, mCameraProxy, mCameraId, mClientName, mClientUid, mClientPid, videoSize, mFrameRate, mPreviewSurface); + *cameraSource = mCameraSource; } AVUtils::get()->cacheCaptureBuffers(mCamera, mVideoEncoder); mCamera.clear(); @@ -1887,6 +1888,13 @@ status_t StagefrightRecorder::stop() { mCameraSourceTimeLapse = NULL; } + if (mVideoEncoderSource != NULL) { + mVideoEncoderSource->notifyPerformanceMode(); + } + if (mCameraSource != NULL) { + mCameraSource->notifyPerformanceMode(); + } + if (mWriter != NULL) { err = mWriter->stop(); mWriter.clear(); @@ -1965,6 +1973,7 @@ status_t StagefrightRecorder::reset() { mCaptureFps = 0.0f; mTimeBetweenCaptureUs = -1; mCameraSourceTimeLapse = NULL; + mCameraSource = NULL; mMetaDataStoredInVideoBuffers = kMetadataBufferTypeInvalid; mEncoderProfiles = MediaProfiles::getInstance(); mRotationDegrees = 0; diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 01ce38001..7caa24993 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -121,6 +121,7 @@ struct StagefrightRecorder : public MediaRecorderBase { float mCaptureFps; int64_t mTimeBetweenCaptureUs; sp mCameraSourceTimeLapse; + sp mCameraSource; String8 mParams; diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index 904b60cd3..2d364ba4a 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -188,7 +188,6 @@ void MediaCodecSource::Puller::stop() { interrupt = queue->mReadPendingSince && (queue->mReadPendingSince < ALooper::GetNowUs() - 1000000); queue->flush(); // flush any unprocessed pulled buffers } - } void MediaCodecSource::Puller::interruptSource() { @@ -1076,4 +1075,12 @@ void MediaCodecSource::onMessageReceived(const sp &msg) { } } +void MediaCodecSource::notifyPerformanceMode() { + if (mIsVideo && mEncoder != NULL) { + sp params = new AMessage; + params->setInt32("qti.request.perf", true); + mEncoder->setParameters(params); + } +} + } // namespace android From e9d466957ea74db480a9d84043406f597c4caf2e Mon Sep 17 00:00:00 2001 From: Uma Mehta Date: Thu, 19 Jan 2017 15:02:55 +0530 Subject: [PATCH 40/93] stagefright: MPEG4Writer: fix Integer overflow unsigned int was getting assigned to a negative value, which in turn was leading to a crash in htonl. Fixing integer overflow in writeCttsBox. Change-Id: I2c4e8efcd1a1b215c412c9e26637f0b9b563a781 --- media/libstagefright/MPEG4Writer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 0fdb61e39..71c5a2f7c 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -3479,7 +3479,7 @@ void MPEG4Writer::Track::writeCttsBox() { mOwner->beginBox("ctts"); mOwner->writeInt32(0); // version=0, flags=0 - uint32_t delta = mMinCttsOffsetTimeUs - getStartTimeOffsetScaledTime(); + int64_t delta = mMinCttsOffsetTimeUs - getStartTimeOffsetScaledTime(); mCttsTableEntries->adjustEntries([delta](size_t /* ix */, uint32_t (&value)[2]) { // entries are pairs; adjust only ctts uint32_t duration = htonl(value[1]); // back to host byte order From 0f9fcc7de348e2d4f7ecd091a5b27f5817b7d759 Mon Sep 17 00:00:00 2001 From: Manikanta Kanamarlapudi Date: Mon, 23 Jan 2017 15:34:33 +0530 Subject: [PATCH 41/93] Stagefright: Create CameraSource for HSR Existing architecture chooses CameraSourceTimeLapse for High Speed Recording where timestamps are manipulated based on frame rate. For HSR, Capture rate and Frame rate are equal and no need of timestamps manipulation. Hence create CameraSource. Change-Id: I7f420f5b15fb3c05bb7f918430ca9b7a630ed18e CRs-Fixed: 1091389 --- media/libmediaplayerservice/StagefrightRecorder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index e92aefa02..659eb64b4 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -1465,7 +1465,7 @@ status_t StagefrightRecorder::setupCameraSource( Size videoSize; videoSize.width = mVideoWidth; videoSize.height = mVideoHeight; - if (mCaptureFpsEnable) { + if (mCaptureFpsEnable && mCaptureFps != mFrameRate ) { if (mTimeBetweenCaptureUs < 0) { ALOGE("Invalid mTimeBetweenTimeLapseFrameCaptureUs value: %" PRId64 "", mTimeBetweenCaptureUs); From ddd0b8ede6317dd97e0c2bb7ba5178093f884f44 Mon Sep 17 00:00:00 2001 From: Aalique Grahame Date: Tue, 31 Jan 2017 14:28:07 -0800 Subject: [PATCH 42/93] AudioPolicyMng: check for null audioSession when realeasing input When releasing input, check whether the audio session retrieved is null rather than checking the value of index which was already verified earlier on. CRs-Fixed: 1114286 Change-Id: I31901b9ca9de9f3a561c9dbcc0a1d39ecbd06744 --- services/audiopolicy/managerdefault/AudioPolicyManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index f2eb931fe..7049bbe67 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -1882,7 +1882,7 @@ void AudioPolicyManager::releaseInput(audio_io_handle_t input, ALOG_ASSERT(inputDesc != 0); sp audioSession = inputDesc->getAudioSession(session); - if (index < 0) { + if (audioSession == 0) { ALOGW("releaseInput() unknown session %d on input %d", session, input); return; } From 81346e890c12b3893f4bf83ed0c5ab119b3a096b Mon Sep 17 00:00:00 2001 From: Alexy Joseph Date: Thu, 2 Feb 2017 18:47:14 -0800 Subject: [PATCH 43/93] vraudioservice: Instantiation Instantiate vraudioservice from within audioserver Change-Id: Icb8f0a892fb0e29dd69a19709aff80471422e37a --- media/audioserver/Android.mk | 6 ++++++ media/audioserver/main_audioserver.cpp | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk index 0947687c3..3d16a36d0 100644 --- a/media/audioserver/Android.mk +++ b/media/audioserver/Android.mk @@ -76,4 +76,10 @@ ifeq ($(strip $(DOLBY_ENABLE)),true) endif # DOLBY_END +ifeq ($(strip $(SPATIAL_AUDIO_ENABLED)), true) + LOCAL_CFLAGS += -DVRAUDIOSERVICE_ENABLE + LOCAL_C_INCLUDES += $(vr_audio_includes) + LOCAL_SHARED_LIBRARIES += libvraudio +endif + include $(BUILD_EXECUTABLE) diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp index 6a7f9cae8..a63cc7899 100644 --- a/media/audioserver/main_audioserver.cpp +++ b/media/audioserver/main_audioserver.cpp @@ -56,6 +56,10 @@ #include "DolbyMemoryService.h" #endif +#ifdef VRAUDIOSERVICE_ENABLE +#include "VRAudioService.h" +#endif + using namespace android; int main(int argc __unused, char **argv) @@ -154,6 +158,9 @@ int main(int argc __unused, char **argv) DolbyMemoryService::instantiate(); #endif SoundTriggerHwService::instantiate(); +#ifdef VRAUDIOSERVICE_ENABLE + VRAudioServiceNative::instantiate(); +#endif ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); } From 1bb5b32944194725e301632f06a9736f45851da5 Mon Sep 17 00:00:00 2001 From: Sharad Sangle Date: Mon, 6 Feb 2017 19:34:54 +0530 Subject: [PATCH 44/93] NuPlayerRenderer: update mAnchorTimeMediaUs on new audio time Currently mAnchorTimeMediaUs is not getting updated in case of new audio time is not greter than kMinimumAudioClockUpdatePeriodUs, but due to this for very small duration clips the progress bar does not go till end, as the mMaxTimeMediaUs of mediaClock is not updated correctly on newAudiotime. Make sure the mAnchorTimeMediaUs updated irrespective of new audio time is greater than kMinimumAudioClockUpdatePeriodUs or not so that mediaClock returns the correct timestamp having correct mMaxTimeMediaUs Change-Id: If67cd144ea633222f62ae60a7251cc32ac80df33 --- media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 11ef82f40..6fcb97bf8 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -1132,10 +1132,10 @@ void NuPlayer::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) { if (nowUs >= mNextAudioClockUpdateTimeUs) { int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs); mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs); - mAnchorTimeMediaUs = mediaTimeUs; mUseVirtualAudioSink = false; mNextAudioClockUpdateTimeUs = nowUs + kMinimumAudioClockUpdatePeriodUs; } + mAnchorTimeMediaUs = mediaTimeUs; } else { int64_t unused; if ((mMediaClock->getMediaTime(nowUs, &unused) != OK) From be643b7e07590b036729a599a9be0fb9c5e8414d Mon Sep 17 00:00:00 2001 From: Ranjith Kagathi Ananda Date: Mon, 14 Nov 2016 18:19:43 -0800 Subject: [PATCH 45/93] Camera: Add null check on mDevice to avoid crash Null check on mDevice before calling stopPreviewL. Its already checked in ::disconnect(). Add the check in ::stopPreview() as well Change-Id: I489303c21176c108c92538f8cf30720fc4312082 --- services/camera/libcameraservice/api1/Camera2Client.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp index 08a06effe..1b116d661 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.cpp +++ b/services/camera/libcameraservice/api1/Camera2Client.cpp @@ -878,6 +878,7 @@ void Camera2Client::stopPreview() { Mutex::Autolock icl(mBinderSerializationLock); status_t res; if ( (res = checkPid(__FUNCTION__) ) != OK) return; + if (mDevice == 0) return; stopPreviewL(); } From 1ebf50bbf74ee3ae79ac5c63d0995501da78d2a7 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Tue, 15 Nov 2016 17:19:58 -0800 Subject: [PATCH 46/93] Effect: Use local cached data for Effect commit Test: POC, Cts Effect, BassBoost, EnvReverb, Equalizer, Test: LoudnessEnhancer, PresetReverb, Virtualizer, Visualizer Bug: 32220769 Change-Id: Iea96ba0daf71691ee8954cca4ba1c10fe827626e (cherry picked from commit dd79ccda92c1e9b982b2d0f8877d98e5258fbb73) (cherry picked from commit a155de4d70e0b9ac8fc02b2bdcbb2e8e6cca46ff) --- services/audioflinger/Effects.cpp | 57 ++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index a790ad41e..56671877d 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -1314,36 +1314,54 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode, // particular client process: no risk to block the whole media server process or mixer // threads if we are stuck here Mutex::Autolock _l(mCblk->lock); - if (mCblk->clientIndex > EFFECT_PARAM_BUFFER_SIZE || - mCblk->serverIndex > EFFECT_PARAM_BUFFER_SIZE) { + + // keep local copy of index in case of client corruption b/32220769 + const uint32_t clientIndex = mCblk->clientIndex; + const uint32_t serverIndex = mCblk->serverIndex; + if (clientIndex > EFFECT_PARAM_BUFFER_SIZE || + serverIndex > EFFECT_PARAM_BUFFER_SIZE) { mCblk->serverIndex = 0; mCblk->clientIndex = 0; return BAD_VALUE; } status_t status = NO_ERROR; - while (mCblk->serverIndex < mCblk->clientIndex) { - int reply; - uint32_t rsize = sizeof(int); - int *p = (int *)(mBuffer + mCblk->serverIndex); - int size = *p++; - if (((uint8_t *)p + size) > mBuffer + mCblk->clientIndex) { + effect_param_t *param = NULL; + for (uint32_t index = serverIndex; index < clientIndex;) { + int *p = (int *)(mBuffer + index); + const int size = *p++; + if (size < 0 + || size > EFFECT_PARAM_BUFFER_SIZE + || ((uint8_t *)p + size) > mBuffer + clientIndex) { ALOGW("command(): invalid parameter block size"); + status = BAD_VALUE; break; } - effect_param_t *param = (effect_param_t *)p; - if (param->psize == 0 || param->vsize == 0) { - ALOGW("command(): null parameter or value size"); - mCblk->serverIndex += size; - continue; + + // copy to local memory in case of client corruption b/32220769 + param = (effect_param_t *)realloc(param, size); + if (param == NULL) { + ALOGW("command(): out of memory"); + status = NO_MEMORY; + break; } - uint32_t psize = sizeof(effect_param_t) + - ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + - param->vsize; + memcpy(param, p, size); + + int reply = 0; + uint32_t rsize = sizeof(reply); status_t ret = mEffect->command(EFFECT_CMD_SET_PARAM, - psize, - p, + size, + param, &rsize, &reply); + + // verify shared memory: server index shouldn't change; client index can't go back. + if (serverIndex != mCblk->serverIndex + || clientIndex > mCblk->clientIndex) { + android_errorWriteLog(0x534e4554, "32220769"); + status = BAD_VALUE; + break; + } + // stop at first error encountered if (ret != NO_ERROR) { status = ret; @@ -1353,8 +1371,9 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode, *(int *)pReplyData = reply; break; } - mCblk->serverIndex += size; + index += size; } + free(param); mCblk->serverIndex = 0; mCblk->clientIndex = 0; return status; From 9e96973464cb326d4d8193475f3d197572e75870 Mon Sep 17 00:00:00 2001 From: rago Date: Tue, 22 Nov 2016 18:02:48 -0800 Subject: [PATCH 47/93] Fix security vulnerability: potential OOB write in audioserver Bug: 32705438 Bug: 32703959 Test: cts security test Change-Id: I8900c92fa55b56c4c2c9d721efdbabe6bfc8a4a4 (cherry picked from commit e275907e576601a3579747c3a842790bacf111e2) (cherry picked from commit b0bcddb44d992e74140a3f5eedc7177977ea8e34) --- .../lvm/wrapper/Bundle/EffectBundle.cpp | 27 ++++++++++++++----- media/libmedia/IEffect.cpp | 12 +++++++++ services/audioflinger/Effects.cpp | 16 +++++++++++ 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index 536ce78e1..ca5a3d45f 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -3127,10 +3127,6 @@ int Effect_command(effect_handle_t self, //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_GET_PARAM start"); effect_param_t *p = (effect_param_t *)pCmdData; - if (SIZE_MAX - sizeof(effect_param_t) < (size_t)p->psize) { - android_errorWriteLog(0x534e4554, "26347509"); - return -EINVAL; - } if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) || cmdSize < (sizeof(effect_param_t) + p->psize) || pReplyData == NULL || replySize == NULL || @@ -3138,13 +3134,32 @@ int Effect_command(effect_handle_t self, ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: ERROR"); return -EINVAL; } + if (EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) < (size_t)p->psize) { + android_errorWriteLog(0x534e4554, "26347509"); + ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: psize too big"); + return -EINVAL; + } + uint32_t paddedParamSize = ((p->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) * + sizeof(int32_t); + if ((EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) < paddedParamSize) || + (EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) - paddedParamSize < + p->vsize)) { + ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: padded_psize or vsize too big"); + return -EINVAL; + } + uint32_t expectedReplySize = sizeof(effect_param_t) + paddedParamSize + p->vsize; + if (*replySize < expectedReplySize) { + ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: min. replySize %u, got %u bytes", + expectedReplySize, *replySize); + android_errorWriteLog(0x534e4554, "32705438"); + return -EINVAL; + } memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize); p = (effect_param_t *)pReplyData; - int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); - + uint32_t voffset = paddedParamSize; if(pContext->EffectType == LVM_BASS_BOOST){ p->status = android::BassBoost_getParameter(pContext, p->data, diff --git a/media/libmedia/IEffect.cpp b/media/libmedia/IEffect.cpp index faf579509..af6d8de85 100644 --- a/media/libmedia/IEffect.cpp +++ b/media/libmedia/IEffect.cpp @@ -25,6 +25,9 @@ namespace android { +// Maximum command/reply size expected +#define EFFECT_PARAM_SIZE_MAX 65536 + enum { ENABLE = IBinder::FIRST_CALL_TRANSACTION, DISABLE, @@ -156,6 +159,10 @@ status_t BnEffect::onTransact( uint32_t cmdSize = data.readInt32(); char *cmd = NULL; if (cmdSize) { + if (cmdSize > EFFECT_PARAM_SIZE_MAX) { + reply->writeInt32(NO_MEMORY); + return NO_ERROR; + } cmd = (char *)calloc(cmdSize, 1); if (cmd == NULL) { reply->writeInt32(NO_MEMORY); @@ -167,6 +174,11 @@ status_t BnEffect::onTransact( uint32_t replySz = replySize; char *resp = NULL; if (replySize) { + if (replySize > EFFECT_PARAM_SIZE_MAX) { + free(cmd); + reply->writeInt32(NO_MEMORY); + return NO_ERROR; + } resp = (char *)calloc(replySize, 1); if (resp == NULL) { free(cmd); diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index 56671877d..abdb4830e 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -626,6 +626,22 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode, android_errorWriteLog(0x534e4554, "32438594"); return -EINVAL; } + if (cmdCode == EFFECT_CMD_GET_PARAM && + (sizeof(effect_param_t) > *replySize + || ((effect_param_t *)pCmdData)->psize > *replySize + - sizeof(effect_param_t) + || ((effect_param_t *)pCmdData)->vsize > *replySize + - sizeof(effect_param_t) + - ((effect_param_t *)pCmdData)->psize + || roundUpDelta(((effect_param_t *)pCmdData)->psize, (uint32_t)sizeof(int)) > + *replySize + - sizeof(effect_param_t) + - ((effect_param_t *)pCmdData)->psize + - ((effect_param_t *)pCmdData)->vsize)) { + ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: reply size inconsistent"); + android_errorWriteLog(0x534e4554, "32705438"); + return -EINVAL; + } if ((cmdCode == EFFECT_CMD_SET_PARAM || cmdCode == EFFECT_CMD_SET_PARAM_DEFERRED) && // DEFERRED not generally used (sizeof(effect_param_t) > cmdSize From 09e23a3f280e3bad006c2ec9239cbecf6a3d48fa Mon Sep 17 00:00:00 2001 From: Mansoor Aftab Date: Thu, 9 Feb 2017 12:59:42 -0800 Subject: [PATCH 48/93] Revert "update stune group for cameraserver to top-app" This reverts commit 052c4955b8d31f7dc3484d40ee14cf18caccdae1. The original change is device specific removing from common frameworks location Change-Id: Ie80e8aae4afb9f3f2655680600553cf26d6f63f3 --- camera/cameraserver/cameraserver.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/camera/cameraserver/cameraserver.rc b/camera/cameraserver/cameraserver.rc index fea5a1d5c..9b637b212 100644 --- a/camera/cameraserver/cameraserver.rc +++ b/camera/cameraserver/cameraserver.rc @@ -3,4 +3,4 @@ service cameraserver /system/bin/cameraserver user cameraserver group audio camera input drmrpc ioprio rt 4 - writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks + writepid /dev/cpuset/camera-daemon/tasks /dev/stune/foreground/tasks From b22178b4624c1971678dee918b5354704972106d Mon Sep 17 00:00:00 2001 From: Jay Wang Date: Mon, 13 Feb 2017 13:01:23 -0800 Subject: [PATCH 49/93] cameraserver: disable background scheduling of cameraserver Due to I2c21d4c1788777c2d0d77227bb872701b35c4ff6, any background thread only allows RT bandwidth of just 10msec. This causes RT throttling error when CAM thread is being raised to RT task status because the msm-adhoc bus mutex is an RT mutex. To avoid this issue, we disable the background scheduling of cameraserver caused by binder call. Change-Id: I16ddbd832a606d136575c3d343c63ebc8d161c5b --- camera/cameraserver/main_cameraserver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp index f4be468e4..ea80ad49d 100644 --- a/camera/cameraserver/main_cameraserver.cpp +++ b/camera/cameraserver/main_cameraserver.cpp @@ -31,5 +31,6 @@ int main(int argc __unused, char** argv __unused) ALOGI("ServiceManager: %p", sm.get()); CameraService::instantiate(); ProcessState::self()->startThreadPool(); + IPCThreadState::self()->disableBackgroundScheduling(true); IPCThreadState::self()->joinThreadPool(); } From 628b18a673d4750096918933a21dd8ea295ecd8c Mon Sep 17 00:00:00 2001 From: Satya Krishna Pindiproli Date: Wed, 15 Feb 2017 14:59:02 +0530 Subject: [PATCH 50/93] StagefrightRecorder: avoid 30ms offset in pause duration for HSR recording For HSR recording, there is a loss of a/v sync when pause/resume operations are done continuously. mCaptureFpsEnable is true for HSR and 30ms is deducted from the total paused duration which causes a/v sync issues when QC AAC encoder is used (check Ia201f3df011c61ce8ed47c3ccb7a2e6a457c2cef). Remove the check for mCaptureFpsEnable to avoid the 30ms offset in total paused duration to fix the issue. CRs-Fixed: 2006474 Change-Id: I98dc605a3c535ee0ff757deb1caea7b9e29a3297 --- media/libmediaplayerservice/StagefrightRecorder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 659eb64b4..674060690 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -1857,7 +1857,7 @@ status_t StagefrightRecorder::resume() { mTotalPausedDurationUs += (systemTime() / 1000) - mPauseStartTimeUs; bool isQCHwAACEnc = property_get_bool("qcom.hw.aac.encoder", true); - if (!isQCHwAACEnc || mAudioEncoder != AUDIO_ENCODER_AAC || mCaptureFpsEnable) { + if (!isQCHwAACEnc || mAudioEncoder != AUDIO_ENCODER_AAC) { // 30 ms buffer to avoid timestamp overlap mTotalPausedDurationUs -= (30000*(mCaptureFpsEnable ? (mCaptureFps / mFrameRate) : 1)); } From f05062e896e85cf05fb4bb5b23ad04fcde2212e2 Mon Sep 17 00:00:00 2001 From: Manikanta Kanamarlapudi Date: Fri, 17 Feb 2017 14:31:49 +0530 Subject: [PATCH 51/93] stagefright: correct timestamp in buffer metadata In batch-mode, multiple buffers are sent together as a batch from camera to encoder. After pause/resume, pause duration gets subtracted from the time stamps before queueing to the encoder. Batch mode needs updated base time stamp to calculate the timestamps of the buffers in the batch. Hence update the time stamp offsetted with pause duration in buffer meta data. CRs-Fixed: 1106432 Change-Id: I6cdfff4f0f7a25c7b4156382a224688bdda03d28 --- media/libstagefright/MediaCodecSource.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index 2d364ba4a..625bec122 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -690,6 +690,7 @@ status_t MediaCodecSource::feedEncoderInputBuffers() { if (mIsVideo) { mDecodingTimeQueue.push_back(timeUs); if (mFlags & FLAG_USE_METADATA_INPUT) { + mbuf->meta_data()->setInt64(kKeyTime, timeUs); AVUtils::get()->addDecodingTimesFromBatch(mbuf, mDecodingTimeQueue); } } else { From 9de83c4cfe6c9755d1377ce4e89adf3ebee807c0 Mon Sep 17 00:00:00 2001 From: Surajit Podder Date: Wed, 15 Feb 2017 02:42:01 +0530 Subject: [PATCH 52/93] video: Skip wait for audio for video only recording Avoid waiting for video track to catch up to last audio timestamp for video only recording. Change-Id: I370c61f563a4eaf931e9f43fc139df329fac6fb1 --- media/libstagefright/MPEG4Writer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 71c5a2f7c..6ef6bde59 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -440,7 +440,8 @@ MPEG4Writer::MPEG4Writer(int fd) mAreGeoTagsAvailable(false), mStartTimeOffsetMs(-1), mMetaKeys(new AMessage()), - mIsAudioAMR(false) { + mIsAudioAMR(false), + mLastAudioTimeStampUs(0) { addDeviceMeta(); // Verify mFd is seekable @@ -1993,7 +1994,7 @@ status_t MPEG4Writer::Track::stop() { return OK; } - if (!mIsAudio) { + if (!mIsAudio && mOwner->getLastAudioTimeStamp()) { Mutex::Autolock lock(mTrackCompletionLock); mIsStopping = true; if (mTrackCompletionSignal.waitRelative(mTrackCompletionLock, 1e9 /* 1 sec */)) { From a4113653a439d692d4cd08305d5225a4335fedf3 Mon Sep 17 00:00:00 2001 From: Satya Krishna Pindiproli Date: Thu, 19 Jan 2017 19:45:53 +0530 Subject: [PATCH 53/93] frameworks/av: enable bytestream mode in extractor selectively Enable bytestream mode in extractor only when playback is through MediaPlayer APIs instead of enabling it by default. CRs-Fixed: 2005045 Change-Id: I74c2236fa70ae60da8fbcb1fbabb5a66b43b272c --- include/media/IMediaExtractorService.h | 3 ++- include/media/stagefright/MediaExtractor.h | 8 ++++++-- .../mediaplayerservice/AVNuExtensions.h | 3 ++- .../mediaplayerservice/AVNuUtils.cpp | 6 +++++- media/libavextensions/stagefright/AVExtensions.h | 5 +++-- media/libavextensions/stagefright/AVFactory.cpp | 5 +++-- media/libmedia/IMediaExtractorService.cpp | 8 ++++++-- .../nuplayer/GenericSource.cpp | 3 ++- media/libstagefright/MediaExtractor.cpp | 16 +++++++++------- .../mediaextractor/MediaExtractorService.cpp | 7 ++++--- services/mediaextractor/MediaExtractorService.h | 3 ++- 11 files changed, 44 insertions(+), 23 deletions(-) diff --git a/include/media/IMediaExtractorService.h b/include/media/IMediaExtractorService.h index 4d7b317fc..a50fd74f6 100644 --- a/include/media/IMediaExtractorService.h +++ b/include/media/IMediaExtractorService.h @@ -30,7 +30,8 @@ class IMediaExtractorService: public IInterface public: DECLARE_META_INTERFACE(MediaExtractorService); - virtual sp makeExtractor(const sp &source, const char *mime) = 0; + virtual sp makeExtractor(const sp &source, const char *mime, + const uint32_t extFlags) = 0; }; diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h index 6bf8c9e3b..84feb6ba3 100644 --- a/include/media/stagefright/MediaExtractor.h +++ b/include/media/stagefright/MediaExtractor.h @@ -30,9 +30,11 @@ class MetaData; class MediaExtractor : public BnMediaExtractor { public: static sp Create( - const sp &source, const char *mime = NULL); + const sp &source, const char *mime = NULL, + const uint32_t flags = 0); static sp CreateFromService( - const sp &source, const char *mime = NULL); + const sp &source, const char *mime = NULL, + const uint32_t flags = 0); virtual size_t countTracks() = 0; virtual sp getTrack(size_t index) = 0; @@ -73,6 +75,8 @@ class MediaExtractor : public BnMediaExtractor { virtual const char * name() { return ""; } + virtual void setExtraFlags(uint32_t flags) {} + protected: MediaExtractor(); virtual ~MediaExtractor() {} diff --git a/media/libavextensions/mediaplayerservice/AVNuExtensions.h b/media/libavextensions/mediaplayerservice/AVNuExtensions.h index 5bbeb8f64..93d524aa3 100644 --- a/media/libavextensions/mediaplayerservice/AVNuExtensions.h +++ b/media/libavextensions/mediaplayerservice/AVNuExtensions.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 - 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013 - 2017, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -75,6 +75,7 @@ struct AVNuUtils { virtual audio_format_t getPCMFormat(const sp &); virtual void setCodecOutputFormat(const sp &); virtual bool isByteStreamModeEnabled(const sp &); + virtual uint32_t getFlags(); // ----- NO TRESSPASSING BEYOND THIS LINE ------ DECLARE_LOADABLE_SINGLETON(AVNuUtils); diff --git a/media/libavextensions/mediaplayerservice/AVNuUtils.cpp b/media/libavextensions/mediaplayerservice/AVNuUtils.cpp index 1e3ad3563..4fed2123f 100644 --- a/media/libavextensions/mediaplayerservice/AVNuUtils.cpp +++ b/media/libavextensions/mediaplayerservice/AVNuUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 - 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013 - 2017, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -80,6 +80,10 @@ bool AVNuUtils::isByteStreamModeEnabled(const sp &) { return false; } +uint32_t AVNuUtils::getFlags() { + return 0; +} + // ----- NO TRESSPASSING BEYOND THIS LINE ------ AVNuUtils::AVNuUtils() {} diff --git a/media/libavextensions/stagefright/AVExtensions.h b/media/libavextensions/stagefright/AVExtensions.h index e528a2ed4..9d2c9a0f1 100644 --- a/media/libavextensions/stagefright/AVExtensions.h +++ b/media/libavextensions/stagefright/AVExtensions.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 - 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013 - 2017, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -60,7 +60,8 @@ struct AudioSource; struct AVFactory { virtual sp createACodec(); virtual MediaExtractor* createExtendedExtractor( - const sp &source, const char *mime, const sp &meta); + const sp &source, const char *mime, const sp &meta, + const uint32_t flags); virtual ElementaryStreamQueue* createESQueue( ElementaryStreamQueue::Mode mode, uint32_t flags = 0); virtual CameraSource *CreateCameraSourceFromCamera( diff --git a/media/libavextensions/stagefright/AVFactory.cpp b/media/libavextensions/stagefright/AVFactory.cpp index fe8c614ad..65e661f9e 100644 --- a/media/libavextensions/stagefright/AVFactory.cpp +++ b/media/libavextensions/stagefright/AVFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 - 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013 - 2017, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -54,7 +54,8 @@ sp AVFactory::createACodec() { } MediaExtractor* AVFactory::createExtendedExtractor( - const sp &, const char *, const sp &) { + const sp &, const char *, const sp &, + const uint32_t) { return NULL; } diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp index d170c222d..0fb95806f 100644 --- a/media/libmedia/IMediaExtractorService.cpp +++ b/media/libmedia/IMediaExtractorService.cpp @@ -38,10 +38,12 @@ class BpMediaExtractorService : public BpInterface { } - virtual sp makeExtractor(const sp &source, const char *mime) { + virtual sp makeExtractor(const sp &source, const char *mime, + const uint32_t extFlags) { Parcel data, reply; data.writeInterfaceToken(IMediaExtractorService::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(source)); + data.writeUint32(extFlags); if (mime != NULL) { data.writeCString(mime); } @@ -75,8 +77,10 @@ status_t BnMediaExtractorService::onTransact( // for MediaBuffers for this process. MediaBuffer::useSharedMemory(); sp source = interface_cast(b); + uint32_t extFlags; + data.readUint32(&extFlags); const char *mime = data.readCString(); - sp ex = makeExtractor(source, mime); + sp ex = makeExtractor(source, mime, extFlags); reply->writeStrongBinder(IInterface::asBinder(ex)); return NO_ERROR; } diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index e20b26e16..9f6a737b1 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -180,7 +180,8 @@ status_t NuPlayer::GenericSource::initFromDataSource() { extractor = mWVMExtractor; } else { extractor = MediaExtractor::Create(mDataSource, - mimeType.isEmpty() ? NULL : mimeType.string()); + mimeType.isEmpty() ? NULL : mimeType.string(), + mIsStreaming ? 0 : AVNuUtils::get()->getFlags()); } if (extractor == NULL) { diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp index 92f8b291f..5aaa3cbd6 100644 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -143,15 +143,16 @@ sp RemoteDataSource::DrmInitialization(const char *mime) { // static sp MediaExtractor::Create( - const sp &source, const char *mime) { - ALOGV("MediaExtractor::Create %s", mime); + const sp &source, const char *mime, + const uint32_t flags) { + ALOGV("MediaExtractor::Create %s flags %d", mime, flags); char value[PROPERTY_VALUE_MAX]; if (property_get("media.stagefright.extractremote", value, NULL) && (!strcmp("0", value) || !strcasecmp("false", value))) { // local extractor ALOGW("creating media extractor in calling process"); - return CreateFromService(source, mime); + return CreateFromService(source, mime, flags); } else { // Check if it's WVM, since WVMExtractor needs to be created in the media server process, // not the extractor process. @@ -180,7 +181,7 @@ sp MediaExtractor::Create( if (binder != 0) { sp mediaExService(interface_cast(binder)); - sp ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime); + sp ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime, flags); return ex; } else { ALOGE("extractor service not running"); @@ -191,9 +192,10 @@ sp MediaExtractor::Create( } sp MediaExtractor::CreateFromService( - const sp &source, const char *mime) { + const sp &source, const char *mime, + const uint32_t flags) { - ALOGV("MediaExtractor::CreateFromService %s", mime); + ALOGV("MediaExtractor::CreateFromService %s flags %d", mime, flags); DataSource::RegisterDefaultSniffers(); sp meta; @@ -235,7 +237,7 @@ sp MediaExtractor::CreateFromService( } MediaExtractor *ret = NULL; - if ((ret = AVFactory::get()->createExtendedExtractor(source, mime, meta)) != NULL) { + if ((ret = AVFactory::get()->createExtendedExtractor(source, mime, meta, flags)) != NULL) { } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4) || !strcasecmp(mime, "audio/mp4")) { ret = new MPEG4Extractor(source); diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp index 4a8016651..022dad82b 100644 --- a/services/mediaextractor/MediaExtractorService.cpp +++ b/services/mediaextractor/MediaExtractorService.cpp @@ -27,12 +27,13 @@ namespace android { sp MediaExtractorService::makeExtractor( - const sp &remoteSource, const char *mime) { - ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime); + const sp &remoteSource, const char *mime, + const uint32_t extFlags) { + ALOGV("@@@ MediaExtractorService::makeExtractor for %s extFlags %d", mime, extFlags); sp localSource = DataSource::CreateFromIDataSource(remoteSource); - sp ret = MediaExtractor::CreateFromService(localSource, mime); + sp ret = MediaExtractor::CreateFromService(localSource, mime, extFlags); ALOGV("extractor service created %p (%s)", ret.get(), diff --git a/services/mediaextractor/MediaExtractorService.h b/services/mediaextractor/MediaExtractorService.h index 078af0c22..7e315e6a6 100644 --- a/services/mediaextractor/MediaExtractorService.h +++ b/services/mediaextractor/MediaExtractorService.h @@ -33,7 +33,8 @@ class MediaExtractorService : public BinderService, publi static const char* getServiceName() { return "media.extractor"; } - virtual sp makeExtractor(const sp &source, const char *mime); + virtual sp makeExtractor(const sp &source, const char *mime, + const uint32_t extFlags); virtual status_t dump(int fd, const Vector& args); virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, From 90a7b120e449f6cacb0c61eb114daa1c4a5e6089 Mon Sep 17 00:00:00 2001 From: Jay Wang Date: Mon, 13 Feb 2017 13:01:23 -0800 Subject: [PATCH 54/93] cameraserver: disable background scheduling of cameraserver Due to I2c21d4c1788777c2d0d77227bb872701b35c4ff6, any background thread only allows RT bandwidth of just 10msec. This causes RT throttling error when CAM thread is being raised to RT task status because the msm-adhoc bus mutex is an RT mutex. To avoid this issue, we disable the background scheduling of cameraserver caused by binder call. Change-Id: I16ddbd832a606d136575c3d343c63ebc8d161c5b --- camera/cameraserver/main_cameraserver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp index f4be468e4..ea80ad49d 100644 --- a/camera/cameraserver/main_cameraserver.cpp +++ b/camera/cameraserver/main_cameraserver.cpp @@ -31,5 +31,6 @@ int main(int argc __unused, char** argv __unused) ALOGI("ServiceManager: %p", sm.get()); CameraService::instantiate(); ProcessState::self()->startThreadPool(); + IPCThreadState::self()->disableBackgroundScheduling(true); IPCThreadState::self()->joinThreadPool(); } From ecaab0e18068636acda720acb104506a1c08df79 Mon Sep 17 00:00:00 2001 From: Surajit Podder Date: Wed, 15 Feb 2017 02:42:01 +0530 Subject: [PATCH 55/93] video: Skip wait for audio for video only recording Avoid waiting for video track to catch up to last audio timestamp for video only recording. Change-Id: I370c61f563a4eaf931e9f43fc139df329fac6fb1 --- media/libstagefright/MPEG4Writer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 71c5a2f7c..6ef6bde59 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -440,7 +440,8 @@ MPEG4Writer::MPEG4Writer(int fd) mAreGeoTagsAvailable(false), mStartTimeOffsetMs(-1), mMetaKeys(new AMessage()), - mIsAudioAMR(false) { + mIsAudioAMR(false), + mLastAudioTimeStampUs(0) { addDeviceMeta(); // Verify mFd is seekable @@ -1993,7 +1994,7 @@ status_t MPEG4Writer::Track::stop() { return OK; } - if (!mIsAudio) { + if (!mIsAudio && mOwner->getLastAudioTimeStamp()) { Mutex::Autolock lock(mTrackCompletionLock); mIsStopping = true; if (mTrackCompletionSignal.waitRelative(mTrackCompletionLock, 1e9 /* 1 sec */)) { From 8ff74c305866ad58f9f600f77fd55de16e7e994a Mon Sep 17 00:00:00 2001 From: Zhou Song Date: Mon, 27 Feb 2017 17:44:47 +0800 Subject: [PATCH 56/93] NuPlayer: fix possible deadlock due to recursive mutex access The interface getCurrentPosition() should be called without mutex held from any threads now, since fillAudioBuffer() has already locked the mutex at the begining, recursive access can cause deadlock. Use the interface of MediaClock instead can avoid this. CRs-Fixed: 2014325 Change-Id: Iefdd061d745f548a207dd96f15c323fa7900d40d --- media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 11ef82f40..7b0d0fd3a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -847,12 +847,12 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { if (mAudioFirstAnchorTimeMediaUs >= 0) { int64_t nowUs = ALooper::GetNowUs(); - int64_t nowMediaUs = 0; + int64_t nowMediaUs = -1; int64_t playedDuration = mAudioSink->getPlayedOutDurationUs(nowUs); if (playedDuration >= 0) { nowMediaUs = mAudioFirstAnchorTimeMediaUs + playedDuration; } else { - getCurrentPosition(&nowMediaUs); + mMediaClock->getMediaTime(nowUs, &nowMediaUs); } // we don't know how much data we are queueing for offloaded tracks. mMediaClock->updateAnchor(nowMediaUs, nowUs, INT64_MAX); From 08cdbb6dcda924c7b182ad74011267ffd428325a Mon Sep 17 00:00:00 2001 From: Surajit Podder Date: Tue, 7 Mar 2017 17:09:58 +0530 Subject: [PATCH 57/93] video: Disable sync frame decoder mode for closest seek Disable sync frame decoder mode for closest seek mode, to ensure that the target frame can be decoded. Change-Id: Ib39fee7bb796c967639aa85be46fd913796041f6 --- media/libstagefright/StagefrightMetadataRetriever.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index c2e71d5dc..513693aa3 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -161,7 +161,7 @@ static VideoFrame *extractVideoFrame( // TODO: Use Flexible color instead videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar); - videoFormat->setInt32("thumbnail-mode", 1); + // For the thumbnail extraction case, try to allocate single buffer in both // input and output ports, if seeking to a sync frame. NOTE: This request may // fail if component requires more than that for decoding. @@ -169,6 +169,7 @@ static VideoFrame *extractVideoFrame( if (!isSeekingClosest) { videoFormat->setInt32("android._num-input-buffers", 1); videoFormat->setInt32("android._num-output-buffers", 1); + videoFormat->setInt32("thumbnail-mode", 1); } status_t err; From 17204db2c404a696c332f6f71ee2621ba19a7cbd Mon Sep 17 00:00:00 2001 From: Mridul Singh Date: Wed, 1 Mar 2017 11:37:34 -0800 Subject: [PATCH 58/93] Camera: Add NULL check on mDevice to avoid crash. NULL check on mDevice before calling cancelAutoFocus. Also adding the same check in disconnect. CRs-Fixed: 2000357 1082919 Change-Id: If57e12913bebfca6ab9b871a0bdcc24d663e7107 --- services/camera/libcameraservice/api1/Camera2Client.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp index 1b116d661..86887bd9d 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.cpp +++ b/services/camera/libcameraservice/api1/Camera2Client.cpp @@ -430,9 +430,10 @@ binder::Status Camera2Client::disconnect() { ALOGV("Camera %d: Disconnecting device", mCameraId); - mDevice->disconnect(); - - mDevice.clear(); + if (mDevice != nullptr) { + mDevice->disconnect(); + mDevice.clear(); + } CameraService::Client::disconnect(); @@ -1337,7 +1338,7 @@ status_t Camera2Client::cancelAutoFocus() { ALOGV("%s: Camera %d", __FUNCTION__, mCameraId); status_t res; if ( (res = checkPid(__FUNCTION__) ) != OK) return res; - + if (mDevice == 0) return NO_INIT; int triggerId; { SharedParameters::Lock l(mParameters); From 5c3b35c09324408b402dab450bda91c64ee53b3f Mon Sep 17 00:00:00 2001 From: Manikanta Kanamarlapudi Date: Tue, 14 Mar 2017 12:20:07 +0530 Subject: [PATCH 59/93] stagefright: Remove extra memcpy Remove extra memcpy which was added due to improper cleanup of merge conflicts while aosp upgrade Change-Id: Ibd61ea227138449ce5e4e0ec548863b02e1f4ac5 --- media/libstagefright/MediaCodecSource.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index 625bec122..20e1f911d 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -887,7 +887,6 @@ void MediaCodecSource::onMessageReceived(const sp &msg) { break; } - memcpy(mbuf->data(), outbuf->data(), outbuf->size()); sp meta = mbuf->meta_data(); AVUtils::get()->setDeferRelease(meta); mbuf->setObserver(this); From ca5fcdeaeb2b2ec18f8b68836c48a307901962e4 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 12 Jan 2017 15:49:04 -0800 Subject: [PATCH 60/93] Don't initialize sync sample parameters until the end to avoid leaving them in a partially initialized state. Bug: 33137046 Test: ran CTS tests Change-Id: I1f5c070233c5917d85da9e930e01a3fc51a0a0ec (cherry picked from commit a9660fe122ca382e1777e0c5d3c42ca67ffb0377) (cherry picked from commit bc62c086e9ba7530723dc8874b83159f4d77d976) --- media/libstagefright/SampleTable.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index eb1f193de..161ddfcfe 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -517,8 +517,6 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) return ERROR_MALFORMED; } - mSyncSampleOffset = data_offset; - uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { @@ -530,13 +528,13 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) return ERROR_MALFORMED; } - mNumSyncSamples = U32_AT(&header[4]); + uint32_t numSyncSamples = U32_AT(&header[4]); - if (mNumSyncSamples < 2) { + if (numSyncSamples < 2) { ALOGV("Table of sync samples is empty or has only a single entry!"); } - uint64_t allocSize = (uint64_t)mNumSyncSamples * sizeof(uint32_t); + uint64_t allocSize = (uint64_t)numSyncSamples * sizeof(uint32_t); if (allocSize > kMaxTotalSize) { ALOGE("Sync sample table size too large."); return ERROR_OUT_OF_RANGE; @@ -554,22 +552,27 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) return ERROR_OUT_OF_RANGE; } - mSyncSamples = new (std::nothrow) uint32_t[mNumSyncSamples]; + mSyncSamples = new (std::nothrow) uint32_t[numSyncSamples]; if (!mSyncSamples) { ALOGE("Cannot allocate sync sample table with %llu entries.", - (unsigned long long)mNumSyncSamples); + (unsigned long long)numSyncSamples); return ERROR_OUT_OF_RANGE; } - if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, + if (mDataSource->readAt(data_offset + 8, mSyncSamples, (size_t)allocSize) != (ssize_t)allocSize) { + delete mSyncSamples; + mSyncSamples = NULL; return ERROR_IO; } - for (size_t i = 0; i < mNumSyncSamples; ++i) { + for (size_t i = 0; i < numSyncSamples; ++i) { mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1; } + mSyncSampleOffset = data_offset; + mNumSyncSamples = numSyncSamples; + return OK; } From cdea9bf8e2b829780bcad8e36e808f80e6cd437f Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 1 Dec 2016 15:28:29 -0800 Subject: [PATCH 61/93] DO NOT MERGE - improve audio effect framwework thread safety - Reorganize handle effect creation code to make sure the effect engine is created with both thread and effect chain mutex held. - Reorganize handle disconnect code to make sure the effect engine is released with both thread and effect chain mutex held. - Protect IEffect interface methods in EffectHande with a Mutex. - Only pin effect if the session was acquired first. - Do not use strong pointer to EffectModule in EffectHandles: only the EffectChain has a single strong reference to the EffectModule. Bug: 32707507 Change-Id: Ia1098cba2cd32cc2d1c9dfdff4adc2388dfed80e (cherry picked from commit b378b73dd7480b584340b8028802c9ca2d625123) (cherry picked from commit 22e26d8ee73488c58ba3e7928e5da155151abfd0) --- services/audioflinger/AudioFlinger.cpp | 23 +- services/audioflinger/AudioFlinger.h | 1 + services/audioflinger/Effects.cpp | 226 +++++++++++------- services/audioflinger/Effects.h | 37 ++- services/audioflinger/Threads.cpp | 51 ++-- services/audioflinger/Threads.h | 7 +- .../service/AudioPolicyInterfaceImpl.cpp | 5 +- 7 files changed, 226 insertions(+), 124 deletions(-) diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index f2adb5bdf..a33607e42 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1402,7 +1402,7 @@ void AudioFlinger::removeNotificationClient(pid_t pid) ALOGV("%d died, releasing its sessions", pid); size_t num = mAudioSessionRefs.size(); bool removed = false; - for (size_t i = 0; i< num; ) { + for (size_t i = 0; i < num; ) { AudioSessionRef *ref = mAudioSessionRefs.itemAt(i); ALOGV(" pid %d @ %zu", ref->mPid, i); if (ref->mPid == pid) { @@ -2407,7 +2407,7 @@ void AudioFlinger::acquireAudioSessionId(audio_session_t audioSession, pid_t pid } size_t num = mAudioSessionRefs.size(); - for (size_t i = 0; i< num; i++) { + for (size_t i = 0; i < num; i++) { AudioSessionRef *ref = mAudioSessionRefs.editItemAt(i); if (ref->mSessionid == audioSession && ref->mPid == caller) { ref->mCnt++; @@ -2428,7 +2428,7 @@ void AudioFlinger::releaseAudioSessionId(audio_session_t audioSession, pid_t pid caller = pid; } size_t num = mAudioSessionRefs.size(); - for (size_t i = 0; i< num; i++) { + for (size_t i = 0; i < num; i++) { AudioSessionRef *ref = mAudioSessionRefs.itemAt(i); if (ref->mSessionid == audioSession && ref->mPid == caller) { ref->mCnt--; @@ -2446,6 +2446,18 @@ void AudioFlinger::releaseAudioSessionId(audio_session_t audioSession, pid_t pid ALOGW_IF(caller != getpid_cached, "session id %d not found for pid %d", audioSession, caller); } +bool AudioFlinger::isSessionAcquired_l(audio_session_t audioSession) +{ + size_t num = mAudioSessionRefs.size(); + for (size_t i = 0; i < num; i++) { + AudioSessionRef *ref = mAudioSessionRefs.itemAt(i); + if (ref->mSessionid == audioSession) { + return true; + } + } + return false; +} + void AudioFlinger::purgeStaleEffects_l() { ALOGV("purging stale effects"); @@ -2839,8 +2851,9 @@ sp AudioFlinger::createEffect( sp client = registerPid(pid); // create effect on selected output thread + bool pinned = (sessionId > AUDIO_SESSION_OUTPUT_MIX) && isSessionAcquired_l(sessionId); handle = thread->createEffect_l(client, effectClient, priority, sessionId, - &desc, enabled, &lStatus); + &desc, enabled, &lStatus, pinned); if (handle != 0 && id != NULL) { *id = handle->id(); } @@ -3045,7 +3058,7 @@ bool AudioFlinger::updateOrphanEffectChains(const sp ALOGV("updateOrphanEffectChains session %d index %zd", session, index); if (index >= 0) { sp chain = mOrphanEffectChains.valueAt(index); - if (chain->removeEffect_l(effect) == 0) { + if (chain->removeEffect_l(effect, true) == 0) { ALOGV("updateOrphanEffectChains removing effect chain at index %zd", index); mOrphanEffectChains.removeItemsAt(index); } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 11522a6dd..a417754f2 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -607,6 +607,7 @@ class AudioFlinger : void removeNotificationClient(pid_t pid); bool isNonOffloadableGlobalEffectEnabled_l(); void onNonOffloadableGlobalEffectEnable(); + bool isSessionAcquired_l(audio_session_t audioSession); // Store an effect chain to mOrphanEffectChains keyed vector. // Called when a thread exits and effects are still attached to it. diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index abdb4830e..0f1202604 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -78,8 +78,9 @@ AudioFlinger::EffectModule::EffectModule(ThreadBase *thread, const wp& chain, effect_descriptor_t *desc, int id, - audio_session_t sessionId) - : mPinned(sessionId > AUDIO_SESSION_OUTPUT_MIX), + audio_session_t sessionId, + bool pinned) + : mPinned(pinned), mThread(thread), mChain(chain), mId(id), mSessionId(sessionId), mDescriptor(*desc), // mConfig is set by configure() and not used before then @@ -90,7 +91,7 @@ AudioFlinger::EffectModule::EffectModule(ThreadBase *thread, mSuspended(false), mAudioFlinger(thread->mAudioFlinger) { - ALOGV("Constructor %p", this); + ALOGV("Constructor %p pinned %d", this, pinned); int lStatus; // create effect engine from effect factory @@ -105,6 +106,8 @@ AudioFlinger::EffectModule::EffectModule(ThreadBase *thread, goto Error; } + setOffloaded(thread->type() == ThreadBase::OFFLOAD, thread->id()); + ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface); return; Error: @@ -117,9 +120,8 @@ AudioFlinger::EffectModule::~EffectModule() { ALOGV("Destructor %p", this); if (mEffectInterface != NULL) { - remove_effect_from_hal_l(); - // release effect engine - EffectRelease(mEffectInterface); + ALOGW("EffectModule %p destructor called with unreleased interface", this); + release_l(); } } @@ -134,7 +136,7 @@ status_t AudioFlinger::EffectModule::addHandle(EffectHandle *handle) size_t i; for (i = 0; i < size; i++) { EffectHandle *h = mHandles[i]; - if (h == NULL || h->destroyed_l()) { + if (h == NULL || h->disconnected()) { continue; } // first non destroyed handle is considered in control @@ -162,9 +164,14 @@ status_t AudioFlinger::EffectModule::addHandle(EffectHandle *handle) return status; } -size_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle) +ssize_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle) { Mutex::Autolock _l(mLock); + return removeHandle_l(handle); +} + +ssize_t AudioFlinger::EffectModule::removeHandle_l(EffectHandle *handle) +{ size_t size = mHandles.size(); size_t i; for (i = 0; i < size; i++) { @@ -173,9 +180,10 @@ size_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle) } } if (i == size) { - return size; + ALOGW("%s %p handle not found %p", __FUNCTION__, this, handle); + return BAD_VALUE; } - ALOGV("removeHandle() %p removed handle %p in position %zu", this, handle, i); + ALOGV("removeHandle_l() %p removed handle %p in position %zu", this, handle, i); mHandles.removeAt(i); // if removed from first place, move effect control from this handle to next in line @@ -202,7 +210,7 @@ AudioFlinger::EffectHandle *AudioFlinger::EffectModule::controlHandle_l() // the first valid handle in the list has control over the module for (size_t i = 0; i < mHandles.size(); i++) { EffectHandle *h = mHandles[i]; - if (h != NULL && !h->destroyed_l()) { + if (h != NULL && !h->disconnected()) { return h; } } @@ -210,29 +218,22 @@ AudioFlinger::EffectHandle *AudioFlinger::EffectModule::controlHandle_l() return NULL; } -size_t AudioFlinger::EffectModule::disconnect(EffectHandle *handle, bool unpinIfLast) +// unsafe method called when the effect parent thread has been destroyed +ssize_t AudioFlinger::EffectModule::disconnectHandle(EffectHandle *handle, bool unpinIfLast) { ALOGV("disconnect() %p handle %p", this, handle); - // keep a strong reference on this EffectModule to avoid calling the - // destructor before we exit - sp keep(this); - { - if (removeHandle(handle) == 0) { - if (!isPinned() || unpinIfLast) { - sp thread = mThread.promote(); - if (thread != 0) { - Mutex::Autolock _l(thread->mLock); - thread->removeEffect_l(this); - } - sp af = mAudioFlinger.promote(); - if (af != 0) { - af->updateOrphanEffectChains(this); - } - AudioSystem::unregisterEffect(mId); - } + Mutex::Autolock _l(mLock); + ssize_t numHandles = removeHandle_l(handle); + if ((numHandles == 0) && (!mPinned || unpinIfLast)) { + AudioSystem::unregisterEffect(mId); + sp af = mAudioFlinger.promote(); + if (af != 0) { + mLock.unlock(); + af->updateOrphanEffectChains(this); + mLock.lock(); } } - return mHandles.size(); + return numHandles; } bool AudioFlinger::EffectModule::updateState() { @@ -576,6 +577,17 @@ status_t AudioFlinger::EffectModule::stop_l() return status; } +// must be called with EffectChain::mLock held +void AudioFlinger::EffectModule::release_l() +{ + if (mEffectInterface != NULL) { + remove_effect_from_hal_l(); + // release effect engine + EffectRelease(mEffectInterface); + mEffectInterface = NULL; + } +} + status_t AudioFlinger::EffectModule::remove_effect_from_hal_l() { if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC || @@ -668,7 +680,7 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode, uint32_t size = (replySize == NULL) ? 0 : *replySize; for (size_t i = 1; i < mHandles.size(); i++) { EffectHandle *h = mHandles[i]; - if (h != NULL && !h->destroyed_l()) { + if (h != NULL && !h->disconnected()) { h->commandExecuted(cmdCode, cmdSize, pCmdData, size, pReplyData); } } @@ -721,7 +733,7 @@ status_t AudioFlinger::EffectModule::setEnabled_l(bool enabled) } for (size_t i = 1; i < mHandles.size(); i++) { EffectHandle *h = mHandles[i]; - if (h != NULL && !h->destroyed_l()) { + if (h != NULL && !h->disconnected()) { h->setEnabled(enabled); } } @@ -888,8 +900,7 @@ bool AudioFlinger::EffectModule::purgeHandles() Mutex::Autolock _l(mLock); for (size_t i = 0; i < mHandles.size(); i++) { EffectHandle *handle = mHandles[i]; - if (handle != NULL && !handle->destroyed_l()) { - handle->effect().clear(); + if (handle != NULL && !handle->disconnected()) { if (handle->hasControl()) { enabled = handle->enabled(); } @@ -1116,7 +1127,7 @@ void AudioFlinger::EffectModule::dump(int fd, const Vector& args __unu result.append("\t\t\t Pid Priority Ctrl Locked client server\n"); for (size_t i = 0; i < mHandles.size(); ++i) { EffectHandle *handle = mHandles[i]; - if (handle != NULL && !handle->destroyed_l()) { + if (handle != NULL && !handle->disconnected()) { handle->dumpToBuffer(buffer, SIZE); result.append(buffer); } @@ -1142,7 +1153,7 @@ AudioFlinger::EffectHandle::EffectHandle(const sp& effect, int32_t priority) : BnEffect(), mEffect(effect), mEffectClient(effectClient), mClient(client), mCblk(NULL), - mPriority(priority), mHasControl(false), mEnabled(false), mDestroyed(false) + mPriority(priority), mHasControl(false), mEnabled(false), mDisconnected(false) { ALOGV("constructor %p", this); @@ -1165,14 +1176,6 @@ AudioFlinger::EffectHandle::EffectHandle(const sp& effect, AudioFlinger::EffectHandle::~EffectHandle() { ALOGV("Destructor %p", this); - - if (mEffect == 0) { - mDestroyed = true; - return; - } - mEffect->lock(); - mDestroyed = true; - mEffect->unlock(); disconnect(false); } @@ -1183,13 +1186,15 @@ status_t AudioFlinger::EffectHandle::initCheck() status_t AudioFlinger::EffectHandle::enable() { + AutoMutex _l(mLock); ALOGV("enable %p", this); + sp effect = mEffect.promote(); + if (effect == 0 || mDisconnected) { + return DEAD_OBJECT; + } if (!mHasControl) { return INVALID_OPERATION; } - if (mEffect == 0) { - return DEAD_OBJECT; - } if (mEnabled) { return NO_ERROR; @@ -1197,20 +1202,20 @@ status_t AudioFlinger::EffectHandle::enable() mEnabled = true; - sp thread = mEffect->thread().promote(); + sp thread = effect->thread().promote(); if (thread != 0) { - thread->checkSuspendOnEffectEnabled(mEffect, true, mEffect->sessionId()); + thread->checkSuspendOnEffectEnabled(effect, true, effect->sessionId()); } // checkSuspendOnEffectEnabled() can suspend this same effect when enabled - if (mEffect->suspended()) { + if (effect->suspended()) { return NO_ERROR; } - status_t status = mEffect->setEnabled(true); + status_t status = effect->setEnabled(true); if (status != NO_ERROR) { if (thread != 0) { - thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId()); + thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId()); } mEnabled = false; } else { @@ -1221,13 +1226,13 @@ status_t AudioFlinger::EffectHandle::enable() Mutex::Autolock _l(t->mLock); t->broadcast_l(); } - if (!mEffect->isOffloadable()) { + if (!effect->isOffloadable()) { if (thread->type() == ThreadBase::OFFLOAD || (thread->type() == ThreadBase::DIRECT && thread->mIsDirectPcm)) { PlaybackThread *t = (PlaybackThread *)thread.get(); t->invalidateTracks(AUDIO_STREAM_MUSIC); } - if (mEffect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) { + if (effect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) { thread->mAudioFlinger->onNonOffloadableGlobalEffectEnable(); } } @@ -1239,27 +1244,29 @@ status_t AudioFlinger::EffectHandle::enable() status_t AudioFlinger::EffectHandle::disable() { ALOGV("disable %p", this); + AutoMutex _l(mLock); + sp effect = mEffect.promote(); + if (effect == 0 || mDisconnected) { + return DEAD_OBJECT; + } if (!mHasControl) { return INVALID_OPERATION; } - if (mEffect == 0) { - return DEAD_OBJECT; - } if (!mEnabled) { return NO_ERROR; } mEnabled = false; - if (mEffect->suspended()) { + if (effect->suspended()) { return NO_ERROR; } - status_t status = mEffect->setEnabled(false); + status_t status = effect->setEnabled(false); - sp thread = mEffect->thread().promote(); + sp thread = effect->thread().promote(); if (thread != 0) { - thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId()); + thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId()); if ((thread->type() == ThreadBase::OFFLOAD) || (thread->type() == ThreadBase::DIRECT && thread->mIsDirectPcm)){ PlaybackThread *t = (PlaybackThread *)thread.get(); @@ -1273,25 +1280,39 @@ status_t AudioFlinger::EffectHandle::disable() void AudioFlinger::EffectHandle::disconnect() { + ALOGV("%s %p", __FUNCTION__, this); disconnect(true); } void AudioFlinger::EffectHandle::disconnect(bool unpinIfLast) { - ALOGV("disconnect(%s)", unpinIfLast ? "true" : "false"); - if (mEffect == 0) { + AutoMutex _l(mLock); + ALOGV("disconnect(%s) %p", unpinIfLast ? "true" : "false", this); + if (mDisconnected) { + if (unpinIfLast) { + android_errorWriteLog(0x534e4554, "32707507"); + } return; } - // restore suspended effects if the disconnected handle was enabled and the last one. - if ((mEffect->disconnect(this, unpinIfLast) == 0) && mEnabled) { - sp thread = mEffect->thread().promote(); - if (thread != 0) { - thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId()); + mDisconnected = true; + sp thread; + { + sp effect = mEffect.promote(); + if (effect != 0) { + thread = effect->thread().promote(); + } + } + if (thread != 0) { + thread->disconnectEffectHandle(this, unpinIfLast); + } else { + ALOGW("%s Effect handle %p disconnected after thread destruction", __FUNCTION__, this); + // try to cleanup as much as we can + sp effect = mEffect.promote(); + if (effect != 0) { + effect->disconnectHandle(this, unpinIfLast); } } - // release sp on module => module destructor can be called now - mEffect.clear(); if (mClient != 0) { if (mCblk != NULL) { // unlike ~TrackBase(), mCblk is never a local new, so don't delete @@ -1311,15 +1332,17 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode, void *pReplyData) { ALOGVV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p", - cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get()); + cmdCode, mHasControl, mEffect.unsafe_get()); + AutoMutex _l(mLock); + sp effect = mEffect.promote(); + if (effect == 0 || mDisconnected) { + return DEAD_OBJECT; + } // only get parameter command is permitted for applications not controlling the effect if (!mHasControl && cmdCode != EFFECT_CMD_GET_PARAM) { return INVALID_OPERATION; } - if (mEffect == 0) { - return DEAD_OBJECT; - } if (mClient == 0) { return INVALID_OPERATION; } @@ -1364,7 +1387,7 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode, int reply = 0; uint32_t rsize = sizeof(reply); - status_t ret = mEffect->command(EFFECT_CMD_SET_PARAM, + status_t ret = effect->command(EFFECT_CMD_SET_PARAM, size, param, &rsize, @@ -1401,7 +1424,7 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode, return disable(); } - return mEffect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData); + return effect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData); } void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal, bool enabled) @@ -1483,7 +1506,6 @@ AudioFlinger::EffectChain::~EffectChain() if (mOwnInBuffer) { delete mInBuffer; } - } // getEffectFromDesc_l() must be called with ThreadBase::mLock held @@ -1601,13 +1623,38 @@ void AudioFlinger::EffectChain::process_l() } } -// addEffect_l() must be called with PlaybackThread::mLock held +// createEffect_l() must be called with ThreadBase::mLock held +status_t AudioFlinger::EffectChain::createEffect_l(sp& effect, + ThreadBase *thread, + effect_descriptor_t *desc, + int id, + audio_session_t sessionId, + bool pinned) +{ + Mutex::Autolock _l(mLock); + effect = new EffectModule(thread, this, desc, id, sessionId, pinned); + status_t lStatus = effect->status(); + if (lStatus == NO_ERROR) { + lStatus = addEffect_ll(effect); + } + if (lStatus != NO_ERROR) { + effect.clear(); + } + return lStatus; +} + +// addEffect_l() must be called with ThreadBase::mLock held status_t AudioFlinger::EffectChain::addEffect_l(const sp& effect) +{ + Mutex::Autolock _l(mLock); + return addEffect_ll(effect); +} +// addEffect_l() must be called with ThreadBase::mLock and EffectChain::mLock held +status_t AudioFlinger::EffectChain::addEffect_ll(const sp& effect) { effect_descriptor_t desc = effect->desc(); uint32_t insertPref = desc.flags & EFFECT_FLAG_INSERT_MASK; - Mutex::Autolock _l(mLock); effect->setChain(this); sp thread = mThread.promote(); if (thread == 0) { @@ -1721,8 +1768,9 @@ status_t AudioFlinger::EffectChain::addEffect_l(const sp& effect) #endif // LINE_ADDED_BY_DOLBY } -// removeEffect_l() must be called with PlaybackThread::mLock held -size_t AudioFlinger::EffectChain::removeEffect_l(const sp& effect) +// removeEffect_l() must be called with ThreadBase::mLock held +size_t AudioFlinger::EffectChain::removeEffect_l(const sp& effect, + bool release) { Mutex::Autolock _l(mLock); size_t size = mEffects.size(); @@ -1737,6 +1785,10 @@ size_t AudioFlinger::EffectChain::removeEffect_l(const sp& effect) mEffects[i]->state() == EffectModule::STOPPING) { mEffects[i]->stop(); } + if (release) { + mEffects[i]->release_l(); + } + if (type == EFFECT_FLAG_TYPE_AUXILIARY) { delete[] effect->inBuffer(); } else { @@ -1760,7 +1812,7 @@ size_t AudioFlinger::EffectChain::removeEffect_l(const sp& effect) return mEffects.size(); } -// setDevice_l() must be called with PlaybackThread::mLock held +// setDevice_l() must be called with ThreadBase::mLock held void AudioFlinger::EffectChain::setDevice_l(audio_devices_t device) { size_t size = mEffects.size(); @@ -1769,7 +1821,7 @@ void AudioFlinger::EffectChain::setDevice_l(audio_devices_t device) } } -// setMode_l() must be called with PlaybackThread::mLock held +// setMode_l() must be called with ThreadBase::mLock held void AudioFlinger::EffectChain::setMode_l(audio_mode_t mode) { size_t size = mEffects.size(); @@ -1778,7 +1830,7 @@ void AudioFlinger::EffectChain::setMode_l(audio_mode_t mode) } } -// setAudioSource_l() must be called with PlaybackThread::mLock held +// setAudioSource_l() must be called with ThreadBase::mLock held void AudioFlinger::EffectChain::setAudioSource_l(audio_source_t source) { size_t size = mEffects.size(); @@ -1787,7 +1839,7 @@ void AudioFlinger::EffectChain::setAudioSource_l(audio_source_t source) } } -// setVolume_l() must be called with PlaybackThread::mLock or EffectChain::mLock held +// setVolume_l() must be called with ThreadBase::mLock or EffectChain::mLock held bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right, bool force) { uint32_t newLeft = *left; @@ -1848,7 +1900,7 @@ bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right, boo return hasControl; } -// resetVolume_l() must be called with PlaybackThread::mLock or EffectChain::mLock held +// resetVolume_l() must be called with ThreadBase::mLock or EffectChain::mLock held void AudioFlinger::EffectChain::resetVolume_l() { if ((mLeftVolume != UINT_MAX) && (mRightVolume != UINT_MAX)) { @@ -1949,7 +2001,7 @@ void AudioFlinger::EffectChain::setEffectSuspended_l( effect->setSuspended(false); effect->lock(); EffectHandle *handle = effect->controlHandle_l(); - if (handle != NULL && !handle->destroyed_l()) { + if (handle != NULL && !handle->disconnected()) { effect->setEnabled_l(handle->enabled()); } effect->unlock(); diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h index 818bf9416..864d508ed 100644 --- a/services/audioflinger/Effects.h +++ b/services/audioflinger/Effects.h @@ -45,7 +45,8 @@ class EffectModule : public RefBase { const wp& chain, effect_descriptor_t *desc, int id, - audio_session_t sessionId); + audio_session_t sessionId, + bool pinned); virtual ~EffectModule(); enum effect_state { @@ -93,8 +94,9 @@ class EffectModule : public RefBase { const wp& thread() { return mThread; } status_t addHandle(EffectHandle *handle); - size_t disconnect(EffectHandle *handle, bool unpinIfLast); - size_t removeHandle(EffectHandle *handle); + ssize_t disconnectHandle(EffectHandle *handle, bool unpinIfLast); + ssize_t removeHandle(EffectHandle *handle); + ssize_t removeHandle_l(EffectHandle *handle); const effect_descriptor_t& desc() const { return mDescriptor; } wp& chain() { return mChain; } @@ -124,6 +126,7 @@ class EffectModule : public RefBase { status_t setOffloaded(bool offloaded, audio_io_handle_t io); bool isOffloaded() const; void addEffectToHal_l(); + void release_l(); void dump(int fd, const Vector& args); @@ -208,12 +211,17 @@ class EffectHandle: public android::BnEffect { bool enabled() const { return mEnabled; } // Getters - int id() const { return mEffect->id(); } + wp effect() const { return mEffect; } + int id() const { + sp effect = mEffect.promote(); + if (effect == 0) { + return 0; + } + return effect->id(); + } int priority() const { return mPriority; } bool hasControl() const { return mHasControl; } - sp effect() const { return mEffect; } - // destroyed_l() must be called with the associated EffectModule mLock held - bool destroyed_l() const { return mDestroyed; } + bool disconnected() const { return mDisconnected; } void dumpToBuffer(char* buffer, size_t size); @@ -222,7 +230,8 @@ class EffectHandle: public android::BnEffect { EffectHandle(const EffectHandle&); EffectHandle& operator =(const EffectHandle&); - sp mEffect; // pointer to controlled EffectModule + Mutex mLock; // protects IEffect method calls + wp mEffect; // pointer to controlled EffectModule sp mEffectClient; // callback interface for client notifications /*const*/ sp mClient; // client for shared memory allocation, see disconnect() sp mCblkMemory; // shared memory for control block @@ -233,8 +242,7 @@ class EffectHandle: public android::BnEffect { bool mHasControl; // true if this handle is controlling the effect bool mEnabled; // cached enable state: needed when the effect is // restored after being suspended - bool mDestroyed; // Set to true by destructor. Access with EffectModule - // mLock held + bool mDisconnected; // Set to true by disconnect() }; // the EffectChain class represents a group of effects associated to one audio session. @@ -269,8 +277,15 @@ class EffectChain : public RefBase { mLock.unlock(); } + status_t createEffect_l(sp& effect, + ThreadBase *thread, + effect_descriptor_t *desc, + int id, + audio_session_t sessionId, + bool pinned); status_t addEffect_l(const sp& handle); - size_t removeEffect_l(const sp& handle); + status_t addEffect_ll(const sp& handle); + size_t removeEffect_l(const sp& handle, bool release = false); audio_session_t sessionId() const { return mSessionId; } void setSessionId(audio_session_t sessionId) { mSessionId = sessionId; } diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 1434a56ab..4e96b41b3 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -1427,7 +1427,8 @@ sp AudioFlinger::ThreadBase::createEffect_l( audio_session_t sessionId, effect_descriptor_t *desc, int *enabled, - status_t *status) + status_t *status, + bool pinned) { sp effect; sp handle; @@ -1526,20 +1527,7 @@ sp AudioFlinger::ThreadBase::createEffect_l( } effectRegistered = true; // create a new effect module if none present in the chain - effect = new EffectModule(this, chain, desc, id, sessionId); - lStatus = effect->status(); - if (lStatus != NO_ERROR) { - goto Exit; - } - - bool setVal = false; - if (mType == OFFLOAD || (mType == DIRECT && mIsDirectPcm)) { - setVal = true; - } - - effect->setOffloaded(setVal, mId); - - lStatus = chain->addEffect_l(effect); + lStatus = chain->createEffect_l(effect, this, desc, id, sessionId, pinned); if (lStatus != NO_ERROR) { goto Exit; } @@ -1583,6 +1571,33 @@ sp AudioFlinger::ThreadBase::createEffect_l( return handle; } +void AudioFlinger::ThreadBase::disconnectEffectHandle(EffectHandle *handle, + bool unpinIfLast) +{ + bool remove = false; + sp effect; + { + Mutex::Autolock _l(mLock); + + effect = handle->effect().promote(); + if (effect == 0) { + return; + } + // restore suspended effects if the disconnected handle was enabled and the last one. + remove = (effect->removeHandle(handle) == 0) && (!effect->isPinned() || unpinIfLast); + if (remove) { + removeEffect_l(effect, true); + } + } + if (remove) { + mAudioFlinger->updateOrphanEffectChains(effect); + AudioSystem::unregisterEffect(effect->id()); + if (handle->enabled()) { + checkSuspendOnEffectEnabled(effect, false, effect->sessionId()); + } + } +} + sp AudioFlinger::ThreadBase::getEffect(audio_session_t sessionId, int effectId) { @@ -1652,9 +1667,9 @@ status_t AudioFlinger::ThreadBase::addEffect_l(const sp& effect) return NO_ERROR; } -void AudioFlinger::ThreadBase::removeEffect_l(const sp& effect) { +void AudioFlinger::ThreadBase::removeEffect_l(const sp& effect, bool release) { - ALOGV("removeEffect_l() %p effect %p", this, effect.get()); + ALOGV("%s %p effect %p", __FUNCTION__, this, effect.get()); effect_descriptor_t desc = effect->desc(); if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { detachAuxEffect_l(effect->id()); @@ -1663,7 +1678,7 @@ void AudioFlinger::ThreadBase::removeEffect_l(const sp& effect) { sp chain = effect->chain().promote(); if (chain != 0) { // remove effect chain if removing last effect - if (chain->removeEffect_l(effect) == 0) { + if (chain->removeEffect_l(effect, release) == 0) { removeEffectChain_l(chain); } } else { diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 80388c1af..085882dae 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -295,7 +295,8 @@ class ThreadBase : public Thread { audio_session_t sessionId, effect_descriptor_t *desc, int *enabled, - status_t *status /*non-NULL*/); + status_t *status /*non-NULL*/, + bool pinned); // return values for hasAudioSession (bit field) enum effect_state { @@ -334,7 +335,9 @@ class ThreadBase : public Thread { status_t addEffect_l(const sp< EffectModule>& effect); // remove and effect module. Also removes the effect chain is this was the last // effect - void removeEffect_l(const sp< EffectModule>& effect); + void removeEffect_l(const sp< EffectModule>& effect, bool release = false); + // disconnect an effect handle from module and destroy module if last handle + void disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast); // detach all tracks connected to an auxiliary effect virtual void detachAuxEffect_l(int effectId __unused) {} // returns a combination of: diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index 2bbc04538..e3c3f545b 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -399,7 +399,6 @@ void AudioPolicyService::releaseInput(audio_io_handle_t input, spaudioPolicyEffects; { Mutex::Autolock _l(mLock); - mAudioPolicyManager->releaseInput(input, session); audioPolicyEffects = mAudioPolicyEffects; } if (audioPolicyEffects != 0) { @@ -409,6 +408,10 @@ void AudioPolicyService::releaseInput(audio_io_handle_t input, ALOGW("Failed to release effects on input %d", input); } } + { + Mutex::Autolock _l(mLock); + mAudioPolicyManager->releaseInput(input, session); + } } status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream, From 2fa34e1763daa9b9b73175658d3476782a09882e Mon Sep 17 00:00:00 2001 From: Sharad Sangle Date: Mon, 13 Mar 2017 12:08:45 +0530 Subject: [PATCH 62/93] Audio: Make sure effects are enabled for PCM offload After AOSP security fix Ia1098cba2cd32cc2d1c9dfdff4adc2388dfed80e need to make sure that effects are applied on PCM offloaded streams. Change-Id: I8bb8c0e1c1fb70f1795cf8b0708a99508d8b564a --- services/audioflinger/Effects.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index 0f1202604..ebfe57357 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -106,7 +106,8 @@ AudioFlinger::EffectModule::EffectModule(ThreadBase *thread, goto Error; } - setOffloaded(thread->type() == ThreadBase::OFFLOAD, thread->id()); + setOffloaded((thread->type() == ThreadBase::OFFLOAD || + (thread->type() == ThreadBase::DIRECT && thread->mIsDirectPcm)), thread->id()); ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface); return; From efc2c73a748b7acd99f4fdf200e6a11cdd834cb0 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 15 Dec 2016 14:46:09 -0800 Subject: [PATCH 63/93] DO NOT MERGE - audioflinger: fix recursive mutex lock in EffectHandle. Bug: 33661708 Bug: 32707507 Bug: 32095713 Test: run CTS AudioEffectTest#test5_0Command, Custom binder test Change-Id: I03f674f126c191143bd8bdfe236f793e975826a5 (cherry picked from commit 31a4598a1908b3ccac7ddb33c511ce66840aa911) (cherry picked from commit 8415635765380be496da9b4578d8f134a527d86b) --- services/audioflinger/Effects.cpp | 32 ++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index ebfe57357..d80a57d5a 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -1335,6 +1335,24 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode, ALOGVV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p", cmdCode, mHasControl, mEffect.unsafe_get()); + if (cmdCode == EFFECT_CMD_ENABLE) { + if (*replySize < sizeof(int)) { + android_errorWriteLog(0x534e4554, "32095713"); + return BAD_VALUE; + } + *(int *)pReplyData = NO_ERROR; + *replySize = sizeof(int); + return enable(); + } else if (cmdCode == EFFECT_CMD_DISABLE) { + if (*replySize < sizeof(int)) { + android_errorWriteLog(0x534e4554, "32095713"); + return BAD_VALUE; + } + *(int *)pReplyData = NO_ERROR; + *replySize = sizeof(int); + return disable(); + } + AutoMutex _l(mLock); sp effect = mEffect.promote(); if (effect == 0 || mDisconnected) { @@ -1350,11 +1368,17 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode, // handle commands that are not forwarded transparently to effect engine if (cmdCode == EFFECT_CMD_SET_PARAM_COMMIT) { + if (*replySize < sizeof(int)) { + android_errorWriteLog(0x534e4554, "32095713"); + return BAD_VALUE; + } + *(int *)pReplyData = NO_ERROR; + *replySize = sizeof(int); + // No need to trylock() here as this function is executed in the binder thread serving a // particular client process: no risk to block the whole media server process or mixer // threads if we are stuck here Mutex::Autolock _l(mCblk->lock); - // keep local copy of index in case of client corruption b/32220769 const uint32_t clientIndex = mCblk->clientIndex; const uint32_t serverIndex = mCblk->serverIndex; @@ -1417,12 +1441,6 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode, mCblk->serverIndex = 0; mCblk->clientIndex = 0; return status; - } else if (cmdCode == EFFECT_CMD_ENABLE) { - *(int *)pReplyData = NO_ERROR; - return enable(); - } else if (cmdCode == EFFECT_CMD_DISABLE) { - *(int *)pReplyData = NO_ERROR; - return disable(); } return effect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData); From 6e8d3ae4ca505a3c4ca94ce777ed72434fc23bcf Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Tue, 24 Jan 2017 18:08:59 -0800 Subject: [PATCH 64/93] avc_utils: skip empty NALs from malformed bistreams Avoid a CHECK and make it the decoder's repsonsibility to handle a malformed bistream gracefully. Bug: 34509901 Bug: 33137046 Test: StagefrightTest#testStagefright_bug_27855419_CVE_2016_2463 Change-Id: I2d94f8da63d65a86a9c711c45546e4c695e0f3b4 (cherry picked from commit 91fe76a157847825601b8f7a627efd1c9cbadcae) (cherry picked from commit 371d728a9eae3da669567075b7075ba15e611ded) --- media/libstagefright/avc_utils.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp index a199eddc1..2a27f304f 100644 --- a/media/libstagefright/avc_utils.cpp +++ b/media/libstagefright/avc_utils.cpp @@ -456,7 +456,10 @@ bool IsIDR(const sp &buffer) { const uint8_t *nalStart; size_t nalSize; while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) { - CHECK_GT(nalSize, 0u); + if (nalSize == 0u) { + ALOGW("skipping empty nal unit from potentially malformed bitstream"); + continue; + } unsigned nalType = nalStart[0] & 0x1f; From f5df103ff79010996400e154b9799090e1d64c12 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 1 Feb 2017 15:35:35 -0800 Subject: [PATCH 65/93] Turn off overflow protection for various math functions These functions also exist as arm assembly files, where the overflows just wrap around, and this makes their plain C equivalents behave the same. Bug: 32577290 Bug: 33071964 Test: ran PoC for bug 32577290 using plain C source code Change-Id: I73c2609589e7a89d36f6c44391548312259daf14 (cherry picked from commit cbf5e6915c42c691a6ccb9a5d249e450f9e67467) --- .../codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h | 10 ++++++++++ .../libstagefright/codecs/mp3dec/src/pvmp3_dct_16.cpp | 3 +++ media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp | 1 + .../libstagefright/codecs/mp3dec/src/pvmp3_mdct_18.cpp | 1 + 4 files changed, 15 insertions(+) diff --git a/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h b/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h index ba438206d..7f480a6dc 100644 --- a/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h +++ b/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h @@ -50,6 +50,7 @@ extern "C" + __attribute__((no_sanitize("integer"))) __inline int32 pv_abs(int32 a) { int32 b = (a < 0) ? -a : a; @@ -59,49 +60,58 @@ extern "C" + __attribute__((no_sanitize("integer"))) __inline Int32 fxp_mul32_Q30(const Int32 a, const Int32 b) { return (Int32)(((int64)(a) * b) >> 30); } + __attribute__((no_sanitize("integer"))) __inline Int32 fxp_mac32_Q30(const Int32 a, const Int32 b, Int32 L_add) { return (L_add + (Int32)(((int64)(a) * b) >> 30)); } + __attribute__((no_sanitize("integer"))) __inline Int32 fxp_mul32_Q32(const Int32 a, const Int32 b) { return (Int32)(((int64)(a) * b) >> 32); } + __attribute__((no_sanitize("integer"))) __inline Int32 fxp_mul32_Q28(const Int32 a, const Int32 b) { return (Int32)(((int64)(a) * b) >> 28); } + __attribute__((no_sanitize("integer"))) __inline Int32 fxp_mul32_Q27(const Int32 a, const Int32 b) { return (Int32)(((int64)(a) * b) >> 27); } + __attribute__((no_sanitize("integer"))) __inline Int32 fxp_mul32_Q26(const Int32 a, const Int32 b) { return (Int32)(((int64)(a) * b) >> 26); } + __attribute__((no_sanitize("integer"))) __inline Int32 fxp_mac32_Q32(Int32 L_add, const Int32 a, const Int32 b) { return (L_add + (Int32)(((int64)(a) * b) >> 32)); } + __attribute__((no_sanitize("integer"))) __inline Int32 fxp_msb32_Q32(Int32 L_sub, const Int32 a, const Int32 b) { return (L_sub - ((Int32)(((int64)(a) * b) >> 32))); } + __attribute__((no_sanitize("integer"))) __inline Int32 fxp_mul32_Q29(const Int32 a, const Int32 b) { return (Int32)(((int64)(a) * b) >> 29); diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_16.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_16.cpp index a71efc4b4..949e7be0f 100644 --- a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_16.cpp +++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_16.cpp @@ -149,6 +149,7 @@ const int32 CosTable_dct32[16] = ; FUNCTION CODE ----------------------------------------------------------------------------*/ +__attribute__((no_sanitize("integer"))) void pvmp3_dct_16(int32 vec[], int32 flag) { int32 tmp0; @@ -308,6 +309,7 @@ void pvmp3_dct_16(int32 vec[], int32 flag) /*---------------------------------------------------------------------------- ; FUNCTION CODE ----------------------------------------------------------------------------*/ +__attribute__((no_sanitize("integer"))) void pvmp3_merge_in_place_N32(int32 vec[]) { @@ -366,6 +368,7 @@ void pvmp3_merge_in_place_N32(int32 vec[]) +__attribute__((no_sanitize("integer"))) void pvmp3_split(int32 *vect) { diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp index ce3ec64a6..fa581b31b 100644 --- a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp +++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp @@ -117,6 +117,7 @@ Returns ; FUNCTION CODE ----------------------------------------------------------------------------*/ +__attribute__((no_sanitize("integer"))) void pvmp3_dct_9(int32 vec[]) { diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_18.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_18.cpp index 09a735bf2..324290e14 100644 --- a/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_18.cpp +++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_18.cpp @@ -129,6 +129,7 @@ const int32 cosTerms_1_ov_cos_phi[18] = +__attribute__((no_sanitize("integer"))) void pvmp3_mdct_18(int32 vec[], int32 *history, const int32 *window) { int32 i; From e24c84c591a5609beddac087b99294cc7e9e4220 Mon Sep 17 00:00:00 2001 From: Chaithanya Krishna Bacharaju Date: Tue, 28 Feb 2017 15:08:29 +0530 Subject: [PATCH 66/93] soundtrigger: Modify conditional check in detach - All the required SoundTrigger models of a module client are not getting unloaded and removed as part of detach. - mModels.size() is evaluated for every iteration which gives current size of vector which results in exit of loop without checking for all models in case elements are removed in loop. removeItemsAt would modify the vector indices for each iteration and this would result in skipping access of some models. - Iterate from end of models to check and unload. CRs-Fixed: 2012759 Change-Id: Iead537989c4d0fc3873c08d1f1b51bb22f814da7 --- services/soundtrigger/SoundTriggerHwService.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp index b2f269840..85563567e 100644 --- a/services/soundtrigger/SoundTriggerHwService.cpp +++ b/services/soundtrigger/SoundTriggerHwService.cpp @@ -563,10 +563,11 @@ void SoundTriggerHwService::Module::detach(const sp& moduleClient) ALOGV("remove client %p", moduleClient.get()); mModuleClients.removeAt(index); - for (size_t i = 0; i < mModels.size(); i++) { - sp model = mModels.valueAt(i); + //iterate in reverse order as models are removed from list inside the loop + for (size_t i = mModels.size(); i > 0; i--) { + sp model = mModels.valueAt(i - 1); if (moduleClient == model->mModuleClient) { - mModels.removeItemsAt(i); + mModels.removeItemsAt(i - 1); ALOGV("detach() unloading model %d", model->mHandle); if (model->mState == Model::STATE_ACTIVE) { mHwDevice->stop_recognition(mHwDevice, model->mHandle); From 6d010b4061713ca04d2d056606fb8d525ae6077f Mon Sep 17 00:00:00 2001 From: Satya Krishna Pindiproli Date: Tue, 14 Mar 2017 17:57:54 +0530 Subject: [PATCH 67/93] audiopolicy: return proper devices from getDevicesForStream HDMI/Display Port does not behave like a fixed volume device during playback of compressed streams. This is because getDeviceForStream(AUDIO_STREAM_MUSIC) returns HDMI + Speaker which is not treated as a fixed volume device. getDeviceForStream returns HDMI + Speaker as getDeviceForStrategy returns Speaker for STRATEGY_ACCESSIBILITY which is appended to the list although the stream is not active. Add only those devices which have outputs with the current stream active to fix the issue. CRs-Fixed: 2014016 Change-Id: Ia7bf565ed51011da040564c6628f67a671355013 --- services/audiopolicy/managerdefault/AudioPolicyManager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 7049bbe67..90cccf1bb 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -4526,10 +4526,9 @@ audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stre for (size_t i = 0; i < outputs.size(); i++) { sp outputDesc = mOutputs.valueFor(outputs[i]); if (outputDesc->isStreamActive((audio_stream_type_t)curStream)) { - curDevices |= outputDesc->device(); + devices |= outputDesc->device(); } } - devices |= curDevices; } /*Filter SPEAKER_SAFE out of results, as AudioService doesn't know about it From e026e4e07ce41db8b4d6b5e006cd2f08883a5050 Mon Sep 17 00:00:00 2001 From: Aniket Kumar Lata Date: Mon, 6 Mar 2017 12:33:52 -0800 Subject: [PATCH 68/93] audiopolicy: Invalidate direct PCM tracks when mono is set Invalidate direct PCM offloaded tracks when mono is enabled. With this change, the AudioTrack client/Media Player must recreate the tracks as non-offloaded PCM. Change-Id: I30c883f88c262eb8a4888014e47558503048c139 CRs-Fixed: 2013919 --- services/audiopolicy/managerdefault/AudioPolicyManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 7049bbe67..80e8e0cbc 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -3192,7 +3192,8 @@ status_t AudioPolicyManager::setMasterMono(bool mono) Vector offloaded; for (size_t i = 0; i < mOutputs.size(); ++i) { sp desc = mOutputs.valueAt(i); - if (desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { + if (desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD || + desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) { offloaded.push(desc->mIoHandle); } } From def08782196b6de6a1eda7a5e1022320739ef191 Mon Sep 17 00:00:00 2001 From: Weiyin Jiang Date: Mon, 27 Feb 2017 17:33:37 +0800 Subject: [PATCH 69/93] stagefright: stop audio encoding before releasing writer thread Writer thread in encoder usecase gets stuck in destructor if recorder is stopped right after being paused. This is because encoder source is paused when recoder pauses, then omx encoder data flow stops. This in turn causes MediaCodecSource::read() to be blocked infinitely. The proper sequence to exit the main thread of encoding writer is to stop the source firstly before waiting for thread termination. Change-Id: Ic70bdc2ad06d3e03f6a2966c7c7cc2557a214349 CRs-Fixed: 2012015 --- media/libstagefright/AACWriter.cpp | 2 +- media/libstagefright/AMRWriter.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp index 8b1e1c35e..b72015c5e 100644 --- a/media/libstagefright/AACWriter.cpp +++ b/media/libstagefright/AACWriter.cpp @@ -154,11 +154,11 @@ status_t AACWriter::reset() { mDone = true; void *dummy; + status_t status = mSource->stop(); pthread_join(mThread, &dummy); status_t err = static_cast(reinterpret_cast(dummy)); { - status_t status = mSource->stop(); if (err == OK && (status != OK && status != ERROR_END_OF_STREAM)) { err = status; diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp index 961b57fa9..632f14859 100644 --- a/media/libstagefright/AMRWriter.cpp +++ b/media/libstagefright/AMRWriter.cpp @@ -149,11 +149,11 @@ status_t AMRWriter::reset() { mDone = true; void *dummy; + status_t status = mSource->stop(); pthread_join(mThread, &dummy); status_t err = static_cast(reinterpret_cast(dummy)); { - status_t status = mSource->stop(); if (err == OK && (status != OK && status != ERROR_END_OF_STREAM)) { err = status; From 0eeaa1cf2e6cfc02dafe8e9c62302547bfa475e6 Mon Sep 17 00:00:00 2001 From: Satya Krishna Pindiproli Date: Sun, 2 Apr 2017 10:34:05 +0530 Subject: [PATCH 70/93] Revert "audiopolicy: return proper devices from getDevicesForStream" This reverts commit c6abb7e1916601e7a9b97a1124acbdcd91ebe22e as there is a CTS regression (AudioManagerTest#testVolume) due to it. getDevicesForStream() can get called for an inactive stream, so the device for that stream/strategy as per PolicyEngine should be returned instead of AUDIO_DEVICE_NONE. CRs-Fixed: 2025755 Change-Id: I1a03dcf74a91ee33a843a923fa77170dfdbd6ff9 --- services/audiopolicy/managerdefault/AudioPolicyManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 22e33b39c..80e8e0cbc 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -4527,9 +4527,10 @@ audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stre for (size_t i = 0; i < outputs.size(); i++) { sp outputDesc = mOutputs.valueFor(outputs[i]); if (outputDesc->isStreamActive((audio_stream_type_t)curStream)) { - devices |= outputDesc->device(); + curDevices |= outputDesc->device(); } } + devices |= curDevices; } /*Filter SPEAKER_SAFE out of results, as AudioService doesn't know about it From 71d760b6a82fab84cc0120aa71b238aab4caeced Mon Sep 17 00:00:00 2001 From: Satya Krishna Pindiproli Date: Sun, 2 Apr 2017 10:34:05 +0530 Subject: [PATCH 71/93] Revert "audiopolicy: return proper devices from getDevicesForStream" This reverts commit c6abb7e1916601e7a9b97a1124acbdcd91ebe22e as there is a CTS regression (AudioManagerTest#testVolume) due to it. getDevicesForStream() can get called for an inactive stream, so the device for that stream/strategy as per PolicyEngine should be returned instead of AUDIO_DEVICE_NONE. CRs-Fixed: 2025755 Change-Id: I1a03dcf74a91ee33a843a923fa77170dfdbd6ff9 --- services/audiopolicy/managerdefault/AudioPolicyManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 22e33b39c..80e8e0cbc 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -4527,9 +4527,10 @@ audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stre for (size_t i = 0; i < outputs.size(); i++) { sp outputDesc = mOutputs.valueFor(outputs[i]); if (outputDesc->isStreamActive((audio_stream_type_t)curStream)) { - devices |= outputDesc->device(); + curDevices |= outputDesc->device(); } } + devices |= curDevices; } /*Filter SPEAKER_SAFE out of results, as AudioService doesn't know about it From 7a151d6ae2c352a656c4abcc9705804bfdd8e23f Mon Sep 17 00:00:00 2001 From: Chaithanya Krishna Bacharaju Date: Fri, 7 Apr 2017 13:38:49 +0530 Subject: [PATCH 72/93] audiopolicy: Do not select A2DP device if suspended A2DP output device is selected when SCO is active and A2DP suspended. Add support to avoid selection of A2DP device in such scenario. Modify conditional checks to ensure mA2dpSuspended is set to true or false when A2DP playback is on primary output as well. Retain original code to avoid suspend/restore output in case A2DP is on primary output. Change-Id: I55da447636f8901979fc0fce6858a31cdf525b7b --- .../interface/AudioPolicyManagerObserver.h | 2 ++ .../audiopolicy/enginedefault/src/Engine.cpp | 3 +++ .../managerdefault/AudioPolicyManager.cpp | 18 +++++++++++++----- .../managerdefault/AudioPolicyManager.h | 4 ++++ 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h index 846fa48bc..e6bd2e208 100755 --- a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h +++ b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h @@ -55,6 +55,8 @@ class AudioPolicyManagerObserver virtual const sp &getDefaultOutputDevice() const = 0; + virtual const bool &getA2dpSuspended() const = 0; + protected: virtual ~AudioPolicyManagerObserver() {} }; diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp index 6db66b085..b3f306533 100755 --- a/services/audiopolicy/enginedefault/src/Engine.cpp +++ b/services/audiopolicy/enginedefault/src/Engine.cpp @@ -352,6 +352,7 @@ audio_devices_t Engine::getDeviceForStrategyInt(routing_strategy strategy, // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP if (!isInCall() && (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) && + (!mApmObserver->getA2dpSuspended()) && (outputs.isA2dpOnPrimary() || (outputs.getA2dpOutput() != 0))) { device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; if (device) break; @@ -384,6 +385,7 @@ audio_devices_t Engine::getDeviceForStrategyInt(routing_strategy strategy, // A2DP speaker when forcing to speaker output if (!isInCall() && (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) && + (!mApmObserver->getA2dpSuspended()) && (outputs.isA2dpOnPrimary() || (outputs.getA2dpOutput() != 0))) { device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; if (device) break; @@ -482,6 +484,7 @@ audio_devices_t Engine::getDeviceForStrategyInt(routing_strategy strategy, } if ((device2 == AUDIO_DEVICE_NONE) && (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) && + (!mApmObserver->getA2dpSuspended()) && (outputs.isA2dpOnPrimary() || (outputs.getA2dpOutput() != 0))) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; if (device2 == AUDIO_DEVICE_NONE) { diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 8be5849cb..561d24963 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -4372,7 +4372,9 @@ void AudioPolicyManager::checkOutputForAllStrategies() void AudioPolicyManager::checkA2dpSuspend() { audio_io_handle_t a2dpOutput = mOutputs.getA2dpOutput(); - if (a2dpOutput == 0 || mOutputs.isA2dpOnPrimary()) { + bool a2dpOnPrimary = mOutputs.isA2dpOnPrimary(); + + if ((a2dpOutput == 0) && !a2dpOnPrimary) { mA2dpSuspended = false; return; } @@ -4385,13 +4387,15 @@ void AudioPolicyManager::checkA2dpSuspend() // (NOT already suspended) && // ((SCO device is connected && // (forced usage for communication || for record is SCO))) || - // (phone state is ringing || in call) + // (phone state is ringing || in call) && + // (A2DP output is present and not on primary output) // // restore A2DP output if: // (Already suspended) && // ((SCO device is NOT connected || // (forced usage NOT for communication && NOT for record is SCO))) && - // (phone state is NOT ringing && NOT in call) + // (phone state is NOT ringing && NOT in call) && + // (A2DP output is present and not on primary output) // if (mA2dpSuspended) { if ((!isScoConnected || @@ -4400,7 +4404,9 @@ void AudioPolicyManager::checkA2dpSuspend() ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) && (mEngine->getPhoneState() != AUDIO_MODE_RINGTONE))) { - mpClientInterface->restoreOutput(a2dpOutput); + if ((a2dpOutput != 0) && !a2dpOnPrimary) { + mpClientInterface->restoreOutput(a2dpOutput); + } mA2dpSuspended = false; } } else { @@ -4410,7 +4416,9 @@ void AudioPolicyManager::checkA2dpSuspend() ((mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) || (mEngine->getPhoneState() == AUDIO_MODE_RINGTONE))) { - mpClientInterface->suspendOutput(a2dpOutput); + if ((a2dpOutput != 0) && !a2dpOnPrimary) { + mpClientInterface->suspendOutput(a2dpOutput); + } mA2dpSuspended = true; } } diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index 78f9e6597..98ee92e97 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -294,6 +294,10 @@ class AudioPolicyManager : public AudioPolicyInterface, public AudioPolicyManage { return mDefaultOutputDevice; } + virtual const bool &getA2dpSuspended() const + { + return mA2dpSuspended; + } protected: void addOutput(audio_io_handle_t output, sp outputDesc); void removeOutput(audio_io_handle_t output); From 2ce011ddb05aacfcec4f5184d19f9aece90415c9 Mon Sep 17 00:00:00 2001 From: Anubhav Phukan Date: Thu, 9 Mar 2017 14:42:18 +0530 Subject: [PATCH 73/93] media : Changing time stamp manipulation in HFR recording. Earlier during pause resume operations the pause duration was multiplied with the ratio of capture FPS and the desired frame rate of the recorded video. This logic led to situations where if the pause duration was less than the above quantity, on subtracting, the value would come negative. This led to elongation of the length of the video beyond the desired length. Also the earlier logic led to miscalculation of the timeoffset that needs to be subtracted from the timestamp from camera. This led to elongation of time length as the value subtracted was much lesser than what was required. Change-Id: I98cdb14bb2b9c86013df9b2c8f2e558f184b633e --- media/libmediaplayerservice/StagefrightRecorder.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 674060690..2d94db399 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -1859,7 +1859,14 @@ status_t StagefrightRecorder::resume() { bool isQCHwAACEnc = property_get_bool("qcom.hw.aac.encoder", true); if (!isQCHwAACEnc || mAudioEncoder != AUDIO_ENCODER_AAC) { // 30 ms buffer to avoid timestamp overlap - mTotalPausedDurationUs -= (30000*(mCaptureFpsEnable ? (mCaptureFps / mFrameRate) : 1)); + if (mCaptureFpsEnable) { + if ((systemTime() / 1000) - mPauseStartTimeUs > + (30000 * mFrameRate) / mCaptureFps) { + mTotalPausedDurationUs -= (30000 * mFrameRate) / mCaptureFps; + } + } else { + mTotalPausedDurationUs -= 30000; + } } } From 118f4a4cb2bcc890fd152622957b24d240a28701 Mon Sep 17 00:00:00 2001 From: Weiyin Jiang Date: Wed, 12 Apr 2017 20:34:12 +0800 Subject: [PATCH 74/93] audio: hold effect mutex when releasing effect engine release_l() is invoked from effect destructor which doesn't hold effect chain mutex, which results into multi-thread contention. Holding effect mutex when releasing effect engine to improve thread safety. Change-Id: I2056693f79bcb3df9a5a9dac1b700d50ed535372 CRs-Fixed: 2026604 --- services/audioflinger/Effects.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index d80a57d5a..0fee352bd 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -581,6 +581,7 @@ status_t AudioFlinger::EffectModule::stop_l() // must be called with EffectChain::mLock held void AudioFlinger::EffectModule::release_l() { + Mutex::Autolock _l(mLock); if (mEffectInterface != NULL) { remove_effect_from_hal_l(); // release effect engine From 75c28ca6468c3724de6d627fd97e8f501f466578 Mon Sep 17 00:00:00 2001 From: Weiyin Jiang Date: Thu, 4 May 2017 13:07:12 +0800 Subject: [PATCH 75/93] libmedia: synchronize access to meta Assignment of IMediaSource::mMetaData of type sp in IMediaSource::getFormat() is not thread-safe and is found to be causing stability issues. Synchronize access to meta smart pointer to prevent potential race condition. CRs-Fixed: 2038194 Change-Id: I8a94d82d69f35307e5fab8174d752a847f47a2f2 --- media/libmedia/IMediaSource.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp index f79530e51..1f4d51019 100644 --- a/media/libmedia/IMediaSource.cpp +++ b/media/libmedia/IMediaSource.cpp @@ -107,6 +107,7 @@ class BpMediaSource : public BpInterface { data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor()); status_t ret = remote()->transact(GETFORMAT, data, &reply); if (ret == NO_ERROR) { + AutoMutex _l(mLock); mMetaData = MetaData::createFromParcel(reply); return mMetaData; } @@ -221,6 +222,8 @@ class BpMediaSource : public BpInterface { // NuPlayer passes pointers-to-metadata around, so we use this to keep the metadata alive // XXX: could we use this for caching, or does metadata change on the fly? sp mMetaData; + // ensure synchronize access to mMetaData + Mutex mLock; // Cache all IMemory objects received from MediaExtractor. // We gc IMemory objects that are no longer active (referenced by a MediaBuffer). From ccda08c1d8e029fc7858575411cc47d50feb7511 Mon Sep 17 00:00:00 2001 From: Santhosh Behara Date: Wed, 26 Apr 2017 14:56:26 +0530 Subject: [PATCH 76/93] stagefright: MPEG4Writer: Skip wait for audio in few conditions Avoid waiting for video track to catch up to last audio timestamp in conditions when maxfileduration or maxfilesize limit is reached or if writer encounters any malformed error. Also, update the wait timeout interval to 500msec instead of 1sec as camera can hold maximum 15 frames when EIS is enabled. Change-Id: Idb3330137009be05a2bb4131a192c8f483546b6f --- media/libstagefright/MPEG4Writer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 6ef6bde59..5d31461a3 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -70,6 +70,7 @@ static const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 2^32-1 : max FAT32 static const uint8_t kNalUnitTypeSeqParamSet = 0x07; static const uint8_t kNalUnitTypePicParamSet = 0x08; static const int64_t kInitialDelayTimeUs = 700000LL; +static const nsecs_t kWaitDuration = 500000000LL; //500msec ~15frames delay static const char kMetaKey_Version[] = "com.android.version"; #ifdef SHOW_MODEL_BUILD @@ -1994,10 +1995,13 @@ status_t MPEG4Writer::Track::stop() { return OK; } - if (!mIsAudio && mOwner->getLastAudioTimeStamp()) { + if (!mIsAudio && mOwner->getLastAudioTimeStamp() && + !mOwner->exceedsFileDurationLimit() && + !mOwner->exceedsFileSizeLimit() && + !mIsMalformed) { Mutex::Autolock lock(mTrackCompletionLock); mIsStopping = true; - if (mTrackCompletionSignal.waitRelative(mTrackCompletionLock, 1e9 /* 1 sec */)) { + if (mTrackCompletionSignal.waitRelative(mTrackCompletionLock, kWaitDuration)) { ALOGW("Timed-out waiting for video track to reach final audio timestamp !"); } } From ace33e56e0bcbec9652bffca6850ea56235b3bfe Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Wed, 21 Oct 2015 16:38:43 -0700 Subject: [PATCH 77/93] NuPlayer: Decoder: Check for valid codec on resume The MediaCodec member associated with an NuPlayerDecoder is cleared if configure fails. A pending seek operation in NuPlayer can issue a ResumeDecoderAction. Add a NULL check before accessing the MediaCodec instance to handle this resume. Change-Id: Idc6c15168ec922ca1bd6d867cbe59847647c6f26 CRs-Fixed: 913215 --- media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 888ce68f2..c1506157b 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -457,7 +457,14 @@ void NuPlayer::Decoder::onResume(bool notifyComplete) { if (notifyComplete) { mResumePending = true; } - mCodec->start(); + + if (mCodec != NULL) { + mCodec->start(); + } else { + ALOGW("Decoder %s onResume without a valid codec object", + mComponentName.c_str()); + handleError(NO_INIT); + } } void NuPlayer::Decoder::doFlush(bool notifyComplete) { From c7652c33362df88b19caf7003af88c825e4b4f00 Mon Sep 17 00:00:00 2001 From: Ray Essick Date: Thu, 23 Feb 2017 16:08:09 -0800 Subject: [PATCH 78/93] Validate lengths in HEVC metadata parsing Add code to validate the size parameter passed to HecvParameterSets::addNalUnit(). Previously vulnerable to decrementing an unsigned past 0, yielding a huge result value. Bug: 35467107 Test: ran POC, no crash, emitted new "bad length" log entry Change-Id: Ia169b9edc1e0f7c5302e3c68aa90a54e8863d79e (cherry picked from commit e0dcf097cc029d056926029a29419e1650cbdf1b) (cherry picked from commit 1552726c8a9a7579fcb00f7849d8a1d59e4f571c) --- media/libstagefright/HevcUtils.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/media/libstagefright/HevcUtils.cpp b/media/libstagefright/HevcUtils.cpp index 718710a01..7d463a91c 100644 --- a/media/libstagefright/HevcUtils.cpp +++ b/media/libstagefright/HevcUtils.cpp @@ -45,16 +45,32 @@ HevcParameterSets::HevcParameterSets() } status_t HevcParameterSets::addNalUnit(const uint8_t* data, size_t size) { + if (size < 1) { + ALOGE("empty NAL b/35467107"); + return ERROR_MALFORMED; + } uint8_t nalUnitType = (data[0] >> 1) & 0x3f; status_t err = OK; switch (nalUnitType) { case 32: // VPS + if (size < 2) { + ALOGE("invalid NAL/VPS size b/35467107"); + return ERROR_MALFORMED; + } err = parseVps(data + 2, size - 2); break; case 33: // SPS + if (size < 2) { + ALOGE("invalid NAL/SPS size b/35467107"); + return ERROR_MALFORMED; + } err = parseSps(data + 2, size - 2); break; case 34: // PPS + if (size < 2) { + ALOGE("invalid NAL/PPS size b/35467107"); + return ERROR_MALFORMED; + } err = parsePps(data + 2, size - 2); break; case 39: // Prefix SEI From d3585592b81e9b22ca3cdb85deff22e3cde56bba Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Mon, 24 Oct 2016 11:38:31 -0700 Subject: [PATCH 79/93] FLACExtractor: copy protect mWriteBuffer Bug: 30895578 Bug: 34970788 Change-Id: I4cba36bbe3502678210e5925181683df9726b431 (cherry picked from commit 328cd66cc72ba7bc5452ed5a93f29ddcd73aa9f9) (cherry picked from commit 8ee699977c155c6d67e4abd8b4259b5447148a80) (cherry picked from commit 0be0ed5a7c9d288f324675e80b0fca657570a8bf) --- media/libstagefright/FLACExtractor.cpp | 35 ++++++++++++++------------ 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp index 13b66f304..543e0af58 100644 --- a/media/libstagefright/FLACExtractor.cpp +++ b/media/libstagefright/FLACExtractor.cpp @@ -73,6 +73,10 @@ class FLACSource : public MediaSource { class FLACParser : public RefBase { public: + enum { + kMaxChannels = 8, + }; + FLACParser( const sp &dataSource, // If metadata pointers aren't provided, we don't fill them @@ -122,7 +126,7 @@ class FLACParser : public RefBase { // media buffers size_t mMaxBufferSize; MediaBufferGroup *mGroup; - void (*mCopy)(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels); + void (*mCopy)(short *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels); // handle to underlying libFLAC parser FLAC__StreamDecoder *mDecoder; @@ -139,7 +143,7 @@ class FLACParser : public RefBase { bool mWriteRequested; bool mWriteCompleted; FLAC__FrameHeader mWriteHeader; - const FLAC__int32 * const *mWriteBuffer; + FLAC__int32 const * mWriteBuffer[kMaxChannels]; // most recent error reported by libFLAC parser FLAC__StreamDecoderErrorStatus mErrorStatus; @@ -323,7 +327,7 @@ FLAC__StreamDecoderWriteStatus FLACParser::writeCallback( mWriteRequested = false; // FLAC parser doesn't free or realloc buffer until next frame or finish mWriteHeader = frame->header; - mWriteBuffer = buffer; + memmove(mWriteBuffer, buffer, sizeof(const FLAC__int32 * const) * getChannels()); mWriteCompleted = true; return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } else { @@ -382,7 +386,7 @@ void FLACParser::errorCallback(FLAC__StreamDecoderErrorStatus status) static void copyMono8( short *dst, - const int *const *src, + const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned /* nChannels */) { for (unsigned i = 0; i < nSamples; ++i) { @@ -392,7 +396,7 @@ static void copyMono8( static void copyStereo8( short *dst, - const int *const *src, + const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned /* nChannels */) { for (unsigned i = 0; i < nSamples; ++i) { @@ -401,7 +405,7 @@ static void copyStereo8( } } -static void copyMultiCh8(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels) +static void copyMultiCh8(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels) { for (unsigned i = 0; i < nSamples; ++i) { for (unsigned c = 0; c < nChannels; ++c) { @@ -412,7 +416,7 @@ static void copyMultiCh8(short *dst, const int *const *src, unsigned nSamples, u static void copyMono16( short *dst, - const int *const *src, + const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned /* nChannels */) { for (unsigned i = 0; i < nSamples; ++i) { @@ -422,7 +426,7 @@ static void copyMono16( static void copyStereo16( short *dst, - const int *const *src, + const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned /* nChannels */) { for (unsigned i = 0; i < nSamples; ++i) { @@ -431,7 +435,7 @@ static void copyStereo16( } } -static void copyMultiCh16(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels) +static void copyMultiCh16(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels) { for (unsigned i = 0; i < nSamples; ++i) { for (unsigned c = 0; c < nChannels; ++c) { @@ -444,7 +448,7 @@ static void copyMultiCh16(short *dst, const int *const *src, unsigned nSamples, static void copyMono24( short *dst, - const int *const *src, + const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned /* nChannels */) { for (unsigned i = 0; i < nSamples; ++i) { @@ -454,7 +458,7 @@ static void copyMono24( static void copyStereo24( short *dst, - const int *const *src, + const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned /* nChannels */) { for (unsigned i = 0; i < nSamples; ++i) { @@ -463,7 +467,7 @@ static void copyStereo24( } } -static void copyMultiCh24(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels) +static void copyMultiCh24(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels) { for (unsigned i = 0; i < nSamples; ++i) { for (unsigned c = 0; c < nChannels; ++c) { @@ -474,7 +478,7 @@ static void copyMultiCh24(short *dst, const int *const *src, unsigned nSamples, static void copyTrespass( short * /* dst */, - const int *const * /* src */, + const int *[FLACParser::kMaxChannels] /* src */, unsigned /* nSamples */, unsigned /* nChannels */) { TRESPASS(); @@ -499,7 +503,6 @@ FLACParser::FLACParser( mStreamInfoValid(false), mWriteRequested(false), mWriteCompleted(false), - mWriteBuffer(NULL), mErrorStatus((FLAC__StreamDecoderErrorStatus) -1) { ALOGV("FLACParser::FLACParser"); @@ -555,7 +558,7 @@ status_t FLACParser::init() } if (mStreamInfoValid) { // check channel count - if (getChannels() == 0 || getChannels() > 8) { + if (getChannels() == 0 || getChannels() > kMaxChannels) { ALOGE("unsupported channel count %u", getChannels()); return NO_INIT; } @@ -591,7 +594,7 @@ status_t FLACParser::init() static const struct { unsigned mChannels; unsigned mBitsPerSample; - void (*mCopy)(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels); + void (*mCopy)(short *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels); } table[] = { { 1, 8, copyMono8 }, { 2, 8, copyStereo8 }, From 30d60035c68a16c454a5bcda6f81094595762276 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 9 Mar 2017 15:01:55 -0800 Subject: [PATCH 80/93] Fix integer overflow and divide-by-zero Bug: 35763994 Test: ran CTS with and without fix Change-Id: If835e97ce578d4fa567e33e349e48fb7b2559e0e (cherry picked from commit 8538a603ef992e75f29336499cb783f3ec19f18c) (cherry picked from commit 76a66d3e9cea6ce8f4d5bf71ed8a0ea6f113a355) --- media/libstagefright/AMRExtractor.cpp | 2 +- media/libstagefright/NuMediaExtractor.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp index 0e98db828..2892520c0 100644 --- a/media/libstagefright/AMRExtractor.cpp +++ b/media/libstagefright/AMRExtractor.cpp @@ -259,7 +259,7 @@ status_t AMRSource::read( int64_t seekTimeUs; ReadOptions::SeekMode mode; - if (options && options->getSeekTo(&seekTimeUs, &mode)) { + if (mOffsetTableLength > 0 && options && options->getSeekTo(&seekTimeUs, &mode)) { size_t size; int64_t seekFrame = seekTimeUs / 20000ll; // 20ms per frame. mCurrentTimeUs = seekFrame * 20000ll; diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp index 276d73136..4558b3c1c 100644 --- a/media/libstagefright/NuMediaExtractor.cpp +++ b/media/libstagefright/NuMediaExtractor.cpp @@ -618,7 +618,7 @@ bool NuMediaExtractor::getTotalBitrate(int64_t *bitrate) const { } off64_t size; - if (mDurationUs >= 0 && mDataSource->getSize(&size) == OK) { + if (mDurationUs > 0 && mDataSource->getSize(&size) == OK) { *bitrate = size * 8000000ll / mDurationUs; // in bits/sec return true; } From 8330df2b912b2f5263fbb76bce85cd3d8f2aa33f Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 10 Mar 2017 11:28:44 -0800 Subject: [PATCH 81/93] Fix out of bounds access Bug: 34618607 Change-Id: I84f0ef948414d0b2d54e8948b6c30b8ae4da2b36 (cherry picked from commit d1c19c57f66d91ea8033c8fa6510a8760a6e663b) (cherry picked from commit 94a2371d16769e8136a83215a1af34034ad7752f) --- media/libstagefright/id3/ID3.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp index ba8ce2a4c..2bbe319a6 100644 --- a/media/libstagefright/id3/ID3.cpp +++ b/media/libstagefright/id3/ID3.cpp @@ -379,7 +379,7 @@ bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) { flags &= ~1; } - if (flags & 2) { + if ((flags & 2) && (dataSize >= 2)) { // This file has "unsynchronization", so we have to replace occurrences // of 0xff 0x00 with just 0xff in order to get the real data. @@ -395,11 +395,15 @@ bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) { mData[writeOffset++] = mData[readOffset++]; } // move the remaining data following this frame - memmove(&mData[writeOffset], &mData[readOffset], oldSize - readOffset); + if (readOffset <= oldSize) { + memmove(&mData[writeOffset], &mData[readOffset], oldSize - readOffset); + } else { + ALOGE("b/34618607 (%zu %zu %zu %zu)", readOffset, writeOffset, oldSize, mSize); + android_errorWriteLog(0x534e4554, "34618607"); + } - flags &= ~2; } - + flags &= ~2; if (flags != prevFlags || iTunesHack) { WriteSyncsafeInteger(&mData[offset + 4], dataSize); mData[offset + 8] = flags >> 8; From 64702edb3f478e6c73617c13b2e67e27219e4c52 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 3 Mar 2017 13:37:27 -0800 Subject: [PATCH 82/93] Fix NPDs in h263 decoder Bug: 35269635 Test: decoded PoC with and without patch Change-Id: I636a14360c7801cc5bca63c9cb44d1d235df8fd8 (cherry picked from commit 2ad2a92318a3b9daf78ebcdc597085adbf32600d) (cherry picked from commit ddc86fc36a42a441f592cb848a06331b0861c3b1) --- .../codecs/m4v_h263/dec/src/mb_motion_comp.cpp | 18 +++++++++++++++++- .../codecs/m4v_h263/dec/src/pvdec_api.cpp | 7 +++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/mb_motion_comp.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/mb_motion_comp.cpp index fbc7be1aa..877723d75 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/src/mb_motion_comp.cpp +++ b/media/libstagefright/codecs/m4v_h263/dec/src/mb_motion_comp.cpp @@ -15,6 +15,10 @@ * and limitations under the License. * ------------------------------------------------------------------- */ + +#define LOG_TAG "m4v_h263" +#include + /* ------------------------------------------------------------------------------ INPUT AND OUTPUT DEFINITIONS @@ -236,6 +240,11 @@ void MBMotionComp( /* Pointer to previous luminance frame */ c_prev = prev->yChan; + if (!c_prev) { + ALOGE("b/35269635"); + android_errorWriteLog(0x534e4554, "35269635"); + return; + } pred_block = video->mblock->pred_block; @@ -574,7 +583,14 @@ void SkippedMBMotionComp( /* zero motion compensation for previous frame */ /*mby*width + mbx;*/ - c_prev = prev->yChan + offset; + c_prev = prev->yChan; + if (!c_prev) { + ALOGE("b/35269635"); + android_errorWriteLog(0x534e4554, "35269635"); + return; + } + c_prev += offset; + /*by*width_uv + bx;*/ cu_prev = prev->uChan + (offset >> 2) + (xpos >> 2); /*by*width_uv + bx;*/ diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp index c1720c639..8d5d0712b 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp +++ b/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp @@ -15,6 +15,8 @@ * and limitations under the License. * ------------------------------------------------------------------- */ +#define LOG_TAG "pvdec_api" +#include #include "mp4dec_lib.h" #include "vlc_decode.h" #include "bitstream.h" @@ -1335,6 +1337,11 @@ Bool PVDecodeVopBody(VideoDecControls *decCtrl, int32 buffer_size[]) } } + if (!video->prevVop->yChan) { + ALOGE("b/35269635"); + android_errorWriteLog(0x534e4554, "35269635"); + return PV_FALSE; + } oscl_memcpy(currVop->yChan, video->prevVop->yChan, (decCtrl->size*3) / 2); video->prevVop = prevVop; From 4d12b0a27d8e5ed0ba5bd4ec8d597fb0d366ef1a Mon Sep 17 00:00:00 2001 From: Ray Essick Date: Mon, 13 Mar 2017 11:59:57 -0700 Subject: [PATCH 83/93] Add bounds check in SoftAACEncoder2::onQueueFilled() Original code blindly copied some header information into the user-supplied buffer without checking for sufficient space. The code does check when it gets to filling the data -- it's just the header copies that weren't checked. Bug: 34617444 Test: ran POC before/after Change-Id: I6e80ec90616f6cd02bb8316cd2d6e309b7e4729d (cherry picked from commit 6231243626b8b9c57593b1f0ee417f2c4af4c0aa) (cherry picked from commit f8fc1e85e2007be748b4d3342a8de36602208e2a) --- media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp index 5f516cbc5..f00a5d1b0 100644 --- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp +++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp @@ -510,6 +510,15 @@ void SoftAACEncoder2::onQueueFilled(OMX_U32 /* portIndex */) { BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; + + if (outHeader->nOffset + encInfo.confSize > outHeader->nAllocLen) { + ALOGE("b/34617444"); + android_errorWriteLog(0x534e4554,"34617444"); + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + mSignalledError = true; + return; + } + outHeader->nFilledLen = encInfo.confSize; outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG; From 5eae13e6c90aa2d68b6f033de401ec078f5a2c0b Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Mon, 13 Feb 2017 18:48:39 -0800 Subject: [PATCH 84/93] AudioFlinger: Check framecount overflow when creating track Test: Native POC Bug: 34749571 Change-Id: I7529658e52ac7e64d162eb5338f10fb25eaa8fe7 (cherry picked from commit 1883f69de5f2c4e71df58d5b71d7c39f9779b50c) (cherry picked from commit eaa3969f757291f151efedde17ec529b8659024d) (cherry picked from commit 51e72602eb3b7ee9aedc63e6cf7ca58958775481) --- services/audioflinger/Tracks.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index dd3fe909c..da15556b3 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -133,9 +133,24 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( mUid = clientUid; // ALOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize); + + size_t bufferSize = buffer == NULL ? roundup(frameCount) : frameCount; + // check overflow when computing bufferSize due to multiplication by mFrameSize. + if (bufferSize < frameCount // roundup rounds down for values above UINT_MAX / 2 + || mFrameSize == 0 // format needs to be correct + || bufferSize > SIZE_MAX / mFrameSize) { + android_errorWriteLog(0x534e4554, "34749571"); + return; + } + bufferSize *= mFrameSize; + size_t size = sizeof(audio_track_cblk_t); - size_t bufferSize = (buffer == NULL ? roundup(frameCount) : frameCount) * mFrameSize; if (buffer == NULL && alloc == ALLOC_CBLK) { + // check overflow when computing allocation size for streaming tracks. + if (size > SIZE_MAX - bufferSize) { + android_errorWriteLog(0x534e4554, "34749571"); + return; + } size += bufferSize; } From d97375fc6feb1684d242cd89015b655f7904d43d Mon Sep 17 00:00:00 2001 From: Aalique Grahame Date: Tue, 9 May 2017 14:24:24 -0700 Subject: [PATCH 85/93] stagefright: don't assume 16 bit format Don't assume 16 bit format for audio clip when calculating frame size. Otherwise data that is not frame aligned will be sent to NuPlayer, resulting in dropped data. Instead pass frame size based on audio format. CRs-Fixed: 2020023 Change-Id: I33097c6928ba355c6a3a6f4428c3957067f2397e --- include/media/stagefright/SkipCutBuffer.h | 4 +-- include/media/stagefright/Utils.h | 7 +++++ media/libstagefright/ACodec.cpp | 25 ++++++++++++---- media/libstagefright/DataConverter.cpp | 34 +--------------------- media/libstagefright/SkipCutBuffer.cpp | 7 +---- media/libstagefright/Utils.cpp | 35 +++++++++++++++++++++++ 6 files changed, 66 insertions(+), 46 deletions(-) diff --git a/include/media/stagefright/SkipCutBuffer.h b/include/media/stagefright/SkipCutBuffer.h index 61f9949d8..264c7d616 100644 --- a/include/media/stagefright/SkipCutBuffer.h +++ b/include/media/stagefright/SkipCutBuffer.h @@ -31,8 +31,8 @@ class SkipCutBuffer: public RefBase { public: // 'skip' is the number of frames to skip from the beginning // 'cut' is the number of frames to cut from the end - // 'num16BitChannels' is the number of channels, which are assumed to be 16 bit wide each - SkipCutBuffer(size_t skip, size_t cut, size_t num16Channels); + // 'frameSize' is the frame size for the audio clip + SkipCutBuffer(size_t skip, size_t cut, size_t frameSize); // Submit one MediaBuffer for skipping and cutting. This may consume all or // some of the data in the buffer, or it may add data to it. diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h index 01b3e3f00..6c0769290 100644 --- a/include/media/stagefright/Utils.h +++ b/include/media/stagefright/Utils.h @@ -24,6 +24,7 @@ #include #include #include +#include "MediaDefs.h" namespace android { @@ -64,6 +65,12 @@ void mapAACProfileToAudioFormat(audio_format_t& format, uint64_t eAacProfile); // Send information from MetaData to the HAL via AudioSink status_t sendMetaDataToHal(sp& sink, const sp& meta); +// Get pcm format from audio encoding +audio_format_t getAudioFormat(AudioEncoding encoding); + +// Get bytes per sample from audio encoding +size_t getAudioSampleSize(AudioEncoding encoding); + // Check whether the stream defined by meta can be offloaded to hardware bool canOffloadStream(const sp& meta, bool hasVideo, bool isStreaming, audio_stream_type_t streamType); diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 23eee299a..2e238a801 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -73,6 +73,7 @@ #include "include/avc_utils.h" #include "include/DataConverter.h" #include "omx/OMXUtils.h" +#include #ifdef DOLBY_ENABLE #include "DolbyACodecExtImpl.h" #endif // DOLBY_END @@ -5546,14 +5547,28 @@ void ACodec::sendFormatChange() { if (mime == MEDIA_MIMETYPE_AUDIO_RAW && (mEncoderDelay || mEncoderPadding)) { int32_t channelCount; + AudioEncoding encoding; + int32_t frameSize; + int32_t bytesPerSample; CHECK(mOutputFormat->findInt32("channel-count", &channelCount)); - if (mSkipCutBuffer != NULL) { - size_t prevbufsize = mSkipCutBuffer->size(); - if (prevbufsize != 0) { - ALOGW("Replacing SkipCutBuffer holding %zu bytes", prevbufsize); + CHECK(mOutputFormat->findInt32("pcm-encoding", (int32_t*) &encoding)); + bytesPerSample = getAudioSampleSize(encoding); + + if (channelCount == 0 || + channelCount > INT32_MAX / bytesPerSample) { + ALOGW("# channels out of range: %d, using passthrough instead", + channelCount); + mSkipCutBuffer = NULL; + } else { + frameSize = channelCount * bytesPerSample; + if (mSkipCutBuffer != NULL) { + size_t prevbufsize = mSkipCutBuffer->size(); + if (prevbufsize != 0) { + ALOGW("Replacing SkipCutBuffer holding %zu bytes", prevbufsize); + } } + mSkipCutBuffer = new SkipCutBuffer(mEncoderDelay, mEncoderPadding, frameSize); } - mSkipCutBuffer = new SkipCutBuffer(mEncoderDelay, mEncoderPadding, channelCount); } sp notify = mNotify->dup(); diff --git a/media/libstagefright/DataConverter.cpp b/media/libstagefright/DataConverter.cpp index aef0ad66c..d489b94d3 100644 --- a/media/libstagefright/DataConverter.cpp +++ b/media/libstagefright/DataConverter.cpp @@ -27,6 +27,7 @@ #include #include #include +#include namespace android { @@ -83,39 +84,6 @@ size_t SampleConverterBase::targetSize(size_t sourceSize) { return numSamples * mTargetSampleSize; } -static audio_format_t getAudioFormat(AudioEncoding e) { - audio_format_t format = AUDIO_FORMAT_INVALID; - switch (e) { - case kAudioEncodingPcm16bit: - format = AUDIO_FORMAT_PCM_16_BIT; - break; - case kAudioEncodingPcm8bit: - format = AUDIO_FORMAT_PCM_8_BIT; - break; - case kAudioEncodingPcmFloat: - format = AUDIO_FORMAT_PCM_FLOAT; - break; - case kAudioEncodingPcm24bitPacked: - format = AUDIO_FORMAT_PCM_24_BIT_PACKED; - break; - default: - ALOGE("Invalid AudioEncoding %d", e); - } - return format; -} - -static size_t getAudioSampleSize(AudioEncoding e) { - switch (e) { - case kAudioEncodingPcm16bit: - case kAudioEncodingPcm8bit: - case kAudioEncodingPcmFloat: - case kAudioEncodingPcm24bitPacked: - return audio_bytes_per_sample(getAudioFormat(e)); - default: return 0; - } -} - - // static AudioConverter* AudioConverter::Create(AudioEncoding source, AudioEncoding target) { uint32_t sourceSampleSize = getAudioSampleSize(source); diff --git a/media/libstagefright/SkipCutBuffer.cpp b/media/libstagefright/SkipCutBuffer.cpp index d30be8843..16b4f0db5 100644 --- a/media/libstagefright/SkipCutBuffer.cpp +++ b/media/libstagefright/SkipCutBuffer.cpp @@ -24,18 +24,13 @@ namespace android { -SkipCutBuffer::SkipCutBuffer(size_t skip, size_t cut, size_t num16BitChannels) { +SkipCutBuffer::SkipCutBuffer(size_t skip, size_t cut, size_t frameSize) { mWriteHead = 0; mReadHead = 0; mCapacity = 0; mCutBuffer = NULL; - if (num16BitChannels == 0 || num16BitChannels > INT32_MAX / 2) { - ALOGW("# channels out of range: %zu, using passthrough instead", num16BitChannels); - return; - } - size_t frameSize = num16BitChannels * 2; if (skip > INT32_MAX / frameSize || cut > INT32_MAX / frameSize || cut * frameSize > INT32_MAX - 4096) { ALOGW("out of range skip/cut: %zu/%zu, using passthrough instead", diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index b9a29136b..f0d256c72 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -1583,6 +1583,41 @@ const struct aac_format_conv_t* p = &profileLookup[0]; return; } +audio_format_t getAudioFormat(AudioEncoding encoding) { + audio_format_t format = AUDIO_FORMAT_INVALID; + switch (encoding) { + case kAudioEncodingPcm16bit: + format = AUDIO_FORMAT_PCM_16_BIT; + break; + case kAudioEncodingPcm8bit: + format = AUDIO_FORMAT_PCM_8_BIT; + break; + case kAudioEncodingPcmFloat: + format = AUDIO_FORMAT_PCM_FLOAT; + break; + case kAudioEncodingPcm24bitPacked: + format = AUDIO_FORMAT_PCM_24_BIT_PACKED; + break; + default: + ALOGE("Invalid AudioEncoding %d", encoding); + } + return format; +} + +size_t getAudioSampleSize(AudioEncoding encoding) { + switch (encoding) { + case kAudioEncodingPcm16bit: + case kAudioEncodingPcm8bit: + case kAudioEncodingPcmFloat: + case kAudioEncodingPcm24bitPacked: + return audio_bytes_per_sample(getAudioFormat(encoding)); + default: + ALOGW("%s: Using default bytes per sample", __func__); + return audio_bytes_per_sample( + getAudioFormat(kAudioEncodingPcm16bit)); + } +} + bool canOffloadStream(const sp& meta, bool hasVideo, bool isStreaming, audio_stream_type_t streamType) { From 3db0d3157fc9e2d2db8d24ba3740e1025e370f2f Mon Sep 17 00:00:00 2001 From: Weiyin Jiang Date: Thu, 11 May 2017 16:42:35 +0800 Subject: [PATCH 86/93] audio: resize resampler's inframe buffer independent of out buffer As sample rate of input frame may change dynamically, it is possible that the input frame size requested may grow given the output frame size is fixed. If we don't enlarge the input buffer in this case, array out of boundary occurs and corrupts the heap. Fix is to resize resampler's inframe buffer independent of out buffer. CRs-Fixed: 2044381 Change-Id: I43f70dbb3eaadabc8ed06817a04165feab320b3c --- services/audioflinger/AudioResamplerQTI.cpp | 11 +++++++---- services/audioflinger/AudioResamplerQTI.h | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/services/audioflinger/AudioResamplerQTI.cpp b/services/audioflinger/AudioResamplerQTI.cpp index 0f1d26fa1..ccd9cc7a0 100644 --- a/services/audioflinger/AudioResamplerQTI.cpp +++ b/services/audioflinger/AudioResamplerQTI.cpp @@ -25,7 +25,7 @@ namespace android { AudioResamplerQTI::AudioResamplerQTI(int format, int inChannelCount, int32_t sampleRate) :AudioResampler(inChannelCount, sampleRate, QTI_QUALITY), - mTmpBuf(0), mResamplerOutBuf(0), mFrameIndex(0),mOutFrameCount(0) + mTmpBuf(0), mResamplerOutBuf(0), mFrameIndex(0),mOutFrameCount(0), mInFrameRequest(0) { stateSize = QCT_Resampler::MemAlloc(format, inChannelCount, sampleRate, sampleRate); mState = new int16_t[stateSize]; @@ -67,15 +67,18 @@ size_t AudioResamplerQTI::resample(int32_t* out, size_t outFrameCount, inFrameRequest = inFrameCount * 2; } - if (mOutFrameCount < outFrameCount) { - mOutFrameCount = outFrameCount; + if (mInFrameRequest < inFrameRequest) { + mInFrameRequest = inFrameRequest; if (mTmpBuf) { delete [] mTmpBuf; } + mTmpBuf = new int32_t[inFrameRequest + 16]; + } + if (mOutFrameCount < outFrameCount) { + mOutFrameCount = outFrameCount; if(mResamplerOutBuf) { delete [] mResamplerOutBuf; } - mTmpBuf = new int32_t[inFrameRequest + 16]; mResamplerOutBuf = new int32_t[out_count]; } diff --git a/services/audioflinger/AudioResamplerQTI.h b/services/audioflinger/AudioResamplerQTI.h index 1cf93fc56..3cf46eca2 100644 --- a/services/audioflinger/AudioResamplerQTI.h +++ b/services/audioflinger/AudioResamplerQTI.h @@ -40,6 +40,7 @@ class AudioResamplerQTI : public AudioResampler { size_t mFrameIndex; size_t stateSize; size_t mOutFrameCount; + size_t mInFrameRequest; static const int kNumTmpBufSize = 1024; From 673485181dca307ce13e09e9b2bed59938a997ed Mon Sep 17 00:00:00 2001 From: Anubhav Phukan Date: Mon, 1 May 2017 12:21:19 +0530 Subject: [PATCH 87/93] media: Modify timestamps for HFR use case Timeoffset miscalculation may lead to retrograde timestamps which will raise a error in MPEG4Writer. This change prevents such occurences in HFR by making sure that the successive buffers have a timestamp difference of 33 milliseconds. The previous changes for timestamp manipulation have been reverted. Change-Id: I3faf7294f743b1031ccc6624c3348f7e12b339b8 --- include/media/stagefright/MediaCodecSource.h | 4 ++++ .../libavextensions/stagefright/AVExtensions.h | 3 +++ media/libavextensions/stagefright/AVUtils.cpp | 11 ++++++++++- .../StagefrightRecorder.cpp | 18 +++--------------- media/libstagefright/MediaCodecSource.cpp | 10 +++++++--- 5 files changed, 27 insertions(+), 19 deletions(-) diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h index bd411f7d1..2020bbaa4 100644 --- a/include/media/stagefright/MediaCodecSource.h +++ b/include/media/stagefright/MediaCodecSource.h @@ -147,6 +147,10 @@ struct MediaCodecSource : public MediaSource, int32_t mGeneration; + int64_t mPrevBufferTimestampUs; + bool mIsHFR; + int32_t mBatchSize; + DISALLOW_EVIL_CONSTRUCTORS(MediaCodecSource); }; diff --git a/media/libavextensions/stagefright/AVExtensions.h b/media/libavextensions/stagefright/AVExtensions.h index 9d2c9a0f1..8b8792eec 100644 --- a/media/libavextensions/stagefright/AVExtensions.h +++ b/media/libavextensions/stagefright/AVExtensions.h @@ -35,6 +35,7 @@ #include #include #include +#include #include "ESQueue.h" namespace android { @@ -153,6 +154,8 @@ struct AVUtils { virtual bool isAudioMuxFormatSupported(const char *mime); virtual void cacheCaptureBuffers(sp camera, video_encoder encoder); + virtual void getHFRParams(bool*, int32_t*, sp); + virtual int64_t overwriteTimeOffset(bool, int64_t, int64_t *, int64_t, int32_t); virtual const char *getCustomCodecsLocation(); virtual const char *getCustomCodecsPerformanceLocation(); diff --git a/media/libavextensions/stagefright/AVUtils.cpp b/media/libavextensions/stagefright/AVUtils.cpp index e02657869..b936e0435 100644 --- a/media/libavextensions/stagefright/AVUtils.cpp +++ b/media/libavextensions/stagefright/AVUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 - 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013 - 2017, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -135,6 +135,15 @@ void AVUtils::cacheCaptureBuffers(sp, video_encoder) { return; } +void AVUtils::getHFRParams(bool*, int32_t*, sp) { + return; +} + +int64_t AVUtils::overwriteTimeOffset(bool, int64_t inputBufferTimeOffsetUs, int64_t*, + int64_t, int32_t) { + return inputBufferTimeOffsetUs; +} + const char *AVUtils::getCustomCodecsLocation() { return "/etc/media_codecs.xml"; } diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 2d94db399..bb5e44f92 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -1611,6 +1611,7 @@ status_t StagefrightRecorder::setupVideoEncoder( preferBFrames = false; tsLayers = 2; // use at least two layers as resulting video will likely be sped up } else if (mCaptureFps > maxPlaybackFps) { // slow-mo + format->setInt32("high-frame-rate", 1); maxPlaybackFps = mCaptureFps; // assume video will be played back at full capture speed preferBFrames = false; } @@ -1854,22 +1855,9 @@ status_t StagefrightRecorder::resume() { if (mPauseStartTimeUs < bufferStartTimeUs) { mPauseStartTimeUs = bufferStartTimeUs; } - mTotalPausedDurationUs += (systemTime() / 1000) - mPauseStartTimeUs; - - bool isQCHwAACEnc = property_get_bool("qcom.hw.aac.encoder", true); - if (!isQCHwAACEnc || mAudioEncoder != AUDIO_ENCODER_AAC) { - // 30 ms buffer to avoid timestamp overlap - if (mCaptureFpsEnable) { - if ((systemTime() / 1000) - mPauseStartTimeUs > - (30000 * mFrameRate) / mCaptureFps) { - mTotalPausedDurationUs -= (30000 * mFrameRate) / mCaptureFps; - } - } else { - mTotalPausedDurationUs -= 30000; - } - } + // 30 ms buffer to avoid timestamp overlap + mTotalPausedDurationUs += (systemTime() / 1000) - mPauseStartTimeUs - 30000; } - double timeOffset = -mTotalPausedDurationUs; if (mCaptureFpsEnable) { timeOffset *= mCaptureFps / mFrameRate; diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index 20e1f911d..533e86b96 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -327,7 +327,7 @@ sp MediaCodecSource::Create( uint32_t flags) { sp mediaSource = new MediaCodecSource(looper, format, source, consumer, flags); - + AVUtils::get()->getHFRParams(&mediaSource->mIsHFR, &mediaSource->mBatchSize, format); if (mediaSource->init() == OK) { return mediaSource; } @@ -420,7 +420,10 @@ MediaCodecSource::MediaCodecSource( mFirstSampleSystemTimeUs(-1ll), mPausePending(false), mFirstSampleTimeUs(-1ll), - mGeneration(0) { + mGeneration(0), + mPrevBufferTimestampUs(0), + mIsHFR(false), + mBatchSize(0) { CHECK(mLooper != NULL); AString mime; @@ -683,7 +686,8 @@ status_t MediaCodecSource::feedEncoderInputBuffers() { return OK; } } - + mInputBufferTimeOffsetUs = AVUtils::get()->overwriteTimeOffset(mIsHFR, + mInputBufferTimeOffsetUs, &mPrevBufferTimestampUs, timeUs, mBatchSize); timeUs += mInputBufferTimeOffsetUs; // push decoding time for video, or drift time for audio From ce5f5fab650d6584edbae21bb403031029962832 Mon Sep 17 00:00:00 2001 From: Sai Kumar Sanagavarapu Date: Wed, 21 Jun 2017 12:57:08 +0530 Subject: [PATCH 88/93] Camera: Skip stream size check for whitelisted apps. Issue: For quadracfa capture, Blob/YUV output streams need to be configured with custom dimensions which will not be available in advertised stream configurations map. Fix: Skip the stream size check for whitelisted apps to allow configuration of streams with custom dimensions. Setprop to be used: adb shell setprop persist.camera.cfa.packagelist CRs-Fixed: 2075934 Change-Id: Id94b40c94f42bf4579dc6d8bb6273003312ea669 --- .../libcameraservice/api2/CameraDeviceClient.cpp | 12 ++++++++++-- .../libcameraservice/api2/CameraDeviceClient.h | 1 + .../libcameraservice/device3/Camera3Device.cpp | 3 --- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp index a7fe5e732..9ed2ca50c 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp @@ -76,7 +76,15 @@ CameraDeviceClient::CameraDeviceClient(const sp& cameraService, cameraId, cameraFacing, clientPid, clientUid, servicePid), mInputStream(), mStreamingRequestId(REQUEST_ID_NONE), - mRequestIdCounter(0) { + mRequestIdCounter(0), + mPrivilegedClient(false) { + + char value[PROPERTY_VALUE_MAX]; + property_get("persist.camera.cfa.packagelist", value, ""); + String16 packagelist(value); + if (packagelist.contains(clientPackageName.string())) { + mPrivilegedClient = true; + } ATRACE_CALL(); ALOGI("CameraDeviceClient %d: Opened", cameraId); @@ -487,7 +495,7 @@ binder::Status CameraDeviceClient::createStream( int32_t allowedFlags = GraphicBuffer::USAGE_SW_READ_MASK | GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_HW_COMPOSER; - bool flexibleConsumer = (consumerUsage & disallowedFlags) == 0 && + bool flexibleConsumer = !mPrivilegedClient && (consumerUsage & disallowedFlags) == 0 && (consumerUsage & allowedFlags) != 0; sp binder = IInterface::asBinder(bufferProducer); diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h index dde23fb9d..764938ed8 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.h +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h @@ -225,6 +225,7 @@ class CameraDeviceClient : static const int32_t REQUEST_ID_NONE = -1; int32_t mRequestIdCounter; + bool mPrivilegedClient; // The list of output streams whose surfaces are deferred. We have to track them separately // as there are no surfaces available and can not be put into mStreamMap. Once the deferred diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index eece01b46..c324ac6f5 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -471,9 +471,6 @@ ssize_t Camera3Device::getJpegBufferSize(uint32_t width, uint32_t height) const (maxJpegResolution.width * maxJpegResolution.height); ssize_t jpegBufferSize = scaleFactor * (maxJpegBufferSize - kMinJpegBufferSize) + kMinJpegBufferSize; - if (jpegBufferSize > maxJpegBufferSize) { - jpegBufferSize = maxJpegBufferSize; - } return jpegBufferSize; } From 8b91300f1d5eabb355774448a86c9acbea7bd022 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 27 Mar 2017 15:04:25 -0700 Subject: [PATCH 89/93] Don't allow using or allocating a buffer after the first state transition Bug: 35467458 Change-Id: Ia76c8cec8ad2abb95ca29b2a89075f7acab4b174 (cherry picked from commit e25320450ca414dd859fd5d80bcd18ecc91630de) (cherry picked from commit 07954224344fc938f157b3a2af9682690831e234) --- media/libstagefright/omx/OMXNodeInstance.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index a692d095f..cc003c573 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -796,6 +796,12 @@ status_t OMXNodeInstance::useBuffer( return BAD_VALUE; } + if (!mSailed) { + ALOGE("b/35467458"); + android_errorWriteLog(0x534e4554, "35467458"); + return BAD_VALUE; + } + // metadata buffers are not connected cross process // use a backup buffer instead of the actual buffer BufferMeta *buffer_meta; @@ -1227,6 +1233,12 @@ status_t OMXNodeInstance::allocateSecureBuffer( Mutex::Autolock autoLock(mLock); + if (!mSailed) { + ALOGE("b/35467458"); + android_errorWriteLog(0x534e4554, "35467458"); + return BAD_VALUE; + } + BufferMeta *buffer_meta = new BufferMeta(size, portIndex); OMX_BUFFERHEADERTYPE *header; @@ -1282,6 +1294,12 @@ status_t OMXNodeInstance::allocateBufferWithBackup( return BAD_VALUE; } + if (!mSailed) { + ALOGE("b/35467458"); + android_errorWriteLog(0x534e4554, "35467458"); + return BAD_VALUE; + } + // metadata buffers are not connected cross process; only copy if not meta bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid; From c0008c69186d100b10fe63308ecd48e4b951631d Mon Sep 17 00:00:00 2001 From: Ray Essick Date: Wed, 10 May 2017 15:38:51 -0700 Subject: [PATCH 90/93] Prevent OOB write in soft_avc encoder Soft avc encoder cached buffer sizes across a point where the sizes could be reset by an app, allowing crafted requests to hit outside of the current buffer. This remedies that by forcing buffer reallocation with new sizes whenever the encoder state at such 'reset' points. Bug: 35421151 Test: run POC with no crash Change-Id: I8c689846142264f7b6a277332260a6bd8a2bd92d (cherry picked from commit 463452a94907278ca5e4c5632e50bbe59e861544) (cherry picked from commit 5eb118f8299129e323fa402e0605abe696bdc678) --- media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp | 12 ++++++++++++ media/libstagefright/codecs/avcenc/SoftAVCEnc.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp index 9e7a3be15..5b06722fb 100644 --- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp +++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp @@ -614,6 +614,7 @@ OMX_ERRORTYPE SoftAVC::initEncoder() { IV_STATUS_T status; WORD32 level; uint32_t displaySizeY; + CHECK(!mStarted); OMX_ERRORTYPE errType = OMX_ErrorNone; @@ -917,6 +918,9 @@ OMX_ERRORTYPE SoftAVC::releaseEncoder() { } } + // clear other pointers into the space being free()d + mCodecCtx = NULL; + mStarted = false; return OMX_ErrorNone; @@ -1509,6 +1513,14 @@ void SoftAVC::onQueueFilled(OMX_U32 portIndex) { return; } +void SoftAVC::onReset() { + SoftVideoEncoderOMXComponent::onReset(); + + if (releaseEncoder() != OMX_ErrorNone) { + ALOGW("releaseEncoder failed"); + } +} + } // namespace android android::SoftOMXComponent *createSoftOMXComponent( diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.h b/media/libstagefright/codecs/avcenc/SoftAVCEnc.h index cf6f899af..8b24b629e 100644 --- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.h +++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.h @@ -136,6 +136,8 @@ struct SoftAVC : public SoftVideoEncoderOMXComponent { protected: virtual ~SoftAVC(); + virtual void onReset(); + private: enum { kNumBuffers = 2, From b352d00822fc2f046683fc4169713444060ea5c3 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 12 May 2017 15:35:30 -0700 Subject: [PATCH 91/93] Limit ogg packet size A malformed ogg file might lace together a very large packet, which could lead to out of memory conditions. Limit the packet size to avoid this. Bug: 36592202 Change-Id: I8650b3ec54a0de9ec302a7cbac296bb85efcfb3d (cherry picked from commit bf928560aca13c5a615cb3ffc3b6aad16cdf3824) (cherry picked from commit 4efebc8b90d2c6c98d67c9dc0348a713c2a0700f) --- media/libstagefright/OggExtractor.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp index 37e8e9c82..ebbe5102e 100644 --- a/media/libstagefright/OggExtractor.cpp +++ b/media/libstagefright/OggExtractor.cpp @@ -697,7 +697,21 @@ status_t MyOggExtractor::_readNextPacket(MediaBuffer **out, bool calcVorbisTimes if (buffer != NULL) { fullSize += buffer->range_length(); } - MediaBuffer *tmp = new MediaBuffer(fullSize); + if (fullSize > 16 * 1024 * 1024) { // arbitrary limit of 16 MB packet size + if (buffer != NULL) { + buffer->release(); + } + ALOGE("b/36592202"); + return ERROR_MALFORMED; + } + MediaBuffer *tmp = new (std::nothrow) MediaBuffer(fullSize); + if (tmp == NULL) { + if (buffer != NULL) { + buffer->release(); + } + ALOGE("b/36592202"); + return ERROR_MALFORMED; + } if (buffer != NULL) { memcpy(tmp->data(), buffer->data(), buffer->range_length()); tmp->set_range(0, buffer->range_length()); From cb21e81df2cc75416ef1b00a0e2136515ce2b64f Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 12 May 2017 10:45:14 -0700 Subject: [PATCH 92/93] Fix memory leak in error case Bug: 37239013 Change-Id: Ic33e0f7ed946d0729efa46f69aff1a5d35e81b1e (cherry picked from commit ab34612a31e82b713ca0ac043e14f68f3788fbda) (cherry picked from commit 4cd260f382f51b309be9aa48725cc709f5b034f2) --- media/libstagefright/MPEG4Extractor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index bbcf7419a..4dd354d05 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -1272,6 +1272,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { ALOGV("allocated pssh @ %p", pssh.data); ssize_t requested = (ssize_t) pssh.datalen; if (mDataSource->readAt(data_offset + 24, pssh.data, requested) < requested) { + delete[] pssh.data; return ERROR_IO; } mPssh.push_back(pssh); From a31514f18d8a6f2b9f99ba77d1bbf93b9949620a Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 15 May 2017 15:40:14 -0700 Subject: [PATCH 93/93] Modifying MetaData invalidates previous char* so don't use those char* after having updated the MetaData Bug: 36576151 Change-Id: I1430f3151cb929e436fbdac566cf91fc4164b934 (cherry picked from commit 423e74647d1b8fd8b2905356af1fc2b1c67a0f3f) (cherry picked from commit a520c5d445b7cb6ac4c2a09b86d2e860710a32ae) --- media/libstagefright/MPEG4Extractor.cpp | 32 ++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 4dd354d05..4f5e5c5b7 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -507,6 +507,22 @@ sp MPEG4Extractor::getTrackMetaData( const char *mime; CHECK(track->meta->findCString(kKeyMIMEType, &mime)); if (!strncasecmp("video/", mime, 6)) { + // MPEG2 tracks do not provide CSD, so read the stream header + if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG2)) { + off64_t offset; + size_t size; + if (track->sampleTable->getMetaDataForSample( + 0 /* sampleIndex */, &offset, &size, NULL /* sampleTime */) == OK) { + if (size > kMaxTrackHeaderSize) { + size = kMaxTrackHeaderSize; + } + uint8_t header[kMaxTrackHeaderSize]; + if (mDataSource->readAt(offset, &header, size) == (ssize_t)size) { + track->meta->setData(kKeyStreamHeader, 'mdat', header, size); + } + } + } + if (mMoofOffset > 0) { int64_t duration; if (track->meta->findInt64(kKeyDuration, &duration)) { @@ -527,22 +543,6 @@ sp MPEG4Extractor::getTrackMetaData( ((int64_t)sampleTime * 1000000) / track->timescale); } } - - // MPEG2 tracks do not provide CSD, so read the stream header - if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG2)) { - off64_t offset; - size_t size; - if (track->sampleTable->getMetaDataForSample( - 0 /* sampleIndex */, &offset, &size, NULL /* sampleTime */) == OK) { - if (size > kMaxTrackHeaderSize) { - size = kMaxTrackHeaderSize; - } - uint8_t header[kMaxTrackHeaderSize]; - if (mDataSource->readAt(offset, &header, size) == (ssize_t)size) { - track->meta->setData(kKeyStreamHeader, 'mdat', header, size); - } - } - } } }