Merge "media.c2 aidl: Apply bufferpool based allocator interface change" into main
diff --git a/media/aconfig/Android.bp b/media/aconfig/Android.bp
index 96bf4f5..f95d723 100644
--- a/media/aconfig/Android.bp
+++ b/media/aconfig/Android.bp
@@ -14,6 +14,7 @@
name: "aconfig_mediacodec_flags_c_lib",
min_sdk_version: "30",
vendor_available: true,
+ double_loadable: true,
apex_available: [
"//apex_available:platform",
"com.android.media.swcodec",
diff --git a/media/codec2/components/aom/C2SoftAomEnc.cpp b/media/codec2/components/aom/C2SoftAomEnc.cpp
index 71909e5..7c9d3e8 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.cpp
+++ b/media/codec2/components/aom/C2SoftAomEnc.cpp
@@ -338,6 +338,19 @@
}
c2_status_t C2SoftAomEnc::onStop() {
+ IntfImpl::Lock lock = mIntf->lock();
+ std::shared_ptr<C2StreamRequestSyncFrameTuning::output> requestSync = mIntf->getRequestSync_l();
+ lock.unlock();
+ if (requestSync != mRequestSync) {
+ // we can handle IDR immediately
+ if (requestSync->value) {
+ // unset request
+ C2StreamRequestSyncFrameTuning::output clearSync(0u, C2_FALSE);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ mIntf->config({ &clearSync }, C2_MAY_BLOCK, &failures);
+ }
+ mRequestSync = requestSync;
+ }
onRelease();
return C2_OK;
}
diff --git a/media/codec2/hal/aidl/BufferTypes.cpp b/media/codec2/hal/aidl/BufferTypes.cpp
index bc4948b..a0e6aa5 100644
--- a/media/codec2/hal/aidl/BufferTypes.cpp
+++ b/media/codec2/hal/aidl/BufferTypes.cpp
@@ -302,7 +302,7 @@
"invalid receiver connection id (0).";
return bufferpool2::ResultStatus::CRITICAL_ERROR;
} else {
- if (isNewConnection) {
+ if (foundConnection == mConnections.end()) {
foundConnection = mConnections.try_emplace(
connectionId, receiverConnectionId, now).first;
} else {
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/Android.bp b/media/codec2/hal/hidl/1.0/vts/functional/Android.bp
index 1c5c7d6..2054fe6 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/Android.bp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/Android.bp
@@ -44,6 +44,7 @@
"res/bbb_opus_stereo_128kbps_48000hz.info",
"res/bbb_opus_stereo_128kbps_48000hz.opus",
"res/bbb_raw_1ch_8khz_s32le.info",
+ "res/bbb_raw_1ch_8khz_s32le_largeframe.info",
"res/bbb_raw_1ch_8khz_s32le.raw",
"res/bbb_vorbis_stereo_128kbps_48000hz.info",
"res/bbb_vorbis_stereo_128kbps_48000hz.vorbis",
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index c7c04c5..0c30d95 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -32,7 +32,11 @@
#include <codec2/hidl/client.h>
#include "media_c2_hidl_test_common.h"
-using DecodeTestParameters = std::tuple<std::string, std::string, uint32_t, bool>;
+
+using DecodeTestParameters = std::tuple<std::string /*instance_name*/,
+ std::string /*component_name*/,
+ uint32_t /*stream_index*/,
+ bool /*signal end-of-stream nor not*/>;
static std::vector<DecodeTestParameters> gDecodeTestParameters;
using CsdFlushTestParameters = std::tuple<std::string, std::string, bool>;
@@ -56,6 +60,7 @@
{"g711-mlaw", "bbb_g711mulaw_1ch_8khz.raw", "bbb_g711mulaw_1ch_8khz.info"},
{"gsm", "bbb_gsm_1ch_8khz_13kbps.raw", "bbb_gsm_1ch_8khz_13kbps.info"},
{"raw", "bbb_raw_1ch_8khz_s32le.raw", "bbb_raw_1ch_8khz_s32le.info"},
+ {"raw", "bbb_raw_1ch_8khz_s32le.raw", "bbb_raw_1ch_8khz_s32le_largeframe.info"},
{"flac", "bbb_flac_stereo_680kbps_48000hz.flac", "bbb_flac_stereo_680kbps_48000hz.info"},
};
@@ -137,6 +142,9 @@
struct outputMetaData {
uint64_t timestampUs;
uint32_t rangeLength;
+ // The following is used only if C2AccessUnitInfos::output
+ // is present as part of C2Buffer.
+ std::vector<C2AccessUnitInfosStruct> largeFrameInfo;
};
// callback function to process onWorkDone received by Listener
void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
@@ -161,8 +169,18 @@
.capacity();
// List of timestamp values and output size to calculate timestamp
if (mTimestampDevTest) {
- outputMetaData meta = {mTimestampUs, rangeLength};
+ outputMetaData meta = {mTimestampUs, rangeLength, {}};
oBufferMetaData.push_back(meta);
+ std::shared_ptr<const C2AccessUnitInfos::output> inBufferInfo =
+ std::static_pointer_cast<const C2AccessUnitInfos::output>(
+ work->worklets.front()->output.buffers[0]->getInfo(
+ C2AccessUnitInfos::output::PARAM_TYPE));
+ if (inBufferInfo) {
+ for (int nMeta = 0; nMeta < inBufferInfo->flexCount(); nMeta++) {
+ oBufferMetaData.back().largeFrameInfo.push_back(
+ inBufferInfo->m.values[nMeta]);
+ }
+ }
}
}
bool mCsd = false;
@@ -203,6 +221,12 @@
std::string mInfoFile;
size_t mStreamIndex = 0;
+ // These are used only with large frame codec
+ // Specifies the maximum output size in bytes.
+ uint32_t mMaxOutputSize;
+ //Specifies the threshold output size in bytes.
+ uint32_t mOutputThresholdSize;
+
protected:
static void description(const std::string& description) {
RecordProperty("description", description);
@@ -249,6 +273,96 @@
ALOGV("Component Valid");
}
+bool isLargeAudioFrameSupported(const std::shared_ptr<android::Codec2Client::Component> &comp,
+ std::vector<C2FieldSupportedValues>& supportedValues) {
+ C2LargeFrame::output largeFrameParams;
+ std::vector<C2FieldSupportedValuesQuery> validValueInfos = {
+ C2FieldSupportedValuesQuery::Current(
+ C2ParamField(&largeFrameParams, &C2LargeFrame::maxSize)),
+ C2FieldSupportedValuesQuery::Current(
+ C2ParamField(&largeFrameParams,
+ &C2LargeFrame::thresholdSize))};
+ c2_status_t c2err = comp->querySupportedValues(validValueInfos, C2_DONT_BLOCK);
+ if (c2err != C2_OK || validValueInfos.size() != 2) {
+ return false;
+ }
+ supportedValues.clear();
+ for (int i = 0; i < 2; i++) {
+ if (validValueInfos[i].values.type == C2FieldSupportedValues::EMPTY) {
+ return false;
+ }
+ supportedValues.push_back(validValueInfos[i].values);
+ }
+ return true;
+}
+
+c2_status_t configureLargeFrameParams(const std::shared_ptr<android::Codec2Client::Component> &comp,
+ uint32_t& maxOutput, uint32_t& outputThreshold,
+ const std::vector<C2FieldSupportedValues>& supportedValues) {
+
+ if (supportedValues.empty()) {
+ ALOGE("Error: No supported values in large audio frame params");
+ return C2_BAD_VALUE;
+ }
+
+ auto boundBySupportedValues = [](const C2FieldSupportedValues& supportedValues, uint32_t& value)
+ -> c2_status_t {
+ uint32_t oBufMin = 0, oBufMax = 0;
+ switch (supportedValues.type) {
+ case C2FieldSupportedValues::type_t::RANGE:
+ {
+ const auto& range = supportedValues.range;
+ oBufMax = (uint32_t)(range.max).ref<uint32_t>();
+ oBufMin = (uint32_t)(range.min).ref<uint32_t>();
+ value = (value > oBufMax) ? oBufMax :
+ (value < oBufMin) ? oBufMin : value;
+ break;
+ }
+
+ case C2FieldSupportedValues::type_t::VALUES:
+ {
+ uint32_t lastValue;
+ for (const C2Value::Primitive& prim : supportedValues.values) {
+ lastValue = (uint32_t)prim.ref<uint32_t>();
+ if (lastValue > value) {
+ value = lastValue;
+ break;
+ }
+ }
+ if (value > lastValue) {
+ value = lastValue;
+ }
+ break;
+ }
+
+ default:
+ return C2_BAD_VALUE;
+ }
+ return C2_OK;
+ };
+ c2_status_t c2_err = boundBySupportedValues(supportedValues[0], maxOutput);
+ if (c2_err != C2_OK) {
+ return c2_err;
+ }
+ c2_err = boundBySupportedValues(supportedValues[1], outputThreshold);
+ if (c2_err != C2_OK) {
+ return c2_err;
+ }
+ if (outputThreshold > maxOutput) {
+ outputThreshold = maxOutput;
+ }
+ ALOGV("Setting large frame format : Max: %d - Threshold: %d", maxOutput, outputThreshold);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ C2LargeFrame::output largeFrameParams(0u, maxOutput, outputThreshold);
+ std::vector<C2Param*> configParam{&largeFrameParams};
+ c2_status_t status = comp->config(configParam, C2_DONT_BLOCK, &failures);
+ if (status != C2_OK || failures.size() != 0u) {
+ ALOGE("Large frame Audio configuration failed for maxSize: %d, thresholdSize: %d",
+ maxOutput, outputThreshold);
+ }
+ return status;
+}
+
// Set Default config param.
bool setupConfigParam(const std::shared_ptr<android::Codec2Client::Component>& component,
int32_t* bitStreamInfo) {
@@ -317,6 +431,10 @@
typedef std::unique_lock<std::mutex> ULock;
int frameID = offset;
int maxRetry = 0;
+ std::shared_ptr<C2Buffer> buffer;
+ std::vector<C2FieldSupportedValues> largeFrameValues;
+ bool isComponentSupportsLargeAudioFrame = isLargeAudioFrameSupported(component,
+ largeFrameValues);
while (1) {
if (frameID == (int)Info->size() || frameID == (offset + range)) break;
uint32_t flags = 0;
@@ -376,7 +494,17 @@
memcpy(view.base(), data, size);
- work->input.buffers.emplace_back(new LinearBuffer(block));
+ buffer.reset(new LinearBuffer(block));
+ if (!(*Info)[frameID].largeFrameInfo.empty() && isComponentSupportsLargeAudioFrame) {
+ const std::vector<C2AccessUnitInfosStruct>& meta =
+ (*Info)[frameID].largeFrameInfo;
+ ALOGV("Large Audio frame supported for %s, frameID: %d, size: %zu",
+ component->getName().c_str(), frameID, meta.size());
+ const std::shared_ptr<C2AccessUnitInfos::input> largeFrame =
+ C2AccessUnitInfos::input::AllocShared(meta.size(), 0u, meta);
+ buffer->setInfo(largeFrame);
+ }
+ work->input.buffers.push_back(buffer);
free(data);
}
work->worklets.clear();
@@ -403,9 +531,37 @@
auto itOut = oBufferMetaData.begin();
EXPECT_EQ(*itIn, itOut->timestampUs);
uint64_t expectedTimeStamp = *itIn;
- while (itOut != oBufferMetaData.end()) {
+ bool err= false;
+ while (!err && itOut != oBufferMetaData.end()) {
EXPECT_EQ(expectedTimeStamp, itOut->timestampUs);
if (expectedTimeStamp != itOut->timestampUs) break;
+ if (!itOut->largeFrameInfo.empty()) {
+ // checking large audio frame metadata
+ if (itOut->largeFrameInfo[0].timestamp != itOut->timestampUs) {
+ ALOGE("Metadata first time stamp doesn't match");
+ err = true;
+ break;
+ }
+ uint64_t totalSize = 0;
+ uint64_t sampleSize = 0;
+ int64_t nextTimestamp = itOut->timestampUs;
+ for (auto& meta : itOut->largeFrameInfo) {
+ if (nextTimestamp != meta.timestamp) {
+ ALOGE("Metadata timestamp error: expect: %lld, got: %lld",
+ (long long)nextTimestamp, (long long)meta.timestamp);
+ err = true;
+ break;
+ }
+ totalSize += meta.size;
+ sampleSize = (meta.size / (nChannels * 2));
+ nextTimestamp += sampleSize * 1000000ll / nSampleRate;
+ }
+ if (totalSize != itOut->rangeLength) {
+ ALOGE("Metadata size error: expected:%lld, got: %d",
+ (long long)totalSize, itOut->rangeLength);
+ err = true;
+ }
+ }
// buffer samples = ((total bytes) / (ac * (bits per sample / 8))
samplesReceived += ((itOut->rangeLength) / (nChannels * 2));
expectedTimeStamp = samplesReceived * 1000000ll / nSampleRate;
@@ -453,7 +609,8 @@
android::Vector<FrameInfo> Info;
int32_t numCsds = populateInfoVector(mInfoFile, &Info, mTimestampDevTest, &mTimestampUslist);
- ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << mInfoFile;
+ ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << mInfoFile <<
+ " #CSD " << numCsds;
// Reset total no of frames received
mFramesReceived = 0;
@@ -474,10 +631,23 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
std::ifstream eleStream;
eleStream.open(mInputFile, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true);
+
ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
mFlushedIndices, mLinearPool, eleStream, &Info, 0,
(int)Info.size(), signalEOS));
@@ -529,6 +699,18 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
// request EOS for thumbnail
@@ -611,6 +793,18 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
// flush
std::list<std::unique_ptr<C2Work>> flushedWork;
@@ -681,6 +875,7 @@
uint32_t flags = 0;
uint32_t vtsFlags = 0;
uint32_t timestamp = 0;
+ uint32_t nLargeFrames = 0;
bool codecConfig = false;
// This test introduces empty CSD after every 20th frame
// and empty input frames at an interval of 5 frames.
@@ -688,6 +883,7 @@
if (!(frameId % 5)) {
vtsFlags = !(frameId % 20) ? (1 << VTS_BIT_FLAG_CSD_FRAME) : 0;
bytesCount = 0;
+ Info.push_back({bytesCount, vtsFlags, timestamp, {}});
} else {
if (!(eleInfo >> bytesCount)) break;
eleInfo >> flags;
@@ -695,8 +891,20 @@
ASSERT_NE(vtsFlags, 0xFF) << "unrecognized flag entry in info file: " << mInfoFile;
eleInfo >> timestamp;
codecConfig = (vtsFlags & (1 << VTS_BIT_FLAG_CSD_FRAME)) != 0;
+ Info.push_back({bytesCount, vtsFlags, timestamp, {}});
+ if ((vtsFlags & (1 << VTS_BIT_FLAG_LARGE_AUDIO_FRAME)) != 0) {
+ eleInfo >> nLargeFrames;
+ // this is a large audio frame.
+ while(nLargeFrames-- > 0) {
+ eleInfo >> bytesCount;
+ eleInfo >> flags;
+ eleInfo >> timestamp;
+ vtsFlags = mapInfoFlagstoVtsFlags(flags);
+ Info.editItemAt(Info.size() - 1).largeFrameInfo.push_back(
+ {(uint32_t)bytesCount, vtsFlags, timestamp});
+ }
+ }
}
- Info.push_back({bytesCount, vtsFlags, timestamp});
frameId++;
}
eleInfo.close();
@@ -711,6 +919,18 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
eleStream.open(mInputFile, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true);
@@ -766,7 +986,18 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
-
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
std::ifstream eleStream;
eleStream.open(mInputFile, std::ifstream::binary);
@@ -864,4 +1095,4 @@
::testing::InitGoogleTest(&argc, argv);
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
-}
+}
\ No newline at end of file
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml
index 6c04683..9b9c62f 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml
+++ b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml
@@ -38,6 +38,8 @@
<option name="push-file" key="bbb_opus_stereo_128kbps_48000hz.info" value="/data/local/tmp/media/bbb_opus_stereo_128kbps_48000hz.info" />
<option name="push-file" key="bbb_opus_stereo_128kbps_48000hz.opus" value="/data/local/tmp/media/bbb_opus_stereo_128kbps_48000hz.opus" />
<option name="push-file" key="bbb_raw_1ch_8khz_s32le.info" value="/data/local/tmp/media/bbb_raw_1ch_8khz_s32le.info" />
+ <option name="push-file" key="bbb_raw_1ch_8khz_s32le_largeframe.info"
+ value="/data/local/tmp/media/bbb_raw_1ch_8khz_s32le_largeframe.info" />
<option name="push-file" key="bbb_raw_1ch_8khz_s32le.raw" value="/data/local/tmp/media/bbb_raw_1ch_8khz_s32le.raw" />
<option name="push-file" key="bbb_vorbis_stereo_128kbps_48000hz.info" value="/data/local/tmp/media/bbb_vorbis_stereo_128kbps_48000hz.info" />
<option name="push-file" key="bbb_vorbis_stereo_128kbps_48000hz.vorbis" value="/data/local/tmp/media/bbb_vorbis_stereo_128kbps_48000hz.vorbis" />
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
index a72f7bd..92b0bf5 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
@@ -235,12 +235,13 @@
uint32_t flags = 0;
uint32_t vtsFlags = 0;
uint32_t timestamp = 0;
+ uint32_t nLargeFrames = 0;
while (1) {
if (!(eleInfo >> bytesCount)) break;
eleInfo >> flags;
vtsFlags = mapInfoFlagstoVtsFlags(flags);
if (vtsFlags == 0xFF) {
- ALOGE("unrecognized flag entry in info file %s", info.c_str());
+ ALOGE("unrecognized flag(0x%x) entry in info file %s", flags, info.c_str());
return -1;
}
eleInfo >> timestamp;
@@ -250,7 +251,18 @@
if (timestampDevTest && !codecConfig && !nonDisplayFrame) {
timestampUslist->push_back(timestamp);
}
- frameInfo->push_back({bytesCount, vtsFlags, timestamp});
+ frameInfo->push_back({bytesCount, vtsFlags, timestamp, {}});
+ if (vtsFlags & (1 << VTS_BIT_FLAG_LARGE_AUDIO_FRAME)) {
+ eleInfo >> nLargeFrames;
+ while(nLargeFrames-- > 0) {
+ eleInfo >> bytesCount;
+ eleInfo >> flags;
+ eleInfo >> timestamp;
+ vtsFlags = mapInfoFlagstoVtsFlags(flags);
+ frameInfo->editItemAt(frameInfo->size() - 1).largeFrameInfo.push_back(
+ {vtsFlags, static_cast<uint32_t>(bytesCount), timestamp});
+ }
+ }
}
ALOGV("numCsds : %d", numCsds);
eleInfo.close();
@@ -285,5 +297,6 @@
else if (infoFlags == 0x1) return (1 << VTS_BIT_FLAG_SYNC_FRAME);
else if (infoFlags == 0x10) return (1 << VTS_BIT_FLAG_NO_SHOW_FRAME);
else if (infoFlags == 0x20) return (1 << VTS_BIT_FLAG_CSD_FRAME);
+ else if (infoFlags == 0x40) return (1 << VTS_BIT_FLAG_LARGE_AUDIO_FRAME);
return 0xFF;
}
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
index eda7b99..708fe15 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
+++ b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
@@ -54,12 +54,16 @@
VTS_BIT_FLAG_SYNC_FRAME = 1,
VTS_BIT_FLAG_NO_SHOW_FRAME = 2,
VTS_BIT_FLAG_CSD_FRAME = 3,
+ VTS_BIT_FLAG_LARGE_AUDIO_FRAME = 4,
};
struct FrameInfo {
int bytesCount;
uint32_t vtsFlags;
int64_t timestamp;
+ // This is used when access-units are marked with
+ // VTS_BIT_FLAG_LARGE_AUDIO_FRAME
+ std::vector<C2AccessUnitInfosStruct> largeFrameInfo;
};
template <typename... T>
@@ -86,7 +90,6 @@
virtual void onWorkDone(const std::weak_ptr<android::Codec2Client::Component>& comp,
std::list<std::unique_ptr<C2Work>>& workItems) override {
/* TODO */
- ALOGD("onWorkDone called");
(void)comp;
if (callBack) callBack(workItems);
}
@@ -103,7 +106,6 @@
uint32_t errorCode) override {
/* TODO */
(void)comp;
- ALOGD("onError called");
if (errorCode != 0) ALOGE("Error : %u", errorCode);
}
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le_largeframe.info b/media/codec2/hal/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le_largeframe.info
new file mode 100644
index 0000000..291e323
--- /dev/null
+++ b/media/codec2/hal/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le_largeframe.info
@@ -0,0 +1,5 @@
+16384 64 0 1 16384 1 0
+49152 64 1024000 3 16384 1 1024000 16384 1 2048000 16384 1 3072000
+32768 64 4096000 2 16384 1 4096000 16384 1 5120000
+49152 64 6144000 3 16384 1 6144000 16384 1 7168000 16384 1 8192000
+10924 64 9216000 1 10924 1 9216000
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index df89510..f8fd425 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -739,7 +739,7 @@
ASSERT_NE(vtsFlags, 0xFF) << "unrecognized flag entry in info file: " << mInfoFile;
eleInfo >> timestamp;
timestamp += timestampOffset;
- Info.push_back({bytesCount, vtsFlags, timestamp});
+ Info.push_back({bytesCount, vtsFlags, timestamp, {}});
bool codecConfig = (vtsFlags & (1 << VTS_BIT_FLAG_CSD_FRAME)) != 0;
bool nonDisplayFrame = (vtsFlags & (1 << VTS_BIT_FLAG_NO_SHOW_FRAME)) != 0;
@@ -978,7 +978,7 @@
eleInfo >> timestamp;
codecConfig = (vtsFlags & (1 << VTS_BIT_FLAG_CSD_FRAME)) != 0;
}
- Info.push_back({bytesCount, vtsFlags, timestamp});
+ Info.push_back({bytesCount, vtsFlags, timestamp, {}});
frameId++;
}
eleInfo.close();
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index fc3f699..2af18cc 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -974,7 +974,7 @@
if (mModule == nullptr) return NO_INIT;
{
std::lock_guard l(mLock);
- mMapper.resetUnusedPatchesAndPortConfigs();
+ mMapper.resetUnusedPatchesPortConfigsAndPorts();
}
ModuleDebug debug{ .simulateDeviceConnections = enabled };
status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
index d4024a2..2b7f298 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.cpp
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -730,7 +730,7 @@
this, __func__, ioHandle, device.toString().c_str(),
flags.toString().c_str(), toString(source).c_str(),
config->toString().c_str(), mixPortConfig->toString().c_str());
- resetUnusedPatchesAndPortConfigs();
+ resetUnusedPatchesPortConfigsAndPorts();
const AudioConfig initialConfig = *config;
// Find / create AudioPortConfigs for the device port and the mix port,
// then find / create a patch between them, and open a stream on the mix port.
@@ -858,7 +858,7 @@
result = BAD_VALUE;
}
}
- resetUnusedPortConfigs();
+ resetUnusedPortConfigsAndPorts();
return result;
}
@@ -875,7 +875,7 @@
ALOGE("%s: port config id %d not found", __func__, portConfigId);
}
-void Hal2AidlMapper::resetUnusedPatchesAndPortConfigs() {
+void Hal2AidlMapper::resetUnusedPatchesPortConfigsAndPorts() {
// Since patches can be created independently of streams via 'createOrUpdatePatch',
// here we only clean up patches for released streams.
std::set<int32_t> patchesToRelease;
@@ -889,11 +889,11 @@
it = mStreams.erase(it);
}
}
- // 'releaseAudioPatches' also resets unused port configs.
+ // 'releaseAudioPatches' also resets unused port configs and ports.
releaseAudioPatches(patchesToRelease);
}
-void Hal2AidlMapper::resetUnusedPortConfigs() {
+void Hal2AidlMapper::resetUnusedPortConfigsAndPorts() {
// The assumption is that port configs are used to create patches
// (or to open streams, but that involves creation of patches, too). Thus,
// orphaned port configs can and should be reset.
@@ -934,6 +934,7 @@
}
status_t Hal2AidlMapper::setDevicePortConnectedState(const AudioPort& devicePort, bool connected) {
+ resetUnusedPatchesPortConfigsAndPorts();
if (connected) {
AudioDevice matchDevice = devicePort.ext.get<AudioPortExt::device>().device;
std::optional<AudioPort> templatePort;
@@ -968,7 +969,6 @@
}
templatePort = portsIt->second;
}
- resetUnusedPatchesAndPortConfigs();
// Use the ID of the "template" port, use all the information from the provided port.
AudioPort connectedPort = devicePort;
@@ -995,7 +995,6 @@
ALOGD("%s: device port for device %s found in the module %s",
__func__, matchDevice.toString().c_str(), mInstance.c_str());
}
- resetUnusedPatchesAndPortConfigs();
// Disconnection of remote submix out with address "0" is a special case. We need to replace
// the connected port entry with the "augmented template".
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.h b/media/libaudiohal/impl/Hal2AidlMapper.h
index 93ce233..f937173 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.h
+++ b/media/libaudiohal/impl/Hal2AidlMapper.h
@@ -91,7 +91,7 @@
::aidl::android::media::audio::common::AudioPortConfig* portConfig,
Cleanups* cleanups = nullptr);
status_t releaseAudioPatch(int32_t patchId);
- void resetUnusedPatchesAndPortConfigs();
+ void resetUnusedPatchesPortConfigsAndPorts();
status_t setDevicePortConnectedState(
const ::aidl::android::media::audio::common::AudioPort& devicePort, bool connected);
@@ -184,7 +184,7 @@
status_t releaseAudioPatches(const std::set<int32_t>& patchIds);
void resetPatch(int32_t patchId) { (void)releaseAudioPatch(patchId); }
void resetPortConfig(int32_t portConfigId);
- void resetUnusedPortConfigs();
+ void resetUnusedPortConfigsAndPorts();
status_t updateAudioPort(
int32_t portId, ::aidl::android::media::audio::common::AudioPort* port);
status_t updateRoutes();
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index c2d7ee1..5f525d7 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -234,7 +234,9 @@
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
if (!mStream) return NO_INIT;
- return mStream->dump(fd, Args(args).args(), args.size());
+ status_t status = mStream->dump(fd, Args(args).args(), args.size());
+ mStreamPowerLog.dump(fd);
+ return status;
}
status_t StreamHalAidl::start() {
diff --git a/media/libeffects/downmix/Android.bp b/media/libeffects/downmix/Android.bp
index 37633ae..b56872c 100644
--- a/media/libeffects/downmix/Android.bp
+++ b/media/libeffects/downmix/Android.bp
@@ -69,6 +69,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/dynamicsproc/Android.bp b/media/libeffects/dynamicsproc/Android.bp
index 9e154cf..e93a4e6 100644
--- a/media/libeffects/dynamicsproc/Android.bp
+++ b/media/libeffects/dynamicsproc/Android.bp
@@ -95,6 +95,6 @@
],
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/hapticgenerator/Android.bp b/media/libeffects/hapticgenerator/Android.bp
index cc19a80..7d96b53 100644
--- a/media/libeffects/hapticgenerator/Android.bp
+++ b/media/libeffects/hapticgenerator/Android.bp
@@ -84,6 +84,6 @@
],
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/loudness/Android.bp b/media/libeffects/loudness/Android.bp
index 05bbec3..46e4669 100644
--- a/media/libeffects/loudness/Android.bp
+++ b/media/libeffects/loudness/Android.bp
@@ -69,6 +69,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index da5346f..a50ba93 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -130,7 +130,7 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
@@ -161,6 +161,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/preprocessing/Android.bp b/media/libeffects/preprocessing/Android.bp
index 564eb36..994b061 100644
--- a/media/libeffects/preprocessing/Android.bp
+++ b/media/libeffects/preprocessing/Android.bp
@@ -89,6 +89,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/visualizer/Android.bp b/media/libeffects/visualizer/Android.bp
index a8b665b..66ceadf 100644
--- a/media/libeffects/visualizer/Android.bp
+++ b/media/libeffects/visualizer/Android.bp
@@ -70,6 +70,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 0af9d12..712b405 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -137,7 +137,7 @@
cflags: [
"-DDISABLE_AUDIO_SYSTEM_OFFLOAD",
],
- }
+ },
},
}
@@ -273,7 +273,7 @@
"VideoFrameSchedulerBase.cpp",
"VideoFrameScheduler.cpp",
"VideoRenderQualityTracker.cpp",
- ],
+ ],
shared_libs: [
"libstagefright_framecapture_utils",
@@ -330,7 +330,7 @@
"libmedia_ndkformatpriv",
],
- header_libs:[
+ header_libs: [
"libmediadrm_headers",
"libnativeloader-headers",
"libstagefright_xmlparser_headers",
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index c27cfc5..6aac0e5 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -320,8 +320,8 @@
return Status::fromStatus(STATUS_INVALID_OPERATION);
}
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(this)};
+ .uid = static_cast<int32_t>(mUid),
+ .id = getId(this)};
service->removeClient(clientInfo);
*_aidl_return = true;
return Status::ok();
@@ -398,6 +398,10 @@
mCodecName = name;
}
+ inline void setImportance(int importance) {
+ mImportance = importance;
+ }
+
private:
// To get the binder interface to ResourceManagerService.
void getService() {
@@ -437,12 +441,30 @@
mGetServiceFuture = std::async(std::launch::async, [this] { getService(); });
}
+ /**
+ * Get the ClientInfo to communicate with the ResourceManager.
+ *
+ * ClientInfo includes:
+ * - {pid, uid} of the process
+ * - identifier for the client
+ * - name of the client/codec
+ * - importance associated with the client
+ */
+ inline ClientInfoParcel getClientInfo() const {
+ ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
+ .uid = static_cast<int32_t>(mUid),
+ .id = getId(mClient),
+ .name = mCodecName,
+ .importance = mImportance};
+ return std::move(clientInfo);
+ }
private:
- std::mutex mLock;
- pid_t mPid;
- uid_t mUid;
- bool mBinderDied = false;
+ std::mutex mLock;
+ bool mBinderDied = false;
+ pid_t mPid;
+ uid_t mUid;
+ int mImportance = 0;
std::string mCodecName;
/**
* Reconnecting with the ResourceManagerService, after its binder interface dies,
@@ -550,11 +572,7 @@
std::vector<MediaResourceParcel> resources;
std::copy(mMediaResourceParcel.begin(), mMediaResourceParcel.end(),
std::back_inserter(resources));
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- mService->addResource(clientInfo, mClient, resources);
+ mService->addResource(getClientInfo(), mClient, resources);
}
void MediaCodec::ResourceManagerServiceProxy::BinderDiedCallback(void* cookie) {
@@ -587,11 +605,7 @@
}
std::vector<MediaResourceParcel> resources;
resources.push_back(resource);
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->addResource(clientInfo, mClient, resources);
+ service->addResource(getClientInfo(), mClient, resources);
mMediaResourceParcel.emplace(resource);
}
@@ -605,11 +619,7 @@
}
std::vector<MediaResourceParcel> resources;
resources.push_back(resource);
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->removeResource(clientInfo, resources);
+ service->removeResource(getClientInfo(), resources);
mMediaResourceParcel.erase(resource);
}
@@ -620,11 +630,7 @@
ALOGW("Service isn't available");
return;
}
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->removeClient(clientInfo);
+ service->removeClient(getClientInfo());
mMediaResourceParcel.clear();
}
@@ -635,11 +641,7 @@
ALOGW("Service isn't available");
return;
}
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->markClientForPendingRemoval(clientInfo);
+ service->markClientForPendingRemoval(getClientInfo());
mMediaResourceParcel.clear();
}
@@ -652,11 +654,7 @@
return false;
}
bool success;
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- Status status = service->reclaimResource(clientInfo, resources, &success);
+ Status status = service->reclaimResource(getClientInfo(), resources, &success);
return status.isOk() && success;
}
@@ -667,11 +665,7 @@
ALOGW("Service isn't available");
return;
}
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->notifyClientCreated(clientInfo);
+ service->notifyClientCreated(getClientInfo());
}
void MediaCodec::ResourceManagerServiceProxy::notifyClientStarted(
@@ -682,10 +676,7 @@
ALOGW("Service isn't available");
return;
}
- clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
- clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
- clientConfig.clientInfo.id = getId(mClient);
- clientConfig.clientInfo.name = mCodecName;
+ clientConfig.clientInfo = getClientInfo();
service->notifyClientStarted(clientConfig);
}
@@ -697,10 +688,7 @@
ALOGW("Service isn't available");
return;
}
- clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
- clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
- clientConfig.clientInfo.id = getId(mClient);
- clientConfig.clientInfo.name = mCodecName;
+ clientConfig.clientInfo = getClientInfo();
service->notifyClientStopped(clientConfig);
}
@@ -712,10 +700,7 @@
ALOGW("Service isn't available");
return;
}
- clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
- clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
- clientConfig.clientInfo.id = getId(mClient);
- clientConfig.clientInfo.name = mCodecName;
+ clientConfig.clientInfo = getClientInfo();
service->notifyClientConfigChanged(clientConfig);
}
@@ -1716,6 +1701,21 @@
}
}
+void MediaCodec::updateCodecImportance(const sp<AMessage>& msg) {
+ // Update the codec importance.
+ int32_t importance = 0;
+ if (msg->findInt32(KEY_IMPORTANCE, &importance)) {
+ // Ignoring the negative importance.
+ if (importance >= 0) {
+ // Notify RM about the change in the importance.
+ mResourceManagerProxy->setImportance(importance);
+ ClientConfigParcel clientConfig;
+ initClientConfigParcel(clientConfig);
+ mResourceManagerProxy->notifyClientConfigChanged(clientConfig);
+ }
+ }
+}
+
constexpr const char *MediaCodec::asString(TunnelPeekState state, const char *default_string){
switch(state) {
case TunnelPeekState::kLegacyMode:
@@ -2224,23 +2224,9 @@
static void mapFormat(AString componentName, const sp<AMessage> &format, const char *kind,
bool reverse);
-status_t MediaCodec::configure(
- const sp<AMessage> &format,
- const sp<Surface> &nativeWindow,
- const sp<ICrypto> &crypto,
- uint32_t flags) {
- return configure(format, nativeWindow, crypto, NULL, flags);
-}
-
-status_t MediaCodec::configure(
- const sp<AMessage> &format,
- const sp<Surface> &surface,
- const sp<ICrypto> &crypto,
- const sp<IDescrambler> &descrambler,
- uint32_t flags) {
-
- sp<AMessage> msg = new AMessage(kWhatConfigure, this);
+mediametrics_handle_t MediaCodec::createMediaMetrics(const sp<AMessage>& format, uint32_t flags) {
mediametrics_handle_t nextMetricsHandle = mediametrics_create(kCodecKeyName);
+ bool isEncoder = (flags & CONFIGURE_FLAG_ENCODE);
// TODO: validity check log-session-id: it should be a 32-hex-digit.
format->findString("log-session-id", &mLogSessionId);
@@ -2255,8 +2241,7 @@
if (format->findInt32("level", &level)) {
mediametrics_setInt32(nextMetricsHandle, kCodecLevel, level);
}
- mediametrics_setInt32(nextMetricsHandle, kCodecEncoder,
- (flags & CONFIGURE_FLAG_ENCODE) ? 1 : 0);
+ mediametrics_setInt32(nextMetricsHandle, kCodecEncoder, isEncoder);
if (!mLogSessionId.empty()) {
mediametrics_setCString(nextMetricsHandle, kCodecLogSessionId, mLogSessionId.c_str());
@@ -2335,7 +2320,7 @@
}
}
- if (flags & CONFIGURE_FLAG_ENCODE) {
+ if (isEncoder) {
int8_t enableShaping = property_get_bool(enableMediaFormatShapingProperty,
enableMediaFormatShapingDefault);
if (!enableShaping) {
@@ -2380,6 +2365,31 @@
updateLowLatency(format);
+ return nextMetricsHandle;
+}
+
+status_t MediaCodec::configure(
+ const sp<AMessage> &format,
+ const sp<Surface> &nativeWindow,
+ const sp<ICrypto> &crypto,
+ uint32_t flags) {
+ return configure(format, nativeWindow, crypto, NULL, flags);
+}
+
+status_t MediaCodec::configure(
+ const sp<AMessage> &format,
+ const sp<Surface> &surface,
+ const sp<ICrypto> &crypto,
+ const sp<IDescrambler> &descrambler,
+ uint32_t flags) {
+
+ // Update the codec importance.
+ updateCodecImportance(format);
+
+ // Create and set up metrics for this codec.
+ mediametrics_handle_t nextMetricsHandle = createMediaMetrics(format, flags);
+
+ sp<AMessage> msg = new AMessage(kWhatConfigure, this);
msg->setMessage("format", format);
msg->setInt32("flags", flags);
msg->setObject("surface", surface);
@@ -6591,6 +6601,7 @@
return NO_INIT;
}
updateLowLatency(params);
+ updateCodecImportance(params);
mapFormat(mComponentName, params, nullptr, false);
updateTunnelPeek(params);
mCodec->signalSetParameters(params);
diff --git a/media/libstagefright/colorconversion/fuzzer/Android.bp b/media/libstagefright/colorconversion/fuzzer/Android.bp
index 76b054a..237e715 100644
--- a/media/libstagefright/colorconversion/fuzzer/Android.bp
+++ b/media/libstagefright/colorconversion/fuzzer/Android.bp
@@ -47,9 +47,15 @@
],
fuzz_config: {
cc: [
- "android-media-fuzzing-reports@google.com",
+ "android-fwk-video@google.com",
],
- componentid: 155276,
+ componentid: 42195,
+ hotlists: ["4593311"],
+ description: "The fuzzer targets the APIs of libstagefright_color_conversion",
+ vector: "local_no_privileges_required",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index baa5b7e..2f94e5e 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -320,6 +320,9 @@
status_t reclaim(bool force = false);
friend struct ResourceManagerClient;
+ // to create the metrics associated with this codec.
+ mediametrics_handle_t createMediaMetrics(const sp<AMessage>& format, uint32_t flags);
+
private:
enum State {
UNINITIALIZED,
@@ -462,6 +465,7 @@
void resetMetricsFields();
void updateEphemeralMediametrics(mediametrics_handle_t item);
void updateLowLatency(const sp<AMessage> &msg);
+ void updateCodecImportance(const sp<AMessage>& msg);
void onGetMetrics(const sp<AMessage>& msg);
constexpr const char *asString(TunnelPeekState state, const char *default_string="?");
void updateTunnelPeek(const sp<AMessage> &msg);
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 7334639..f4c40e1 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -794,6 +794,7 @@
inline constexpr char KEY_HDR10_PLUS_INFO[] = "hdr10-plus-info";
inline constexpr char KEY_HEIGHT[] = "height";
inline constexpr char KEY_I_FRAME_INTERVAL[] = "i-frame-interval";
+inline constexpr char KEY_IMPORTANCE[] = "importance";
inline constexpr char KEY_INTRA_REFRESH_PERIOD[] = "intra-refresh-period";
inline constexpr char KEY_IS_ADTS[] = "is-adts";
inline constexpr char KEY_IS_AUTOSELECT[] = "is-autoselect";
@@ -809,6 +810,9 @@
inline constexpr char KEY_MAX_FPS_TO_ENCODER[] = "max-fps-to-encoder";
inline constexpr char KEY_MAX_HEIGHT[] = "max-height";
inline constexpr char KEY_MAX_INPUT_SIZE[] = "max-input-size";
+inline constexpr char KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE[] = "buffer-batch-max-output-size";
+inline constexpr char KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE[] =
+ "buffer-batch-threshold-output-size";
inline constexpr char KEY_MAX_OUTPUT_CHANNEL_COUNT[] = "max-output-channel-count";
inline constexpr char KEY_MAX_PTS_GAP_TO_ENCODER[] = "max-pts-gap-to-encoder";
inline constexpr char KEY_MAX_WIDTH[] = "max-width";
diff --git a/media/mtp/tests/MtpFuzzer/MtpMockHandle.h b/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
index 111485c..aa632a4 100644
--- a/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
+++ b/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
@@ -45,18 +45,18 @@
pkt.size());
// packet is bigger than what the caller can handle,
- if (pkt.size() > len) {
+ if (pkt.size() - mPacketOffset > len) {
memcpy(data, pkt.data() + mPacketOffset, len);
mPacketOffset += len;
readAmt = len;
// packet is equal or smaller than the caller buffer
} else {
- memcpy(data, pkt.data() + mPacketOffset, pkt.size());
+ memcpy(data, pkt.data() + mPacketOffset, pkt.size() - mPacketOffset);
mPacketNumber++;
mPacketOffset = 0;
- readAmt = pkt.size();
+ readAmt = pkt.size() - mPacketOffset;
}
return readAmt;
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 161b5e3..a26681e 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -428,6 +428,7 @@
EXPORT const char* AMEDIAFORMAT_KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
EXPORT const char* AMEDIAFORMAT_KEY_HEIGHT = "height";
EXPORT const char* AMEDIAFORMAT_KEY_ICC_PROFILE = "icc-profile";
+EXPORT const char* AMEDIAFORMAT_KEY_IMPORTANCE = "importance";
EXPORT const char* AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
EXPORT const char* AMEDIAFORMAT_KEY_IS_ADTS = "is-adts";
EXPORT const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT = "is-autoselect";
@@ -449,6 +450,10 @@
EXPORT const char* AMEDIAFORMAT_KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
+EXPORT const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE =
+ "buffer-batch-max-output-size";
+EXPORT const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE =
+ "buffer-batch-threshold-output-size";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_PTS_GAP_TO_ENCODER = "max-pts-gap-to-encoder";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";
EXPORT const char* AMEDIAFORMAT_KEY_MIME = "mime";
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index b2cdf8d..cc1dd9f 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -168,6 +168,7 @@
extern const char* AMEDIAFORMAT_KEY_GRID_ROWS __INTRODUCED_IN(28);
extern const char* AMEDIAFORMAT_KEY_HDR_STATIC_INFO __INTRODUCED_IN(28);
extern const char* AMEDIAFORMAT_KEY_HEIGHT __INTRODUCED_IN(21);
+extern const char* AMEDIAFORMAT_KEY_IMPORTANCE __INTRODUCED_IN(35);
extern const char* AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD __INTRODUCED_IN(28);
extern const char* AMEDIAFORMAT_KEY_IS_ADTS __INTRODUCED_IN(21);
extern const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT __INTRODUCED_IN(21);
@@ -186,6 +187,8 @@
extern const char* AMEDIAFORMAT_KEY_MAX_B_FRAMES __INTRODUCED_IN(34);
extern const char* AMEDIAFORMAT_KEY_MAX_HEIGHT __INTRODUCED_IN(21);
extern const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE __INTRODUCED_IN(21);
+extern const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE __INTRODUCED_IN(35);
+extern const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE __INTRODUCED_IN(35);
extern const char* AMEDIAFORMAT_KEY_MAX_WIDTH __INTRODUCED_IN(21);
extern const char* AMEDIAFORMAT_KEY_MIME __INTRODUCED_IN(21);
extern const char* AMEDIAFORMAT_KEY_MPEG_USER_DATA __INTRODUCED_IN(28);
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index 794bda0..7f66859 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -74,6 +74,7 @@
name: "libresourcemanagerservice",
srcs: [
+ "ClientImportanceReclaimPolicy.cpp",
"DefaultResourceModel.cpp",
"ProcessPriorityReclaimPolicy.cpp",
"ResourceManagerMetrics.cpp",
diff --git a/services/mediaresourcemanager/ClientImportanceReclaimPolicy.cpp b/services/mediaresourcemanager/ClientImportanceReclaimPolicy.cpp
new file mode 100644
index 0000000..a81b32f
--- /dev/null
+++ b/services/mediaresourcemanager/ClientImportanceReclaimPolicy.cpp
@@ -0,0 +1,88 @@
+/*
+**
+** Copyright 2023, 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.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ClientImportanceReclaimPolicy"
+#include <utils/Log.h>
+
+#include "ResourceTracker.h"
+#include "ResourceManagerService.h"
+#include "ClientImportanceReclaimPolicy.h"
+
+namespace android {
+
+using aidl::android::media::IResourceManagerClient;
+
+ClientImportanceReclaimPolicy::ClientImportanceReclaimPolicy(
+ const std::shared_ptr<ResourceTracker>& resourceTracker)
+ : mResourceTracker(resourceTracker) {
+}
+
+ClientImportanceReclaimPolicy::~ClientImportanceReclaimPolicy() {
+}
+
+// Find the biggest client from the same process with the lowest importance
+// than that of the requesting client.
+bool ClientImportanceReclaimPolicy::getClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients) {
+ pid_t callingPid = reclaimRequestInfo.mCallingPid;
+ int32_t callingImportance = reclaimRequestInfo.mCallingClientImportance;
+ MediaResource::Type type = reclaimRequestInfo.mResources[0].type;
+ MediaResource::SubType subType = reclaimRequestInfo.mResources[0].subType;
+ ClientInfo targetClient;
+ // Look to find the biggest client with lowest importance from the same process that
+ // has the other resources and with the given primary type.
+ bool found = false;
+ MediaResource::SubType primarySubType = subType;
+ for (size_t index = 1; !found && (index < reclaimRequestInfo.mResources.size()); index++) {
+ MediaResource::Type type = reclaimRequestInfo.mResources[index].type;
+ MediaResource::SubType subType = reclaimRequestInfo.mResources[index].subType;
+ found = mResourceTracker->getLeastImportantBiggestClient(
+ callingPid, callingImportance,
+ type, subType, primarySubType,
+ clients, targetClient);
+ }
+ // If no success, then select the biggest client of primary type with lowest importance
+ // from the same process.
+ if (!found) {
+ found = mResourceTracker->getLeastImportantBiggestClient(
+ callingPid, callingImportance,
+ type, subType, MediaResource::SubType::kUnspecifiedSubType,
+ clients, targetClient);
+ }
+ // If we haven't found a client yet, then select the biggest client of different type
+ // with lowest importance from the same process.
+ // This is applicable for codec type only.
+ if (!found) {
+ if (type != MediaResource::Type::kSecureCodec &&
+ type != MediaResource::Type::kNonSecureCodec) {
+ return false;
+ }
+ MediaResourceType otherType = (type == MediaResource::Type::kSecureCodec) ?
+ MediaResource::Type::kNonSecureCodec : MediaResource::Type::kSecureCodec;
+ if (!mResourceTracker->getLeastImportantBiggestClient(
+ callingPid, callingImportance,
+ otherType, subType, MediaResource::SubType::kUnspecifiedSubType,
+ clients, targetClient)) {
+ return false;
+ }
+ }
+ targetClients.emplace_back(targetClient);
+ return true;
+}
+} // namespace android
diff --git a/services/mediaresourcemanager/ClientImportanceReclaimPolicy.h b/services/mediaresourcemanager/ClientImportanceReclaimPolicy.h
new file mode 100644
index 0000000..1a54c7d
--- /dev/null
+++ b/services/mediaresourcemanager/ClientImportanceReclaimPolicy.h
@@ -0,0 +1,64 @@
+/*
+**
+** Copyright 2023, 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.
+*/
+
+#ifndef ANDROID_MEDIA_CLIENTIMPORTANCERECLAIMPOLICY_H_
+#define ANDROID_MEDIA_CLIENTIMPORTANCERECLAIMPOLICY_H_
+
+#include <media/MediaResource.h>
+#include "IReclaimPolicy.h"
+
+namespace android {
+
+class ResourceTracker;
+struct ClientInfo;
+
+/*
+ * Implementation of Reclaim Policy based on the client's importance.
+ *
+ * Find the least important (other than that of requesting client) client from the
+ * same process (that is requesting for the resource).
+ * If there are multiple clients with least importance, then pick the biggest
+ * client among them.
+ *
+ */
+class ClientImportanceReclaimPolicy : public IReclaimPolicy {
+public:
+ explicit ClientImportanceReclaimPolicy(const std::shared_ptr<ResourceTracker>& resourceTracker);
+
+ virtual ~ClientImportanceReclaimPolicy();
+
+ /*
+ * Based on the client importance, identify and return the least important client of
+ * the requesting process from the list of given clients that satisfy the resource requested.
+ *
+ * @param[in] reclaimRequestInfo Information about the resource request
+ * @param[in] client List of clients to select from.
+ * @param[out] targetClients Upon success, this will have the list of identified client(s).
+ *
+ * @return true on success, false otherwise
+ */
+ bool getClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients) override;
+
+private:
+ std::shared_ptr<ResourceTracker> mResourceTracker;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_CLIENTIMPORTANCERECLAIMPOLICY_H_
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 4bdb6e1..3a02443 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -74,10 +74,7 @@
const ResourceList& resources = info.resources;
resourceLog.append(" Resources:\n");
- for (auto it = resources.begin(); it != resources.end(); it++) {
- snprintf(buffer, SIZE, " %s\n", toString(it->second).c_str());
- resourceLog.append(buffer);
- }
+ resourceLog.append(resources.toString());
}
}
@@ -315,31 +312,21 @@
for (size_t i = 0; i < resources.size(); ++i) {
const auto &res = resources[i];
- const auto resType = std::tuple(res.type, res.subType, res.id);
if (res.value < 0 && res.type != MediaResource::Type::kDrmSession) {
ALOGW("Ignoring request to remove negative value of non-drm resource");
continue;
}
- if (info.resources.find(resType) == info.resources.end()) {
- if (res.value <= 0) {
- // We can't init a new entry with negative value, although it's allowed
- // to merge in negative values after the initial add.
- ALOGW("Ignoring request to add new resource entry with value <= 0");
- continue;
- }
+ bool isNewEntry = false;
+ if (!info.resources.add(res, &isNewEntry)) {
+ continue;
+ }
+ if (isNewEntry) {
onFirstAdded(res, info.uid);
- info.resources[resType] = res;
- } else {
- mergeResources(info.resources[resType], res);
}
+
// Add it to the list of added resources for observers.
- auto it = resourceAdded.find(resType);
- if (it == resourceAdded.end()) {
- resourceAdded[resType] = res;
- } else {
- mergeResources(it->second, res);
- }
+ resourceAdded.add(res);
}
if (info.deathNotifier == nullptr && client != nullptr) {
info.deathNotifier = DeathNotifier::Create(
@@ -386,31 +373,22 @@
ResourceList resourceRemoved;
for (size_t i = 0; i < resources.size(); ++i) {
const auto &res = resources[i];
- const auto resType = std::tuple(res.type, res.subType, res.id);
if (res.value < 0) {
ALOGW("Ignoring request to remove negative value of resource");
continue;
}
- // ignore if we don't have it
- if (info.resources.find(resType) != info.resources.end()) {
- MediaResourceParcel &resource = info.resources[resType];
+
+ long removedEntryValue = -1;
+ if (info.resources.remove(res, &removedEntryValue)) {
MediaResourceParcel actualRemoved = res;
- if (resource.value > res.value) {
- resource.value -= res.value;
- } else {
+ if (removedEntryValue != -1) {
onLastRemoved(res, info.uid);
- actualRemoved.value = resource.value;
- info.resources.erase(resType);
+ actualRemoved.value = removedEntryValue;
}
// Add it to the list of removed resources for observers.
- auto it = resourceRemoved.find(resType);
- if (it == resourceRemoved.end()) {
- resourceRemoved[resType] = actualRemoved;
- } else {
- mergeResources(it->second, actualRemoved);
- }
+ resourceRemoved.add(actualRemoved);
}
}
if (mObserverService != nullptr && !resourceRemoved.empty()) {
@@ -453,8 +431,8 @@
}
const ResourceInfo& info = foundClient->second;
- for (auto it = info.resources.begin(); it != info.resources.end(); it++) {
- onLastRemoved(it->second, info.uid);
+ for (const MediaResourceParcel& res : info.resources.getResources()) {
+ onLastRemoved(res, info.uid);
}
// Since this client has been removed, update the metrics collector.
@@ -492,9 +470,10 @@
}
bool ResourceManagerService::getTargetClients(
- int32_t callingPid,
+ const ClientInfoParcel& clientInfo,
const std::vector<MediaResourceParcel>& resources,
std::vector<ClientInfo>& targetClients) {
+ int32_t callingPid = clientInfo.pid;
std::scoped_lock lock{mLock};
if (!mProcessInfo->isPidTrusted(callingPid)) {
pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
@@ -598,10 +577,9 @@
Status ResourceManagerService::reclaimResource(const ClientInfoParcel& clientInfo,
const std::vector<MediaResourceParcel>& resources, bool* _aidl_return) {
- int32_t callingPid = clientInfo.pid;
std::string clientName = clientInfo.name;
String8 log = String8::format("reclaimResource(callingPid %d, uid %d resources %s)",
- callingPid, clientInfo.uid, getString(resources).c_str());
+ clientInfo.pid, clientInfo.uid, getString(resources).c_str());
mServiceLog->add(log);
*_aidl_return = false;
@@ -611,7 +589,7 @@
}
std::vector<ClientInfo> targetClients;
- if (!getTargetClients(callingPid, resources, targetClients)) {
+ if (!getTargetClients(clientInfo, resources, targetClients)) {
// Nothing to reclaim from.
ALOGI("%s: There aren't any clients to reclaim from", __func__);
return Status::ok();
@@ -642,7 +620,7 @@
mResourceManagerMetrics->pushReclaimAtom(clientInfo, priorities, targetClients, reclaimed);
}
-std::shared_ptr<IResourceManagerClient> ResourceManagerService::getClient(
+std::shared_ptr<IResourceManagerClient> ResourceManagerService::getClient_l(
int pid, const int64_t& clientId) const {
std::map<int, ResourceInfos>::const_iterator found = mMap.find(pid);
if (found == mMap.end()) {
@@ -660,7 +638,7 @@
return foundClient->second.client;
}
-bool ResourceManagerService::removeClient(int pid, const int64_t& clientId) {
+bool ResourceManagerService::removeClient_l(int pid, const int64_t& clientId) {
std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
if (found == mMap.end()) {
ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
@@ -687,8 +665,11 @@
int64_t failedClientId = -1;
int32_t failedClientPid = -1;
for (const ClientInfo& targetClient : targetClients) {
- std::shared_ptr<IResourceManagerClient> client = getClient(
- targetClient.mPid, targetClient.mClientId);
+ std::shared_ptr<IResourceManagerClient> client = nullptr;
+ {
+ std::scoped_lock lock{mLock};
+ client = getClient_l(targetClient.mPid, targetClient.mClientId);
+ }
if (client == nullptr) {
// skip already released clients.
continue;
@@ -710,7 +691,7 @@
{
std::scoped_lock lock{mLock};
- bool found = removeClient(failedClientPid, failedClientId);
+ bool found = removeClient_l(failedClientPid, failedClientId);
if (found) {
ALOGW("Failed to reclaim resources from client with pid %d", failedClientPid);
} else {
@@ -1056,8 +1037,7 @@
if (pendingRemovalOnly && !info.pendingRemoval) {
continue;
}
- for (auto it = resources.begin(); it != resources.end(); it++) {
- const MediaResourceParcel &resource = it->second;
+ for (const MediaResourceParcel& resource : resources.getResources()) {
if (hasResourceType(type, subType, resource)) {
if (resource.value > largestValue) {
largestValue = resource.value;
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 44ed005..dc1600a 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -174,7 +174,7 @@
// Gets the list of all the clients who own the list of specified resource type
// and satisfy the resource model and the reclaim policy.
virtual bool getTargetClients(
- int32_t callingPid,
+ const ClientInfoParcel& clientInfo,
const std::vector<MediaResourceParcel>& resources,
std::vector<ClientInfo>& targetClients);
@@ -210,11 +210,11 @@
virtual void removeProcessInfoOverride(int pid);
// Get the client for given pid and the clientId from the map
- virtual std::shared_ptr<IResourceManagerClient> getClient(
+ virtual std::shared_ptr<IResourceManagerClient> getClient_l(
int pid, const int64_t& clientId) const;
// Remove the client for given pid and the clientId from the map
- virtual bool removeClient(int pid, const int64_t& clientId);
+ virtual bool removeClient_l(int pid, const int64_t& clientId);
// Get all the resource status for dump
virtual void getResourceDump(std::string& resourceLog) const;
@@ -233,6 +233,12 @@
virtual const std::map<int, ResourceInfos>& getResourceMap() const {
return mMap;
}
+ // enable/disable process priority based reclaim and client importance based reclaim
+ virtual void setReclaimPolicy(bool processPriority, bool clientImportance) {
+ // Implemented by the refactored/new RMService
+ (void)processPriority;
+ (void)clientImportance;
+ }
// END: TEST only functions
protected:
diff --git a/services/mediaresourcemanager/ResourceManagerServiceNew.cpp b/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
index dde389a..af093ca 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
+++ b/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
@@ -22,6 +22,7 @@
#include <mediautils/ProcessInfo.h>
#include "DefaultResourceModel.h"
+#include "ClientImportanceReclaimPolicy.h"
#include "ProcessPriorityReclaimPolicy.h"
#include "ResourceManagerServiceNew.h"
#include "ResourceTracker.h"
@@ -61,8 +62,10 @@
void ResourceManagerServiceNew::setUpReclaimPolicies() {
mReclaimPolicies.clear();
- // Process priority (oom score) as the Default reclaim policy.
- mReclaimPolicies.push_back(std::make_unique<ProcessPriorityReclaimPolicy>(mResourceTracker));
+ // Add Reclaim policies based on:
+ // - the Process priority (oom score)
+ // - the client/codec importance.
+ setReclaimPolicy(true /* processPriority */, true /* clientImportance */);
}
Status ResourceManagerServiceNew::config(const std::vector<MediaResourcePolicyParcel>& policies) {
@@ -212,6 +215,11 @@
Status ResourceManagerServiceNew::notifyClientConfigChanged(
const ClientConfigParcel& clientConfig) {
+ {
+ // Update the ResourceTracker about the change in the configuration.
+ std::scoped_lock lock{mLock};
+ mResourceTracker->updateResource(clientConfig.clientInfo);
+ }
return ResourceManagerService::notifyClientConfigChanged(clientConfig);
}
@@ -225,9 +233,10 @@
}
bool ResourceManagerServiceNew::getTargetClients(
- int callingPid,
+ const ClientInfoParcel& clientInfo,
const std::vector<MediaResourceParcel>& resources,
std::vector<ClientInfo>& targetClients) {
+ int32_t callingPid = clientInfo.pid;
std::scoped_lock lock{mLock};
if (!mProcessInfo->isPidTrusted(callingPid)) {
pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
@@ -238,7 +247,8 @@
// Use the Resource Model to get a list of all the clients that hold the
// needed/requested resources.
- ReclaimRequestInfo reclaimRequestInfo{callingPid, resources};
+ uint32_t callingImportance = std::max(0, clientInfo.importance);
+ ReclaimRequestInfo reclaimRequestInfo{callingPid, callingImportance, resources};
std::vector<ClientInfo> clients;
if (!mDefaultResourceModel->getAllClients(reclaimRequestInfo, clients)) {
if (clients.empty()) {
@@ -246,7 +256,7 @@
__func__);
return false;
}
- // Since there was a conflict, we need to reclaim all elements.
+ // Since there was a conflict, we need to reclaim all clients.
targetClients = std::move(clients);
} else {
// Select a client among those have the needed resources.
@@ -290,7 +300,7 @@
// Use the DefaultResourceModel to get all the clients with the resources requested.
std::vector<MediaResourceParcel> resources{*resourceRequestInfo.mResource};
- ReclaimRequestInfo reclaimRequestInfo{resourceRequestInfo.mCallingPid, resources};
+ ReclaimRequestInfo reclaimRequestInfo{resourceRequestInfo.mCallingPid, 0, resources};
std::vector<ClientInfo> clients;
mDefaultResourceModel->getAllClients(reclaimRequestInfo, clients);
@@ -346,12 +356,12 @@
return true;
}
-std::shared_ptr<IResourceManagerClient> ResourceManagerServiceNew::getClient(
+std::shared_ptr<IResourceManagerClient> ResourceManagerServiceNew::getClient_l(
int pid, const int64_t& clientId) const {
return mResourceTracker->getClient(pid, clientId);
}
-bool ResourceManagerServiceNew::removeClient(int pid, const int64_t& clientId) {
+bool ResourceManagerServiceNew::removeClient_l(int pid, const int64_t& clientId) {
return mResourceTracker->removeClient(pid, clientId);
}
@@ -359,4 +369,17 @@
return mResourceTracker->getResourceMap();
}
+void ResourceManagerServiceNew::setReclaimPolicy(bool processPriority, bool clientImportance) {
+ mReclaimPolicies.clear();
+ if (processPriority) {
+ // Process priority (oom score) as the Default reclaim policy.
+ mReclaimPolicies.push_back(std::make_unique<ProcessPriorityReclaimPolicy>(
+ mResourceTracker));
+ }
+ if (clientImportance) {
+ mReclaimPolicies.push_back(std::make_unique<ClientImportanceReclaimPolicy>(
+ mResourceTracker));
+ }
+}
+
} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerServiceNew.h b/services/mediaresourcemanager/ResourceManagerServiceNew.h
index 20c3d6e..0599936 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceNew.h
+++ b/services/mediaresourcemanager/ResourceManagerServiceNew.h
@@ -106,27 +106,13 @@
// Returns false if any client belongs to a process with higher priority than the
// calling process. The clients will remain unchanged if returns false.
bool getTargetClients(
- int32_t callingPid,
+ const ClientInfoParcel& clientInfo,
const std::vector<MediaResourceParcel>& resources,
std::vector<ClientInfo>& targetClients) override;
// Removes the pid from the override map.
void removeProcessInfoOverride(int pid) override;
- // Gets the list of all the clients who own the specified resource type.
- // Returns false if any client belongs to a process with higher priority than the
- // calling process. The clients will remain unchanged if returns false.
- bool getAllClients_l(const ResourceRequestInfo& resourceRequestInfo,
- std::vector<ClientInfo>& clientsInfo) override;
-
- // Gets the client who owns specified resource type from lowest possible priority process.
- // Returns false if the calling process priority is not higher than the lowest process
- // priority. The client will remain unchanged if returns false.
- // This function is used only by the unit test.
- bool getLowestPriorityBiggestClient_l(
- const ResourceRequestInfo& resourceRequestInfo,
- ClientInfo& clientInfo) override;
-
// override the pid of given process
bool overridePid_l(int32_t originalPid, int32_t newPid) override;
@@ -137,17 +123,12 @@
// Get priority from process's pid
bool getPriority_l(int pid, int* priority) const override;
- // Gets lowest priority process that has the specified resource type.
- // Returns false if failed. The output parameters will remain unchanged if failed.
- bool getLowestPriorityPid_l(MediaResource::Type type, MediaResource::SubType subType,
- int* lowestPriorityPid, int* lowestPriority) override;
-
// Get the client for given pid and the clientId from the map
- std::shared_ptr<IResourceManagerClient> getClient(
+ std::shared_ptr<IResourceManagerClient> getClient_l(
int pid, const int64_t& clientId) const override;
// Remove the client for given pid and the clientId from the map
- bool removeClient(int pid, const int64_t& clientId) override;
+ bool removeClient_l(int pid, const int64_t& clientId) override;
// Get all the resource status for dump
void getResourceDump(std::string& resourceLog) const override;
@@ -157,6 +138,30 @@
Status removeResource(const ClientInfoParcel& clientInfo, bool checkValid) override;
+ // The following utility functions are used only for testing by ResourceManagerServiceTest
+ // START: TEST only functions
+ // Gets the list of all the clients who own the specified resource type.
+ // Returns false if any client belongs to a process with higher priority than the
+ // calling process. The clients will remain unchanged if returns false.
+ bool getAllClients_l(const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clientsInfo) override;
+
+ // Gets the client who owns specified resource type from lowest possible priority process.
+ // Returns false if the calling process priority is not higher than the lowest process
+ // priority. The client will remain unchanged if returns false.
+ bool getLowestPriorityBiggestClient_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ ClientInfo& clientInfo) override;
+
+ // Gets lowest priority process that has the specified resource type.
+ // Returns false if failed. The output parameters will remain unchanged if failed.
+ bool getLowestPriorityPid_l(MediaResource::Type type, MediaResource::SubType subType,
+ int* lowestPriorityPid, int* lowestPriority) override;
+
+ // enable/disable process priority based reclaim and client importance based reclaim
+ void setReclaimPolicy(bool processPriority, bool clientImportance) override;
+ // END: TEST only functions
+
private:
std::shared_ptr<ResourceTracker> mResourceTracker;
std::unique_ptr<IResourceModel> mDefaultResourceModel;
diff --git a/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp b/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
index cd21327..679ab13 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
@@ -27,6 +27,93 @@
namespace android {
+bool ResourceList::add(const MediaResourceParcel& res, bool* isNewEntry) {
+ // See if it's an existing entry, if so, merge it.
+ for (MediaResourceParcel& item : mResourceList) {
+ if (item.type == res.type && item.subType == res.subType && item.id == res.id) {
+ // We already have an item. Merge them and return
+ mergeResources(item, res);
+ return true;
+ }
+ }
+
+ // Since we have't found this resource yet, it is a new entry.
+ // We can't init a new entry with negative value, although it's allowed
+ // to merge in negative values after the initial add.
+ if (res.value <= 0) {
+ ALOGW("Ignoring request to add new resource entry with value <= 0");
+ return false;
+ }
+ if (isNewEntry) {
+ *isNewEntry = true;
+ }
+ mResourceList.push_back(res);
+ return true;
+}
+
+void ResourceList::addOrUpdate(const MediaResourceParcel& res) {
+ // See if it's an existing entry, just update the value.
+ for (MediaResourceParcel& item : mResourceList) {
+ if (item.type == res.type && item.subType == res.subType && item.id == res.id) {
+ item.value = res.value;
+ return;
+ }
+ }
+
+ // Add the new entry.
+ mResourceList.push_back(res);
+}
+
+bool ResourceList::remove(const MediaResourceParcel& res, long* removedEntryValue) {
+ // Make sure we have an entry for this resource.
+ for (std::vector<MediaResourceParcel>::iterator it = mResourceList.begin();
+ it != mResourceList.end(); it++) {
+ if (it->type == res.type && it->subType == res.subType && it->id == res.id) {
+ if (it->value > res.value) {
+ // Subtract the resource value by given value.
+ it->value -= res.value;
+ } else {
+ // This entry will be removed.
+ if (removedEntryValue) {
+ *removedEntryValue = it->value;
+ }
+ mResourceList.erase(it);
+ }
+ return true;
+ }
+ }
+
+ // No such entry.
+ return false;
+}
+
+std::string ResourceList::toString() const {
+ std::string str;
+ for (const ::aidl::android::media::MediaResourceParcel& res : mResourceList) {
+ str.append(android::toString(res).c_str());
+ str.append("\n");
+ }
+
+ return std::move(str);
+}
+
+bool ResourceList::operator==(const ResourceList& rhs) const {
+ // Make sure the size is the same.
+ if (mResourceList.size() != rhs.mResourceList.size()) {
+ return false;
+ }
+
+ // Create a set from this object and check for the items from the rhs.
+ std::set<::aidl::android::media::MediaResourceParcel> lhs(
+ mResourceList.begin(), mResourceList.end());
+ for (const ::aidl::android::media::MediaResourceParcel& res : rhs.mResourceList) {
+ if (lhs.find(res) == lhs.end()) {
+ return false;
+ }
+ }
+ return true;
+}
+
// Bunch of utility functions that looks for a specific Resource.
// Check whether a given resource (of type and subtype) is found in given resource parcel.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
@@ -53,8 +140,8 @@
// Check whether a given resource (of type and subtype) is found in given resource list.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
const ResourceList& resources) {
- for (auto it = resources.begin(); it != resources.end(); it++) {
- if (hasResourceType(type, subType, it->second)) {
+ for (const MediaResourceParcel& res : resources.getResources()) {
+ if (hasResourceType(type, subType, res)) {
return true;
}
}
@@ -91,7 +178,6 @@
const std::shared_ptr<IResourceManagerClient>& client,
ResourceInfos& infos) {
ResourceInfos::iterator found = infos.find(clientInfo.id);
-
if (found == infos.end()) {
ResourceInfo info{.pid = clientInfo.pid,
.uid = static_cast<uid_t>(clientInfo.uid),
@@ -99,7 +185,8 @@
.name = clientInfo.name.empty()? "<unknown client>" : clientInfo.name,
.client = client,
.deathNotifier = nullptr,
- .pendingRemoval = false};
+ .pendingRemoval = false,
+ .importance = static_cast<uint32_t>(std::max(0, clientInfo.importance))};
auto [it, inserted] = infos.emplace(clientInfo.id, info);
found = it;
}
diff --git a/services/mediaresourcemanager/ResourceManagerServiceUtils.h b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
index 55ea149..32cb219 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceUtils.h
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
@@ -19,6 +19,7 @@
#define ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_
#include <map>
+#include <set>
#include <memory>
#include <vector>
@@ -99,10 +100,47 @@
virtual void binderDied();
};
-// A map of tuple(type, sub-type, id) and the resource parcel.
-typedef std::map<std::tuple<
- MediaResource::Type, MediaResource::SubType, std::vector<uint8_t>>,
- ::aidl::android::media::MediaResourceParcel> ResourceList;
+// Encapsulate Resource List as vector of resources instead of map.
+// Since the number of resource is very limited, maintaining it as
+// std::vector helps with both performance and memory requiremnts.
+struct ResourceList {
+ // Add or Update an entry into ResourceList.
+ // If a new entry is added, isNewEntry will be set to true upon return
+ // returns true on successful update, false otherwise.
+ bool add(const ::aidl::android::media::MediaResourceParcel& res, bool* isNewEntry = nullptr);
+
+ // reduce the resource usage by subtracting the resource value.
+ // If the resource value is 0 after reducing the resource usage,
+ // that entry will be removed and removedEntryValue is set to the
+ // value before it was removed upon return otherwise it will be set to -1.
+ // returns true on successful removal of the resource, false otherwise.
+ bool remove(const ::aidl::android::media::MediaResourceParcel& res,
+ long* removedEntryValue = nullptr);
+
+ // Returns true if there aren't any resource entries.
+ bool empty() const {
+ return mResourceList.empty();
+ }
+
+ // Returns resource list as a non-modifiable vectors
+ const std::vector<::aidl::android::media::MediaResourceParcel>& getResources() const {
+ return mResourceList;
+ }
+
+ // Converts resource list into string format
+ std::string toString() const;
+
+ // BEGIN: Test only function
+ // Check if two resource lists are the same.
+ bool operator==(const ResourceList& rhs) const;
+
+ // Add or Update an entry into ResourceList.
+ void addOrUpdate(const ::aidl::android::media::MediaResourceParcel& res);
+ // END: Test only function
+
+private:
+ std::vector<::aidl::android::media::MediaResourceParcel> mResourceList;
+};
// Encapsulation for Resource Info, that contains
// - pid of the app
@@ -122,15 +160,18 @@
std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
ResourceList resources;
bool pendingRemoval{false};
+ uint32_t importance = 0;
};
/*
* Resource Reclaim request info that encapsulates
* - the calling/requesting process pid.
+ * - the calling/requesting client's importance.
* - the list of resources requesting (to be reclaimed from others)
*/
struct ReclaimRequestInfo {
int mCallingPid = -1;
+ uint32_t mCallingClientImportance = 0;
const std::vector<::aidl::android::media::MediaResourceParcel>& mResources;
};
diff --git a/services/mediaresourcemanager/ResourceObserverService.cpp b/services/mediaresourcemanager/ResourceObserverService.cpp
index 72e249f..21e61e9 100644
--- a/services/mediaresourcemanager/ResourceObserverService.cpp
+++ b/services/mediaresourcemanager/ResourceObserverService.cpp
@@ -286,9 +286,9 @@
{
std::scoped_lock lock{mObserverLock};
- for (auto &res : resources) {
+ for (const MediaResourceParcel& res : resources.getResources()) {
// Skip if this resource doesn't map to any observable type.
- MediaObservableType observableType = getObservableType(res.second);
+ MediaObservableType observableType = getObservableType(res);
if (observableType == MediaObservableType::kInvalid) {
continue;
}
@@ -303,9 +303,9 @@
auto calleeIt = calleeList.find(subscriber.first);
if (calleeIt == calleeList.end()) {
calleeList.emplace(subscriber.first, CalleeInfo{
- subscriber.second, {{observableType, res.second.value}}});
+ subscriber.second, {{observableType, res.value}}});
} else {
- calleeIt->second.monitors.push_back({observableType, res.second.value});
+ calleeIt->second.monitors.push_back({observableType, res.value});
}
}
}
diff --git a/services/mediaresourcemanager/ResourceTracker.cpp b/services/mediaresourcemanager/ResourceTracker.cpp
index 8dc13cc..22381c3 100644
--- a/services/mediaresourcemanager/ResourceTracker.cpp
+++ b/services/mediaresourcemanager/ResourceTracker.cpp
@@ -39,12 +39,12 @@
bool foundResource = false;
bool matchedPrimary =
(primarySubType == MediaResource::SubType::kUnspecifiedSubType) ? true : false;
- for (auto it = resources.begin(); it != resources.end(); it++) {
- if (hasResourceType(type, subType, it->second)) {
+ for (const MediaResourceParcel& res : resources.getResources()) {
+ if (hasResourceType(type, subType, res)) {
foundResource = true;
- } else if (it->second.subType == primarySubType) {
+ } else if (res.subType == primarySubType) {
matchedPrimary = true;
- } else if (isHwCodec(it->second.subType) == isHwCodec(primarySubType)) {
+ } else if (isHwCodec(res.subType) == isHwCodec(primarySubType)) {
matchedPrimary = true;
}
if (matchedPrimary && foundResource) {
@@ -111,31 +111,20 @@
ResourceList resourceAdded;
for (const MediaResourceParcel& res : resources) {
- const auto resType = std::tuple(res.type, res.subType, res.id);
-
if (res.value < 0 && res.type != MediaResource::Type::kDrmSession) {
ALOGV("%s: Ignoring request to remove negative value of non-drm resource", __func__);
continue;
}
- if (info.resources.find(resType) == info.resources.end()) {
- if (res.value <= 0) {
- // We can't init a new entry with negative value, although it's allowed
- // to merge in negative values after the initial add.
- ALOGV("%s: Ignoring request to add new resource entry with value <= 0", __func__);
- continue;
- }
+ bool isNewEntry = false;
+ if (!info.resources.add(res, &isNewEntry)) {
+ continue;
+ }
+ if (isNewEntry) {
onFirstAdded(res, info.uid);
- info.resources[resType] = res;
- } else {
- mergeResources(info.resources[resType], res);
}
+
// Add it to the list of added resources for observers.
- auto it = resourceAdded.find(resType);
- if (it == resourceAdded.end()) {
- resourceAdded[resType] = res;
- } else {
- mergeResources(it->second, res);
- }
+ resourceAdded.add(res);
}
if (info.deathNotifier == nullptr && client != nullptr) {
info.deathNotifier = DeathNotifier::Create(client, mService, clientInfo);
@@ -147,6 +136,18 @@
return !resourceAdded.empty();
}
+bool ResourceTracker::updateResource(const aidl::android::media::ClientInfoParcel& clientInfo) {
+ ResourceInfos& infos = getResourceInfosForEdit(clientInfo.pid);
+
+ ResourceInfos::iterator found = infos.find(clientInfo.id);
+ if (found == infos.end()) {
+ return false;
+ }
+ // Update the client importance.
+ found->second.importance = std::max(0, clientInfo.importance);
+ return true;
+}
+
bool ResourceTracker::removeResource(const ClientInfoParcel& clientInfo,
const std::vector<MediaResourceParcel>& resources) {
int32_t pid = clientInfo.pid;
@@ -174,31 +175,21 @@
ResourceInfo& info = foundClient->second;
ResourceList resourceRemoved;
for (const MediaResourceParcel& res : resources) {
- const auto resType = std::tuple(res.type, res.subType, res.id);
-
if (res.value < 0) {
ALOGV("%s: Ignoring request to remove negative value of resource", __func__);
continue;
}
- // ignore if we don't have it
- if (info.resources.find(resType) != info.resources.end()) {
- MediaResourceParcel& resource = info.resources[resType];
+
+ long removedEntryValue = -1;
+ if (info.resources.remove(res, &removedEntryValue)) {
MediaResourceParcel actualRemoved = res;
- if (resource.value > res.value) {
- resource.value -= res.value;
- } else {
+ if (removedEntryValue != -1) {
onLastRemoved(res, info.uid);
- actualRemoved.value = resource.value;
- info.resources.erase(resType);
+ actualRemoved.value = removedEntryValue;
}
// Add it to the list of removed resources for observers.
- auto it = resourceRemoved.find(resType);
- if (it == resourceRemoved.end()) {
- resourceRemoved[resType] = actualRemoved;
- } else {
- mergeResources(it->second, actualRemoved);
- }
+ resourceRemoved.add(actualRemoved);
}
}
if (mObserverService != nullptr && !resourceRemoved.empty()) {
@@ -231,8 +222,8 @@
}
const ResourceInfo& info = foundClient->second;
- for (auto& [resType, resParcel] : info.resources) {
- onLastRemoved(resParcel, info.uid);
+ for (const MediaResourceParcel& res : info.resources.getResources()) {
+ onLastRemoved(res, info.uid);
}
if (mObserverService != nullptr && !info.resources.empty()) {
@@ -511,8 +502,7 @@
if (!info.pendingRemoval) {
continue;
}
- for (auto it = resources.begin(); it != resources.end(); it++) {
- const MediaResourceParcel& resource = it->second;
+ for (const MediaResourceParcel& resource : resources.getResources()) {
if (hasResourceType(type, subType, resource)) {
if (resource.value > largestValue) {
largestValue = resource.value;
@@ -555,10 +545,73 @@
const ResourceList& resources = info->resources;
bool matchedPrimary =
(primarySubType == MediaResource::SubType::kUnspecifiedSubType) ? true : false;
- for (auto it = resources.begin(); !matchedPrimary && it != resources.end(); it++) {
- if (it->second.subType == primarySubType) {
+ for (const MediaResourceParcel& resource : resources.getResources()) {
+ if (resource.subType == primarySubType) {
matchedPrimary = true;
- } else if (isHwCodec(it->second.subType) == isHwCodec(primarySubType)) {
+ break;
+ } else if (isHwCodec(resource.subType) == isHwCodec(primarySubType)) {
+ matchedPrimary = true;
+ break;
+ }
+ }
+ // Primary type doesn't match, skip the client
+ if (!matchedPrimary) {
+ continue;
+ }
+ for (const MediaResourceParcel& resource : resources.getResources()) {
+ if (hasResourceType(type, subType, resource)) {
+ if (resource.value > largestValue) {
+ largestValue = resource.value;
+ clientId = info->clientId;
+ uid = info->uid;
+ }
+ }
+ }
+ }
+
+ if (clientId == -1) {
+ ALOGE("%s: can't find resource type %s and subtype %s for pid %d",
+ __func__, asString(type), asString(subType), targetPid);
+ return false;
+ }
+
+ clientInfo.mPid = targetPid;
+ clientInfo.mUid = uid;
+ clientInfo.mClientId = clientId;
+ return true;
+}
+
+bool ResourceTracker::getLeastImportantBiggestClient(int targetPid, int32_t importance,
+ MediaResource::Type type,
+ MediaResource::SubType subType,
+ MediaResource::SubType primarySubType,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& clientInfo) {
+ uid_t uid = -1;
+ int64_t clientId = -1;
+ uint64_t largestValue = 0;
+
+ for (const ClientInfo& client : clients) {
+ // Skip the clients that doesn't belong go the targetPid
+ if (client.mPid != targetPid) {
+ continue;
+ }
+ const ResourceInfo* info = getResourceInfo(client.mPid, client.mClientId);
+ if (info == nullptr) {
+ continue;
+ }
+
+ // Make sure the importance is lower.
+ if (info->importance <= importance) {
+ continue;
+ }
+ const ResourceList& resources = info->resources;
+ bool matchedPrimary =
+ (primarySubType == MediaResource::SubType::kUnspecifiedSubType) ? true : false;
+ for (const MediaResourceParcel& resource : resources.getResources()) {
+ if (resource.subType == primarySubType) {
+ matchedPrimary = true;
+ } else if (isHwCodec(resource.subType) == isHwCodec(primarySubType)) {
matchedPrimary = true;
}
}
@@ -566,8 +619,7 @@
if (!matchedPrimary) {
continue;
}
- for (auto it = resources.begin(); it != resources.end(); it++) {
- const MediaResourceParcel& resource = it->second;
+ for (const MediaResourceParcel& resource : resources.getResources()) {
if (hasResourceType(type, subType, resource)) {
if (resource.value > largestValue) {
largestValue = resource.value;
@@ -616,10 +668,7 @@
const ResourceList& resources = info.resources;
resourceLogs.append(" Resources:\n");
- for (auto it = resources.begin(); it != resources.end(); it++) {
- snprintf(buffer, SIZE, " %s\n", toString(it->second).c_str());
- resourceLogs.append(buffer);
- }
+ resourceLogs.append(resources.toString());
}
}
resourceLogs.append(" Process Pid override:\n");
diff --git a/services/mediaresourcemanager/ResourceTracker.h b/services/mediaresourcemanager/ResourceTracker.h
index e5f33ec..20c904d 100644
--- a/services/mediaresourcemanager/ResourceTracker.h
+++ b/services/mediaresourcemanager/ResourceTracker.h
@@ -67,6 +67,9 @@
const std::shared_ptr<::aidl::android::media::IResourceManagerClient>& client,
const std::vector<::aidl::android::media::MediaResourceParcel>& resources);
+ // Update the resource info, if there is any changes.
+ bool updateResource(const aidl::android::media::ClientInfoParcel& clientInfo);
+
// Remove a set of resources from the given client.
// returns true on success, false otherwise.
bool removeResource(const aidl::android::media::ClientInfoParcel& clientInfo,
@@ -159,6 +162,17 @@
ClientInfo& clientInfo,
MediaResource::SubType primarySubType = MediaResource::SubType::kUnspecifiedSubType);
+ // Find the biggest client from the process pid, that has the least importance
+ // (than given importance) among the given list of clients.
+ // If applicable, match the primary type too.
+ // returns true on success, false otherwise.
+ bool getLeastImportantBiggestClient(int targetPid, int32_t importance,
+ MediaResource::Type type,
+ MediaResource::SubType subType,
+ MediaResource::SubType primarySubType,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& clientInfo);
+
// Find the client that belongs to given process(pid) and with the given clientId.
// A nullptr is returned upon failure to find the client.
std::shared_ptr<::aidl::android::media::IResourceManagerClient> getClient(
diff --git a/services/mediaresourcemanager/aidl/android/media/ClientInfoParcel.aidl b/services/mediaresourcemanager/aidl/android/media/ClientInfoParcel.aidl
index eb4bc42..aa14ace 100644
--- a/services/mediaresourcemanager/aidl/android/media/ClientInfoParcel.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/ClientInfoParcel.aidl
@@ -41,4 +41,11 @@
* Name of the resource associated with the client.
*/
@utf8InCpp String name;
+
+ /*
+ * Client importance, which ranges from 0 to int_max.
+ * The default importance is high (0)
+ * Based on the reclaim policy, this could be used during reclaim.
+ */
+ int importance = 0;
}
diff --git a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
index 58dbb8d..7e8a4a0 100644
--- a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
+++ b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
@@ -123,14 +123,16 @@
struct TestClient : public BnResourceManagerClient {
- TestClient(int pid, int uid, const std::shared_ptr<ResourceManagerService> &service)
- : mPid(pid), mUid(uid), mService(service) {}
+ TestClient(int pid, int uid, int32_t clientImportance,
+ const std::shared_ptr<ResourceManagerService> &service)
+ : mPid(pid), mUid(uid), mClientImportance(clientImportance), mService(service) {}
Status reclaimResource(bool* _aidl_return) override {
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
.uid = static_cast<int32_t>(mUid),
.id = getId(ref<TestClient>()),
- .name = "none"};
+ .name = "none",
+ .importance = mClientImportance};
mService->removeClient(clientInfo);
mWasReclaimResourceCalled = true;
*_aidl_return = true;
@@ -150,10 +152,15 @@
virtual ~TestClient() {}
+ inline int pid() const { return mPid; }
+ inline int uid() const { return mUid; }
+ inline int32_t clientImportance() const { return mClientImportance; }
+
private:
bool mWasReclaimResourceCalled = false;
int mPid;
int mUid;
+ int32_t mClientImportance = 0;
std::shared_ptr<ResourceManagerService> mService;
DISALLOW_EVIL_CONSTRUCTORS(TestClient);
};
@@ -168,6 +175,10 @@
static const int kMidPriorityPid = 25;
static const int kHighPriorityPid = 10;
+static const int32_t kHighestCodecImportance = 0;
+static const int32_t kLowestCodecImportance = 100;
+static const int32_t kMidCodecImportance = 50;
+
using EventType = TestSystemCallback::EventType;
using EventEntry = TestSystemCallback::EventEntry;
bool operator== (const EventEntry& lhs, const EventEntry& rhs) {
@@ -212,13 +223,14 @@
} else {
mService = ResourceManagerService::Create(new TestProcessInfo, mSystemCB);
}
- mTestClient1 = ::ndk::SharedRefBase::make<TestClient>(kTestPid1, kTestUid1, mService);
- mTestClient2 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, mService);
- mTestClient3 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, mService);
+ mTestClient1 = ::ndk::SharedRefBase::make<TestClient>(kTestPid1, kTestUid1, 0, mService);
+ mTestClient2 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, 0, mService);
+ mTestClient3 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, 0, mService);
}
- std::shared_ptr<IResourceManagerClient> createTestClient(int pid, int uid) {
- return ::ndk::SharedRefBase::make<TestClient>(pid, uid, mService);
+ std::shared_ptr<IResourceManagerClient> createTestClient(int pid, int uid,
+ int32_t importance = 0) {
+ return ::ndk::SharedRefBase::make<TestClient>(pid, uid, importance, mService);
}
sp<TestSystemCallback> mSystemCB;
@@ -233,9 +245,7 @@
// convert resource1 to ResourceList
ResourceList r1;
for (size_t i = 0; i < resources1.size(); ++i) {
- const auto &res = resources1[i];
- const auto resType = std::tuple(res.type, res.subType, res.id);
- r1[resType] = res;
+ r1.addOrUpdate(resources1[i]);
}
return r1 == resources2;
}
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 9d4beef..b3a0932 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -209,7 +209,6 @@
resources1.clear();
resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MIN));
- expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MIN));
mService->addResource(client1Info, mTestClient1, resources1);
// Expected result:
@@ -1498,6 +1497,264 @@
client3Config.width * client3Config.height));
EXPECT_TRUE(currentPixelCountP2 == 0);
}
+
+ void addNonSecureVideoCodecResource(std::shared_ptr<IResourceManagerClient>& client,
+ std::vector<ClientInfoParcel>& infos) {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(createNonSecureVideoCodecResource(1));
+
+ TestClient* testClient = toTestClient(client);
+ ClientInfoParcel clientInfo {.pid = static_cast<int32_t>(testClient->pid()),
+ .uid = static_cast<int32_t>(testClient->uid()),
+ .id = getId(client),
+ .name = "none",
+ .importance = testClient->clientImportance()};
+ mService->addResource(clientInfo, client, resources);
+ infos.push_back(clientInfo);
+ }
+
+ bool doReclaimResource(const ClientInfoParcel& clientInfo) {
+ bool result = false;
+ std::vector<MediaResourceParcel> reclaimResources;
+ reclaimResources.push_back(createNonSecureVideoCodecResource(1));
+ bool success = mService->reclaimResource(clientInfo, reclaimResources, &result).isOk();
+ return success && result;
+ }
+
+ // Verifies the resource reclaim policies
+ // - this verifies the reclaim policies based on:
+ // - process priority (oom score)
+ // - client priority
+ void testReclaimPolicies() {
+ // Create 3 clients with codec importance high, mid and low for a low
+ // priority pid.
+ std::vector<std::shared_ptr<IResourceManagerClient>> lowPriPidClients;
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kHighestCodecImportance));
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kMidCodecImportance));
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kLowestCodecImportance));
+
+ // Create 3 clients with codec importance high, mid and low for a high
+ // priority pid.
+ std::vector<std::shared_ptr<IResourceManagerClient>> highPriPidClients;
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kHighestCodecImportance));
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kMidCodecImportance));
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kLowestCodecImportance));
+
+ // Add non secure video codec resources for all the 3 clients of low priority pid.
+ std::vector<ClientInfoParcel> lowPriPidClientInfos;
+ for (auto& client : lowPriPidClients) {
+ addNonSecureVideoCodecResource(client, lowPriPidClientInfos);
+ }
+ // Add non secure video codec resources for all the 3 clients of high priority pid.
+ std::vector<ClientInfoParcel> highPriPidClientInfos;
+ for (auto& client : highPriPidClients) {
+ addNonSecureVideoCodecResource(client, highPriPidClientInfos);
+ }
+
+ // 1. Set reclaim policy as "Process Priority".
+ // - A process should be reclaiming from:
+ // - a lower priority process if there is any
+ // - else fail.
+ mService->setReclaimPolicy(true /*process priority*/, false /*codec importance*/);
+
+ // 1.A:
+ // - high priority process should be able to reclaim successfully.
+ // - A process should be reclaiming from the low priority process.
+ EXPECT_TRUE(doReclaimResource(highPriPidClientInfos[0]));
+ // Verify that the high priority pid's clients are untouched.
+ bool success = true;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = false;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+ // Verify that the one of the client from the low priority pid has been reclaimed.
+ success = false;
+ for (auto& client : lowPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 1.B:
+ // - low priority process should fail to reclaim.
+ EXPECT_FALSE(doReclaimResource(lowPriPidClientInfos[0]));
+
+ // 2. Set reclaim policy as "Client Importance".
+ // - A process should be reclaiming from:
+ // - a lower priority client from the same process if any
+ // - else fail.
+ mService->setReclaimPolicy(false /*process priority*/, true /*codec importance*/);
+
+ // 2.A:
+ // - high priority process should be able to reclaim successfully.
+ // - Process should be reclaiming from a lower priority client from the
+ // same process.
+ EXPECT_TRUE(doReclaimResource(highPriPidClientInfos[0]));
+ // Verify that the low priority pid's clients are untouched.
+ success = true;
+ for (auto& client : lowPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = false;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+ // Verify that the one of the low priority client from the high priority
+ // pid has been reclaimed.
+ success = false;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 2.B:
+ // - high priority process should be able to reclaim successfully.
+ // - Process should be reclaiming from a lower priority client from the
+ // same process.
+ EXPECT_TRUE(doReclaimResource(lowPriPidClientInfos[0]));
+ // Verify that the high priority pid's clients are untouched.
+ success = true;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = false;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+ // Verify that the one of the low priority client from the low priority
+ // pid has been reclaimed.
+ success = false;
+ for (auto& client : lowPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 2.C:
+ // - lowest priority client from high priority process should fail to reclaim.
+ EXPECT_FALSE(doReclaimResource(highPriPidClientInfos[2]));
+
+ // 2.D:
+ // - lowest priority client from low priority process should fail to reclaim.
+ EXPECT_FALSE(doReclaimResource(lowPriPidClientInfos[2]));
+
+ // 3. Set reclaim policy as "Process Priority and Client Importance".
+ // - A process should be reclaiming from:
+ // - a lower priority process if there is any
+ // - else a lower priority client from the same process if any
+ // - else fail.
+ mService->setReclaimPolicy(true /*process priority*/, true /*codec importance*/);
+
+ // Remove all clients from the low priority process so that we have
+ // only one process (with high priority) with all the resources.
+ for (const auto& clientInfo : lowPriPidClientInfos) {
+ mService->removeClient(clientInfo);
+ }
+ lowPriPidClientInfos.clear();
+ lowPriPidClients.clear();
+ // 3.A:
+ // - high priority process should be able to reclaim successfully.
+ EXPECT_TRUE(doReclaimResource(highPriPidClientInfos[0]));
+ // Verify that the one of the client from the high priority pid has been reclaimed.
+ success = false;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 3.B, set the policy back to ReclaimPolicyProcessPriority
+ mService->setReclaimPolicy(true /*process priority*/, false /*codec importance*/);
+
+ // Since there is only one process, the reclaim should fail.
+ EXPECT_FALSE(doReclaimResource(highPriPidClientInfos[0]));
+
+ // 4. Set reclaim policy as "Process Priority and Client Importance".
+ // - A process should be reclaiming from:
+ // - from a lower priority process if there are any
+ // - else from a lower priority client from the same process if there are any
+ // - else fail.
+ mService->setReclaimPolicy(true /*process priority*/, true /*codec importance*/);
+
+ // Remove all clients from the high priority process so that we can
+ // start a new/fresh resource allocation.
+ for (const auto& clientInfo : highPriPidClientInfos) {
+ mService->removeClient(clientInfo);
+ }
+ highPriPidClientInfos.clear();
+ highPriPidClients.clear();
+
+ // Create 3 clients with codec importance high for a low priority pid.
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kHighestCodecImportance));
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kHighestCodecImportance));
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kHighestCodecImportance));
+
+ // Create 3 clients with codec importance low for a high priority pid.
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kLowestCodecImportance));
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kLowestCodecImportance));
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kLowestCodecImportance));
+
+ // Add non secure video codec resources for all the 3 clients of low priority pid.
+ for (auto& client : lowPriPidClients) {
+ addNonSecureVideoCodecResource(client, lowPriPidClientInfos);
+ }
+ // Add non secure video codec resources for all the 3 clients of high priority pid.
+ for (auto& client : highPriPidClients) {
+ addNonSecureVideoCodecResource(client, highPriPidClientInfos);
+ }
+
+ // 4.A:
+ // - high priority process should be able to reclaim successfully.
+ EXPECT_TRUE(doReclaimResource(highPriPidClientInfos[0]));
+ // Since all clients are of same priority with in high priority process,
+ // none of the clients should be reclaimed.
+ success = true;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = false;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+ // Verify that the one of the client from the low priority pid has been reclaimed.
+ success = false;
+ for (auto& client : lowPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 4.B, set the policy back to ReclaimPolicyProcessPriority
+ // If low priority process tries to reclaim, it should fail as there
+ // aren't any lower priority clients or lower priority processes.
+ EXPECT_FALSE(doReclaimResource(lowPriPidClientInfos[0]));
+ }
};
class ResourceManagerServiceNewTest : public ResourceManagerServiceTest {
@@ -1678,4 +1935,8 @@
testConcurrentCodecs();
}
+TEST_F(ResourceManagerServiceNewTest, reclaimPolicies) {
+ testReclaimPolicies();
+}
+
} // namespace android