Merge "Update finalUsage datatype to uint64_t." into main
diff --git a/media/OWNERS b/media/OWNERS
index 976fb9e..b926075 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -14,5 +14,8 @@
taklee@google.com
wonsik@google.com
+# For TEST_MAPPING tv-presubmit and tv-postsubmit configurations:
+per-file TEST_MAPPING = blindahl@google.com
+
# go/android-fwk-media-solutions for info on areas of ownership.
include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index cd5d354..d388596 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -44,5 +44,11 @@
],
"file_patterns": ["(?i)drm|crypto"]
}
+ ],
+ // Postsubmit tests for TV devices
+ "tv-postsubmit": [
+ {
+ "name": "DecoderRenderTest"
+ }
]
}
diff --git a/media/aconfig/codec_fwk.aconfig b/media/aconfig/codec_fwk.aconfig
index a2b6a82..6d934ee 100644
--- a/media/aconfig/codec_fwk.aconfig
+++ b/media/aconfig/codec_fwk.aconfig
@@ -88,6 +88,26 @@
}
flag {
+ name: "set_callback_stall"
+ namespace: "codec_fwk"
+ description: "Bugfix flag for setCallback stall"
+ bug: "326010604"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "set_state_early"
+ namespace: "codec_fwk"
+ description: "Bugfix flag for setting state early to avoid a race condition"
+ bug: "298613712"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "teamfood"
namespace: "codec_fwk"
description: "Feature flag to track teamfood population"
diff --git a/media/codec2/components/aom/C2SoftAomEnc.cpp b/media/codec2/components/aom/C2SoftAomEnc.cpp
index 256bcb8..722b13a 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.cpp
+++ b/media/codec2/components/aom/C2SoftAomEnc.cpp
@@ -29,6 +29,12 @@
#include "C2SoftAomEnc.h"
+/* Quantization param values defined by the spec */
+#define AOM_QP_MIN 0
+#define AOM_QP_MAX 63
+#define AOM_QP_DEFAULT_MIN AOM_QP_MIN
+#define AOM_QP_DEFAULT_MAX AOM_QP_MAX
+
namespace android {
constexpr char COMPONENT_NAME[] = "c2.android.av1.encoder";
@@ -175,6 +181,19 @@
.inRange(C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)})
.withSetter(CodedColorAspectsSetter, mColorAspects)
.build());
+
+ addParameter(
+ DefineParam(mPictureQuantization, C2_PARAMKEY_PICTURE_QUANTIZATION)
+ .withDefault(C2StreamPictureQuantizationTuning::output::AllocShared(
+ 0 /* flexCount */, 0u /* stream */))
+ .withFields({C2F(mPictureQuantization, m.values[0].type_).oneOf(
+ {C2Config::I_FRAME, C2Config::P_FRAME}),
+ C2F(mPictureQuantization, m.values[0].min).inRange(
+ AOM_QP_DEFAULT_MIN, AOM_QP_DEFAULT_MAX),
+ C2F(mPictureQuantization, m.values[0].max).inRange(
+ AOM_QP_DEFAULT_MIN, AOM_QP_DEFAULT_MAX)})
+ .withSetter(PictureQuantizationSetter)
+ .build());
}
C2R C2SoftAomEnc::IntfImpl::BitrateSetter(bool mayBlock, C2P<C2StreamBitrateInfo::output>& me) {
@@ -307,6 +326,54 @@
return C2R::Ok();
}
+C2R C2SoftAomEnc::IntfImpl::PictureQuantizationSetter(
+ bool mayBlock, C2P<C2StreamPictureQuantizationTuning::output>& me) {
+ (void)mayBlock;
+ int32_t iMin = AOM_QP_DEFAULT_MIN, pMin = AOM_QP_DEFAULT_MIN;
+ int32_t iMax = AOM_QP_DEFAULT_MAX, pMax = AOM_QP_DEFAULT_MAX;
+ for (size_t i = 0; i < me.v.flexCount(); ++i) {
+ const C2PictureQuantizationStruct &layer = me.v.m.values[i];
+ // layerMin is clamped to [AOM_QP_MIN, layerMax] to avoid error
+ // cases where layer.min > layer.max
+ int32_t layerMax = std::clamp(layer.max, AOM_QP_MIN, AOM_QP_MAX);
+ int32_t layerMin = std::clamp(layer.min, AOM_QP_MIN, layerMax);
+ if (layer.type_ == C2Config::picture_type_t(I_FRAME)) {
+ iMax = layerMax;
+ iMin = layerMin;
+ ALOGV("iMin %d iMax %d", iMin, iMax);
+ } else if (layer.type_ == C2Config::picture_type_t(P_FRAME)) {
+ pMax = layerMax;
+ pMin = layerMin;
+ ALOGV("pMin %d pMax %d", pMin, pMax);
+ }
+ }
+ ALOGV("PictureQuantizationSetter(entry): i %d-%d p %d-%d",
+ iMin, iMax, pMin, pMax);
+
+ // aom library takes same range for I/P picture type
+ int32_t maxFrameQP = std::min(iMax, pMax);
+ int32_t minFrameQP = std::max(iMin, pMin);
+ if (minFrameQP > maxFrameQP) {
+ minFrameQP = maxFrameQP;
+ }
+ // put them back into the structure
+ for (size_t i = 0; i < me.v.flexCount(); ++i) {
+ const C2PictureQuantizationStruct &layer = me.v.m.values[i];
+
+ if (layer.type_ == C2Config::picture_type_t(I_FRAME)) {
+ me.set().m.values[i].max = maxFrameQP;
+ me.set().m.values[i].min = minFrameQP;
+ }
+ else if (layer.type_ == C2Config::picture_type_t(P_FRAME)) {
+ me.set().m.values[i].max = maxFrameQP;
+ me.set().m.values[i].min = minFrameQP;
+ }
+ }
+ ALOGV("PictureQuantizationSetter(exit): minFrameQP = %d maxFrameQP = %d",
+ minFrameQP, maxFrameQP);
+ return C2R::Ok();
+}
+
uint32_t C2SoftAomEnc::IntfImpl::getLevel_l() const {
return mProfileLevel->level - LEVEL_AV1_2;
}
@@ -558,6 +625,7 @@
mQuality = mIntf->getQuality_l();
mComplexity = mIntf->getComplexity_l();
mAV1EncLevel = mIntf->getLevel_l();
+ mQpBounds = mIntf->getPictureQuantization_l();
}
@@ -575,6 +643,18 @@
break;
}
+ if (mQpBounds->flexCount() > 0) {
+ // read min max qp for sequence
+ for (size_t i = 0; i < mQpBounds->flexCount(); ++i) {
+ const C2PictureQuantizationStruct &layer = mQpBounds->m.values[i];
+ if (layer.type_ == C2Config::picture_type_t(I_FRAME)) {
+ mMaxQuantizer = layer.max;
+ mMinQuantizer = layer.min;
+ break;
+ }
+ }
+ }
+
mCodecInterface = aom_codec_av1_cx();
if (!mCodecInterface) goto CleanUp;
diff --git a/media/codec2/components/aom/C2SoftAomEnc.h b/media/codec2/components/aom/C2SoftAomEnc.h
index 7e5ea63..067b04f 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.h
+++ b/media/codec2/components/aom/C2SoftAomEnc.h
@@ -109,6 +109,7 @@
std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
+ std::shared_ptr<C2StreamPictureQuantizationTuning::output> mQpBounds;
aom_codec_err_t setupCodecParameters();
};
@@ -126,6 +127,8 @@
const C2P<C2StreamPictureSizeInfo::input>& size,
const C2P<C2StreamFrameRateInfo::output>& frameRate,
const C2P<C2StreamBitrateInfo::output>& bitrate);
+ static C2R PictureQuantizationSetter(bool mayBlock,
+ C2P<C2StreamPictureQuantizationTuning::output> &me);
// unsafe getters
std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const { return mSize; }
@@ -150,6 +153,9 @@
std::shared_ptr<C2StreamPixelFormatInfo::input> getPixelFormat_l() const {
return mPixelFormat;
}
+ std::shared_ptr<C2StreamPictureQuantizationTuning::output> getPictureQuantization_l() const {
+ return mPictureQuantization;
+ }
uint32_t getSyncFramePeriod() const;
static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input>& me);
static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output>& me,
@@ -171,6 +177,7 @@
std::shared_ptr<C2StreamColorAspectsInfo::input> mColorAspects;
std::shared_ptr<C2StreamColorAspectsInfo::output> mCodedColorAspects;
std::shared_ptr<C2StreamPixelFormatInfo::input> mPixelFormat;
+ std::shared_ptr<C2StreamPictureQuantizationTuning::output> mPictureQuantization;
};
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
index dab7b89..318f093 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -446,6 +446,7 @@
{
IntfImpl::Lock lock = mIntf->lock();
mPixelFormatInfo = mIntf->getPixelFormat_l();
+ mColorAspects = mIntf->getDefaultColorAspects_l();
}
mWidth = 320;
@@ -591,6 +592,41 @@
return;
}
+ // handle dynamic config parameters
+ {
+ IntfImpl::Lock lock = mIntf->lock();
+ std::shared_ptr<C2StreamColorAspectsTuning::output> defaultColorAspects =
+ mIntf->getDefaultColorAspects_l();
+ lock.unlock();
+
+ if (mColorAspects->range != defaultColorAspects->range ||
+ mColorAspects->primaries != defaultColorAspects->primaries ||
+ mColorAspects->matrix != defaultColorAspects->matrix ||
+ mColorAspects->transfer != defaultColorAspects->transfer) {
+
+ mColorAspects->range = defaultColorAspects->range;
+ mColorAspects->primaries = defaultColorAspects->primaries;
+ mColorAspects->matrix = defaultColorAspects->matrix;
+ mColorAspects->transfer = defaultColorAspects->transfer;
+
+ C2StreamColorAspectsTuning::output colorAspect(0u, defaultColorAspects->range,
+ defaultColorAspects->primaries, defaultColorAspects->transfer,
+ defaultColorAspects->matrix);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ c2_status_t err = mIntf->config({&colorAspect}, C2_MAY_BLOCK, &failures);
+ if (err == C2_OK) {
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(colorAspect));
+ } else {
+ ALOGE("Config update colorAspect failed");
+ mSignalledError = true;
+ work->workletsProcessed = 1u;
+ work->result = C2_CORRUPTED;
+ return;
+ }
+ }
+ }
+
size_t inOffset = 0u;
size_t inSize = 0u;
C2ReadView rView = mDummyReadView;
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.h b/media/codec2/components/vpx/C2SoftVpxDec.h
index e9d6dc9..93cc213 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.h
+++ b/media/codec2/components/vpx/C2SoftVpxDec.h
@@ -66,6 +66,7 @@
// configurations used by component in process
// (TODO: keep this in intf but make them internal only)
std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormatInfo;
+ std::shared_ptr<C2StreamColorAspectsTuning::output> mColorAspects;
std::shared_ptr<IntfImpl> mIntf;
vpx_codec_ctx_t *mCodecCtx;
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index 66ce5ea..1c5772f 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -354,12 +354,9 @@
return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.);
}
-C2R C2SoftVpxEnc::IntfImpl::PictureQuantizationSetter(bool mayBlock,
- C2P<C2StreamPictureQuantizationTuning::output>
- &me) {
+C2R C2SoftVpxEnc::IntfImpl::PictureQuantizationSetter(
+ bool mayBlock, C2P<C2StreamPictureQuantizationTuning::output>& me) {
(void)mayBlock;
- // these are the ones we're going to set, so want them to default
- // to the DEFAULT values for the codec
int32_t iMin = VPX_QP_DEFAULT_MIN, pMin = VPX_QP_DEFAULT_MIN;
int32_t iMax = VPX_QP_DEFAULT_MAX, pMax = VPX_QP_DEFAULT_MAX;
for (size_t i = 0; i < me.v.flexCount(); ++i) {
@@ -382,8 +379,8 @@
iMin, iMax, pMin, pMax);
// vpx library takes same range for I/P picture type
- int32_t maxFrameQP = std::min({iMax, pMax});
- int32_t minFrameQP = std::max({iMin, pMin});
+ int32_t maxFrameQP = std::min(iMax, pMax);
+ int32_t minFrameQP = std::max(iMin, pMin);
if (minFrameQP > maxFrameQP) {
minFrameQP = maxFrameQP;
}
diff --git a/media/codec2/hal/aidl/Android.bp b/media/codec2/hal/aidl/Android.bp
index 48b6e21..e16e2b1 100644
--- a/media/codec2/hal/aidl/Android.bp
+++ b/media/codec2/hal/aidl/Android.bp
@@ -8,6 +8,7 @@
name: "libcodec2_aidl_client",
defaults: [
+ "aconfig_lib_cc_static_link.defaults",
"libcodec2_hal_selection",
],
@@ -65,6 +66,7 @@
],
defaults: [
+ "aconfig_lib_cc_static_link.defaults",
"libcodec2_hal_selection",
],
diff --git a/media/codec2/hal/common/Android.bp b/media/codec2/hal/common/Android.bp
index 7d7b285..4c9da33 100644
--- a/media/codec2/hal/common/Android.bp
+++ b/media/codec2/hal/common/Android.bp
@@ -31,6 +31,10 @@
],
static_libs: ["aconfig_mediacodec_flags_c_lib"],
+
+ defaults: [
+ "aconfig_lib_cc_static_link.defaults",
+ ],
}
cc_library_static {
diff --git a/media/codec2/hal/common/MultiAccessUnitHelper.cpp b/media/codec2/hal/common/MultiAccessUnitHelper.cpp
index 8086ef2..b1fa82f 100644
--- a/media/codec2/hal/common/MultiAccessUnitHelper.cpp
+++ b/media/codec2/hal/common/MultiAccessUnitHelper.cpp
@@ -27,6 +27,7 @@
#include <C2Debug.h>
#include <C2PlatformSupport.h>
+static inline constexpr uint32_t MAX_SUPPORTED_SIZE = ( 10 * 512000 * 8 * 2u);
namespace android {
static C2R MultiAccessUnitParamsSetter(
@@ -39,8 +40,6 @@
res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.thresholdSize)));
} else if (me.v.maxSize < me.v.thresholdSize) {
me.set().maxSize = me.v.thresholdSize;
- } else if (me.v.thresholdSize == 0 && me.v.maxSize > 0) {
- me.set().thresholdSize = me.v.maxSize;
}
std::vector<std::unique_ptr<C2SettingResult>> failures;
res.retrieveFailures(&failures);
@@ -61,9 +60,9 @@
.withDefault(new C2LargeFrame::output(0u, 0, 0))
.withFields({
C2F(mLargeFrameParams, maxSize).inRange(
- 0, c2_min(UINT_MAX, 10 * 512000 * 8 * 2u)),
+ 0, c2_min(UINT_MAX, MAX_SUPPORTED_SIZE)),
C2F(mLargeFrameParams, thresholdSize).inRange(
- 0, c2_min(UINT_MAX, 10 * 512000 * 8 * 2u))
+ 0, c2_min(UINT_MAX, MAX_SUPPORTED_SIZE))
})
.withSetter(MultiAccessUnitParamsSetter)
.build());
@@ -115,6 +114,18 @@
return false;
}
+bool MultiAccessUnitInterface::getMaxInputSize(
+ C2StreamMaxBufferSizeInfo::input* const maxInputSize) const {
+ if (maxInputSize == nullptr || mC2ComponentIntf == nullptr) {
+ return false;
+ }
+ c2_status_t err = mC2ComponentIntf->query_vb({maxInputSize}, {}, C2_MAY_BLOCK, nullptr);
+ if (err != OK) {
+ return false;
+ }
+ return true;
+}
+
//C2MultiAccessUnitBuffer
class C2MultiAccessUnitBuffer : public C2Buffer {
public:
@@ -128,6 +139,7 @@
MultiAccessUnitHelper::MultiAccessUnitHelper(
const std::shared_ptr<MultiAccessUnitInterface>& intf,
std::shared_ptr<C2BlockPool>& linearPool):
+ mMultiAccessOnOffAllowed(true),
mInit(false),
mInterface(intf),
mLinearPool(linearPool) {
@@ -152,6 +164,63 @@
return result;
}
+bool MultiAccessUnitHelper::tryReconfigure(const std::unique_ptr<C2Param> ¶m) {
+ C2LargeFrame::output *lfp = C2LargeFrame::output::From(param.get());
+ if (lfp == nullptr) {
+ return false;
+ }
+ bool isDecoder = (mInterface->kind() == C2Component::KIND_DECODER) ? true : false;
+ if (!isDecoder) {
+ C2StreamMaxBufferSizeInfo::input maxInputSize(0);
+ if (!mInterface->getMaxInputSize(&maxInputSize)) {
+ LOG(ERROR) << "Error in reconfigure: "
+ << "Encoder failed to respond with a valid max input size";
+ return false;
+ }
+ // This is assuming a worst case compression ratio of 1:1
+ // In no case the encoder should give an output more than
+ // what is being provided to the encoder in a single call.
+ if (lfp->maxSize < maxInputSize.value) {
+ lfp->maxSize = maxInputSize.value;
+ }
+ }
+ lfp->maxSize =
+ (lfp->maxSize > MAX_SUPPORTED_SIZE) ? MAX_SUPPORTED_SIZE :
+ (lfp->maxSize < 0) ? 0 : lfp->maxSize;
+ lfp->thresholdSize =
+ (lfp->thresholdSize > MAX_SUPPORTED_SIZE) ? MAX_SUPPORTED_SIZE :
+ (lfp->thresholdSize < 0) ? 0 : lfp->thresholdSize;
+ C2LargeFrame::output currentConfig = mInterface->getLargeFrameParam();
+ if ((currentConfig.maxSize == lfp->maxSize)
+ && (currentConfig.thresholdSize == lfp->thresholdSize)) {
+ // no need to update
+ return false;
+ }
+ if (isDecoder) {
+ bool isOnOffTransition =
+ (currentConfig.maxSize == 0 && lfp->maxSize != 0)
+ || (currentConfig.maxSize != 0 && lfp->maxSize == 0);
+ if (isOnOffTransition && !mMultiAccessOnOffAllowed) {
+ LOG(ERROR) << "Setting new configs not allowed"
+ << " MaxSize: " << lfp->maxSize
+ << " ThresholdSize: " << lfp->thresholdSize;
+ return false;
+ }
+ }
+ std::vector<C2Param*> config{lfp};
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ if (C2_OK != mInterface->config(config, C2_MAY_BLOCK, &failures)) {
+ LOG(ERROR) << "Dynamic config not applied for"
+ << " MaxSize: " << lfp->maxSize
+ << " ThresholdSize: " << lfp->thresholdSize;
+ return false;
+ }
+ LOG(DEBUG) << "Updated from param maxSize "
+ << lfp->maxSize
+ << " ThresholdSize " << lfp->thresholdSize;
+ return true;
+}
+
std::shared_ptr<MultiAccessUnitInterface> MultiAccessUnitHelper::getInterface() {
return mInterface;
}
@@ -163,6 +232,7 @@
void MultiAccessUnitHelper::reset() {
std::lock_guard<std::mutex> l(mLock);
mFrameHolder.clear();
+ mMultiAccessOnOffAllowed = true;
}
c2_status_t MultiAccessUnitHelper::error(
@@ -181,6 +251,7 @@
}
}
mFrameHolder.clear();
+ mMultiAccessOnOffAllowed = true;
return C2_OK;
}
@@ -232,16 +303,23 @@
uint64_t newFrameIdx = mFrameIndex++;
// TODO: Do not split buffers if component inherantly supports MultipleFrames.
// if thats case, only replace frameindex.
- auto cloneInputWork = [&newFrameIdx](std::unique_ptr<C2Work>& inWork, uint32_t flags) {
+ auto cloneInputWork = [&frameInfo, &newFrameIdx, this]
+ (std::unique_ptr<C2Work>& inWork, uint32_t flags) -> std::unique_ptr<C2Work> {
std::unique_ptr<C2Work> newWork(new C2Work);
newWork->input.flags = (C2FrameData::flags_t)flags;
newWork->input.ordinal = inWork->input.ordinal;
newWork->input.ordinal.frameIndex = newFrameIdx;
if (!inWork->input.configUpdate.empty()) {
for (std::unique_ptr<C2Param>& param : inWork->input.configUpdate) {
- newWork->input.configUpdate.push_back(
- std::move(C2Param::Copy(*(param.get()))));
+ if (param->index() == C2LargeFrame::output::PARAM_TYPE) {
+ if (tryReconfigure(param)) {
+ frameInfo.mConfigUpdate.push_back(std::move(param));
+ }
+ } else {
+ newWork->input.configUpdate.push_back(std::move(param));
+ }
}
+ inWork->input.configUpdate.clear();
}
newWork->input.infoBuffers = (inWork->input.infoBuffers);
if (!inWork->worklets.empty() && inWork->worklets.front() != nullptr) {
@@ -331,6 +409,7 @@
frameInfo.mLargeFrameTuning = multiAccessParams;
std::lock_guard<std::mutex> l(mLock);
mFrameHolder.push_back(std::move(frameInfo));
+ mMultiAccessOnOffAllowed = false;
}
}
return C2_OK;
@@ -360,6 +439,7 @@
std::list<MultiAccessUnitInfo>::iterator frame =
mFrameHolder.begin();
while (!foundFrame && frame != mFrameHolder.end()) {
+ c2_status_t res = C2_OK;
auto it = frame->mComponentFrameIds.find(thisFrameIndex);
if (it != frame->mComponentFrameIds.end()) {
foundFrame = true;
@@ -369,8 +449,7 @@
if (work->result != C2_OK
|| work->worklets.empty()
|| !work->worklets.front()
- || (frame->mLargeFrameTuning.thresholdSize == 0
- || frame->mLargeFrameTuning.maxSize == 0)) {
+ || frame->mLargeFrameTuning.maxSize == 0) {
if (removeEntry) {
frame->mComponentFrameIds.erase(it);
removeEntry = false;
@@ -388,10 +467,27 @@
addOutWork(frame->mLargeWork);
frame->reset();
if (workResult != C2_OK) {
- frame->mAccessUnitInfos.clear();
+ frame->mComponentFrameIds.clear();
+ removeEntry = false;
}
- } else if (C2_OK != processWorklets(*frame, work, addOutWork)) {
- LOG(DEBUG) << "Error while processing work";
+ } else if (C2_OK != (res = processWorklets(*frame, work, addOutWork))) {
+ // Upon error in processing worklets, we return the work with
+ // result set to the error. This should indicate the error to the
+ // framework and thus doing what is necessary to handle the
+ // error.
+ LOG(DEBUG) << "Error while processing worklets";
+ if (frame->mLargeWork == nullptr) {
+ frame->mLargeWork.reset(new C2Work);
+ frame->mLargeWork->input.ordinal = frame->inOrdinal;
+ frame->mLargeWork->input.ordinal.frameIndex =
+ frame->inOrdinal.frameIndex;
+ }
+ frame->mLargeWork->result = res;
+ finalizeWork(*frame);
+ addOutWork(frame->mLargeWork);
+ frame->reset();
+ frame->mComponentFrameIds.clear();
+ removeEntry = false;
}
if (removeEntry) {
LOG(DEBUG) << "Removing entry: " << thisFrameIndex
@@ -528,9 +624,6 @@
LOG(DEBUG) << "maxOutSize " << frame.mLargeFrameTuning.maxSize
<< " threshold " << frame.mLargeFrameTuning.thresholdSize;
- if ((*worklet)->output.buffers.size() > 0) {
- allocateWork(frame, true, true);
- }
LOG(DEBUG) << "This worklet has " << (*worklet)->output.buffers.size() << " buffers"
<< " ts: " << (*worklet)->output.ordinal.timestamp.peekull();
int64_t workletTimestamp = (*worklet)->output.ordinal.timestamp.peekull();
@@ -552,43 +645,39 @@
inputSize -= (inputSize % frameSize);
}
while (inputOffset < inputSize) {
- if (frame.mWview->offset() >= frame.mLargeFrameTuning.thresholdSize) {
+ if ((frame.mWview != nullptr)
+ && (frame.mWview->offset() >= frame.mLargeFrameTuning.thresholdSize)) {
frame.mLargeWork->result = C2_OK;
finalizeWork(frame, flagsForCopy);
addWork(frame.mLargeWork);
frame.reset();
- allocateWork(frame, true, true);
}
if (mInterface->kind() == C2Component::KIND_ENCODER) {
if (inputSize > frame.mLargeFrameTuning.maxSize) {
- LOG(ERROR) << "Enc: Output buffer too small for AU, configured with "
- << frame.mLargeFrameTuning.maxSize
- << " block size: " << blocks.front().size()
- << "alloc size " << frame.mWview->size();
- if (frame.mLargeWork
- && frame.mWview && frame.mWview->offset() > 0) {
+ LOG(WARNING) << "WARNING Encoder:"
+ << " Output buffer too small for configuration"
+ << " configured max size " << frame.mLargeFrameTuning.maxSize
+ << " access unit size " << inputSize;
+ if (frame.mLargeWork && (frame.mWview && frame.mWview->offset() > 0)) {
+ frame.mLargeWork->result = C2_OK;
finalizeWork(frame, flagsForCopy);
addWork(frame.mLargeWork);
frame.reset();
- allocateWork(frame, true, false);
}
- frame.mLargeWork->result = C2_NO_MEMORY;
- finalizeWork(frame, 0, true);
- addWork(frame.mLargeWork);
- frame.reset();
- return C2_NO_MEMORY;
- } else if (inputSize > frame.mWview->size()) {
+ frame.mLargeFrameTuning.maxSize = inputSize;
+ } else if ((frame.mWview != nullptr)
+ && (inputSize > frame.mWview->size())) {
LOG(DEBUG) << "Enc: Large frame hitting bufer limit, current size "
<< frame.mWview->offset();
- if (frame.mLargeWork
- && frame.mWview && frame.mWview->offset() > 0) {
+ if (frame.mWview->offset() > 0) {
+ frame.mLargeWork->result = C2_OK;
finalizeWork(frame, flagsForCopy);
addWork(frame.mLargeWork);
frame.reset();
- allocateWork(frame, true, true);
}
}
}
+ allocateWork(frame, true, true);
C2ReadView rView = blocks.front().map().get();
if (rView.error()) {
LOG(ERROR) << "Buffer read view error";
@@ -683,26 +772,39 @@
frame.mWview->setOffset(0);
std::shared_ptr<C2Buffer> c2Buffer = C2Buffer::CreateLinearBuffer(
frame.mBlock->share(0, size, ::C2Fence()));
- if (frame.mAccessUnitInfos.size() > 0) {
- if (finalFlags & C2FrameData::FLAG_END_OF_STREAM) {
- frame.mAccessUnitInfos.back().flags |=
- C2FrameData::FLAG_END_OF_STREAM;
- }
- std::shared_ptr<C2AccessUnitInfos::output> largeFrame =
- C2AccessUnitInfos::output::AllocShared(
- frame.mAccessUnitInfos.size(), 0u, frame.mAccessUnitInfos);
- frame.mInfos.push_back(largeFrame);
- frame.mAccessUnitInfos.clear();
- }
- for (auto &info : frame.mInfos) {
- c2Buffer->setInfo(std::const_pointer_cast<C2Info>(info));
- }
frame.mLargeWork->worklets.front()->output.buffers.push_back(std::move(c2Buffer));
- frame.mInfos.clear();
- frame.mBlock.reset();
- frame.mWview.reset();
+ }
+ if (frame.mLargeWork->worklets.front()->output.buffers.size() > 0) {
+ std::shared_ptr<C2Buffer>& c2Buffer =
+ frame.mLargeWork->worklets.front()->output.buffers.front();
+ if (c2Buffer != nullptr) {
+ if (frame.mAccessUnitInfos.size() > 0) {
+ if (finalFlags & C2FrameData::FLAG_END_OF_STREAM) {
+ frame.mAccessUnitInfos.back().flags |= C2FrameData::FLAG_END_OF_STREAM;
+ }
+ std::shared_ptr<C2AccessUnitInfos::output> largeFrame =
+ C2AccessUnitInfos::output::AllocShared(
+ frame.mAccessUnitInfos.size(), 0u, frame.mAccessUnitInfos);
+ frame.mInfos.push_back(largeFrame);
+ frame.mAccessUnitInfos.clear();
+ }
+ for (auto &info : frame.mInfos) {
+ c2Buffer->setInfo(std::const_pointer_cast<C2Info>(info));
+ }
+ }
+ }
+ if (frame.mConfigUpdate.size() > 0) {
+ outFrameData.configUpdate.insert(
+ outFrameData.configUpdate.end(),
+ make_move_iterator(frame.mConfigUpdate.begin()),
+ make_move_iterator(frame.mConfigUpdate.end()));
}
}
+ frame.mConfigUpdate.clear();
+ frame.mInfos.clear();
+ frame.mBlock.reset();
+ frame.mWview.reset();
+
LOG(DEBUG) << "Multi access-unitflag setting as " << finalFlags;
return C2_OK;
}
@@ -735,6 +837,7 @@
mBlock.reset();
mWview.reset();
mInfos.clear();
+ mConfigUpdate.clear();
mAccessUnitInfos.clear();
mLargeWork.reset();
}
diff --git a/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h b/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h
index bb4464c..070a1f5 100644
--- a/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h
+++ b/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h
@@ -46,6 +46,7 @@
protected:
bool getDecoderSampleRateAndChannelCount(
uint32_t * const sampleRate_, uint32_t * const channelCount_) const;
+ bool getMaxInputSize(C2StreamMaxBufferSizeInfo::input* const maxInputSize) const;
const std::shared_ptr<C2ComponentInterface> mC2ComponentIntf;
std::shared_ptr<C2LargeFrame::output> mLargeFrameParams;
C2ComponentKindSetting mKind;
@@ -140,6 +141,11 @@
std::vector<std::shared_ptr<const C2Info>> mInfos;
/*
+ * Vector for holding config updates from the wrapper
+ */
+ std::vector<std::unique_ptr<C2Param>> mConfigUpdate;
+
+ /*
* C2AccessUnitInfos for the current buffer
*/
std::vector<C2AccessUnitInfosStruct> mAccessUnitInfos;
@@ -170,6 +176,11 @@
};
/*
+ * Reconfigure helper
+ */
+ bool tryReconfigure(const std::unique_ptr<C2Param> &p);
+
+ /*
* Creates a linear block to be used with work
*/
c2_status_t createLinearBlock(MultiAccessUnitInfo &frame);
@@ -195,6 +206,14 @@
uint32_t size,
int64_t timestamp);
+ // Flag to allow dynamic on/off settings on this helper.
+ // Once enabled and buffers in transit, it is not possible
+ // to turn this module off by setting the max output value
+ // to 0. This is because the skip cut buffer expects the
+ // metadata to be always present along with a valid buffer.
+ // This flag is used to monitor that state of this module.
+ bool mMultiAccessOnOffAllowed;
+
bool mInit;
// Interface of this module
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
index ab47b7c..36907e1 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
@@ -263,9 +263,6 @@
ALOGV("mComponent->reset() timeConsumed=%" PRId64 " us", timeConsumed);
ASSERT_EQ(err, C2_OK);
- err = mComponent->start();
- ASSERT_EQ(err, C2_OK);
-
// Query supported params by the component
std::vector<std::shared_ptr<C2ParamDescriptor>> params;
startTime = getNowUs();
@@ -298,6 +295,9 @@
timeConsumed);
}
+ err = mComponent->start();
+ ASSERT_EQ(err, C2_OK);
+
std::list<std::unique_ptr<C2Work>> workList;
startTime = getNowUs();
err = mComponent->queue(&workList);
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index 362373e..7076bac 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -91,6 +91,10 @@
"libcodec2_client",
],
+ defaults: [
+ "aconfig_lib_cc_static_link.defaults",
+ ],
+
sanitize: {
cfi: true,
misc_undefined: [
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index e2936c8..2550dcf 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -1144,7 +1144,7 @@
std::optional<Smpte2086> smpte2086;
status_t status = mapper.getSmpte2086(buffer.get(), &smpte2086);
- if (status != OK) {
+ if (status != OK || !smpte2086) {
err = C2_CORRUPTED;
} else {
if (smpte2086) {
@@ -1164,7 +1164,7 @@
std::optional<Cta861_3> cta861_3;
status = mapper.getCta861_3(buffer.get(), &cta861_3);
- if (status != OK) {
+ if (status != OK || !cta861_3) {
err = C2_CORRUPTED;
} else {
if (cta861_3) {
@@ -1183,7 +1183,7 @@
dynamicInfo->reset();
std::optional<std::vector<uint8_t>> vec;
status_t status = mapper.getSmpte2094_40(buffer.get(), &vec);
- if (status != OK) {
+ if (status != OK || !vec) {
dynamicInfo->reset();
err = C2_CORRUPTED;
} else {
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index 9f57bfd..dc06ee6 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -53,6 +53,7 @@
],
defaults: [
+ "aconfig_lib_cc_static_link.defaults",
"libcodec2_hal_selection",
],
diff --git a/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp b/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp
index 1d2da6a..c7a04da 100644
--- a/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp
+++ b/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp
@@ -36,6 +36,7 @@
[[clang::no_destroy]] static std::once_flag gSmOnce;
sp<FakeServiceManager> gFakeServiceManager;
+sp<AudioFlingerServerAdapter> gAudioFlingerServerAdapter;
bool addService(const String16& serviceName, const sp<FakeServiceManager>& fakeServiceManager,
FuzzedDataProvider& fdp) {
@@ -47,22 +48,10 @@
return true;
}
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- FuzzedDataProvider fdp(data, size);
-
- std::call_once(gSmOnce, [&] {
- /* Create a FakeServiceManager instance and add required services */
- gFakeServiceManager = sp<FakeServiceManager>::make();
- setDefaultServiceManager(gFakeServiceManager);
- });
- gFakeServiceManager->clear();
-
- for (const char* service : {"activity", "sensor_privacy", "permission", "scheduling_policy",
- "batterystats", "media.metrics"}) {
- if (!addService(String16(service), gFakeServiceManager, fdp)) {
- return 0;
- }
- }
+extern "C" int LLVMFuzzerInitialize(int* /*argc*/, char*** /*argv*/) {
+ /* Create a FakeServiceManager instance and add required services */
+ gFakeServiceManager = sp<FakeServiceManager>::make();
+ setDefaultServiceManager(gFakeServiceManager);
auto configService = ndk::SharedRefBase::make<ConfigMock>();
CHECK_EQ(NO_ERROR, AServiceManager_addService(configService.get()->asBinder().get(),
@@ -80,22 +69,37 @@
// Disable creating thread pool for fuzzer instance of audio flinger and audio policy services
AudioSystem::disableThreadPool();
- const auto audioFlinger = sp<AudioFlinger>::make();
- const auto afAdapter = sp<AudioFlingerServerAdapter>::make(audioFlinger);
+ return 0;
+}
- CHECK_EQ(NO_ERROR,
- gFakeServiceManager->addService(
- String16(IAudioFlinger::DEFAULT_SERVICE_NAME), IInterface::asBinder(afAdapter),
- false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
- const auto audioPolicyService = sp<AudioPolicyService>::make();
+ for (const char* service : {"activity", "sensor_privacy", "permission", "scheduling_policy",
+ "batterystats", "media.metrics"}) {
+ if (!addService(String16(service), gFakeServiceManager, fdp)) {
+ return 0;
+ }
+ }
- CHECK_EQ(NO_ERROR,
- gFakeServiceManager->addService(String16("media.audio_policy"), audioPolicyService,
- false /* allowIsolated */,
- IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+ // TODO(330882064) : Initialise Audio Flinger and Audio Policy services every time
+ std::call_once(gSmOnce, [&] {
+ const auto audioFlinger = sp<AudioFlinger>::make();
+ gAudioFlingerServerAdapter = sp<AudioFlingerServerAdapter>::make(audioFlinger);
+ CHECK_EQ(NO_ERROR,
+ gFakeServiceManager->addService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME),
+ IInterface::asBinder(gAudioFlingerServerAdapter),
+ false /* allowIsolated */,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
- fuzzService(media::IAudioFlingerService::asBinder(afAdapter), std::move(fdp));
+ const auto audioPolicyService = sp<AudioPolicyService>::make();
+ CHECK_EQ(NO_ERROR,
+ gFakeServiceManager->addService(String16("media.audio_policy"), audioPolicyService,
+ false /* allowIsolated */,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+ });
+
+ fuzzService(media::IAudioFlingerService::asBinder(gAudioFlingerServerAdapter), std::move(fdp));
return 0;
}
diff --git a/media/libaudiohal/impl/EffectProxy.cpp b/media/libaudiohal/impl/EffectProxy.cpp
index 9aa02e2..fb4658f 100644
--- a/media/libaudiohal/impl/EffectProxy.cpp
+++ b/media/libaudiohal/impl/EffectProxy.cpp
@@ -82,8 +82,7 @@
ndk::ScopedAStatus EffectProxy::setOffloadParam(const effect_offload_param_t* offload) {
const auto& itor = std::find_if(mSubEffects.begin(), mSubEffects.end(), [&](const auto& sub) {
const auto& desc = sub.descriptor;
- return offload->isOffload ==
- (desc.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL);
+ return offload->isOffload == desc.common.flags.offloadIndication;
});
if (itor == mSubEffects.end()) {
ALOGE("%s no %soffload sub-effect found", __func__, offload->isOffload ? "" : "non-");
@@ -93,7 +92,7 @@
}
mActiveSubIdx = std::distance(mSubEffects.begin(), itor);
- ALOGI("%s: active %soffload sub-effect %zu descriptor: %s", __func__,
+ ALOGI("%s: active %soffload sub-effect %zu: %s", __func__,
offload->isOffload ? "" : "non-", mActiveSubIdx,
::android::audio::utils::toString(mSubEffects[mActiveSubIdx].descriptor.common.id.uuid)
.c_str());
@@ -163,7 +162,7 @@
ndk::ScopedAStatus EffectProxy::getDescriptor(Descriptor* desc) {
*desc = mSubEffects[mActiveSubIdx].descriptor;
- desc->common.id.uuid = desc->common.id.proxy.value();
+ desc->common = mDescriptorCommon;
return ndk::ScopedAStatus::ok();
}
@@ -185,42 +184,35 @@
return ndk::ScopedAStatus::ok();
}
+// Sub-effects are required to have identical features, so here we return the SW sub-effect
+// descriptor, with the implementation UUID replaced with proxy UUID, and flags setting respect all
+// sub-effects.
Descriptor::Common EffectProxy::buildDescriptorCommon(
const AudioUuid& uuid, const std::vector<Descriptor>& subEffectDescs) {
- // initial flag values before we know which sub-effect to active (with setOffloadParam)
- // align to HIDL EffectProxy flags
- Descriptor::Common common = {.flags = {.type = Flags::Type::INSERT,
- .insert = Flags::Insert::LAST,
- .volume = Flags::Volume::CTRL}};
-
+ Descriptor::Common swCommon;
+ const Flags& firstFlag = subEffectDescs[0].common.flags;
+ bool offloadExist = false;
for (const auto& desc : subEffectDescs) {
- if (desc.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL) {
- common.flags.hwAcceleratorMode = Flags::HardwareAccelerator::TUNNEL;
+ if (desc.common.flags.offloadIndication) {
+ offloadExist = true;
+ } else {
+ swCommon = desc.common;
}
-
- // set indication if any sub-effect indication was set
- common.flags.offloadIndication |= desc.common.flags.offloadIndication;
- common.flags.deviceIndication |= desc.common.flags.deviceIndication;
- common.flags.audioModeIndication |= desc.common.flags.audioModeIndication;
- common.flags.audioSourceIndication |= desc.common.flags.audioSourceIndication;
- // Set to NONE if any sub-effect not supporting any Volume command
- if (desc.common.flags.volume == Flags::Volume::NONE) {
- common.flags.volume = Flags::Volume::NONE;
- }
- // set to AUXILIARY if any sub-effect is of AUXILIARY type
- if (desc.common.flags.type == Flags::Type::AUXILIARY) {
- common.flags.type = Flags::Type::AUXILIARY;
+ if (desc.common.flags.audioModeIndication != firstFlag.audioModeIndication ||
+ desc.common.flags.audioSourceIndication != firstFlag.audioSourceIndication ||
+ desc.common.flags.sinkMetadataIndication != firstFlag.sinkMetadataIndication ||
+ desc.common.flags.sourceMetadataIndication != firstFlag.sourceMetadataIndication ||
+ desc.common.flags.deviceIndication != firstFlag.deviceIndication) {
+ ALOGW("Inconsistent flags %s vs %s", desc.common.flags.toString().c_str(),
+ firstFlag.toString().c_str());
}
}
- // copy type UUID from any of sub-effects, all sub-effects should have same type
- common.id.type = subEffectDescs[0].common.id.type;
+ swCommon.flags.offloadIndication = offloadExist;
// replace implementation UUID with proxy UUID.
- common.id.uuid = uuid;
- common.id.proxy = std::nullopt;
- common.name = "Proxy";
- common.implementor = "AOSP";
- return common;
+ swCommon.id.uuid = uuid;
+ swCommon.id.proxy = std::nullopt;
+ return swCommon;
}
// Handle with active sub-effect first, only send to other sub-effects when success
diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
index 3b2f344..64cc7ed 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
@@ -188,7 +188,6 @@
aidlEffect = ndk::SharedRefBase::make<EffectProxy>(
aidlUuid, mProxyUuidDescriptorMap.at(aidlUuid) /* sub-effect descriptor list */,
mFactory);
- mProxyList.emplace_back(std::static_pointer_cast<EffectProxy>(aidlEffect));
} else {
RETURN_STATUS_IF_ERROR(
statusTFromBinderStatus(mFactory->createEffect(aidlUuid, &aidlEffect)));
@@ -205,15 +204,9 @@
}
status_t EffectsFactoryHalAidl::dumpEffects(int fd) {
- status_t ret = OK;
- // record the error ret and continue dump as many effects as possible
- for (const auto& proxy : mProxyList) {
- if (status_t temp = BAD_VALUE; proxy && (temp = proxy->dump(fd, nullptr, 0)) != OK) {
- ret = temp;
- }
- }
+ // TODO: b/333803769 improve the effect dump implementation
RETURN_STATUS_IF_ERROR(mFactory->dump(fd, nullptr, 0));
- return ret;
+ return OK;
}
status_t EffectsFactoryHalAidl::allocateBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) {
diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.h b/media/libaudiohal/impl/EffectsFactoryHalAidl.h
index 73089b0..3b8628c 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalAidl.h
+++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.h
@@ -84,9 +84,6 @@
// Query result of pre and post processing from effect factory
const std::vector<Processing> mAidlProcessings;
- // list of the EffectProxy instances
- std::list<std::shared_ptr<EffectProxy>> mProxyList;
-
virtual ~EffectsFactoryHalAidl() = default;
status_t getHalDescriptorWithImplUuid(
const ::aidl::android::media::audio::common::AudioUuid& uuid,
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index fed2919..70e7949 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -366,24 +366,28 @@
if (mIsInput) {
return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), reply);
} else {
- if (mContext.isAsynchronous()) {
+ if (const auto state = getState(); state == StreamDescriptor::State::IDLE) {
// Handle pause-flush-resume sequence. 'flush' from PAUSED goes to
// IDLE. We move here from IDLE to ACTIVE (same as 'start' from PAUSED).
- const auto state = getState();
- if (state == StreamDescriptor::State::IDLE) {
- StreamDescriptor::Reply localReply{};
- StreamDescriptor::Reply* innerReply = reply ?: &localReply;
- RETURN_STATUS_IF_ERROR(
- sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply));
- if (innerReply->state != StreamDescriptor::State::ACTIVE) {
- ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
- __func__, toString(innerReply->state).c_str());
- return INVALID_OPERATION;
- }
- return OK;
+ StreamDescriptor::Reply localReply{};
+ StreamDescriptor::Reply* innerReply = reply ?: &localReply;
+ RETURN_STATUS_IF_ERROR(
+ sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply));
+ if (innerReply->state != StreamDescriptor::State::ACTIVE) {
+ ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
+ __func__, toString(innerReply->state).c_str());
+ return INVALID_OPERATION;
}
+ return OK;
+ } else if (state == StreamDescriptor::State::PAUSED ||
+ state == StreamDescriptor::State::TRANSFER_PAUSED ||
+ state == StreamDescriptor::State::DRAIN_PAUSED) {
+ return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
+ } else {
+ ALOGE("%s: unexpected stream state: %s (expected IDLE or one of *PAUSED states)",
+ __func__, toString(state).c_str());
+ return INVALID_OPERATION;
}
- return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
}
}
@@ -506,27 +510,31 @@
"%s %s: must be invoked from the worker thread (%d)",
__func__, command.toString().c_str(), workerTid);
}
- if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
- ALOGE("%s: failed to write command %s to MQ", __func__, command.toString().c_str());
- return NOT_ENOUGH_DATA;
- }
StreamDescriptor::Reply localReply{};
- if (reply == nullptr) {
- reply = &localReply;
- }
- if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
- ALOGE("%s: failed to read from reply MQ, command %s", __func__, command.toString().c_str());
- return NOT_ENOUGH_DATA;
- }
{
- std::lock_guard l(mLock);
- // Not every command replies with 'latencyMs' field filled out, substitute the last
- // returned value in that case.
- if (reply->latencyMs <= 0) {
- reply->latencyMs = mLastReply.latencyMs;
+ std::lock_guard l(mCommandReplyLock);
+ if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
+ ALOGE("%s: failed to write command %s to MQ", __func__, command.toString().c_str());
+ return NOT_ENOUGH_DATA;
}
- mLastReply = *reply;
- mLastReplyExpirationNs = uptimeNanos() + mLastReplyLifeTimeNs;
+ if (reply == nullptr) {
+ reply = &localReply;
+ }
+ if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
+ ALOGE("%s: failed to read from reply MQ, command %s",
+ __func__, command.toString().c_str());
+ return NOT_ENOUGH_DATA;
+ }
+ {
+ std::lock_guard l(mLock);
+ // Not every command replies with 'latencyMs' field filled out, substitute the last
+ // returned value in that case.
+ if (reply->latencyMs <= 0) {
+ reply->latencyMs = mLastReply.latencyMs;
+ }
+ mLastReply = *reply;
+ mLastReplyExpirationNs = uptimeNanos() + mLastReplyLifeTimeNs;
+ }
}
switch (reply->status) {
case STATUS_OK: return OK;
diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h
index 53d46e5..b20eb00 100644
--- a/media/libaudiohal/impl/StreamHalAidl.h
+++ b/media/libaudiohal/impl/StreamHalAidl.h
@@ -243,6 +243,15 @@
const bool mIsInput;
const audio_config_base_t mConfig;
const StreamContextAidl mContext;
+ // This lock is used to make sending of a command and receiving a reply an atomic
+ // operation. Otherwise, when two threads are trying to send a command, they may both advance to
+ // reading of the reply once the HAL has consumed the command from the MQ, and that creates a
+ // race condition between them.
+ //
+ // Note that only access to command and reply MQs needs to be protected because the data MQ is
+ // only accessed by the I/O thread. Also, there is no need to protect lookup operations on the
+ // queues as they are thread-safe, only send/receive operation must be protected.
+ std::mutex mCommandReplyLock;
private:
static audio_config_base_t configToBase(const audio_config& config) {
@@ -256,6 +265,8 @@
std::lock_guard l(mLock);
return mLastReply.state;
}
+ // Note: Since `sendCommand` takes mLock while holding mCommandReplyLock, never call
+ // it with `mLock` being held.
status_t sendCommand(
const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command,
::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr,
diff --git a/media/libaudioprocessing/AudioMixerBase.cpp b/media/libaudioprocessing/AudioMixerBase.cpp
index 3d11d92..7e362f7 100644
--- a/media/libaudioprocessing/AudioMixerBase.cpp
+++ b/media/libaudioprocessing/AudioMixerBase.cpp
@@ -1122,7 +1122,7 @@
aux = t->auxBuffer + numFrames;
}
for (int outFrames = frameCount; outFrames > 0; ) {
- // t->in == nullptr can happen if the track was flushed just after having
+ // t->mIn == nullptr can happen if the track was flushed just after having
// been enabled for mixing.
if (t->mIn == nullptr) {
break;
diff --git a/media/libeffects/data/Android.bp b/media/libeffects/data/Android.bp
new file mode 100644
index 0000000..2acf229
--- /dev/null
+++ b/media/libeffects/data/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+prebuilt_etc {
+ name: "framework-audio_effects.xml",
+ src: "audio_effects.xml",
+ filename: "audio_effects.xml",
+}
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
index 9c440df..ada301b 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
@@ -118,26 +118,21 @@
RetCode DynamicsProcessingContext::setPreEq(
const std::vector<DynamicsProcessing::ChannelConfig>& channels) {
- return setDpChannels_l<dp_fx::DPEq>(channels, mEngineArchitecture.preEqStage.inUse,
- StageType::PREEQ);
+ return setDpChannels_l<dp_fx::DPEq>(channels, StageType::PREEQ);
}
RetCode DynamicsProcessingContext::setPostEq(
const std::vector<DynamicsProcessing::ChannelConfig>& channels) {
- return setDpChannels_l<dp_fx::DPEq>(channels, mEngineArchitecture.postEqStage.inUse,
- StageType::POSTEQ);
+ return setDpChannels_l<dp_fx::DPEq>(channels, StageType::POSTEQ);
}
RetCode DynamicsProcessingContext::setMbc(
const std::vector<DynamicsProcessing::ChannelConfig>& channels) {
- return setDpChannels_l<dp_fx::DPMbc>(channels, mEngineArchitecture.mbcStage.inUse,
- StageType::MBC);
+ return setDpChannels_l<dp_fx::DPMbc>(channels, StageType::MBC);
}
RetCode DynamicsProcessingContext::setPreEqBand(
const std::vector<DynamicsProcessing::EqBandConfig>& bands) {
- RETURN_VALUE_IF(!mEngineArchitecture.preEqStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
- "preEqNotInUse");
RETURN_VALUE_IF(
!validateBandConfig(bands, mChannelCount, mEngineArchitecture.preEqStage.bandCount),
RetCode::ERROR_ILLEGAL_PARAMETER, "eqBandNotValid");
@@ -146,8 +141,6 @@
RetCode DynamicsProcessingContext::setPostEqBand(
const std::vector<DynamicsProcessing::EqBandConfig>& bands) {
- RETURN_VALUE_IF(!mEngineArchitecture.postEqStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
- "postEqNotInUse");
RETURN_VALUE_IF(
!validateBandConfig(bands, mChannelCount, mEngineArchitecture.postEqStage.bandCount),
RetCode::ERROR_ILLEGAL_PARAMETER, "eqBandNotValid");
@@ -156,8 +149,6 @@
RetCode DynamicsProcessingContext::setMbcBand(
const std::vector<DynamicsProcessing::MbcBandConfig>& bands) {
- RETURN_VALUE_IF(!mEngineArchitecture.mbcStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
- "mbcNotInUse");
RETURN_VALUE_IF(
!validateBandConfig(bands, mChannelCount, mEngineArchitecture.mbcStage.bandCount),
RetCode::ERROR_ILLEGAL_PARAMETER, "eqBandNotValid");
@@ -166,8 +157,6 @@
RetCode DynamicsProcessingContext::setLimiter(
const std::vector<DynamicsProcessing::LimiterConfig>& limiters) {
- RETURN_VALUE_IF(!mEngineArchitecture.limiterInUse, RetCode::ERROR_ILLEGAL_PARAMETER,
- "limiterNotInUse");
RETURN_VALUE_IF(!validateLimiterConfig(limiters, mChannelCount),
RetCode::ERROR_ILLEGAL_PARAMETER, "limiterConfigNotValid");
return setBands_l<DynamicsProcessing::LimiterConfig>(limiters, StageType::LIMITER);
@@ -419,9 +408,7 @@
}
freqs[band.band] = band.cutoffFrequencyHz;
}
- return std::is_sorted(freqs.begin(), freqs.end(), [](const auto& a, const auto& b) {
- return a.second <= b.second; //index is already sorted as map key
- });
+ return true;
}
bool DynamicsProcessingContext::validateLimiterConfig(
@@ -442,17 +429,10 @@
template <typename D>
RetCode DynamicsProcessingContext::setDpChannels_l(
- const std::vector<DynamicsProcessing::ChannelConfig>& channels, bool stageInUse,
- StageType type) {
+ const std::vector<DynamicsProcessing::ChannelConfig>& channels, StageType type) {
RetCode ret = RetCode::SUCCESS;
std::unordered_set<int> channelSet;
- if (!stageInUse) {
- LOG(WARNING) << __func__ << " not in use " << ::android::internal::ToString(channels);
- return RetCode::ERROR_ILLEGAL_PARAMETER;
- }
-
- RETURN_VALUE_IF(!stageInUse, RetCode::ERROR_ILLEGAL_PARAMETER, "stageNotInUse");
for (auto& it : channels) {
if (0 != channelSet.count(it.channel)) {
LOG(WARNING) << __func__ << " duplicated channel " << it.channel;
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
index a059dd0..ce657db 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
@@ -99,7 +99,7 @@
dp_fx::DPEq* getEqWithType_l(StageType type, int ch);
template <typename D>
RetCode setDpChannels_l(const std::vector<DynamicsProcessing::ChannelConfig>& channels,
- bool stageInUse, StageType type);
+ StageType type);
template <typename T /* BandConfig */>
RetCode setBands_l(const std::vector<T>& bands, StageType type);
RetCode setDpChannelBand_l(const std::any& anyConfig, StageType type,
diff --git a/media/libeffects/visualizer/aidl/Visualizer.cpp b/media/libeffects/visualizer/aidl/Visualizer.cpp
index 9c2b71e..9b493d4 100644
--- a/media/libeffects/visualizer/aidl/Visualizer.cpp
+++ b/media/libeffects/visualizer/aidl/Visualizer.cpp
@@ -72,7 +72,7 @@
.uuid = getEffectImplUuidVisualizer(),
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
- .insert = Flags::Insert::LAST,
+ .insert = Flags::Insert::FIRST,
.volume = Flags::Volume::NONE},
.name = VisualizerImpl::kEffectName,
.implementor = "The Android Open Source Project"},
diff --git a/media/libheif/OWNERS b/media/libheif/OWNERS
new file mode 100644
index 0000000..a61ad21
--- /dev/null
+++ b/media/libheif/OWNERS
@@ -0,0 +1,2 @@
+include platform/frameworks/av:/media/janitors/avic_OWNERS
+include platform/frameworks/av:/media/janitors/codec_OWNERS
\ No newline at end of file
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index bb49b5a..bd43fe2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -2098,9 +2098,12 @@
displayHeight,
cropLeft, cropTop);
} else {
- CHECK(inputFormat->findInt32("width", &displayWidth));
- CHECK(inputFormat->findInt32("height", &displayHeight));
-
+ if (!inputFormat->findInt32("width", &displayWidth)
+ || !inputFormat->findInt32("height", &displayHeight)) {
+ ALOGW("Either video width or video height missing, reporting 0x0!");
+ notifyListener(MEDIA_SET_VIDEO_SIZE, 0, 0);
+ return;
+ }
ALOGV("Video input format %d x %d", displayWidth, displayHeight);
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 1593aa0..e06efac 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -7575,6 +7575,22 @@
return true;
}
+ // When Acodec receive an error event at LoadedToIdleState, it will not release
+ // allocated buffers, which will cause gralloc buffer leak issue. We need to first release
+ // these buffers and then process the error event
+ case OMX_EventError:
+ {
+ if (mCodec->allYourBuffersAreBelongToUs(kPortIndexInput)) {
+ mCodec->freeBuffersOnPort(kPortIndexInput);
+ }
+
+ if (mCodec->allYourBuffersAreBelongToUs(kPortIndexOutput)) {
+ mCodec->freeBuffersOnPort(kPortIndexOutput);
+ }
+
+ return BaseState::onOMXEvent(event, data1, data2);
+ }
+
default:
return BaseState::onOMXEvent(event, data1, data2);
}
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 886285e..c9a2eea 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -318,6 +318,10 @@
"aconfig_mediacodec_flags_c_lib",
],
+ defaults: [
+ "aconfig_lib_cc_static_link.defaults",
+ ],
+
static_libs: [
"android.media.codec-aconfig-cc",
"libstagefright_esds",
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 19e51fd..0401e82 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -3975,6 +3975,15 @@
switch (mState) {
case INITIALIZING:
{
+ // Resource error during INITIALIZING state needs to be logged
+ // through metrics, to be able to track such occurrences.
+ if (isResourceError(err)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecError, err);
+ mediametrics_setCString(mMetricsHandle, kCodecErrorState,
+ stateString(mState).c_str());
+ flushMediametrics();
+ initMediametrics();
+ }
setState(UNINITIALIZED);
break;
}
@@ -4912,8 +4921,8 @@
if (flags & CONFIGURE_FLAG_USE_CRYPTO_ASYNC) {
mFlags |= kFlagUseCryptoAsync;
if ((mFlags & kFlagUseBlockModel)) {
- ALOGW("CrytoAsync not yet enabled for block model,\
- falling back to normal");
+ ALOGW("CrytoAsync not yet enabled for block model, "
+ "falling back to normal");
}
}
}
@@ -4970,8 +4979,7 @@
mDescrambler = static_cast<IDescrambler *>(descrambler);
mBufferChannel->setDescrambler(mDescrambler);
- if ((mFlags & kFlagUseCryptoAsync) &&
- mCrypto && (mDomain == DOMAIN_VIDEO)) {
+ if ((mFlags & kFlagUseCryptoAsync) && mCrypto) {
// set kFlagUseCryptoAsync but do-not use this for block model
// this is to propagate the error in onCryptoError()
// TODO (b/274628160): Enable Use of CONFIG_FLAG_USE_CRYPTO_ASYNC
@@ -6052,6 +6060,10 @@
mErrorLog.clear();
}
+ if (android::media::codec::provider_->set_state_early()) {
+ mState = newState;
+ }
+
if (newState == UNINITIALIZED) {
// return any straggling buffers, e.g. if we got here on an error
returnBuffersToCodec();
@@ -6062,7 +6074,9 @@
mFlags &= ~kFlagSawMediaServerDie;
}
- mState = newState;
+ if (!android::media::codec::provider_->set_state_early()) {
+ mState = newState;
+ }
if (mBatteryChecker != nullptr) {
mBatteryChecker->setExecuting(isExecuting());
@@ -6263,15 +6277,8 @@
cryptoInfo->setInt32("secure", mFlags & kFlagIsSecure);
sp<RefBase> obj;
if (msg->findObject("cryptoInfos", &obj)) {
- sp<CryptoInfosWrapper> infos{(CryptoInfosWrapper*)obj.get()};
- sp<CryptoInfosWrapper> asyncInfos{
- new CryptoInfosWrapper(std::vector<std::unique_ptr<CodecCryptoInfo>>())};
- for (std::unique_ptr<CodecCryptoInfo> &info : infos->value) {
- if (info) {
- asyncInfos->value.emplace_back(new CryptoAsync::CryptoAsyncInfo(info));
- }
- }
- buffer->meta()->setObject("cryptoInfos", asyncInfos);
+ // this object is a standalone object when created (no copy requied here)
+ buffer->meta()->setObject("cryptoInfos", obj);
} else {
size_t key_len = (key != nullptr)? 16 : 0;
size_t iv_len = (iv != nullptr)? 16 : 0;
@@ -6410,7 +6417,6 @@
}
}
if (mCryptoAsync) {
- // TODO b/316565675 - enable async path for audio
// prepare a message and enqueue
sp<AMessage> cryptoInfo = new AMessage();
buildCryptoInfoAMessage(cryptoInfo, CryptoAsync::kActionDecrypt);
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index 0e89521..d50bc1e 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -139,6 +139,7 @@
<Limit name="bitrate" range="1-40000000" />
</Variant>
<Feature name="adaptive-playback" />
+ <Feature name="dynamic-color-aspects" />
<Attribute name="software-codec" />
</MediaCodec>
<MediaCodec name="c2.android.hevc.decoder" type="video/hevc" variant="slow-cpu,!slow-cpu">
@@ -160,6 +161,7 @@
<Limit name="bitrate" range="1-5000000" />
</Variant>
<Feature name="adaptive-playback" />
+ <Feature name="dynamic-color-aspects" />
<Attribute name="software-codec" />
</MediaCodec>
<MediaCodec name="c2.android.vp8.decoder" type="video/x-vnd.on2.vp8" variant="slow-cpu,!slow-cpu">
@@ -178,6 +180,7 @@
<Limit name="bitrate" range="1-40000000" />
</Variant>
<Feature name="adaptive-playback" />
+ <Feature name="dynamic-color-aspects" />
<Attribute name="software-codec" />
</MediaCodec>
<MediaCodec name="c2.android.vp9.decoder" type="video/x-vnd.on2.vp9" variant="slow-cpu,!slow-cpu">
@@ -197,6 +200,7 @@
<Limit name="bitrate" range="1-5000000" />
</Variant>
<Feature name="adaptive-playback" />
+ <Feature name="dynamic-color-aspects" />
<Attribute name="software-codec" />
</MediaCodec>
<MediaCodec name="c2.android.av1.decoder" type="video/av01" variant="slow-cpu,!slow-cpu">
@@ -216,6 +220,8 @@
<Limit name="bitrate" range="1-5000000" />
</Variant>
<Feature name="adaptive-playback" />
+ <Feature name="dynamic-color-aspects" />
+ <Feature name="low-latency" />
<Attribute name="software-codec" />
</MediaCodec>
<MediaCodec name="c2.android.av1-dav1d.decoder" type="video/av01" variant="slow-cpu,!slow-cpu" rank="1024">
@@ -234,6 +240,8 @@
<Limit name="bitrate" range="1-5000000" />
</Variant>
<Feature name="adaptive-playback" />
+ <Feature name="dynamic-color-aspects" />
+ <Feature name="low-latency" />
<Attribute name="software-codec" />
</MediaCodec>
<MediaCodec name="c2.android.mpeg2.decoder" type="video/mpeg2" domain="tv">
@@ -351,6 +359,7 @@
<Limit name="bitrate" range="1-20000000" />
</Variant>
<Feature name="bitrate-modes" value="VBR,CBR" />
+ <Feature name="qp-bounds" />
<Attribute name="software-codec" />
</MediaCodec>
<MediaCodec name="c2.android.hevc.encoder" type="video/hevc" variant="!slow-cpu">
@@ -365,6 +374,7 @@
<Limit name="complexity" range="0-10" default="0" />
<Limit name="quality" range="0-100" default="80" />
<Feature name="bitrate-modes" value="VBR,CBR,CQ" />
+ <Feature name="qp-bounds" />
<Attribute name="software-codec" />
</MediaCodec>
<MediaCodec name="c2.android.vp9.encoder" type="video/x-vnd.on2.vp9" variant="!slow-cpu">
@@ -377,6 +387,7 @@
<Limit name="block-count" range="1-3600" /> <!-- max 1280x720 -->
<Limit name="bitrate" range="1-40000000" />
<Feature name="bitrate-modes" value="VBR,CBR" />
+ <Feature name="qp-bounds" />
<Attribute name="software-codec" />
</MediaCodec>
<MediaCodec name="c2.android.av1.encoder" type="video/av01" enabled="false" minsdk="34" variant="slow-cpu,!slow-cpu">
@@ -395,6 +406,7 @@
<Limit name="quality" range="0-100" default="80" />
<Limit name="complexity" range="0-5" default="0" />
<Feature name="bitrate-modes" value="VBR,CBR,CQ" />
+ <Feature name="qp-bounds" />
<Attribute name="software-codec" />
</MediaCodec>
</Encoders>
diff --git a/media/libstagefright/tests/fuzzers/Android.bp b/media/libstagefright/tests/fuzzers/Android.bp
index 2bcfd67..43542c5 100644
--- a/media/libstagefright/tests/fuzzers/Android.bp
+++ b/media/libstagefright/tests/fuzzers/Android.bp
@@ -32,6 +32,15 @@
"liblog",
"media_permission-aidl-cpp",
],
+ fuzz_config: {
+ componentid: 42195,
+ hotlists: ["4593311"],
+ description: "The fuzzer targets the APIs of libstagefright",
+ vector: "local_no_privileges_required",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
+ },
}
cc_fuzz {
diff --git a/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp b/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
index 4218d2d..3f850c2 100644
--- a/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
+++ b/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
@@ -24,61 +24,64 @@
namespace android {
-#define MAX_MEDIA_BUFFER_SIZE 2048
+static const android_pixel_format_t kColorFormats[] = {
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ HAL_PIXEL_FORMAT_RGB_565,
+ HAL_PIXEL_FORMAT_BGRA_8888,
+ HAL_PIXEL_FORMAT_RGBA_1010102,
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, /* To cover the default case */
+};
-// Fuzzer entry point.
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
- // Init our wrapper
+static const MediaSource::ReadOptions::SeekMode kSeekModes[] = {
+ MediaSource::ReadOptions::SeekMode::SEEK_PREVIOUS_SYNC,
+ MediaSource::ReadOptions::SeekMode::SEEK_NEXT_SYNC,
+ MediaSource::ReadOptions::SeekMode::SEEK_CLOSEST_SYNC,
+ MediaSource::ReadOptions::SeekMode::SEEK_CLOSEST,
+ MediaSource::ReadOptions::SeekMode::SEEK_FRAME_INDEX,
+};
+
+static const std::string kComponentNames[] = {
+ "c2.android.avc.decoder", "c2.android.hevc.decoder", "c2.android.vp8.decoder",
+ "c2.android.vp9.decoder", "c2.android.av1.decoder", "c2.android.mpeg4.decoder",
+ "c2.android.h263.decoder",
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
FuzzedDataProvider fdp(data, size);
+ std::string component = fdp.PickValueInArray(kComponentNames);
+ AString componentName(component.c_str());
+ sp<MetaData> trackMeta = generateMetaData(&fdp, component);
+ sp<IMediaSource> source = sp<IMediaSourceFuzzImpl>::make(&fdp, gMaxMediaBufferSize);
- std::string name = fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
- AString componentName(name.c_str());
- sp<MetaData> trackMeta = generateMetaData(&fdp);
- sp<IMediaSource> source = new IMediaSourceFuzzImpl(&fdp, MAX_MEDIA_BUFFER_SIZE);
-
- // Image or video Decoder?
- sp<FrameDecoder> decoder;
- bool isVideoDecoder = fdp.ConsumeBool();
- if (isVideoDecoder) {
- decoder = new VideoFrameDecoder(componentName, trackMeta, source);
+ sp<FrameDecoder> decoder = nullptr;
+ if (fdp.ConsumeBool()) {
+ decoder = sp<MediaImageDecoder>::make(componentName, trackMeta, source);
} else {
- decoder = new MediaImageDecoder(componentName, trackMeta, source);
+ decoder = sp<VideoFrameDecoder>::make(componentName, trackMeta, source);
}
- while (fdp.remaining_bytes()) {
- uint8_t switchCase = fdp.ConsumeIntegralInRange<uint8_t>(0, 3);
- switch (switchCase) {
- case 0: {
- int64_t frameTimeUs = fdp.ConsumeIntegral<int64_t>();
- int option = fdp.ConsumeIntegral<int>();
- int colorFormat = fdp.ConsumeIntegral<int>();
- decoder->init(frameTimeUs, option, colorFormat);
- break;
- }
- case 1:
- decoder->extractFrame();
- break;
- case 2: {
- FrameRect rect;
- rect.left = fdp.ConsumeIntegral<int32_t>();
- rect.top = fdp.ConsumeIntegral<int32_t>();
- rect.right = fdp.ConsumeIntegral<int32_t>();
- rect.bottom = fdp.ConsumeIntegral<int32_t>();
- decoder->extractFrame(&rect);
- break;
- }
- case 3: {
- sp<MetaData> trackMeta = generateMetaData(&fdp);
- decoder->getMetadataOnly(trackMeta,
- /*colorFormat*/ fdp.ConsumeIntegral<int>(),
- /*thumbnail*/ fdp.ConsumeBool());
- break;
- }
- }
+ if (decoder.get() &&
+ decoder->init(fdp.ConsumeIntegral<uint64_t>() /* frameTimeUs */,
+ fdp.PickValueInArray(kSeekModes) /* option */,
+ fdp.PickValueInArray(kColorFormats) /* colorFormat */) == OK) {
+ auto frameDecoderAPI = fdp.PickValueInArray<const std::function<void()>>({
+ [&]() { decoder->extractFrame(); },
+ [&]() {
+ FrameRect rect(fdp.ConsumeIntegral<int32_t>() /* left */,
+ fdp.ConsumeIntegral<int32_t>() /* top */,
+ fdp.ConsumeIntegral<int32_t>() /* right */,
+ fdp.ConsumeIntegral<int32_t>() /* bottom */
+ );
+ decoder->extractFrame(&rect);
+ },
+ [&]() {
+ FrameDecoder::getMetadataOnly(
+ trackMeta, fdp.PickValueInArray(kColorFormats) /* colorFormat */,
+ fdp.ConsumeBool() /* thumbnail */);
+ },
+ });
+ frameDecoderAPI();
}
-
- generated_mime_types.clear();
-
return 0;
}
diff --git a/media/libstagefright/tests/fuzzers/FrameDecoderHelpers.h b/media/libstagefright/tests/fuzzers/FrameDecoderHelpers.h
index 228c04a..5430530 100644
--- a/media/libstagefright/tests/fuzzers/FrameDecoderHelpers.h
+++ b/media/libstagefright/tests/fuzzers/FrameDecoderHelpers.h
@@ -20,69 +20,100 @@
#include <media/stagefright/MetaData.h>
#include "MediaMimeTypes.h"
-#define MAX_METADATA_BUF_SIZE 512
-
namespace android {
std::vector<std::shared_ptr<char>> generated_mime_types;
+constexpr uint8_t kMinKeyHeight = 32;
+constexpr uint8_t kMinKeyWidth = 32;
+constexpr uint16_t kMaxKeyHeight = 2160;
+constexpr uint16_t kMaxKeyWidth = 3840;
+size_t gMaxMediaBufferSize = 0;
-sp<MetaData> generateMetaData(FuzzedDataProvider *fdp) {
- sp<MetaData> newMeta = new MetaData();
+sp<MetaData> generateMetaData(FuzzedDataProvider* fdp, std::string componentName = std::string()) {
+ sp<MetaData> newMeta = sp<MetaData>::make();
- // random MIME Type
- const char *mime_type;
- size_t index = fdp->ConsumeIntegralInRange<size_t>(0, kMimeTypes.size());
- // Let there be a chance of a true random string
- if (index == kMimeTypes.size()) {
- std::string mime_str = fdp->ConsumeRandomLengthString(64);
- std::shared_ptr<char> mime_cstr(new char[mime_str.length()+1]);
- generated_mime_types.push_back(mime_cstr);
- strncpy(mime_cstr.get(), mime_str.c_str(), mime_str.length()+1);
- mime_type = mime_cstr.get();
- } else {
- mime_type = kMimeTypes[index];
+ const char* mime;
+ if(!componentName.empty())
+ {
+ auto it = decoderToMediaType.find(componentName);
+ mime = it->second;
}
- newMeta->setCString(kKeyMIMEType, mime_type);
+ else{
+ size_t index = fdp->ConsumeIntegralInRange<size_t>(0, kMimeTypes.size());
+ // Let there be a chance of a true random string
+ if (index == kMimeTypes.size()) {
+ std::string mime_str = fdp->ConsumeRandomLengthString(64);
+ std::shared_ptr<char> mime_cstr(new char[mime_str.length()+1]);
+ generated_mime_types.push_back(mime_cstr);
+ strncpy(mime_cstr.get(), mime_str.c_str(), mime_str.length()+1);
+ mime = mime_cstr.get();
+ } else {
+ mime = kMimeTypes[index];
+ }
+ }
+ newMeta->setCString(kKeyMIMEType, mime);
- // Thumbnail time
- newMeta->setInt64(kKeyThumbnailTime, fdp->ConsumeIntegral<int64_t>());
+ auto height = fdp->ConsumeIntegralInRange<uint16_t>(kMinKeyHeight, kMaxKeyHeight);
+ auto width = fdp->ConsumeIntegralInRange<uint16_t>(kMinKeyWidth, kMaxKeyWidth);
+ newMeta->setInt32(kKeyHeight, height);
+ newMeta->setInt32(kKeyWidth, width);
- // Values used by allocVideoFrame
- newMeta->setInt32(kKeyRotation, fdp->ConsumeIntegral<int32_t>());
- size_t profile_size =
- fdp->ConsumeIntegralInRange<size_t>(0, MAX_METADATA_BUF_SIZE);
- std::vector<uint8_t> profile_bytes =
- fdp->ConsumeBytes<uint8_t>(profile_size);
- newMeta->setData(kKeyIccProfile,
- fdp->ConsumeIntegral<int32_t>(),
- profile_bytes.empty() ? nullptr : profile_bytes.data(),
- profile_bytes.size());
- newMeta->setInt32(kKeySARWidth, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeySARHeight, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeyDisplayWidth, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeyDisplayHeight, fdp->ConsumeIntegral<int32_t>());
+ gMaxMediaBufferSize = height * width;
- // Values used by findThumbnailInfo
- newMeta->setInt32(kKeyThumbnailWidth, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeyThumbnailHeight, fdp->ConsumeIntegral<int32_t>());
- size_t thumbnail_size =
- fdp->ConsumeIntegralInRange<size_t>(0, MAX_METADATA_BUF_SIZE);
- std::vector<uint8_t> thumb_bytes =
- fdp->ConsumeBytes<uint8_t>(thumbnail_size);
- newMeta->setData(kKeyThumbnailHVCC,
- fdp->ConsumeIntegral<int32_t>(),
- thumb_bytes.empty() ? nullptr : thumb_bytes.data(),
- thumb_bytes.size());
+ if (fdp->ConsumeBool()) {
+ newMeta->setInt32(kKeyTileHeight,
+ fdp->ConsumeIntegralInRange<uint16_t>(kMinKeyHeight, height));
+ newMeta->setInt32(kKeyTileWidth,
+ fdp->ConsumeIntegralInRange<uint16_t>(kMinKeyWidth, width));
+ newMeta->setInt32(kKeyGridRows, fdp->ConsumeIntegral<uint8_t>());
+ newMeta->setInt32(kKeyGridCols, fdp->ConsumeIntegral<uint8_t>());
+ }
- // Values used by findGridInfo
- newMeta->setInt32(kKeyTileWidth, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeyTileHeight, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeyGridRows, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeyGridCols, fdp->ConsumeIntegral<int32_t>());
+ if (fdp->ConsumeBool()) {
+ newMeta->setInt32(kKeySARHeight, fdp->ConsumeIntegral<uint8_t>());
+ newMeta->setInt32(kKeySARWidth, fdp->ConsumeIntegral<uint8_t>());
+ }
- // A few functions perform a CHECK() that height/width are set
- newMeta->setInt32(kKeyHeight, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeyWidth, fdp->ConsumeIntegral<int32_t>());
+ if (fdp->ConsumeBool()) {
+ newMeta->setInt32(kKeyDisplayHeight,
+ fdp->ConsumeIntegralInRange<uint16_t>(height, UINT16_MAX));
+ newMeta->setInt32(kKeyDisplayWidth,
+ fdp->ConsumeIntegralInRange<uint16_t>(width, UINT16_MAX));
+ }
+
+ if (fdp->ConsumeBool()) {
+ newMeta->setRect(kKeyCropRect, fdp->ConsumeIntegral<int32_t>() /* left */,
+ fdp->ConsumeIntegral<int32_t>() /* top */,
+ fdp->ConsumeIntegral<int32_t>() /* right */,
+ fdp->ConsumeIntegral<int32_t>() /* bottom */);
+ }
+
+ if (fdp->ConsumeBool()) {
+ newMeta->setInt32(kKeyRotation, fdp->ConsumeIntegralInRange<uint8_t>(0, 3) * 90);
+ }
+
+ if (fdp->ConsumeBool()) {
+ newMeta->setInt64(kKeyThumbnailTime, fdp->ConsumeIntegral<uint64_t>());
+ newMeta->setInt32(kKeyThumbnailHeight, fdp->ConsumeIntegral<uint8_t>());
+ newMeta->setInt32(kKeyThumbnailWidth, fdp->ConsumeIntegral<uint8_t>());
+
+ size_t thumbnailSize = fdp->ConsumeIntegral<size_t>();
+ std::vector<uint8_t> thumbnailData = fdp->ConsumeBytes<uint8_t>(thumbnailSize);
+ if (mime == MEDIA_MIMETYPE_VIDEO_AV1) {
+ newMeta->setData(kKeyThumbnailAV1C, fdp->ConsumeIntegral<int32_t>() /* type */,
+ thumbnailData.data(), thumbnailData.size());
+ } else {
+ newMeta->setData(kKeyThumbnailHVCC, fdp->ConsumeIntegral<int32_t>() /* type */,
+ thumbnailData.data(), thumbnailData.size());
+ }
+ }
+
+ if (fdp->ConsumeBool()) {
+ size_t profileSize = fdp->ConsumeIntegral<size_t>();
+ std::vector<uint8_t> profileData = fdp->ConsumeBytes<uint8_t>(profileSize);
+ newMeta->setData(kKeyIccProfile, fdp->ConsumeIntegral<int32_t>() /* type */,
+ profileData.data(), profileData.size());
+ }
return newMeta;
}
diff --git a/media/libstagefright/tests/fuzzers/IMediaSourceFuzzImpl.h b/media/libstagefright/tests/fuzzers/IMediaSourceFuzzImpl.h
index e769950..7e6f662 100644
--- a/media/libstagefright/tests/fuzzers/IMediaSourceFuzzImpl.h
+++ b/media/libstagefright/tests/fuzzers/IMediaSourceFuzzImpl.h
@@ -19,31 +19,33 @@
#include <media/stagefright/MediaSource.h>
+#define MAX_FRAMES 5
+
namespace android {
class IMediaSourceFuzzImpl : public IMediaSource {
public:
- IMediaSourceFuzzImpl(FuzzedDataProvider *_fdp, size_t _max_buffer_size) :
- fdp(_fdp),
- max_buffer_size(_max_buffer_size) {}
- status_t start(MetaData*) override { return 0; }
- status_t stop() override { return 0; }
- sp<MetaData> getFormat() override { return nullptr; }
- status_t read(MediaBufferBase**,
- const MediaSource::ReadOptions*) override;
- status_t readMultiple(Vector<MediaBufferBase*>*, uint32_t,
- const MediaSource::ReadOptions*) override;
- bool supportReadMultiple() override { return true; }
- bool supportNonblockingRead() override { return true; }
- status_t pause() override { return 0; }
+ IMediaSourceFuzzImpl(FuzzedDataProvider* _fdp, size_t _max_buffer_size)
+ : frames_read(0), fdp(_fdp), min_buffer_size(32 * 32), max_buffer_size(_max_buffer_size) {}
+ status_t start(MetaData*) override { return 0; }
+ status_t stop() override { return 0; }
+ sp<MetaData> getFormat() override { return nullptr; }
+ status_t read(MediaBufferBase**, const MediaSource::ReadOptions*) override;
+ status_t readMultiple(Vector<MediaBufferBase*>*, uint32_t,
+ const MediaSource::ReadOptions*) override;
+ bool supportReadMultiple() override { return true; }
+ bool supportNonblockingRead() override { return true; }
+ status_t pause() override { return 0; }
protected:
IBinder* onAsBinder() { return nullptr; }
private:
- FuzzedDataProvider *fdp;
- std::vector<std::shared_ptr<MediaBufferBase>> buffer_bases;
- const size_t max_buffer_size;
+ uint8_t frames_read;
+ FuzzedDataProvider* fdp;
+ const size_t min_buffer_size;
+ const size_t max_buffer_size;
+ std::vector<uint8_t> buf;
};
// This class is simply to expose the destructor
@@ -53,32 +55,41 @@
~MediaBufferFuzzImpl() {}
};
-status_t IMediaSourceFuzzImpl::read(MediaBufferBase **buffer,
- const MediaSource::ReadOptions *options) {
+status_t IMediaSourceFuzzImpl::read(MediaBufferBase** buffer, const MediaSource::ReadOptions*) {
Vector<MediaBufferBase*> buffers;
- status_t ret = readMultiple(&buffers, 1, options);
+ status_t ret = readMultiple(&buffers, 1, nullptr);
*buffer = buffers.empty() ? nullptr : buffers[0];
return ret;
}
-status_t IMediaSourceFuzzImpl::readMultiple(Vector<MediaBufferBase*>* buffers,
- uint32_t maxNumBuffers, const MediaSource::ReadOptions*) {
- uint32_t num_buffers =
- fdp->ConsumeIntegralInRange<uint32_t>(0, maxNumBuffers);
- for(uint32_t i = 0; i < num_buffers; i++) {
- std::vector<uint8_t> buf = fdp->ConsumeBytes<uint8_t>(
- fdp->ConsumeIntegralInRange<size_t>(0, max_buffer_size));
+status_t IMediaSourceFuzzImpl::readMultiple(Vector<MediaBufferBase*>* buffers, uint32_t,
+ const MediaSource::ReadOptions*) {
+ if (++frames_read == MAX_FRAMES) {
+ auto size = fdp->ConsumeIntegralInRange<size_t>(min_buffer_size, max_buffer_size);
+ buf = fdp->ConsumeBytes<uint8_t>(size);
+ if (buf.size() < size) {
+ buf.resize(size, 0);
+ }
- std::shared_ptr<MediaBufferBase> mbb(
- new MediaBufferFuzzImpl(buf.data(), buf.size()));
+ MediaBufferBase* mbb = new MediaBufferFuzzImpl(buf.data(), buf.size());
+ mbb->meta_data().setInt64(kKeyTime, fdp->ConsumeIntegral<uint64_t>());
+ buffers->push_back(mbb);
- buffer_bases.push_back(mbb);
- buffers->push_back(mbb.get());
+ return ERROR_END_OF_STREAM;
}
- // STATUS_OK
- return 0;
+ auto size = fdp->ConsumeIntegralInRange<size_t>(min_buffer_size, max_buffer_size);
+ buf = fdp->ConsumeBytes<uint8_t>(size);
+ if (buf.size() < size) {
+ buf.resize(size, 0);
+ }
+
+ MediaBufferBase* mbb = new MediaBufferFuzzImpl(buf.data(), buf.size());
+ mbb->meta_data().setInt64(kKeyTime, fdp->ConsumeIntegral<uint64_t>());
+ buffers->push_back(mbb);
+
+ return OK;
}
} // namespace android
diff --git a/media/libstagefright/tests/fuzzers/MediaMimeTypes.h b/media/libstagefright/tests/fuzzers/MediaMimeTypes.h
index 9f337ac..de7814e 100644
--- a/media/libstagefright/tests/fuzzers/MediaMimeTypes.h
+++ b/media/libstagefright/tests/fuzzers/MediaMimeTypes.h
@@ -18,6 +18,7 @@
#define FUZZER_MEDIAMIMETYPES_H_
#include <media/stagefright/foundation/MediaDefs.h>
+#include <unordered_map>
namespace android {
@@ -80,6 +81,15 @@
MEDIA_MIMETYPE_DATA_TIMED_ID3
};
+static const std::unordered_map<std::string, const char*> decoderToMediaType = {
+ {"c2.android.vp8.decoder", MEDIA_MIMETYPE_VIDEO_VP8},
+ {"c2.android.vp9.decoder", MEDIA_MIMETYPE_VIDEO_VP9},
+ {"c2.android.av1.decoder", MEDIA_MIMETYPE_VIDEO_AV1},
+ {"c2.android.avc.decoder", MEDIA_MIMETYPE_VIDEO_AVC},
+ {"c2.android.hevc.decoder", MEDIA_MIMETYPE_VIDEO_HEVC},
+ {"c2.android.mpeg4.decoder", MEDIA_MIMETYPE_VIDEO_MPEG4},
+ {"c2.android.h263.decoder", MEDIA_MIMETYPE_VIDEO_H263}};
+
} // namespace android
#endif // FUZZER_MEDIAMIMETYPES_H_
diff --git a/media/libstagefright/tests/fuzzers/MediaMuxerFuzzer.cpp b/media/libstagefright/tests/fuzzers/MediaMuxerFuzzer.cpp
index 70d73c8..5ac2a54 100644
--- a/media/libstagefright/tests/fuzzers/MediaMuxerFuzzer.cpp
+++ b/media/libstagefright/tests/fuzzers/MediaMuxerFuzzer.cpp
@@ -13,94 +13,221 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-// Authors: corbin.souffrant@leviathansecurity.com
-// dylan.katz@leviathansecurity.com
-#include <MediaMuxerFuzzer.h>
-#include <cutils/ashmem.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <media/stagefright/MediaMuxer.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/MediaDefs.h>
namespace android {
+const uint8_t kMinSize = 0;
+const uint8_t kMinTrackCount = 0;
-// Can't seem to get setBuffer or setString working. It always segfaults on a
-// null pointer read or memleaks. So that functionality is missing.
-void createMessage(AMessage *msg, FuzzedDataProvider *fdp) {
- size_t count = fdp->ConsumeIntegralInRange<size_t>(0, 32);
- while (fdp->remaining_bytes() > 0 && count > 0) {
- uint8_t function_id =
- fdp->ConsumeIntegralInRange<uint8_t>(0, amessage_setvals.size() - 1);
- amessage_setvals[function_id](msg, fdp);
- count--;
- }
+enum kBufferFlags { BUFFER_FLAG_SYNCFRAME = 1, BUFFER_FLAG_CODECCONFIG = 2, BUFFER_FLAG_EOS = 4 };
+
+constexpr char kMuxerFile[] = "MediaMuxer";
+
+const std::string kAudioMimeTypes[] = {
+ MEDIA_MIMETYPE_AUDIO_AMR_NB,
+ MEDIA_MIMETYPE_AUDIO_AMR_WB,
+ MEDIA_MIMETYPE_AUDIO_MPEG,
+ MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I,
+ MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
+ MEDIA_MIMETYPE_AUDIO_MIDI,
+ MEDIA_MIMETYPE_AUDIO_AAC,
+ MEDIA_MIMETYPE_AUDIO_QCELP,
+ MEDIA_MIMETYPE_AUDIO_VORBIS,
+ MEDIA_MIMETYPE_AUDIO_OPUS,
+ MEDIA_MIMETYPE_AUDIO_G711_ALAW,
+ MEDIA_MIMETYPE_AUDIO_G711_MLAW,
+ MEDIA_MIMETYPE_AUDIO_RAW,
+ MEDIA_MIMETYPE_AUDIO_FLAC,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS,
+ MEDIA_MIMETYPE_AUDIO_MSGSM,
+ MEDIA_MIMETYPE_AUDIO_AC3,
+ MEDIA_MIMETYPE_AUDIO_EAC3,
+ MEDIA_MIMETYPE_AUDIO_EAC3_JOC,
+ MEDIA_MIMETYPE_AUDIO_AC4,
+ MEDIA_MIMETYPE_AUDIO_MPEGH_MHA1,
+ MEDIA_MIMETYPE_AUDIO_MPEGH_MHM1,
+ MEDIA_MIMETYPE_AUDIO_MPEGH_BL_L3,
+ MEDIA_MIMETYPE_AUDIO_MPEGH_BL_L4,
+ MEDIA_MIMETYPE_AUDIO_MPEGH_LC_L3,
+ MEDIA_MIMETYPE_AUDIO_MPEGH_LC_L4,
+ MEDIA_MIMETYPE_AUDIO_SCRAMBLED,
+ MEDIA_MIMETYPE_AUDIO_ALAC,
+ MEDIA_MIMETYPE_AUDIO_WMA,
+ MEDIA_MIMETYPE_AUDIO_MS_ADPCM,
+ MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM,
+ MEDIA_MIMETYPE_AUDIO_DTS,
+ MEDIA_MIMETYPE_AUDIO_DTS_HD,
+ MEDIA_MIMETYPE_AUDIO_DTS_HD_MA,
+ MEDIA_MIMETYPE_AUDIO_DTS_UHD,
+ MEDIA_MIMETYPE_AUDIO_DTS_UHD_P1,
+ MEDIA_MIMETYPE_AUDIO_DTS_UHD_P2,
+ MEDIA_MIMETYPE_AUDIO_EVRC,
+ MEDIA_MIMETYPE_AUDIO_EVRCB,
+ MEDIA_MIMETYPE_AUDIO_EVRCWB,
+ MEDIA_MIMETYPE_AUDIO_EVRCNW,
+ MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS,
+ MEDIA_MIMETYPE_AUDIO_APTX,
+ MEDIA_MIMETYPE_AUDIO_DRA,
+ MEDIA_MIMETYPE_AUDIO_DOLBY_MAT,
+ MEDIA_MIMETYPE_AUDIO_DOLBY_MAT_1_0,
+ MEDIA_MIMETYPE_AUDIO_DOLBY_MAT_2_0,
+ MEDIA_MIMETYPE_AUDIO_DOLBY_MAT_2_1,
+ MEDIA_MIMETYPE_AUDIO_DOLBY_TRUEHD,
+ MEDIA_MIMETYPE_AUDIO_AAC_MP4,
+ MEDIA_MIMETYPE_AUDIO_AAC_MAIN,
+ MEDIA_MIMETYPE_AUDIO_AAC_LC,
+ MEDIA_MIMETYPE_AUDIO_AAC_SSR,
+ MEDIA_MIMETYPE_AUDIO_AAC_LTP,
+ MEDIA_MIMETYPE_AUDIO_AAC_HE_V1,
+ MEDIA_MIMETYPE_AUDIO_AAC_SCALABLE,
+ MEDIA_MIMETYPE_AUDIO_AAC_ERLC,
+ MEDIA_MIMETYPE_AUDIO_AAC_LD,
+ MEDIA_MIMETYPE_AUDIO_AAC_HE_V2,
+ MEDIA_MIMETYPE_AUDIO_AAC_ELD,
+ MEDIA_MIMETYPE_AUDIO_AAC_XHE,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADIF,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_MAIN,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_LC,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_SSR,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_LTP,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_HE_V1,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_SCALABLE,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_ERLC,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_LD,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_HE_V2,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_ELD,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_XHE,
+ MEDIA_MIMETYPE_AUDIO_AAC_LATM_LC,
+ MEDIA_MIMETYPE_AUDIO_AAC_LATM_HE_V1,
+ MEDIA_MIMETYPE_AUDIO_AAC_LATM_HE_V2,
+ MEDIA_MIMETYPE_AUDIO_IEC61937,
+ MEDIA_MIMETYPE_AUDIO_IEC60958,
+};
+
+const std::string kVideoMimeTypes[] = {
+ MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9,
+ MEDIA_MIMETYPE_VIDEO_AV1, MEDIA_MIMETYPE_VIDEO_AVC,
+ MEDIA_MIMETYPE_VIDEO_HEVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
+ MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_VIDEO_MPEG2,
+ MEDIA_MIMETYPE_VIDEO_RAW, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
+ MEDIA_MIMETYPE_VIDEO_SCRAMBLED, MEDIA_MIMETYPE_VIDEO_DIVX,
+ MEDIA_MIMETYPE_VIDEO_DIVX3, MEDIA_MIMETYPE_VIDEO_XVID,
+ MEDIA_MIMETYPE_VIDEO_MJPEG,
+};
+
+void getSampleAudioFormat(FuzzedDataProvider& fdp, AMessage* format) {
+ std::string mimeType = fdp.PickValueInArray(kAudioMimeTypes);
+ format->setString("mime", mimeType.c_str(), mimeType.length());
+ format->setInt32("sample-rate", fdp.ConsumeIntegral<int32_t>());
+ format->setInt32("channel-count", fdp.ConsumeIntegral<int32_t>());
+}
+
+void getSampleVideoFormat(FuzzedDataProvider& fdp, AMessage* format) {
+ std::string mimeType = fdp.PickValueInArray(kVideoMimeTypes);
+ format->setString("mime", mimeType.c_str(), mimeType.length());
+ format->setInt32("height", fdp.ConsumeIntegral<int32_t>());
+ format->setInt32("width", fdp.ConsumeIntegral<int32_t>());
+ format->setInt32("time-lapse-fps", fdp.ConsumeIntegral<int32_t>());
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
- FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ FuzzedDataProvider fdp(data, size);
- size_t data_size = fdp.ConsumeIntegralInRange<size_t>(0, size);
- int fd = ashmem_create_region("mediamuxer_fuzz_region", data_size);
- if (fd < 0)
+ // memfd_create() creates an anonymous file and returns a file
+ // descriptor that refers to it. MFD_ALLOW_SEALING allows sealing
+ // operations on this file.
+ int32_t fd = memfd_create(kMuxerFile, MFD_ALLOW_SEALING);
+ if (fd == -1) {
+ ALOGE("memfd_create failed: %s", strerror(errno));
+ return 0;
+ }
+
+ auto outputFormat = (MediaMuxer::OutputFormat)fdp.ConsumeIntegralInRange<int32_t>(
+ MediaMuxer::OutputFormat::OUTPUT_FORMAT_MPEG_4,
+ MediaMuxer::OutputFormat::OUTPUT_FORMAT_LIST_END);
+
+ sp<MediaMuxer> mMuxer = MediaMuxer::create(fd, outputFormat);
+ if (mMuxer == nullptr) {
+ close(fd);
+ return 0;
+ }
+
+ // Used to consume a maximum of 80% of the data to send buffer data to writeSampleData().
+ // This ensures that we don't completely exhaust data and use the rest 20% for fuzzing
+ // of APIs.
+ const size_t kMaxSize = (size * 80) / 100;
+ while (fdp.remaining_bytes()) {
+ auto invokeMediaMuxerAPI = fdp.PickValueInArray<const std::function<void()>>({
+ [&]() {
+ // Using 'return' here due to a timeout bug present in OGGWriter.cpp
+ // (b/310316183).
+ if (outputFormat == MediaMuxer::OutputFormat::OUTPUT_FORMAT_OGG) {
+ return;
+ }
+
+ sp<AMessage> format = sp<AMessage>::make();
+ fdp.ConsumeBool() ? getSampleAudioFormat(fdp, format.get())
+ : getSampleVideoFormat(fdp, format.get());
+
+ mMuxer->addTrack(fdp.ConsumeBool() ? format : nullptr);
+ },
+ [&]() {
+ mMuxer->setLocation(fdp.ConsumeIntegral<int32_t>() /* latitude */,
+ fdp.ConsumeIntegral<int32_t>() /* longitude */);
+ },
+ [&]() { mMuxer->setOrientationHint(fdp.ConsumeIntegral<int32_t>() /* degrees */); },
+ [&]() { mMuxer->start(); },
+ [&]() {
+ std::vector<uint8_t> sample = fdp.ConsumeBytes<uint8_t>(
+ fdp.ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize));
+ sp<ABuffer> buffer = sp<ABuffer>::make(sample.data(), sample.size());
+
+ size_t offset = fdp.ConsumeIntegralInRange<size_t>(kMinSize, sample.size());
+ size_t length =
+ fdp.ConsumeIntegralInRange<size_t>(kMinSize, buffer->size() - offset);
+ buffer->setRange(offset, length);
+
+ sp<AMessage> meta = buffer->meta();
+ meta->setInt64("sample-file-offset", fdp.ConsumeIntegral<int64_t>());
+ meta->setInt64("last-sample-index-in-chunk", fdp.ConsumeIntegral<int64_t>());
+
+ uint32_t flags = 0;
+ if (fdp.ConsumeBool()) {
+ flags |= kBufferFlags::BUFFER_FLAG_SYNCFRAME;
+ }
+ if (fdp.ConsumeBool()) {
+ flags |= kBufferFlags::BUFFER_FLAG_CODECCONFIG;
+ }
+ if (fdp.ConsumeBool()) {
+ flags |= kBufferFlags::BUFFER_FLAG_EOS;
+ }
+
+ size_t trackIndex = fdp.ConsumeBool()
+ ? fdp.ConsumeIntegralInRange<size_t>(
+ kMinTrackCount, mMuxer->getTrackCount())
+ : fdp.ConsumeIntegral<size_t>();
+ int64_t timeUs = fdp.ConsumeIntegral<int64_t>();
+ mMuxer->writeSampleData(fdp.ConsumeBool() ? buffer : nullptr, trackIndex,
+ timeUs, flags);
+ },
+ [&]() {
+ mMuxer->getTrackFormat(
+ fdp.ConsumeBool() ? fdp.ConsumeIntegralInRange<size_t>(
+ kMinTrackCount, mMuxer->getTrackCount())
+ : fdp.ConsumeIntegral<size_t>() /* idx */);
+ },
+ [&]() { mMuxer->stop(); },
+ });
+
+ invokeMediaMuxerAPI();
+ }
+
+ close(fd);
return 0;
-
- uint8_t *sh_data = static_cast<uint8_t *>(
- mmap(NULL, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
- if (sh_data == MAP_FAILED)
- return 0;
-
- MediaMuxer::OutputFormat format =
- (MediaMuxer::OutputFormat)fdp.ConsumeIntegralInRange<int32_t>(0, 4);
- sp<MediaMuxer> mMuxer = MediaMuxer::create(fd, format);
- if (mMuxer == nullptr) {
- return 0;
- }
-
- while (fdp.remaining_bytes() > 1) {
- switch (fdp.ConsumeIntegralInRange<uint8_t>(0, 4)) {
- case 0: {
- // For some reason it only likes mp4s here...
- if (format == 1 || format == 4)
- break;
-
- sp<AMessage> a_format(new AMessage);
- createMessage(a_format.get(), &fdp);
- mMuxer->addTrack(a_format);
- break;
- }
- case 1: {
- mMuxer->start();
- break;
- }
- case 2: {
- int degrees = fdp.ConsumeIntegral<int>();
- mMuxer->setOrientationHint(degrees);
- break;
- }
- case 3: {
- int latitude = fdp.ConsumeIntegral<int>();
- int longitude = fdp.ConsumeIntegral<int>();
- mMuxer->setLocation(latitude, longitude);
- break;
- }
- case 4: {
- size_t buf_size = fdp.ConsumeIntegralInRange<size_t>(0, data_size);
- sp<ABuffer> a_buffer(new ABuffer(buf_size));
-
- size_t trackIndex = fdp.ConsumeIntegral<size_t>();
- int64_t timeUs = fdp.ConsumeIntegral<int64_t>();
- uint32_t flags = fdp.ConsumeIntegral<uint32_t>();
- mMuxer->writeSampleData(a_buffer, trackIndex, timeUs, flags);
- }
- }
- }
-
- if (fdp.ConsumeBool())
- mMuxer->stop();
-
- munmap(sh_data, data_size);
- close(fd);
- return 0;
}
} // namespace android
diff --git a/media/libstagefright/tests/fuzzers/MediaMuxerFuzzer.h b/media/libstagefright/tests/fuzzers/MediaMuxerFuzzer.h
deleted file mode 100644
index 7d4421d..0000000
--- a/media/libstagefright/tests/fuzzers/MediaMuxerFuzzer.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// Authors: corbin.souffrant@leviathansecurity.com
-// dylan.katz@leviathansecurity.com
-
-#pragma once
-
-#include <fuzzer/FuzzedDataProvider.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-namespace android {
-
-// Mappings vectors are the list of attributes that the MediaMuxer
-// class looks for in the message.
-static std::vector<const char *> floatMappings{
- "capture-rate",
- "time-lapse-fps",
- "frame-rate",
-};
-
-static std::vector<const char *> int64Mappings{
- "exif-offset", "exif-size", "target-time",
- "thumbnail-time", "timeUs", "durationUs",
-};
-
-static std::vector<const char *> int32Mappings{"loop",
- "time-scale",
- "crypto-mode",
- "crypto-default-iv-size",
- "crypto-encrypted-byte-block",
- "crypto-skip-byte-block",
- "frame-count",
- "max-bitrate",
- "pcm-big-endian",
- "temporal-layer-count",
- "temporal-layer-id",
- "thumbnail-width",
- "thumbnail-height",
- "track-id",
- "valid-samples",
- "color-format",
- "ca-system-id",
- "is-sync-frame",
- "bitrate",
- "max-bitrate",
- "width",
- "height",
- "sar-width",
- "sar-height",
- "display-width",
- "display-height",
- "is-default",
- "tile-width",
- "tile-height",
- "grid-rows",
- "grid-cols",
- "rotation-degrees",
- "channel-count",
- "sample-rate",
- "bits-per-sample",
- "channel-mask",
- "encoder-delay",
- "encoder-padding",
- "is-adts",
- "frame-rate",
- "max-height",
- "max-width",
- "max-input-size",
- "haptic-channel-count",
- "pcm-encoding",
- "aac-profile"};
-
-static const std::vector<std::function<void(AMessage *, FuzzedDataProvider *)>>
- amessage_setvals = {
- [](AMessage *msg, FuzzedDataProvider *fdp) -> void {
- msg->setRect("crop", fdp->ConsumeIntegral<int32_t>(),
- fdp->ConsumeIntegral<int32_t>(),
- fdp->ConsumeIntegral<int32_t>(),
- fdp->ConsumeIntegral<int32_t>());
- },
- [](AMessage *msg, FuzzedDataProvider *fdp) -> void {
- msg->setFloat(floatMappings[fdp->ConsumeIntegralInRange<size_t>(
- 0, floatMappings.size() - 1)],
- fdp->ConsumeFloatingPoint<float>());
- },
- [](AMessage *msg, FuzzedDataProvider *fdp) -> void {
- msg->setInt64(int64Mappings[fdp->ConsumeIntegralInRange<size_t>(
- 0, int64Mappings.size() - 1)],
- fdp->ConsumeIntegral<int64_t>());
- },
- [](AMessage *msg, FuzzedDataProvider *fdp) -> void {
- msg->setInt32(int32Mappings[fdp->ConsumeIntegralInRange<size_t>(
- 0, int32Mappings.size() - 1)],
- fdp->ConsumeIntegral<int32_t>());
- }};
-} // namespace android
diff --git a/media/libstagefright/tests/fuzzers/corpus/0ef67b8a074fed50b8875df345ab2e62175c34c9 b/media/libstagefright/tests/fuzzers/corpus/0ef67b8a074fed50b8875df345ab2e62175c34c9
new file mode 100644
index 0000000..652581f
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/corpus/0ef67b8a074fed50b8875df345ab2e62175c34c9
Binary files differ
diff --git a/media/libstagefright/tests/fuzzers/corpus/60eb43c963545c0b2676dad3e4c38cfe87136bbc b/media/libstagefright/tests/fuzzers/corpus/60eb43c963545c0b2676dad3e4c38cfe87136bbc
new file mode 100644
index 0000000..60ca169
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/corpus/60eb43c963545c0b2676dad3e4c38cfe87136bbc
Binary files differ
diff --git a/media/libstagefright/tests/fuzzers/corpus/8c7cb9439f81a8e00b651b3658fe24116f37df7e b/media/libstagefright/tests/fuzzers/corpus/8c7cb9439f81a8e00b651b3658fe24116f37df7e
new file mode 100644
index 0000000..c03bcad
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/corpus/8c7cb9439f81a8e00b651b3658fe24116f37df7e
Binary files differ
diff --git a/media/libstagefright/tests/fuzzers/corpus/c624e73c16c59dfbc3c563416cfc962e3c3a96a0 b/media/libstagefright/tests/fuzzers/corpus/c624e73c16c59dfbc3c563416cfc962e3c3a96a0
new file mode 100644
index 0000000..52f2d5a
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/corpus/c624e73c16c59dfbc3c563416cfc962e3c3a96a0
Binary files differ
diff --git a/media/libstagefright/tests/fuzzers/corpus/c6aff0d7ccaf58a1964a6bcc51777bf1786503ca b/media/libstagefright/tests/fuzzers/corpus/c6aff0d7ccaf58a1964a6bcc51777bf1786503ca
new file mode 100644
index 0000000..83c522f
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/corpus/c6aff0d7ccaf58a1964a6bcc51777bf1786503ca
Binary files differ
diff --git a/media/libstagefright/tests/fuzzers/corpus/ec6bd6069f74a2f6e92442f88efb29288ad6f456 b/media/libstagefright/tests/fuzzers/corpus/ec6bd6069f74a2f6e92442f88efb29288ad6f456
new file mode 100644
index 0000000..62d259b
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/corpus/ec6bd6069f74a2f6e92442f88efb29288ad6f456
Binary files differ
diff --git a/media/libstagefright/tests/fuzzers/corpus/fbf47d9a9173df0a39285c94d89fcbc767d5e774 b/media/libstagefright/tests/fuzzers/corpus/fbf47d9a9173df0a39285c94d89fcbc767d5e774
new file mode 100644
index 0000000..db78b75
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/corpus/fbf47d9a9173df0a39285c94d89fcbc767d5e774
Binary files differ
diff --git a/services/audiopolicy/engine/common/Android.bp b/services/audiopolicy/engine/common/Android.bp
index d7eb2c8..878e0e9 100644
--- a/services/audiopolicy/engine/common/Android.bp
+++ b/services/audiopolicy/engine/common/Android.bp
@@ -61,4 +61,7 @@
"com.android.media.audio-aconfig-cc",
"server_configurable_flags",
],
+ defaults: [
+ "aconfig_lib_cc_static_link.defaults",
+ ],
}
diff --git a/services/audiopolicy/engineconfigurable/Android.bp b/services/audiopolicy/engineconfigurable/Android.bp
index aaf89a0..2c3c4be 100644
--- a/services/audiopolicy/engineconfigurable/Android.bp
+++ b/services/audiopolicy/engineconfigurable/Android.bp
@@ -53,4 +53,7 @@
"libutils",
"libxml2",
],
+ defaults: [
+ "aconfig_lib_cc_static_link.defaults",
+ ],
}
diff --git a/services/audiopolicy/enginedefault/Android.bp b/services/audiopolicy/enginedefault/Android.bp
index 1563d5f..f5958ba 100644
--- a/services/audiopolicy/enginedefault/Android.bp
+++ b/services/audiopolicy/enginedefault/Android.bp
@@ -40,4 +40,7 @@
"libutils",
"libxml2",
],
+ defaults: [
+ "aconfig_lib_cc_static_link.defaults",
+ ],
}
diff --git a/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp b/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp
index d582062..f5e72f5 100644
--- a/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp
@@ -38,6 +38,7 @@
[[clang::no_destroy]] static std::once_flag gSmOnce;
sp<FakeServiceManager> gFakeServiceManager;
+sp<AudioPolicyService> gAudioPolicyService;
bool addService(const String16& serviceName, const sp<FakeServiceManager>& fakeServiceManager,
FuzzedDataProvider& fdp) {
@@ -49,22 +50,10 @@
return true;
}
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- FuzzedDataProvider fdp(data, size);
-
- std::call_once(gSmOnce, [&] {
- /* Create a FakeServiceManager instance and add required services */
- gFakeServiceManager = sp<FakeServiceManager>::make();
- setDefaultServiceManager(gFakeServiceManager);
- });
- gFakeServiceManager->clear();
-
- for (const char* service : {"activity", "sensor_privacy", "permission", "scheduling_policy",
- "batterystats", "media.metrics"}) {
- if (!addService(String16(service), gFakeServiceManager, fdp)) {
- return 0;
- }
- }
+extern "C" int LLVMFuzzerInitialize(int* /*argc*/, char*** /*argv*/) {
+ /* Create a FakeServiceManager instance and add required services */
+ gFakeServiceManager = sp<FakeServiceManager>::make();
+ setDefaultServiceManager(gFakeServiceManager);
auto configService = ndk::SharedRefBase::make<ConfigMock>();
CHECK_EQ(NO_ERROR, AServiceManager_addService(configService.get()->asBinder().get(),
@@ -82,22 +71,37 @@
// Disable creating thread pool for fuzzer instance of audio flinger and audio policy services
AudioSystem::disableThreadPool();
- const auto audioFlinger = sp<AudioFlinger>::make();
- const auto afAdapter = sp<AudioFlingerServerAdapter>::make(audioFlinger);
+ return 0;
+}
- CHECK_EQ(NO_ERROR,
- gFakeServiceManager->addService(
- String16(IAudioFlinger::DEFAULT_SERVICE_NAME), IInterface::asBinder(afAdapter),
- false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
- const auto audioPolicyService = sp<AudioPolicyService>::make();
+ for (const char* service : {"activity", "sensor_privacy", "permission", "scheduling_policy",
+ "batterystats", "media.metrics"}) {
+ if (!addService(String16(service), gFakeServiceManager, fdp)) {
+ return 0;
+ }
+ }
- CHECK_EQ(NO_ERROR,
- gFakeServiceManager->addService(String16("media.audio_policy"), audioPolicyService,
- false /* allowIsolated */,
- IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+ // TODO(330882064) : Initialise Audio Flinger and Audio Policy services every time
+ std::call_once(gSmOnce, [&] {
+ const auto audioFlinger = sp<AudioFlinger>::make();
+ const auto audioFlingerServerAdapter = sp<AudioFlingerServerAdapter>::make(audioFlinger);
+ CHECK_EQ(NO_ERROR,
+ gFakeServiceManager->addService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME),
+ IInterface::asBinder(audioFlingerServerAdapter),
+ false /* allowIsolated */,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
- fuzzService(media::IAudioPolicyService::asBinder(audioPolicyService), std::move(fdp));
+ gAudioPolicyService = sp<AudioPolicyService>::make();
+ CHECK_EQ(NO_ERROR,
+ gFakeServiceManager->addService(String16("media.audio_policy"),
+ gAudioPolicyService, false /* allowIsolated */,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+ });
+
+ fuzzService(media::IAudioPolicyService::asBinder(gAudioPolicyService), std::move(fdp));
return 0;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 42afa1e..d427de4 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -123,8 +123,8 @@
device->toAudioPort(&devicePort);
if (status_t status = mpClientInterface->setDeviceConnectedState(&devicePort, state);
status != OK) {
- ALOGE("Error %d while setting connected state for device %s",
- static_cast<int>(state),
+ ALOGE("Error %d while setting connected state %d for device %s",
+ status, static_cast<int>(state),
device->getDeviceTypeAddr().toString(false).c_str());
}
}
@@ -212,9 +212,9 @@
if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) {
mAvailableOutputDevices.remove(device);
- mHwModules.cleanUpForDevice(device);
-
broadcastDeviceConnectionState(device, media::DeviceConnectedState::DISCONNECTED);
+
+ mHwModules.cleanUpForDevice(device);
return INVALID_OPERATION;
}
@@ -2086,7 +2086,14 @@
// sampling rate match
if (samplingRate > SAMPLE_RATE_HZ_DEFAULT) {
- currentMatchCriteria[4] = outputDesc->getSamplingRate();
+ int diff; // avoid unsigned integer overflow.
+ __builtin_sub_overflow(outputDesc->getSamplingRate(), samplingRate, &diff);
+
+ // prefer the closest output sampling rate greater than or equal to target
+ // if none exists, prefer the closest output sampling rate less than target.
+ //
+ // criteria is offset to make non-negative.
+ currentMatchCriteria[4] = diff >= 0 ? -diff + 200'000'000 : diff + 100'000'000;
}
// performance flags match
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 74d3474..8642fd4 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -2373,6 +2373,116 @@
)
);
+namespace {
+
+class AudioPolicyManagerTestClientOpenFails : public AudioPolicyManagerTestClient {
+ public:
+ status_t openOutput(audio_module_handle_t module,
+ audio_io_handle_t *output,
+ audio_config_t * halConfig,
+ audio_config_base_t * mixerConfig,
+ const sp<DeviceDescriptorBase>& device,
+ uint32_t * latencyMs,
+ audio_output_flags_t flags) override {
+ return mSimulateFailure ? BAD_VALUE :
+ AudioPolicyManagerTestClient::openOutput(
+ module, output, halConfig, mixerConfig, device, latencyMs, flags);
+ }
+
+ status_t openInput(audio_module_handle_t module,
+ audio_io_handle_t *input,
+ audio_config_t * config,
+ audio_devices_t * device,
+ const String8 & address,
+ audio_source_t source,
+ audio_input_flags_t flags) override {
+ return mSimulateFailure ? BAD_VALUE :
+ AudioPolicyManagerTestClient::openInput(
+ module, input, config, device, address, source, flags);
+ }
+
+ void setSimulateFailure(bool simulateFailure) { mSimulateFailure = simulateFailure; }
+
+ private:
+ bool mSimulateFailure = false;
+};
+
+} // namespace
+
+using DeviceConnectionWithFormatTestParams =
+ std::tuple<audio_devices_t /*type*/, std::string /*name*/, std::string /*address*/,
+ audio_format_t /*format*/>;
+
+class AudioPolicyManagerTestDeviceConnectionFailed :
+ public AudioPolicyManagerTestWithConfigurationFile,
+ public testing::WithParamInterface<DeviceConnectionWithFormatTestParams> {
+ protected:
+ std::string getConfigFile() override { return sBluetoothConfig; }
+ AudioPolicyManagerTestClient* getClient() override {
+ mFullClient = new AudioPolicyManagerTestClientOpenFails;
+ return mFullClient;
+ }
+ void setSimulateOpenFailure(bool simulateFailure) {
+ mFullClient->setSimulateFailure(simulateFailure); }
+
+ static const std::string sBluetoothConfig;
+
+ private:
+ AudioPolicyManagerTestClientOpenFails* mFullClient;
+};
+
+const std::string AudioPolicyManagerTestDeviceConnectionFailed::sBluetoothConfig =
+ AudioPolicyManagerTestDeviceConnectionFailed::sExecutableDir +
+ "test_audio_policy_configuration_bluetooth.xml";
+
+TEST_P(AudioPolicyManagerTestDeviceConnectionFailed, SetDeviceConnectedStateHasAddress) {
+ const audio_devices_t type = std::get<0>(GetParam());
+ const std::string name = std::get<1>(GetParam());
+ const std::string address = std::get<2>(GetParam());
+ const audio_format_t format = std::get<3>(GetParam());
+
+ EXPECT_EQ(0, mClient->getConnectedDevicePortCount());
+ EXPECT_EQ(0, mClient->getDisconnectedDevicePortCount());
+
+ setSimulateOpenFailure(true);
+ ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+ type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.c_str(), name.c_str(), format));
+
+ // Since the failure happens when opening input/output, the device must be connected
+ // first and then disconnected.
+ EXPECT_EQ(1, mClient->getConnectedDevicePortCount());
+ EXPECT_EQ(1, mClient->getDisconnectedDevicePortCount());
+
+ if (mClient->getConnectedDevicePortCount() > 0) {
+ auto port = mClient->getLastConnectedDevicePort();
+ EXPECT_EQ(type, port->ext.device.type);
+ EXPECT_EQ(0, strncmp(port->ext.device.address, address.c_str(),
+ AUDIO_DEVICE_MAX_ADDRESS_LEN)) << "\"" << port->ext.device.address << "\"";
+ }
+ if (mClient->getDisconnectedDevicePortCount() > 0) {
+ auto port = mClient->getLastDisconnectedDevicePort();
+ EXPECT_EQ(type, port->ext.device.type);
+ EXPECT_EQ(0, strncmp(port->ext.device.address, address.c_str(),
+ AUDIO_DEVICE_MAX_ADDRESS_LEN)) << "\"" << port->ext.device.address << "\"";
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(
+ DeviceConnectionFailure,
+ AudioPolicyManagerTestDeviceConnectionFailed,
+ testing::Values(
+ DeviceConnectionWithFormatTestParams({AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
+ "bt_hfp_in", "00:11:22:33:44:55", AUDIO_FORMAT_DEFAULT}),
+ DeviceConnectionWithFormatTestParams({AUDIO_DEVICE_OUT_BLUETOOTH_SCO,
+ "bt_hfp_out", "00:11:22:33:44:55", AUDIO_FORMAT_DEFAULT}),
+ DeviceConnectionWithFormatTestParams({AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+ "bt_a2dp_out", "00:11:22:33:44:55", AUDIO_FORMAT_DEFAULT}),
+ DeviceConnectionWithFormatTestParams({AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+ "bt_a2dp_out", "00:11:22:33:44:66", AUDIO_FORMAT_LDAC})
+ )
+ );
+
class AudioPolicyManagerCarTest : public AudioPolicyManagerTestDynamicPolicy {
protected:
std::string getConfigFile() override { return sCarConfig; }
@@ -3283,4 +3393,4 @@
// unregister effect should succeed since effect shall have been restore on the client session
ASSERT_EQ(NO_ERROR, mManager->unregisterEffect(effectId));
-}
\ No newline at end of file
+}
diff --git a/services/audiopolicy/tests/resources/Android.bp b/services/audiopolicy/tests/resources/Android.bp
index 3f6a6e3..535dd7a 100644
--- a/services/audiopolicy/tests/resources/Android.bp
+++ b/services/audiopolicy/tests/resources/Android.bp
@@ -11,6 +11,7 @@
name: "audiopolicytest_configuration_files",
srcs: [
"test_audio_policy_configuration.xml",
+ "test_audio_policy_configuration_bluetooth.xml",
"test_audio_policy_primary_only_configuration.xml",
"test_car_ap_atmos_offload_configuration.xml",
"test_invalid_audio_policy_configuration.xml",
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_configuration_bluetooth.xml b/services/audiopolicy/tests/resources/test_audio_policy_configuration_bluetooth.xml
new file mode 100644
index 0000000..0cf1688
--- /dev/null
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration_bluetooth.xml
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<audioPolicyConfiguration version="7.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <globalConfiguration speaker_drc_enabled="true"/>
+
+ <modules>
+ <!-- Primary module -->
+ <module name="primary" halVersion="2.0">
+ <attachedDevices>
+ <item>Speaker</item>
+ <item>Built-In Mic</item>
+ </attachedDevices>
+ <defaultOutputDevice>Speaker</defaultOutputDevice>
+ <mixPorts>
+ <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="primary input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000"
+ channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ <mixPort name="mixport_bt_hfp_output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="mixport_bt_hfp_input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000 11025 16000 44100 48000"
+ channelMasks="AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_MONO"/>
+ </mixPort>
+ <mixPort name="voip_tx" role="sink"
+ flags="AUDIO_INPUT_FLAG_VOIP_TX">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000 16000 32000 48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ </mixPort>
+ <mixPort name="voip_rx" role="source"
+ flags="AUDIO_OUTPUT_FLAG_VOIP_RX">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000 16000 32000 48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
+ </devicePort>
+ <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+ </devicePort>
+ <devicePort tagName="Hdmi" type="AUDIO_DEVICE_OUT_HDMI" role="sink"
+ encodedFormats="AUDIO_FORMAT_AC3">
+ </devicePort>
+ <devicePort tagName="Hdmi-In Mic" type="AUDIO_DEVICE_IN_HDMI" role="source">
+ </devicePort>
+ <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink" />
+ <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"
+ role="source" />
+ <devicePort tagName="BT A2DP Out" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" role="sink"
+ encodedFormats="AUDIO_FORMAT_SBC">
+ <profile name="" format="AUDIO_FORMAT_PCM_8_BIT"
+ samplingRates="44100 48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="USB Device Out" type="AUDIO_DEVICE_OUT_USB_DEVICE" role="sink">
+ </devicePort>
+ <devicePort tagName="USB Device In" type="AUDIO_DEVICE_IN_USB_DEVICE" role="source">
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="Speaker"
+ sources="primary output,voip_rx"/>
+ <route type="mix" sink="primary input"
+ sources="Built-In Mic,Hdmi-In Mic,USB Device In"/>
+ <route type="mix" sink="voip_tx"
+ sources="Built-In Mic"/>
+ <route type="mix" sink="Hdmi"
+ sources="primary output"/>
+ <route type="mix" sink="BT SCO"
+ sources="mixport_bt_hfp_output"/>
+ <route type="mix" sink="mixport_bt_hfp_input"
+ sources="BT SCO Headset Mic"/>
+ <route type="mix" sink="BT A2DP Out"
+ sources="primary output"/>
+ <route type="mix" sink="USB Device Out"
+ sources="primary output"/>
+ </routes>
+ </module>
+
+ <!-- Remote Submix module -->
+ <module name="r_submix" halVersion="2.0">
+ <attachedDevices>
+ <item>Remote Submix In</item>
+ </attachedDevices>
+ <mixPorts>
+ <mixPort name="r_submix output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="r_submix input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="Remote Submix Out" type="AUDIO_DEVICE_OUT_REMOTE_SUBMIX" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="Remote Submix In" type="AUDIO_DEVICE_IN_REMOTE_SUBMIX" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="Remote Submix Out"
+ sources="r_submix output"/>
+ <route type="mix" sink="r_submix input"
+ sources="Remote Submix In"/>
+ </routes>
+ </module>
+
+ <!-- Software Bluetooth Module -->
+ <module name="bluetooth" halVersion="2.0">
+ <mixPorts>
+ <mixPort name="a2dp_sw_output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100 48000 88200 96000"
+ channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="BTS A2DP Out" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100 48000 88200 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="BTS A2DP Out"
+ sources="a2dp_sw_output"/>
+ </routes>
+ </module>
+
+ </modules>
+</audioPolicyConfiguration>
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 2718604..58b3e51 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -3649,19 +3649,18 @@
cleanUpFailedRequests(/*sendRequestError*/ true);
// Check if any stream is abandoned.
checkAndStopRepeatingRequest();
+ // Inform waitUntilRequestProcessed thread of a failed request ID
+ wakeupLatestRequest(/*failedRequestId*/true, latestRequestId);
return true;
} else if (res != OK) {
cleanUpFailedRequests(/*sendRequestError*/ false);
+ // Inform waitUntilRequestProcessed thread of a failed request ID
+ wakeupLatestRequest(/*failedRequestId*/true, latestRequestId);
return false;
}
// Inform waitUntilRequestProcessed thread of a new request ID
- {
- Mutex::Autolock al(mLatestRequestMutex);
-
- mLatestRequestId = latestRequestId;
- mLatestRequestSignal.signal();
- }
+ wakeupLatestRequest(/*failedRequestId*/false, latestRequestId);
// Submit a batch of requests to HAL.
// Use flush lock only when submitting multilple requests in a batch.
@@ -4393,12 +4392,7 @@
hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
captureRequest->mResultExtras);
}
- {
- Mutex::Autolock al(mLatestRequestMutex);
-
- mLatestFailedRequestId = captureRequest->mResultExtras.requestId;
- mLatestRequestSignal.signal();
- }
+ wakeupLatestRequest(/*failedRequestId*/true, captureRequest->mResultExtras.requestId);
}
// Remove yet-to-be submitted inflight request from inflightMap
@@ -5060,6 +5054,20 @@
return OK;
}
+void Camera3Device::RequestThread::wakeupLatestRequest(
+ bool latestRequestFailed,
+ int32_t latestRequestId) {
+ Mutex::Autolock al(mLatestRequestMutex);
+
+ if (latestRequestFailed) {
+ mLatestFailedRequestId = latestRequestId;
+ } else {
+ mLatestRequestId = latestRequestId;
+ }
+ mLatestRequestSignal.signal();
+}
+
+
/**
* PreparerThread inner class methods
*/
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 9a2f2b1..1820702 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -1026,6 +1026,11 @@
const sp<CaptureRequest> &request,
const CameraMetadata& injectedSessionParams);
+ /**
+ * signal mLatestRequestmutex
+ **/
+ void wakeupLatestRequest(bool latestRequestFailed, int32_t latestRequestId);
+
protected:
virtual bool threadLoop();
diff --git a/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp b/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
index 433332c..c6793a9 100644
--- a/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
+++ b/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
@@ -33,6 +33,8 @@
constexpr size_t kLogItemsLowWater = 1;
// high water mark
constexpr size_t kLogItemsHighWater = 2;
+constexpr size_t kMaxItemLength = 16;
+constexpr size_t kMaxApis = 64;
class MediaMetricsServiceFuzzer {
public:
@@ -304,10 +306,11 @@
}
FuzzedDataProvider fdp2 = FuzzedDataProvider(data, size);
-
- while (fdp2.remaining_bytes()) {
+ size_t apiCount = 0;
+ while (fdp2.remaining_bytes() && ++apiCount <= kMaxApis) {
// make a test item
- auto item = std::make_shared<mediametrics::Item>(fdp2.ConsumeRandomLengthString().c_str());
+ auto item = std::make_shared<mediametrics::Item>(
+ fdp2.ConsumeRandomLengthString(kMaxItemLength).c_str());
(*item).set("event", fdp2.ConsumeRandomLengthString().c_str());
// get the actions and execute them
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.cpp b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
index cd00937..a8a1de1 100644
--- a/services/mediaresourcemanager/ResourceManagerMetrics.cpp
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
@@ -109,23 +109,17 @@
return CodecBucketUnspecified;
}
-static bool getLogMessage(int hwCount, int swCount, std::stringstream& logMsg) {
- bool update = false;
- logMsg.clear();
+static std::string getLogMessage(const std::string& firstKey, const long& firstValue,
+ const std::string& secondKey, const long& secondValue) {
- if (hwCount > 0) {
- logMsg << " HW: " << hwCount;
- update = true;
+ std::stringstream logMsg;
+ if (firstValue > 0) {
+ logMsg << firstKey << firstValue;
}
- if (swCount > 0) {
- logMsg << " SW: " << swCount;
- update = true;
+ if (secondValue > 0) {
+ logMsg << secondKey << secondValue;
}
-
- if (update) {
- logMsg << " ] ";
- }
- return update;
+ return logMsg.str();
}
ResourceManagerMetrics::ResourceManagerMetrics(const sp<ProcessInfoInterface>& processInfo) {
@@ -364,6 +358,15 @@
std::scoped_lock lock(mLock);
// post MediaCodecConcurrentUsageReported for this terminated pid.
pushConcurrentUsageReport(pid, uid);
+ // Remove all the metrics associated with this process.
+ std::map<int32_t, ConcurrentCodecs>::iterator it1 = mProcessConcurrentCodecsMap.find(pid);
+ if (it1 != mProcessConcurrentCodecsMap.end()) {
+ mProcessConcurrentCodecsMap.erase(it1);
+ }
+ std::map<int32_t, PixelCount>::iterator it2 = mProcessPixelsMap.find(pid);
+ if (it2 != mProcessPixelsMap.end()) {
+ mProcessPixelsMap.erase(it2);
+ }
}
void ResourceManagerMetrics::pushConcurrentUsageReport(int32_t pid, uid_t uid) {
@@ -400,24 +403,30 @@
std::stringstream peakCodecLog;
peakCodecLog << "Peak { ";
- std::stringstream logMsg;
- if (getLogMessage(peakHwAudioEncoderCount, peakSwAudioEncoderCount, logMsg)) {
- peakCodecLog << "AudioEnc[" << logMsg.str();
+ std::string logMsg;
+ logMsg = getLogMessage(" HW: ", peakHwAudioEncoderCount, " SW: ", peakSwAudioEncoderCount);
+ if (!logMsg.empty()) {
+ peakCodecLog << "AudioEnc[ " << logMsg << " ] ";
}
- if (getLogMessage(peakHwAudioDecoderCount, peakSwAudioDecoderCount, logMsg)) {
- peakCodecLog << "AudioDec[" << logMsg.str();
+ logMsg = getLogMessage(" HW: ", peakHwAudioDecoderCount, " SW: ", peakSwAudioDecoderCount);
+ if (!logMsg.empty()) {
+ peakCodecLog << "AudioDec[" << logMsg << " ] ";
}
- if (getLogMessage(peakHwVideoEncoderCount, peakSwVideoEncoderCount, logMsg)) {
- peakCodecLog << "VideoEnc[" << logMsg.str();
+ logMsg = getLogMessage(" HW: ", peakHwVideoEncoderCount, " SW: ", peakSwVideoEncoderCount);
+ if (!logMsg.empty()) {
+ peakCodecLog << "VideoEnc[" << logMsg << " ] ";
}
- if (getLogMessage(peakHwVideoDecoderCount, peakSwVideoDecoderCount, logMsg)) {
- peakCodecLog << "VideoDec[" << logMsg.str();
+ logMsg = getLogMessage(" HW: ", peakHwVideoDecoderCount, " SW: ", peakSwVideoDecoderCount);
+ if (!logMsg.empty()) {
+ peakCodecLog << "VideoDec[" << logMsg << " ] ";
}
- if (getLogMessage(peakHwImageEncoderCount, peakSwImageEncoderCount, logMsg)) {
- peakCodecLog << "ImageEnc[" << logMsg.str();
+ logMsg = getLogMessage(" HW: ", peakHwImageEncoderCount, " SW: ", peakSwImageEncoderCount);
+ if (!logMsg.empty()) {
+ peakCodecLog << "ImageEnc[" << logMsg << " ] ";
}
- if (getLogMessage(peakHwImageDecoderCount, peakSwImageDecoderCount, logMsg)) {
- peakCodecLog << "ImageDec[" << logMsg.str();
+ logMsg = getLogMessage(" HW: ", peakHwImageDecoderCount, " SW: ", peakSwImageDecoderCount);
+ if (!logMsg.empty()) {
+ peakCodecLog << "ImageDec[" << logMsg << " ] ";
}
peakCodecLog << "}";
@@ -705,4 +714,114 @@
return 0;
}
+static std::string getConcurrentInstanceCount(const std::map<std::string, int>& resourceMap) {
+ if (resourceMap.empty()) {
+ return "";
+ }
+ std::stringstream concurrentInstanceInfo;
+ for (const auto& [name, count] : resourceMap) {
+ if (count > 0) {
+ concurrentInstanceInfo << " Name: " << name << " Instances: " << count << "\n";
+ }
+ }
+
+ std::string info = concurrentInstanceInfo.str();
+ if (info.empty()) {
+ return "";
+ }
+ return " Current Concurrent Codec Instances:\n" + info;
+}
+
+static std::string getAppsPixelCount(const std::map<int32_t, PixelCount>& pixelMap) {
+ if (pixelMap.empty()) {
+ return "";
+ }
+ std::stringstream pixelInfo;
+ for (const auto& [pid, pixelCount] : pixelMap) {
+ std::string logMsg = getLogMessage(" Current Pixels: ", pixelCount.mCurrent,
+ " Peak Pixels: ", pixelCount.mPeak);
+ if (!logMsg.empty()) {
+ pixelInfo << " PID[" << pid << "]: {" << logMsg << " }\n";
+ }
+ }
+
+ return " Applications Pixel Usage:\n" + pixelInfo.str();
+}
+
+static std::string getCodecUsageMetrics(const ConcurrentCodecsMap& codecsMap) {
+ int peakHwAudioEncoderCount = codecsMap[HwAudioEncoder];
+ int peakHwAudioDecoderCount = codecsMap[HwAudioDecoder];
+ int peakHwVideoEncoderCount = codecsMap[HwVideoEncoder];
+ int peakHwVideoDecoderCount = codecsMap[HwVideoDecoder];
+ int peakHwImageEncoderCount = codecsMap[HwImageEncoder];
+ int peakHwImageDecoderCount = codecsMap[HwImageDecoder];
+ int peakSwAudioEncoderCount = codecsMap[SwAudioEncoder];
+ int peakSwAudioDecoderCount = codecsMap[SwAudioDecoder];
+ int peakSwVideoEncoderCount = codecsMap[SwVideoEncoder];
+ int peakSwVideoDecoderCount = codecsMap[SwVideoDecoder];
+ int peakSwImageEncoderCount = codecsMap[SwImageEncoder];
+ int peakSwImageDecoderCount = codecsMap[SwImageDecoder];
+ std::stringstream usageMetrics;
+ std::string logMsg;
+ logMsg = getLogMessage(" HW: ", peakHwAudioEncoderCount, " SW: ", peakSwAudioEncoderCount);
+ if (!logMsg.empty()) {
+ usageMetrics << "AudioEnc[" << logMsg << " ] ";
+ }
+ logMsg = getLogMessage(" HW: ", peakHwAudioDecoderCount, " SW: ", peakSwAudioDecoderCount);
+ if (!logMsg.empty()) {
+ usageMetrics << "AudioDec[" << logMsg << " ] ";
+ }
+ logMsg = getLogMessage(" HW: ", peakHwVideoEncoderCount, " SW: ", peakSwVideoEncoderCount);
+ if (!logMsg.empty()) {
+ usageMetrics << "VideoEnc[" << logMsg << " ] ";
+ }
+ logMsg = getLogMessage(" HW: ", peakHwVideoDecoderCount, " SW: ", peakSwVideoDecoderCount);
+ if (!logMsg.empty()) {
+ usageMetrics << "VideoDec[" << logMsg << " ] ";
+ }
+ logMsg = getLogMessage(" HW: ", peakHwImageEncoderCount, " SW: ", peakSwImageEncoderCount);
+ if (!logMsg.empty()) {
+ usageMetrics << "ImageEnc[" << logMsg << " ] ";
+ }
+ logMsg = getLogMessage(" HW: ", peakHwImageDecoderCount, " SW: ", peakSwImageDecoderCount);
+ if (!logMsg.empty()) {
+ usageMetrics << "ImageDec[" << logMsg << " ] ";
+ }
+
+ return usageMetrics.str();
+}
+
+static std::string getAppsCodecUsageMetrics(
+ const std::map<int32_t, ConcurrentCodecs>& processCodecsMap) {
+ if (processCodecsMap.empty()) {
+ return "";
+ }
+ std::stringstream codecUsage;
+ std::string info;
+ for (const auto& [pid, codecMap] : processCodecsMap) {
+ codecUsage << " PID[" << pid << "]: ";
+ info = getCodecUsageMetrics(codecMap.mCurrent);
+ if (!info.empty()) {
+ codecUsage << "Current Codec Usage: { " << info << "} ";
+ }
+ info = getCodecUsageMetrics(codecMap.mPeak);
+ if (!info.empty()) {
+ codecUsage << "Peak Codec Usage: { " << info << "}";
+ }
+ codecUsage << "\n";
+ }
+
+ return " Applications Codec Usage:\n" + codecUsage.str();
+}
+
+
+std::string ResourceManagerMetrics::dump() const {
+ std::string metricsLog(" Metrics logs:\n");
+ metricsLog += getConcurrentInstanceCount(mConcurrentResourceCountMap);
+ metricsLog += getAppsPixelCount(mProcessPixelsMap);
+ metricsLog += getAppsCodecUsageMetrics(mProcessConcurrentCodecsMap);
+
+ return std::move(metricsLog);
+}
+
} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.h b/services/mediaresourcemanager/ResourceManagerMetrics.h
index 7a5a89f..9904f7d 100644
--- a/services/mediaresourcemanager/ResourceManagerMetrics.h
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.h
@@ -171,6 +171,9 @@
// Get the current concurrent pixel count (associated with the video codecs) for the process.
long getCurrentConcurrentPixelCount(int pid) const;
+ // retrieves metrics log.
+ std::string dump() const;
+
private:
ResourceManagerMetrics(const ResourceManagerMetrics&) = delete;
ResourceManagerMetrics(ResourceManagerMetrics&&) = delete;
@@ -204,9 +207,9 @@
// Map of resources (name) and number of concurrent instances
std::map<std::string, int> mConcurrentResourceCountMap;
- // Map of concurrent codes by CodecBucket across the system.
+ // Map of concurrent codecs by CodecBucket across the system.
ConcurrentCodecsMap mConcurrentCodecsMap;
- // Map of concurrent and peak codes by CodecBucket for each process/application.
+ // Map of concurrent and peak codecs by CodecBucket for each process/application.
std::map<int32_t, ConcurrentCodecs> mProcessConcurrentCodecsMap;
// Uid Observer to monitor the application termination.
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index d37d893..9c2fb7c 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -108,10 +108,17 @@
serviceLog = mServiceLog->toString(" " /* linePrefix */);
}
- // Get all the resource (and overload pid) logs
+ // Get all the resource (and overload pid) log.
std::string resourceLog;
getResourceDump(resourceLog);
+ // Get all the metrics log.
+ std::string metricsLog;
+ {
+ std::scoped_lock lock{mLock};
+ metricsLog = mResourceManagerMetrics->dump();
+ }
+
const size_t SIZE = 256;
char buffer[SIZE];
snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this);
@@ -123,11 +130,16 @@
supportsSecureWithNonSecureCodec);
result.append(buffer);
+ // Add resource log.
result.append(resourceLog.c_str());
+ // Add service log.
result.append(" Events logs (most recent at top):\n");
result.append(serviceLog);
+ // Add metrics log.
+ result.append(metricsLog.c_str());
+
write(fd, result.c_str(), result.size());
return OK;
}
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index 6a64823..5dfec30 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -29,6 +29,9 @@
"libactivitymanager_aidl",
"server_configurable_flags",
],
+ defaults: [
+ "aconfig_lib_cc_static_link.defaults",
+ ],
include_dirs: [
"frameworks/av/include",
"frameworks/av/services/mediaresourcemanager",