Merge "fix warning: dereference of a null pointer"
am: 9a6b9ed394
Change-Id: I8f944dd30a2663262baa00a08c1e4204a29242eb
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index 68e73f2..2d291a8 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -87,7 +87,7 @@
// establish binder interface to camera service
template <typename TCam, typename TCamTraits>
-const sp<::android::hardware::ICameraService>& CameraBase<TCam, TCamTraits>::getCameraService()
+const sp<::android::hardware::ICameraService> CameraBase<TCam, TCamTraits>::getCameraService()
{
Mutex::Autolock _l(gLock);
if (gCameraService.get() == 0) {
@@ -125,7 +125,7 @@
ALOGV("%s: connect", __FUNCTION__);
sp<TCam> c = new TCam(cameraId);
sp<TCamCallbacks> cl = c;
- const sp<::android::hardware::ICameraService>& cs = getCameraService();
+ const sp<::android::hardware::ICameraService> cs = getCameraService();
binder::Status ret;
if (cs != nullptr) {
@@ -233,7 +233,7 @@
template <typename TCam, typename TCamTraits>
status_t CameraBase<TCam, TCamTraits>::getCameraInfo(int cameraId,
struct hardware::CameraInfo* cameraInfo) {
- const sp<::android::hardware::ICameraService>& cs = getCameraService();
+ const sp<::android::hardware::ICameraService> cs = getCameraService();
if (cs == 0) return UNKNOWN_ERROR;
binder::Status res = cs->getCameraInfo(cameraId, cameraInfo);
return res.isOk() ? OK : res.serviceSpecificErrorCode();
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
index 86bf047..8356bcc 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
@@ -75,6 +75,8 @@
}
status_t res = session->provideKeyResponse(response);
if (res == android::OK) {
+ // This is for testing AMediaDrm_setOnEventListener only.
+ sendEvent(kDrmPluginEventVendorDefined, 0, &scope, NULL);
keySetId.clear();
}
return res;
@@ -90,6 +92,8 @@
value = "ClearKey CDM";
} else if (name == "algorithms") {
value = "";
+ } else if (name == "listenerTestSupport") {
+ value = "true";
} else {
ALOGE("App requested unknown string property %s", name.string());
return android::ERROR_DRM_CANNOT_HANDLE;
diff --git a/include/camera/CameraBase.h b/include/camera/CameraBase.h
index 0692a27..41f8621 100644
--- a/include/camera/CameraBase.h
+++ b/include/camera/CameraBase.h
@@ -115,7 +115,7 @@
virtual void binderDied(const wp<IBinder>& who);
// helper function to obtain camera service handle
- static const sp<::android::hardware::ICameraService>& getCameraService();
+ static const sp<::android::hardware::ICameraService> getCameraService();
sp<TCamUser> mCamera;
status_t mStatus;
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
index 8fc410d..2ec89a4 100644
--- a/include/media/stagefright/AudioSource.h
+++ b/include/media/stagefright/AudioSource.h
@@ -87,7 +87,6 @@
int64_t mStartTimeUs;
int16_t mMaxAmplitude;
int64_t mPrevSampleTimeUs;
- int64_t mFirstSampleTimeUs;
int64_t mInitialReadTimeUs;
int64_t mNumFramesReceived;
int64_t mNumClientOwnedBuffers;
diff --git a/include/media/stagefright/SimpleDecodingSource.h b/include/media/stagefright/SimpleDecodingSource.h
index 534097b..e6aee6a 100644
--- a/include/media/stagefright/SimpleDecodingSource.h
+++ b/include/media/stagefright/SimpleDecodingSource.h
@@ -71,12 +71,13 @@
// Construct this using a codec, source and looper.
SimpleDecodingSource(
const sp<MediaCodec> &codec, const sp<IMediaSource> &source, const sp<ALooper> &looper,
- bool usingSurface, const sp<AMessage> &format);
+ bool usingSurface, bool isVorbis, const sp<AMessage> &format);
sp<MediaCodec> mCodec;
sp<IMediaSource> mSource;
sp<ALooper> mLooper;
bool mUsingSurface;
+ bool mIsVorbis;
enum State {
INIT,
STARTED,
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index ff5903d..a80c891 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -1274,6 +1274,9 @@
return true;
}
}
+ if (exitPending()) {
+ return false;
+ }
nsecs_t ns = mReceiver.processAudioBuffer();
switch (ns) {
case 0:
diff --git a/media/libaudioclient/IEffect.cpp b/media/libaudioclient/IEffect.cpp
index 115ca75..ce72dae 100644
--- a/media/libaudioclient/IEffect.cpp
+++ b/media/libaudioclient/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 @@
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 @@
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/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 80f783d..c380bdc 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -1465,17 +1465,25 @@
// horizontal plane, +90 is directly above the user, -90 below
//
//----------------------------------------------------------------------------
-void VirtualizerGetSpeakerAngles(audio_channel_mask_t channelMask __unused,
+void VirtualizerGetSpeakerAngles(audio_channel_mask_t channelMask,
audio_devices_t deviceType __unused, int32_t *pSpeakerAngles) {
// the channel count is guaranteed to be 1 or 2
// the device is guaranteed to be of type headphone
- // this virtualizer is always 2in with speakers at -90 and 90deg of azimuth, 0deg of elevation
- *pSpeakerAngles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_LEFT;
- *pSpeakerAngles++ = -90; // azimuth
- *pSpeakerAngles++ = 0; // elevation
- *pSpeakerAngles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_RIGHT;
- *pSpeakerAngles++ = 90; // azimuth
- *pSpeakerAngles = 0; // elevation
+ // this virtualizer is always using 2 virtual speakers at -90 and 90deg of azimuth, 0deg of
+ // elevation but the return information is sized for nbChannels * 3, so we have to consider
+ // the (false here) case of a single channel, and return only 3 fields.
+ if (audio_channel_count_from_out_mask(channelMask) == 1) {
+ *pSpeakerAngles++ = (int32_t) AUDIO_CHANNEL_OUT_MONO; // same as FRONT_LEFT
+ *pSpeakerAngles++ = 0; // azimuth
+ *pSpeakerAngles = 0; // elevation
+ } else {
+ *pSpeakerAngles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_LEFT;
+ *pSpeakerAngles++ = -90; // azimuth
+ *pSpeakerAngles++ = 0; // elevation
+ *pSpeakerAngles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_RIGHT;
+ *pSpeakerAngles++ = 90; // azimuth
+ *pSpeakerAngles = 0; // elevation
+ }
}
//----------------------------------------------------------------------------
@@ -2357,8 +2365,12 @@
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 +2380,12 @@
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 +2395,12 @@
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));
@@ -2407,9 +2427,13 @@
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 +2503,12 @@
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);
@@ -3097,10 +3125,6 @@
//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 ||
@@ -3108,13 +3132,32 @@
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/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 0eaa3dc..6a126ef 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -61,6 +61,8 @@
#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
@@ -523,18 +525,29 @@
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);
@@ -573,10 +586,18 @@
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) {
diff --git a/media/libmedia/IHDCP.cpp b/media/libmedia/IHDCP.cpp
index 21e35f6..15ed579 100644
--- a/media/libmedia/IHDCP.cpp
+++ b/media/libmedia/IHDCP.cpp
@@ -241,14 +241,11 @@
case HDCP_ENCRYPT:
{
size_t size = data.readInt32();
- size_t bufSize = 2 * size;
-
- // watch out for overflow
void *inData = NULL;
- if (bufSize > size) {
- inData = malloc(bufSize);
+ // watch out for overflow
+ if (size <= SIZE_MAX / 2) {
+ inData = malloc(2 * size);
}
-
if (inData == NULL) {
reply->writeInt32(ERROR_OUT_OF_RANGE);
return OK;
@@ -256,11 +253,16 @@
void *outData = (uint8_t *)inData + size;
- data.read(inData, size);
+ status_t err = data.read(inData, size);
+ if (err != OK) {
+ free(inData);
+ reply->writeInt32(err);
+ return OK;
+ }
uint32_t streamCTR = data.readInt32();
uint64_t inputCTR;
- status_t err = encrypt(inData, size, streamCTR, &inputCTR, outData);
+ err = encrypt(inData, size, streamCTR, &inputCTR, outData);
reply->writeInt32(err);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index d011d70..609b00d 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -368,10 +368,21 @@
mRecorder->setListener(listener);
sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.camera"));
- mCameraDeathListener = new ServiceDeathNotifier(binder, listener,
- MediaPlayerService::CAMERA_PROCESS_DEATH);
- binder->linkToDeath(mCameraDeathListener);
+
+ // WORKAROUND: We don't know if camera exists here and getService might block for 5 seconds.
+ // Use checkService for camera if we don't know it exists.
+ static std::atomic<bool> sCameraChecked(false); // once true never becomes false.
+ static std::atomic<bool> sCameraVerified(false); // once true never becomes false.
+ sp<IBinder> binder = (sCameraVerified || !sCameraChecked)
+ ? sm->getService(String16("media.camera")) : sm->checkService(String16("media.camera"));
+ // If the device does not have a camera, do not create a death listener for it.
+ if (binder != NULL) {
+ sCameraVerified = true;
+ mCameraDeathListener = new ServiceDeathNotifier(binder, listener,
+ MediaPlayerService::CAMERA_PROCESS_DEATH);
+ binder->linkToDeath(mCameraDeathListener);
+ }
+ sCameraChecked = true;
binder = sm->getService(String16("media.codec"));
mCodecDeathListener = new ServiceDeathNotifier(binder, listener,
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index cf38efc..594128c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -754,7 +754,7 @@
status_t NuPlayer::Decoder::fetchInputData(sp<AMessage> &reply) {
sp<ABuffer> accessUnit;
- bool dropAccessUnit;
+ bool dropAccessUnit = true;
do {
status_t err = mSource->dequeueAccessUnit(mIsAudio, &accessUnit);
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 790c6da..efdee77 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -60,7 +60,6 @@
mStartTimeUs(0),
mMaxAmplitude(0),
mPrevSampleTimeUs(0),
- mFirstSampleTimeUs(-1ll),
mInitialReadTimeUs(0),
mNumFramesReceived(0),
mNumClientOwnedBuffers(0) {
@@ -277,12 +276,8 @@
}
if (mSampleRate != mOutSampleRate) {
- if (mFirstSampleTimeUs < 0) {
- mFirstSampleTimeUs = timeUs;
- }
- timeUs = mFirstSampleTimeUs + (timeUs - mFirstSampleTimeUs)
- * (int64_t)mSampleRate / (int64_t)mOutSampleRate;
- buffer->meta_data()->setInt64(kKeyTime, timeUs);
+ timeUs *= (int64_t)mSampleRate / (int64_t)mOutSampleRate;
+ buffer->meta_data()->setInt64(kKeyTime, timeUs);
}
*out = buffer;
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 8061bc6..5ce2b76 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -522,8 +522,6 @@
return ERROR_MALFORMED;
}
- mSyncSampleOffset = data_offset;
-
uint8_t header[8];
if (mDataSource->readAt(
data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
@@ -535,13 +533,13 @@
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;
@@ -559,19 +557,21 @@
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) {
if (mSyncSamples[i] == 0) {
ALOGE("b/32423862, unexpected zero value in stss");
continue;
@@ -579,6 +579,9 @@
mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
}
+ mSyncSampleOffset = data_offset;
+ mNumSyncSamples = numSyncSamples;
+
return OK;
}
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index de21c5e..2503a32 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -18,6 +18,7 @@
#include <media/ICrypto.h>
#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
@@ -74,7 +75,10 @@
err = codec->getOutputFormat(&format);
}
if (err == OK) {
- return new SimpleDecodingSource(codec, source, looper, surface != NULL, format);
+ return new SimpleDecodingSource(codec, source, looper,
+ surface != NULL,
+ strcmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS) == 0,
+ format);
}
ALOGD("Failed to configure codec '%s'", componentName.c_str());
@@ -90,11 +94,12 @@
SimpleDecodingSource::SimpleDecodingSource(
const sp<MediaCodec> &codec, const sp<IMediaSource> &source, const sp<ALooper> &looper,
- bool usingSurface, const sp<AMessage> &format)
+ bool usingSurface, bool isVorbis, const sp<AMessage> &format)
: mCodec(codec),
mSource(source),
mLooper(looper),
mUsingSurface(usingSurface),
+ mIsVorbis(isVorbis),
mProtectedState(format) {
mCodec->getName(&mComponentName);
}
@@ -280,16 +285,25 @@
if (in_buf != NULL) {
int64_t timestampUs = 0;
CHECK(in_buf->meta_data()->findInt64(kKeyTime, ×tampUs));
- if (in_buf->range_length() > in_buffer->capacity()) {
+ if (in_buf->range_length() + (mIsVorbis ? 4 : 0) > in_buffer->capacity()) {
ALOGW("'%s' received %zu input bytes for buffer of size %zu",
mComponentName.c_str(),
- in_buf->range_length(), in_buffer->capacity());
+ in_buf->range_length() + (mIsVorbis ? 4 : 0), in_buffer->capacity());
}
+ size_t cpLen = min(in_buf->range_length(), in_buffer->capacity());
memcpy(in_buffer->base(), (uint8_t *)in_buf->data() + in_buf->range_offset(),
- min(in_buf->range_length(), in_buffer->capacity()));
+ cpLen );
+
+ if (mIsVorbis) {
+ int32_t numPageSamples;
+ if (!in_buf->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
+ numPageSamples = -1;
+ }
+ memcpy(in_buffer->base() + cpLen, &numPageSamples, sizeof(numPageSamples));
+ }
res = mCodec->queueInputBuffer(
- in_ix, 0 /* offset */, in_buf->range_length(),
+ in_ix, 0 /* offset */, in_buf->range_length() + (mIsVorbis ? 4 : 0),
timestampUs, 0 /* flags */);
if (res != OK) {
ALOGI("[%s] failed to queue input buffer #%zu", mComponentName.c_str(), in_ix);
diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp
index 58f2c60..5b8f23a 100644
--- a/media/libstagefright/VBRISeeker.cpp
+++ b/media/libstagefright/VBRISeeker.cpp
@@ -83,8 +83,23 @@
scale,
entrySize);
+ if (entrySize > 4) {
+ ALOGE("invalid VBRI entry size: %zu", entrySize);
+ return NULL;
+ }
+
+ sp<VBRISeeker> 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 @@
return NULL;
}
- sp<VBRISeeker> 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()
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index d1b2f54..1c170b8 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -42,13 +42,9 @@
namespace android {
-static Mutex gWVMutex;
-
WVMExtractor::WVMExtractor(const sp<DataSource> &source)
: mDataSource(source)
{
- Mutex::Autolock autoLock(gWVMutex);
-
if (!getVendorLibHandle()) {
return;
}
@@ -169,8 +165,6 @@
const sp<DataSource> &source, String8 *mimeType, float *confidence,
sp<AMessage> *) {
- Mutex::Autolock autoLock(gWVMutex);
-
if (!WVMExtractor::getVendorLibHandle()) {
return false;
}
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index 0396dc6..763381e 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -456,7 +456,10 @@
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;
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp
index ab0a228..96bbb85 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp
@@ -62,8 +62,7 @@
}
SoftAACEncoder::~SoftAACEncoder() {
- delete[] mInputFrame;
- mInputFrame = NULL;
+ onReset();
if (mEncoderHandle) {
CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
@@ -579,6 +578,17 @@
}
}
+void SoftAACEncoder::onReset() {
+ delete[] mInputFrame;
+ mInputFrame = NULL;
+ mInputSize = 0;
+
+ mSentCodecSpecificData = false;
+ mInputTimeUs = -1ll;
+ mSawInputEOS = false;
+ mSignalledError = false;
+}
+
} // namespace android
android::SoftOMXComponent *createSoftOMXComponent(
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
index d148eb7..981cbbb 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
@@ -43,6 +43,8 @@
virtual void onQueueFilled(OMX_U32 portIndex);
+ virtual void onReset();
+
private:
enum {
kNumBuffers = 4,
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
index 63215ec..5f516cb 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -72,8 +72,7 @@
SoftAACEncoder2::~SoftAACEncoder2() {
aacEncClose(&mAACEncoder);
- delete[] mInputFrame;
- mInputFrame = NULL;
+ onReset();
}
void SoftAACEncoder2::initPorts() {
@@ -703,6 +702,17 @@
}
}
+void SoftAACEncoder2::onReset() {
+ delete[] mInputFrame;
+ mInputFrame = NULL;
+ mInputSize = 0;
+
+ mSentCodecSpecificData = false;
+ mInputTimeUs = -1ll;
+ mSawInputEOS = false;
+ mSignalledError = false;
+}
+
} // namespace android
android::SoftOMXComponent *createSoftOMXComponent(
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
index bce9c24..f1b81e1 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
@@ -42,6 +42,8 @@
virtual void onQueueFilled(OMX_U32 portIndex);
+ virtual void onReset();
+
private:
enum {
kNumBuffers = 4,
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
index f496b0c..d5a26d3 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
@@ -99,6 +99,7 @@
SoftMPEG4Encoder::~SoftMPEG4Encoder() {
ALOGV("Destruct SoftMPEG4Encoder");
+ onReset();
releaseEncoder();
List<BufferInfo *> &outQueue = getPortQueue(1);
List<BufferInfo *> &inQueue = getPortQueue(0);
@@ -201,22 +202,15 @@
}
OMX_ERRORTYPE SoftMPEG4Encoder::releaseEncoder() {
- if (!mStarted) {
- return OMX_ErrorNone;
+ if (mEncParams) {
+ delete mEncParams;
+ mEncParams = NULL;
}
- PVCleanUpVideoEncoder(mHandle);
-
- free(mInputFrameData);
- mInputFrameData = NULL;
-
- delete mEncParams;
- mEncParams = NULL;
-
- delete mHandle;
- mHandle = NULL;
-
- mStarted = false;
+ if (mHandle) {
+ delete mHandle;
+ mHandle = NULL;
+ }
return OMX_ErrorNone;
}
@@ -514,6 +508,19 @@
}
}
+void SoftMPEG4Encoder::onReset() {
+ if (!mStarted) {
+ return;
+ }
+
+ PVCleanUpVideoEncoder(mHandle);
+
+ free(mInputFrameData);
+ mInputFrameData = NULL;
+
+ mStarted = false;
+}
+
} // namespace android
android::SoftOMXComponent *createSoftOMXComponent(
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
index bb6ea92..ae8cb6f 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
@@ -48,6 +48,8 @@
virtual void onQueueFilled(OMX_U32 portIndex);
+ virtual void onReset();
+
protected:
virtual ~SoftMPEG4Encoder();
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 337bff0..adb0dd4 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 @@
+ __attribute__((no_sanitize("integer")))
__inline int32 pv_abs(int32 a)
{
int32 b = (a < 0) ? -a : a;
@@ -59,49 +60,58 @@
+ __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 9b9ae4b..cc99d5c 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 @@
; FUNCTION CODE
----------------------------------------------------------------------------*/
+__attribute__((no_sanitize("integer")))
void pvmp3_dct_16(int32 vec[], int32 flag)
{
int32 tmp0;
@@ -308,6 +309,7 @@
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
+__attribute__((no_sanitize("integer")))
void pvmp3_merge_in_place_N32(int32 vec[])
{
@@ -366,6 +368,7 @@
+__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 d30ce4a..bbb247d 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 @@
; 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 09a735b..324290e 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 @@
+__attribute__((no_sanitize("integer")))
void pvmp3_mdct_18(int32 vec[], int32 *history, const int32 *window)
{
int32 i;
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
index 5edfbb5..56e1f77 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
@@ -793,7 +793,9 @@
if (inputBufferHeader->nTimeStamp > mLastTimestamp) {
frameDuration = (uint32_t)(inputBufferHeader->nTimeStamp - mLastTimestamp);
} else {
- frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate);
+ // Use default of 30 fps in case of 0 frame rate.
+ uint32_t framerate = mFramerate ?: (30 << 16);
+ frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / framerate);
}
mLastTimestamp = inputBufferHeader->nTimeStamp;
codec_return = vpx_codec_encode(
@@ -847,6 +849,11 @@
}
}
+void SoftVPXEncoder::onReset() {
+ releaseEncoder();
+ mLastTimestamp = 0x7FFFFFFFFFFFFFFFLL;
+}
+
} // namespace android
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
index cd0a0cf..2033e64 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
@@ -87,6 +87,8 @@
// encoding of the frame
virtual void onQueueFilled(OMX_U32 portIndex);
+ virtual void onReset();
+
private:
enum TemporalReferences {
// For 1 layer case: reference all (last, golden, and alt ref), but only
diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
index 54f768a..8e4d064 100644
--- a/media/libstagefright/foundation/MediaBufferGroup.cpp
+++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
@@ -39,6 +39,12 @@
MediaBufferGroup::MediaBufferGroup(size_t buffers, size_t buffer_size, size_t growthLimit)
: mGrowthLimit(growthLimit) {
+ if (mGrowthLimit > 0 && buffers > mGrowthLimit) {
+ ALOGW("Preallocated buffers %zu > growthLimit %zu, increasing growthLimit",
+ buffers, mGrowthLimit);
+ mGrowthLimit = buffers;
+ }
+
if (buffer_size >= kSharedMemoryThreshold) {
ALOGD("creating MemoryDealer");
// Using a single MemoryDealer is efficient for a group of shared memory objects.
@@ -102,9 +108,22 @@
void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
Mutex::Autolock autoLock(mLock);
+ // if we're above our growth limit, release buffers if we can
+ for (auto it = mBuffers.begin();
+ mGrowthLimit > 0
+ && mBuffers.size() >= mGrowthLimit
+ && it != mBuffers.end();) {
+ if ((*it)->refcount() == 0) {
+ (*it)->setObserver(nullptr);
+ (*it)->release();
+ it = mBuffers.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
buffer->setObserver(this);
mBuffers.emplace_back(buffer);
- // optionally: mGrowthLimit = max(mGrowthLimit, mBuffers.size());
}
bool MediaBufferGroup::has_buffers() {
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index aaf6b3d..a0eb630 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -839,20 +839,21 @@
}
}
-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 *
@@ -873,11 +874,19 @@
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();
@@ -885,20 +894,30 @@
}
#endif
- size_t descLen = StringSize(&data[2 + mimeLen], encoding);
-
- if (size < 2 ||
- size - 2 < mimeLen ||
- size - 2 - mimeLen < descLen) {
- ALOGW("bogus album art sizes");
+ consumed++;
+ if (consumed >= size) {
+ ALOGW("bogus album art size: pic type");
return NULL;
}
- *length = size - 2 - mimeLen - descLen;
- return &data[2 + mimeLen + descLen];
+ size_t descLen = StringSize(&data[consumed], size - consumed, encoding);
+ consumed += descLen;
+
+ if (consumed >= size) {
+ ALOGW("bogus album art size: description");
+ return NULL;
+ }
+
+ *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)) {
@@ -918,7 +937,10 @@
}
#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;
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 1d819b5..267f24d 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -792,7 +792,8 @@
if (mPrevCaptureUs < 0ll) {
// first capture
mPrevCaptureUs = timeUs;
- mPrevFrameUs = timeUs;
+ // adjust the first sample timestamp.
+ mPrevFrameUs = (timeUs * mTimePerFrameUs) / mTimePerCaptureUs;
} else {
// snap to nearest capture point
int64_t nFrames = (timeUs + mTimePerCaptureUs / 2 - mPrevCaptureUs)
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 8c10310..355a2dd 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -805,13 +805,6 @@
}
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 {
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 0ddee86..40f4cea 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -16,18 +16,39 @@
#define LOG_TAG "MtpDataPacket"
+#include "MtpDataPacket.h"
+
+#include <algorithm>
+#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
-#include <fcntl.h>
-
#include <usbhost/usbhost.h>
-
-#include "MtpDataPacket.h"
#include "MtpStringBuffer.h"
#include "IMtpHandle.h"
namespace android {
+namespace {
+// Reads the exact |count| bytes from |fd| to |buf|.
+// Returns |count| if it succeed to read the bytes. Otherwise returns -1. If it reaches EOF, the
+// function regards it as an error.
+ssize_t readExactBytes(int fd, void* buf, size_t count) {
+ if (count > SSIZE_MAX) {
+ return -1;
+ }
+ size_t read_count = 0;
+ while (read_count < count) {
+ int result = read(fd, static_cast<int8_t*>(buf) + read_count, count - read_count);
+ // Assume that EOF is error.
+ if (result <= 0) {
+ return -1;
+ }
+ read_count += result;
+ }
+ return read_count == count ? count : -1;
+}
+} // namespace
+
MtpDataPacket::MtpDataPacket()
: MtpPacket(MTP_BUFFER_SIZE), // MAX_USBFS_BUFFER_SIZE
mOffset(MTP_CONTAINER_HEADER_SIZE)
@@ -512,29 +533,104 @@
return length;
}
-int MtpDataPacket::writeDataHeader(struct usb_request *request, uint32_t length) {
- MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length);
- MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
- request->buffer = mBuffer;
- request->buffer_length = MTP_CONTAINER_HEADER_SIZE;
- int ret = transfer(request);
- return (ret < 0 ? ret : 0);
-}
+int MtpDataPacket::write(struct usb_request *request, UrbPacketDivisionMode divisionMode) {
+ if (mPacketSize < MTP_CONTAINER_HEADER_SIZE || mPacketSize > MTP_BUFFER_SIZE) {
+ ALOGE("Illegal packet size.");
+ return -1;
+ }
-int MtpDataPacket::write(struct usb_request *request) {
MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
- request->buffer = mBuffer;
- request->buffer_length = mPacketSize;
- int ret = transfer(request);
- return (ret < 0 ? ret : 0);
+
+ size_t processedBytes = 0;
+ while (processedBytes < mPacketSize) {
+ const size_t write_size =
+ processedBytes == 0 && divisionMode == FIRST_PACKET_ONLY_HEADER ?
+ MTP_CONTAINER_HEADER_SIZE : mPacketSize - processedBytes;
+ request->buffer = mBuffer + processedBytes;
+ request->buffer_length = write_size;
+ const int result = transfer(request);
+ if (result < 0) {
+ ALOGE("Failed to write bytes to the device.");
+ return -1;
+ }
+ processedBytes += result;
+ }
+
+ return processedBytes == mPacketSize ? processedBytes : -1;
}
-int MtpDataPacket::write(struct usb_request *request, void* buffer, uint32_t length) {
- request->buffer = buffer;
- request->buffer_length = length;
- int ret = transfer(request);
- return (ret < 0 ? ret : 0);
+int MtpDataPacket::write(struct usb_request *request,
+ UrbPacketDivisionMode divisionMode,
+ int fd,
+ size_t payloadSize) {
+ // Obtain the greatest multiple of minimum packet size that is not greater than
+ // MTP_BUFFER_SIZE.
+ if (request->max_packet_size <= 0) {
+ ALOGE("Cannot determine bulk transfer size due to illegal max packet size %d.",
+ request->max_packet_size);
+ return -1;
+ }
+ const size_t maxBulkTransferSize =
+ MTP_BUFFER_SIZE - (MTP_BUFFER_SIZE % request->max_packet_size);
+ const size_t containerLength = payloadSize + MTP_CONTAINER_HEADER_SIZE;
+ size_t processedBytes = 0;
+ bool readError = false;
+
+ // Bind the packet with given request.
+ request->buffer = mBuffer;
+ allocate(maxBulkTransferSize);
+
+ while (processedBytes < containerLength) {
+ size_t bulkTransferSize = 0;
+
+ // prepare header.
+ const bool headerSent = processedBytes != 0;
+ if (!headerSent) {
+ MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, containerLength);
+ MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
+ bulkTransferSize += MTP_CONTAINER_HEADER_SIZE;
+ }
+
+ // Prepare payload.
+ if (headerSent || divisionMode == FIRST_PACKET_HAS_PAYLOAD) {
+ const size_t processedPayloadBytes =
+ headerSent ? processedBytes - MTP_CONTAINER_HEADER_SIZE : 0;
+ const size_t maxRead = payloadSize - processedPayloadBytes;
+ const size_t maxWrite = maxBulkTransferSize - bulkTransferSize;
+ const size_t bulkTransferPayloadSize = std::min(maxRead, maxWrite);
+ // prepare payload.
+ if (!readError) {
+ const ssize_t result = readExactBytes(
+ fd,
+ mBuffer + bulkTransferSize,
+ bulkTransferPayloadSize);
+ if (result < 0) {
+ ALOGE("Found an error while reading data from FD. Send 0 data instead.");
+ readError = true;
+ }
+ }
+ if (readError) {
+ memset(mBuffer + bulkTransferSize, 0, bulkTransferPayloadSize);
+ }
+ bulkTransferSize += bulkTransferPayloadSize;
+ }
+
+ // Bulk transfer.
+ mPacketSize = bulkTransferSize;
+ request->buffer_length = bulkTransferSize;
+ const int result = transfer(request);
+ if (result != static_cast<ssize_t>(bulkTransferSize)) {
+ // Cannot recover writing error.
+ ALOGE("Found an error while write data to MtpDevice.");
+ return -1;
+ }
+
+ // Update variables.
+ processedBytes += bulkTransferSize;
+ }
+
+ return readError ? -1 : processedBytes;
}
#endif // MTP_HOST
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index 3a6b6cb..a449d6f 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -94,7 +94,6 @@
inline void putEmptyString() { putUInt8(0); }
inline void putEmptyArray() { putUInt32(0); }
-
#ifdef MTP_DEVICE
// fill our buffer with data from the given usb handle
int read(IMtpHandle *h);
@@ -111,9 +110,15 @@
int readDataWait(struct usb_device *device);
int readDataHeader(struct usb_request *ep);
- int writeDataHeader(struct usb_request *ep, uint32_t length);
- int write(struct usb_request *ep);
- int write(struct usb_request *ep, void* buffer, uint32_t length);
+ // Write a whole data packet with payload to the end point given by a request. |divisionMode|
+ // specifies whether to divide header and payload. See |UrbPacketDivisionMode| for meanings of
+ // each value. Return the number of bytes (including header size) sent to the device on success.
+ // Otherwise -1.
+ int write(struct usb_request *request, UrbPacketDivisionMode divisionMode);
+ // Similar to previous write method but it reads the payload from |fd|. If |size| is larger than
+ // MTP_BUFFER_SIZE, the data will be sent by multiple bulk transfer requests.
+ int write(struct usb_request *request, UrbPacketDivisionMode divisionMode,
+ int fd, size_t size);
#endif
inline bool hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; }
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 5f34843..52ea363 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -220,7 +220,10 @@
mTransactionID(0),
mReceivedResponse(false),
mProcessingEvent(false),
- mCurrentEventHandle(0)
+ mCurrentEventHandle(0),
+ mLastSendObjectInfoTransactionID(0),
+ mLastSendObjectInfoObjectHandle(0),
+ mPacketDivisionMode(FIRST_PACKET_HAS_PAYLOAD)
{
mRequestIn1 = usb_request_new(device, ep_in);
mRequestIn2 = usb_request_new(device, ep_in);
@@ -491,6 +494,8 @@
if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) {
MtpResponseCode ret = readResponse();
if (ret == MTP_RESPONSE_OK) {
+ mLastSendObjectInfoTransactionID = mRequest.getTransactionID();
+ mLastSendObjectInfoObjectHandle = mResponse.getParameter(3);
info->mStorageID = mResponse.getParameter(1);
info->mParent = mResponse.getParameter(2);
info->mHandle = mResponse.getParameter(3);
@@ -503,31 +508,21 @@
bool MtpDevice::sendObject(MtpObjectHandle handle, int size, int srcFD) {
Mutex::Autolock autoLock(mMutex);
- int remaining = size;
- mRequest.reset();
- mRequest.setParameter(1, handle);
- bool error = false;
- if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
- // send data header
- writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
-
- // USB writes greater than 16K don't work
- char buffer[MTP_BUFFER_SIZE];
- while (remaining > 0) {
- int count = read(srcFD, buffer, sizeof(buffer));
- if (count > 0) {
- if (mData.write(mRequestOut, buffer, count) < 0) {
- error = true;
- }
- // FIXME check error
- remaining -= count;
- } else {
- break;
- }
- }
+ if (mLastSendObjectInfoTransactionID + 1 != mTransactionID ||
+ mLastSendObjectInfoObjectHandle != handle) {
+ ALOGE("A sendObject request must follow the sendObjectInfo request.");
+ return false;
}
- MtpResponseCode ret = readResponse();
- return (remaining == 0 && ret == MTP_RESPONSE_OK && !error);
+
+ mRequest.reset();
+ if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
+ mData.setOperationCode(mRequest.getOperationCode());
+ mData.setTransactionID(mRequest.getTransactionID());
+ const int writeResult = mData.write(mRequestOut, mPacketDivisionMode, srcFD, size);
+ const MtpResponseCode ret = readResponse();
+ return ret == MTP_RESPONSE_OK && writeResult > 0;
+ }
+ return false;
}
bool MtpDevice::deleteObject(MtpObjectHandle handle) {
@@ -699,8 +694,8 @@
return false;
}
- // If object size 0 byte, the remote device can reply response packet
- // without sending any data packets.
+ // If object size 0 byte, the remote device may reply a response packet without sending any data
+ // packets.
if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
mResponse.copyFrom(mData);
return mResponse.getResponseCode() == MTP_RESPONSE_OK;
@@ -723,6 +718,14 @@
{
int initialDataLength = 0;
void* const initialData = mData.getData(&initialDataLength);
+ if (fullLength > MTP_CONTAINER_HEADER_SIZE && initialDataLength == 0) {
+ // According to the MTP spec, the responder (MTP device) can choose two ways of sending
+ // data. a) The first packet contains the head and as much of the payload as possible
+ // b) The first packet contains only the header. The initiator (MTP host) needs
+ // to remember which way the responder used, and send upcoming data in the same way.
+ ALOGD("Found short packet that contains only a header.");
+ mPacketDivisionMode = FIRST_PACKET_ONLY_HEADER;
+ }
if (initialData) {
if (initialDataLength > 0) {
if (!callback(initialData, offset, initialDataLength, clientData)) {
@@ -846,7 +849,7 @@
ALOGV("sendData\n");
mData.setOperationCode(mRequest.getOperationCode());
mData.setTransactionID(mRequest.getTransactionID());
- int ret = mData.write(mRequestOut);
+ int ret = mData.write(mRequestOut, mPacketDivisionMode);
mData.dump();
return (ret >= 0);
}
@@ -873,12 +876,6 @@
}
}
-bool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
- mData.setOperationCode(operation);
- mData.setTransactionID(mRequest.getTransactionID());
- return (!mData.writeDataHeader(mRequestOut, dataLength));
-}
-
MtpResponseCode MtpDevice::readResponse() {
ALOGV("readResponse\n");
if (mReceivedResponse) {
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index 4be44cf..c84c842 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -62,11 +62,18 @@
bool mProcessingEvent;
int mCurrentEventHandle;
+ // to check if a sendObject request follows the last sendObjectInfo request.
+ MtpTransactionID mLastSendObjectInfoTransactionID;
+ MtpObjectHandle mLastSendObjectInfoObjectHandle;
+
// to ensure only one MTP transaction at a time
Mutex mMutex;
Mutex mEventMutex;
Mutex mEventMutexForInterrupt;
+ // Remember the device's packet division mode.
+ UrbPacketDivisionMode mPacketDivisionMode;
+
public:
typedef bool (*ReadObjectCallback)
(void* data, uint32_t offset, uint32_t length, void* clientData);
diff --git a/media/mtp/MtpTypes.h b/media/mtp/MtpTypes.h
index 720c854..c749c66 100644
--- a/media/mtp/MtpTypes.h
+++ b/media/mtp/MtpTypes.h
@@ -73,6 +73,13 @@
typedef String8 MtpString;
+enum UrbPacketDivisionMode {
+ // First packet only contains a header.
+ FIRST_PACKET_ONLY_HEADER,
+ // First packet contains payload much as possible.
+ FIRST_PACKET_HAS_PAYLOAD
+};
+
}; // namespace android
#endif // _MTP_TYPES_H
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index be71f43..166e6f1 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -221,8 +221,7 @@
static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
- iter = mObj->mIds.begin();
- while (iter != mObj->mIds.end()) {
+ for (iter = mObj->mIds.begin(); iter != mObj->mIds.end(); ++iter) {
if (iter->array() == id.ptr && iter->size() == id.length) {
return true;
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 17cef11..ab42d77 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1359,7 +1359,7 @@
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) {
@@ -2361,7 +2361,7 @@
}
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++;
@@ -2382,7 +2382,7 @@
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--;
@@ -2400,6 +2400,18 @@
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");
@@ -2793,8 +2805,9 @@
sp<Client> 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();
}
@@ -2991,7 +3004,7 @@
ALOGV("updateOrphanEffectChains session %d index %zd", session, index);
if (index >= 0) {
sp<EffectChain> 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 c4b89f8..8f5a7cd 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -585,6 +585,7 @@
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 20d2896..09e7fd8 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -59,8 +59,9 @@
const wp<AudioFlinger::EffectChain>& 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
@@ -71,7 +72,7 @@
mSuspended(false),
mAudioFlinger(thread->mAudioFlinger)
{
- ALOGV("Constructor %p", this);
+ ALOGV("Constructor %p pinned %d", this, pinned);
int lStatus;
// create effect engine from effect factory
@@ -86,6 +87,8 @@
goto Error;
}
+ setOffloaded(thread->type() == ThreadBase::OFFLOAD, thread->id());
+
ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface);
return;
Error:
@@ -98,9 +101,8 @@
{
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();
}
}
@@ -115,7 +117,7 @@
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
@@ -143,9 +145,14 @@
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++) {
@@ -154,9 +161,10 @@
}
}
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
@@ -183,7 +191,7 @@
// 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;
}
}
@@ -191,29 +199,22 @@
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<EffectModule> keep(this);
- {
- if (removeHandle(handle) == 0) {
- if (!isPinned() || unpinIfLast) {
- sp<ThreadBase> thread = mThread.promote();
- if (thread != 0) {
- Mutex::Autolock _l(thread->mLock);
- thread->removeEffect_l(this);
- }
- sp<AudioFlinger> 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<AudioFlinger> af = mAudioFlinger.promote();
+ if (af != 0) {
+ mLock.unlock();
+ af->updateOrphanEffectChains(this);
+ mLock.lock();
}
}
- return mHandles.size();
+ return numHandles;
}
bool AudioFlinger::EffectModule::updateState() {
@@ -559,6 +560,17 @@
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 ||
@@ -602,6 +614,29 @@
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_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
@@ -628,7 +663,7 @@
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);
}
}
@@ -681,7 +716,7 @@
}
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);
}
}
@@ -845,8 +880,7 @@
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();
}
@@ -1073,7 +1107,7 @@
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);
}
@@ -1099,7 +1133,7 @@
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);
@@ -1122,14 +1156,6 @@
AudioFlinger::EffectHandle::~EffectHandle()
{
ALOGV("Destructor %p", this);
-
- if (mEffect == 0) {
- mDestroyed = true;
- return;
- }
- mEffect->lock();
- mDestroyed = true;
- mEffect->unlock();
disconnect(false);
}
@@ -1140,13 +1166,15 @@
status_t AudioFlinger::EffectHandle::enable()
{
+ AutoMutex _l(mLock);
ALOGV("enable %p", this);
+ sp<EffectModule> 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;
@@ -1154,20 +1182,20 @@
mEnabled = true;
- sp<ThreadBase> thread = mEffect->thread().promote();
+ sp<ThreadBase> 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 {
@@ -1177,12 +1205,12 @@
Mutex::Autolock _l(t->mLock);
t->broadcast_l();
}
- if (!mEffect->isOffloadable()) {
+ if (!effect->isOffloadable()) {
if (thread->type() == ThreadBase::OFFLOAD) {
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();
}
}
@@ -1194,27 +1222,29 @@
status_t AudioFlinger::EffectHandle::disable()
{
ALOGV("disable %p", this);
+ AutoMutex _l(mLock);
+ sp<EffectModule> 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<ThreadBase> thread = mEffect->thread().promote();
+ sp<ThreadBase> thread = effect->thread().promote();
if (thread != 0) {
- thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
+ thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
if (thread->type() == ThreadBase::OFFLOAD) {
PlaybackThread *t = (PlaybackThread *)thread.get();
Mutex::Autolock _l(t->mLock);
@@ -1227,25 +1257,39 @@
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<ThreadBase> thread = mEffect->thread().promote();
- if (thread != 0) {
- thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
+ mDisconnected = true;
+ sp<ThreadBase> thread;
+ {
+ sp<EffectModule> 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<EffectModule> 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
@@ -1265,55 +1309,99 @@
void *pReplyData)
{
ALOGVV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p",
- cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get());
+ 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<EffectModule> 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;
}
// 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);
- 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;
- status_t ret = mEffect->command(EFFECT_CMD_SET_PARAM,
- psize,
- p,
+ memcpy(param, p, size);
+
+ int reply = 0;
+ uint32_t rsize = sizeof(reply);
+ status_t ret = effect->command(EFFECT_CMD_SET_PARAM,
+ 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;
@@ -1323,20 +1411,15 @@
*(int *)pReplyData = reply;
break;
}
- mCblk->serverIndex += size;
+ index += size;
}
+ free(param);
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 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)
@@ -1418,7 +1501,6 @@
if (mOwnInBuffer) {
delete mInBuffer;
}
-
}
// getEffectFromDesc_l() must be called with ThreadBase::mLock held
@@ -1534,13 +1616,38 @@
}
}
-// 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<EffectModule>& 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<EffectModule>& 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<EffectModule>& effect)
+{
effect_descriptor_t desc = effect->desc();
uint32_t insertPref = desc.flags & EFFECT_FLAG_INSERT_MASK;
- Mutex::Autolock _l(mLock);
effect->setChain(this);
sp<ThreadBase> thread = mThread.promote();
if (thread == 0) {
@@ -1650,8 +1757,9 @@
return NO_ERROR;
}
-// removeEffect_l() must be called with PlaybackThread::mLock held
-size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect)
+// removeEffect_l() must be called with ThreadBase::mLock held
+size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect,
+ bool release)
{
Mutex::Autolock _l(mLock);
size_t size = mEffects.size();
@@ -1666,6 +1774,10 @@
mEffects[i]->state() == EffectModule::STOPPING) {
mEffects[i]->stop();
}
+ if (release) {
+ mEffects[i]->release_l();
+ }
+
if (type == EFFECT_FLAG_TYPE_AUXILIARY) {
delete[] effect->inBuffer();
} else {
@@ -1677,6 +1789,7 @@
mEffects.removeAt(i);
ALOGV("removeEffect_l() effect %p, removed from chain %p at rank %zu", effect.get(),
this, i);
+
break;
}
}
@@ -1684,7 +1797,7 @@
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();
@@ -1693,7 +1806,7 @@
}
}
-// 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();
@@ -1702,7 +1815,7 @@
}
}
-// 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();
@@ -1711,7 +1824,7 @@
}
}
-// 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;
@@ -1772,7 +1885,7 @@
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)) {
@@ -1873,7 +1986,7 @@
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 96cb607..8fe0b96 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -45,7 +45,8 @@
const wp<AudioFlinger::EffectChain>& 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 @@
const wp<ThreadBase>& 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<EffectChain>& chain() { return mChain; }
@@ -124,6 +126,7 @@
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<String16>& args);
@@ -208,12 +211,17 @@
bool enabled() const { return mEnabled; }
// Getters
- int id() const { return mEffect->id(); }
+ wp<EffectModule> effect() const { return mEffect; }
+ int id() const {
+ sp<EffectModule> effect = mEffect.promote();
+ if (effect == 0) {
+ return 0;
+ }
+ return effect->id();
+ }
int priority() const { return mPriority; }
bool hasControl() const { return mHasControl; }
- sp<EffectModule> 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 @@
EffectHandle(const EffectHandle&);
EffectHandle& operator =(const EffectHandle&);
- sp<EffectModule> mEffect; // pointer to controlled EffectModule
+ Mutex mLock; // protects IEffect method calls
+ wp<EffectModule> mEffect; // pointer to controlled EffectModule
sp<IEffectClient> mEffectClient; // callback interface for client notifications
/*const*/ sp<Client> mClient; // client for shared memory allocation, see disconnect()
sp<IMemory> mCblkMemory; // shared memory for control block
@@ -233,8 +242,7 @@
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 @@
mLock.unlock();
}
+ status_t createEffect_l(sp<EffectModule>& effect,
+ ThreadBase *thread,
+ effect_descriptor_t *desc,
+ int id,
+ audio_session_t sessionId,
+ bool pinned);
status_t addEffect_l(const sp<EffectModule>& handle);
- size_t removeEffect_l(const sp<EffectModule>& handle);
+ status_t addEffect_ll(const sp<EffectModule>& handle);
+ size_t removeEffect_l(const sp<EffectModule>& 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 8a4fbb5..2a29b1b 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1402,7 +1402,8 @@
audio_session_t sessionId,
effect_descriptor_t *desc,
int *enabled,
- status_t *status)
+ status_t *status,
+ bool pinned)
{
sp<EffectModule> effect;
sp<EffectHandle> handle;
@@ -1452,14 +1453,7 @@
}
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;
- }
- effect->setOffloaded(mType == OFFLOAD, mId);
-
- lStatus = chain->addEffect_l(effect);
+ lStatus = chain->createEffect_l(effect, this, desc, id, sessionId, pinned);
if (lStatus != NO_ERROR) {
goto Exit;
}
@@ -1500,6 +1494,33 @@
return handle;
}
+void AudioFlinger::ThreadBase::disconnectEffectHandle(EffectHandle *handle,
+ bool unpinIfLast)
+{
+ bool remove = false;
+ sp<EffectModule> 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::EffectModule> AudioFlinger::ThreadBase::getEffect(audio_session_t sessionId,
int effectId)
{
@@ -1560,9 +1581,9 @@
return NO_ERROR;
}
-void AudioFlinger::ThreadBase::removeEffect_l(const sp<EffectModule>& effect) {
+void AudioFlinger::ThreadBase::removeEffect_l(const sp<EffectModule>& 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());
@@ -1571,7 +1592,7 @@
sp<EffectChain> 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 a55655f..b3b4cf2 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -295,7 +295,8 @@
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 @@
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/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index f64c4f9..8cb5e0f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -385,7 +385,7 @@
DeviceVector deviceList;
uint32_t muteWaitMs = 0;
- if(!hasPrimaryOutput()) {
+ if(!hasPrimaryOutput() || mPrimaryOutput->device() == AUDIO_DEVICE_OUT_STUB) {
return muteWaitMs;
}
audio_devices_t txDevice = getDeviceAndMixForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index c5323d1..0387ee6 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -399,7 +399,6 @@
sp<AudioPolicyEffects>audioPolicyEffects;
{
Mutex::Autolock _l(mLock);
- mAudioPolicyManager->releaseInput(input, session);
audioPolicyEffects = mAudioPolicyEffects;
}
if (audioPolicyEffects != 0) {
@@ -409,6 +408,10 @@
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,
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 9d5f33c..9a7839b 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -238,6 +238,10 @@
{
String8 supportedPreviewFpsRange;
for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+ if (!isFpsSupported(availablePreviewSizes,
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, availableFpsRanges.data.i32[i+1])) {
+ continue;
+ }
if (i != 0) supportedPreviewFpsRange += ",";
supportedPreviewFpsRange += String8::format("(%d,%d)",
availableFpsRanges.data.i32[i] * kFpsToApiScale,
@@ -255,7 +259,10 @@
// from the [min, max] fps range use the max value
int fps = fpsFromRange(availableFpsRanges.data.i32[i],
availableFpsRanges.data.i32[i+1]);
-
+ if (!isFpsSupported(availablePreviewSizes,
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, fps)) {
+ continue;
+ }
// de-dupe frame rates
if (sortedPreviewFrameRates.indexOf(fps) == NAME_NOT_FOUND) {
sortedPreviewFrameRates.add(fps);
@@ -951,21 +958,40 @@
return NO_INIT;
}
+ // Get supported preview fps ranges.
+ Vector<Size> supportedPreviewSizes;
+ Vector<FpsRange> supportedPreviewFpsRanges;
+ const Size PREVIEW_SIZE_BOUND = { MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT };
+ status_t res = getFilteredSizes(PREVIEW_SIZE_BOUND, &supportedPreviewSizes);
+ if (res != OK) return res;
+ for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+ if (!isFpsSupported(supportedPreviewSizes,
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, availableFpsRanges.data.i32[i+1])) {
+ continue;
+ }
+ FpsRange fpsRange = {availableFpsRanges.data.i32[i], availableFpsRanges.data.i32[i+1]};
+ supportedPreviewFpsRanges.add(fpsRange);
+ }
+ if (supportedPreviewFpsRanges.size() == 0) {
+ ALOGE("Supported preview fps range is empty");
+ return NO_INIT;
+ }
+
int32_t bestStillCaptureFpsRange[2] = {
- availableFpsRanges.data.i32[0], availableFpsRanges.data.i32[1]
+ supportedPreviewFpsRanges[0].low, supportedPreviewFpsRanges[0].high
};
int32_t curRange =
bestStillCaptureFpsRange[1] - bestStillCaptureFpsRange[0];
- for (size_t i = 2; i < availableFpsRanges.count; i += 2) {
+ for (size_t i = 1; i < supportedPreviewFpsRanges.size(); i ++) {
int32_t nextRange =
- availableFpsRanges.data.i32[i + 1] -
- availableFpsRanges.data.i32[i];
+ supportedPreviewFpsRanges[i].high -
+ supportedPreviewFpsRanges[i].low;
if ( (nextRange > curRange) || // Maximize size of FPS range first
(nextRange == curRange && // Then minimize low-end FPS
- bestStillCaptureFpsRange[0] > availableFpsRanges.data.i32[i])) {
+ bestStillCaptureFpsRange[0] > supportedPreviewFpsRanges[i].low)) {
- bestStillCaptureFpsRange[0] = availableFpsRanges.data.i32[i];
- bestStillCaptureFpsRange[1] = availableFpsRanges.data.i32[i + 1];
+ bestStillCaptureFpsRange[0] = supportedPreviewFpsRanges[i].low;
+ bestStillCaptureFpsRange[1] = supportedPreviewFpsRanges[i].high;
curRange = nextRange;
}
}
@@ -2836,22 +2862,7 @@
int64_t Parameters::getJpegStreamMinFrameDurationNs(Parameters::Size size) {
if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
- const int STREAM_DURATION_SIZE = 4;
- const int STREAM_FORMAT_OFFSET = 0;
- const int STREAM_WIDTH_OFFSET = 1;
- const int STREAM_HEIGHT_OFFSET = 2;
- const int STREAM_DURATION_OFFSET = 3;
- camera_metadata_ro_entry_t availableStreamMinDurations =
- staticInfo(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
- for (size_t i = 0; i < availableStreamMinDurations.count; i+= STREAM_DURATION_SIZE) {
- int64_t format = availableStreamMinDurations.data.i64[i + STREAM_FORMAT_OFFSET];
- int64_t width = availableStreamMinDurations.data.i64[i + STREAM_WIDTH_OFFSET];
- int64_t height = availableStreamMinDurations.data.i64[i + STREAM_HEIGHT_OFFSET];
- int64_t duration = availableStreamMinDurations.data.i64[i + STREAM_DURATION_OFFSET];
- if (format == HAL_PIXEL_FORMAT_BLOB && width == size.width && height == size.height) {
- return duration;
- }
- }
+ return getMinFrameDurationNs(size, HAL_PIXEL_FORMAT_BLOB);
} else {
Vector<Size> availableJpegSizes = getAvailableJpegSizes();
size_t streamIdx = availableJpegSizes.size();
@@ -2875,6 +2886,57 @@
return -1;
}
+int64_t Parameters::getMinFrameDurationNs(Parameters::Size size, int fmt) {
+ if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
+ ALOGE("Min frame duration for HAL 3.1 or lower is not supported");
+ return -1;
+ }
+
+ const int STREAM_DURATION_SIZE = 4;
+ const int STREAM_FORMAT_OFFSET = 0;
+ const int STREAM_WIDTH_OFFSET = 1;
+ const int STREAM_HEIGHT_OFFSET = 2;
+ const int STREAM_DURATION_OFFSET = 3;
+ camera_metadata_ro_entry_t availableStreamMinDurations =
+ staticInfo(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
+ for (size_t i = 0; i < availableStreamMinDurations.count; i+= STREAM_DURATION_SIZE) {
+ int64_t format = availableStreamMinDurations.data.i64[i + STREAM_FORMAT_OFFSET];
+ int64_t width = availableStreamMinDurations.data.i64[i + STREAM_WIDTH_OFFSET];
+ int64_t height = availableStreamMinDurations.data.i64[i + STREAM_HEIGHT_OFFSET];
+ int64_t duration = availableStreamMinDurations.data.i64[i + STREAM_DURATION_OFFSET];
+ if (format == fmt && width == size.width && height == size.height) {
+ return duration;
+ }
+ }
+
+ return -1;
+}
+
+bool Parameters::isFpsSupported(const Vector<Size> &sizes, int format, int32_t fps) {
+ // Skip the check for older HAL version, as the min duration is not supported.
+ if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
+ return true;
+ }
+
+ // Get min frame duration for each size and check if the given fps range can be supported.
+ const int32_t FPS_MARGIN = 1;
+ for (size_t i = 0 ; i < sizes.size(); i++) {
+ int64_t minFrameDuration = getMinFrameDurationNs(sizes[i], format);
+ if (minFrameDuration <= 0) {
+ ALOGE("Min frame duration (%" PRId64") for size (%dx%d) and format 0x%x is wrong!",
+ minFrameDuration, sizes[i].width, sizes[i].height, format);
+ return false;
+ }
+ int32_t maxSupportedFps = 1e9 / minFrameDuration;
+ // Add some margin here for the case where the hal supports 29.xxxfps.
+ maxSupportedFps += FPS_MARGIN;
+ if (fps > maxSupportedFps) {
+ return false;
+ }
+ }
+ return true;
+}
+
SortedVector<int32_t> Parameters::getAvailableOutputFormats() {
SortedVector<int32_t> outputFormats; // Non-duplicated output formats
if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 798aab5..c8ecbba 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -115,6 +115,11 @@
int32_t height;
};
+ struct FpsRange {
+ int32_t low;
+ int32_t high;
+ };
+
int32_t exposureCompensation;
bool autoExposureLock;
bool autoWhiteBalanceLock;
@@ -390,6 +395,15 @@
// return -1 if input jpeg size cannot be found in supported size list
int64_t getJpegStreamMinFrameDurationNs(Parameters::Size size);
+ // Helper function to get minimum frame duration for a size/format combination
+ // return -1 if input size/format combination cannot be found.
+ int64_t getMinFrameDurationNs(Parameters::Size size, int format);
+
+ // Helper function to check if a given fps is supported by all the sizes with
+ // the same format.
+ // return true if the device doesn't support min frame duration metadata tag.
+ bool isFpsSupported(const Vector<Size> &size, int format, int32_t fps);
+
// Helper function to get non-duplicated available output formats
SortedVector<int32_t> getAvailableOutputFormats();
// Helper function to get available output jpeg sizes
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 94bc303..495de44 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2222,6 +2222,14 @@
}
}
+void Camera3Device::removeInFlightMapEntryLocked(int idx) {
+ mInFlightMap.removeItemsAt(idx, 1);
+
+ // Indicate idle inFlightMap to the status tracker
+ if (mInFlightMap.size() == 0) {
+ mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE);
+ }
+}
void Camera3Device::removeInFlightRequestIfReadyLocked(int idx) {
@@ -2257,13 +2265,7 @@
returnOutputBuffers(request.pendingOutputBuffers.array(),
request.pendingOutputBuffers.size(), 0);
- mInFlightMap.removeItemsAt(idx, 1);
-
- // Indicate idle inFlightMap to the status tracker
- if (mInFlightMap.size() == 0) {
- mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE);
- }
-
+ removeInFlightMapEntryLocked(idx);
ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber);
}
@@ -3440,6 +3442,20 @@
captureRequest->mResultExtras);
}
}
+
+ // Remove yet-to-be submitted inflight request from inflightMap
+ {
+ sp<Camera3Device> parent = mParent.promote();
+ if (parent != NULL) {
+ Mutex::Autolock l(parent->mInFlightLock);
+ ssize_t idx = parent->mInFlightMap.indexOfKey(captureRequest->mResultExtras.frameNumber);
+ if (idx >= 0) {
+ ALOGV("%s: Remove inflight request from queue: frameNumber %" PRId64,
+ __FUNCTION__, captureRequest->mResultExtras.frameNumber);
+ parent->removeInFlightMapEntryLocked(idx);
+ }
+ }
+ }
}
Mutex::Autolock l(mRequestLock);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 33429a6..87c43f3 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -849,6 +849,9 @@
/**** Scope for mInFlightLock ****/
+ // Remove the in-flight map entry of the given index from mInFlightMap.
+ // It must only be called with mInFlightLock held.
+ void removeInFlightMapEntryLocked(int idx);
// Remove the in-flight request of the given index from mInFlightMap
// if it's no longer needed. It must only be called with mInFlightLock held.
void removeInFlightRequestIfReadyLocked(int idx);