Merge "VideoTrackTranscoderTests: start thread pool" into main
diff --git a/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h b/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
index 53f529e..7cba011 100644
--- a/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
+++ b/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
@@ -25,6 +25,7 @@
#define AUDIO_AIDL_CONVERSION_AIDL_CONVERSION_UTIL_CPP
#endif // BACKEND_NDK_IMPL
+#include <functional>
#include <limits>
#include <type_traits>
#include <utility>
diff --git a/media/libaudioclient/TEST_MAPPING b/media/libaudioclient/TEST_MAPPING
index bd508b3..234e858 100644
--- a/media/libaudioclient/TEST_MAPPING
+++ b/media/libaudioclient/TEST_MAPPING
@@ -41,11 +41,19 @@
}
]
}
- ]
+ ],
+ "postsubmit": [
// TODO(b/302036943): Enable once we make it pass with AIDL HAL on CF.
- // "postsubmit": [
// {
// "name": "audioeffect_analysis"
- // }
- // ]
+ // },
+ {
+ "name": "CtsVirtualDevicesTestCases",
+ "options" : [
+ {
+ "include-filter": "android.virtualdevice.cts.VirtualAudioTest"
+ }
+ ]
+ }
+ ]
}
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
index 63ace8c..d4024a2 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.cpp
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -238,6 +238,29 @@
return OK;
}
+status_t Hal2AidlMapper::createOrUpdatePortConfigRetry(
+ const AudioPortConfig& requestedPortConfig, AudioPortConfig* result, bool* created) {
+ AudioPortConfig suggestedOrAppliedPortConfig;
+ RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig,
+ &suggestedOrAppliedPortConfig, created));
+ if (suggestedOrAppliedPortConfig.id == 0) {
+ // Try again with the suggested config
+ suggestedOrAppliedPortConfig.id = requestedPortConfig.id;
+ AudioPortConfig appliedPortConfig;
+ RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(suggestedOrAppliedPortConfig,
+ &appliedPortConfig, created));
+ if (appliedPortConfig.id == 0) {
+ ALOGE("%s: module %s did not apply suggested config %s", __func__,
+ mInstance.c_str(), suggestedOrAppliedPortConfig.toString().c_str());
+ return NO_INIT;
+ }
+ *result = appliedPortConfig;
+ } else {
+ *result = suggestedOrAppliedPortConfig;
+ }
+ return OK;
+}
+
void Hal2AidlMapper::eraseConnectedPort(int32_t portId) {
mPorts.erase(portId);
mConnectedPorts.erase(portId);
@@ -247,6 +270,7 @@
ALOGD("%s: disconnected port replacement: %s", __func__, port.toString().c_str());
mDisconnectedPortReplacement = std::pair<int32_t, AudioPort>();
}
+ updateDynamicMixPorts();
}
status_t Hal2AidlMapper::findOrCreatePatch(
@@ -294,27 +318,19 @@
if (config != nullptr) {
setPortConfigFromConfig(&requestedPortConfig, *config);
}
- AudioPortConfig suggestedOrAppliedPortConfig;
- RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig,
- &suggestedOrAppliedPortConfig, created));
- if (suggestedOrAppliedPortConfig.id == 0) {
- // Try again with the suggested config
- suggestedOrAppliedPortConfig.id = requestedPortConfig.id;
- AudioPortConfig appliedPortConfig;
- RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(suggestedOrAppliedPortConfig,
- &appliedPortConfig, created));
- if (appliedPortConfig.id == 0) {
- ALOGE("%s: module %s did not apply suggested config %s", __func__,
- mInstance.c_str(), suggestedOrAppliedPortConfig.toString().c_str());
- return NO_INIT;
- }
- *portConfig = appliedPortConfig;
- } else {
- *portConfig = suggestedOrAppliedPortConfig;
- }
+ return createOrUpdatePortConfigRetry(requestedPortConfig, portConfig, created);
} else {
- *portConfig = portConfigIt->second;
- *created = false;
+ AudioPortConfig requestedPortConfig = portConfigIt->second;
+ if (config != nullptr) {
+ setPortConfigFromConfig(&requestedPortConfig, *config);
+ }
+
+ if (requestedPortConfig != portConfigIt->second) {
+ return createOrUpdatePortConfigRetry(requestedPortConfig, portConfig, created);
+ } else {
+ *portConfig = portConfigIt->second;
+ *created = false;
+ }
}
return OK;
}
@@ -370,12 +386,12 @@
return BAD_VALUE;
} else {
AudioPortConfig requestedPortConfig = portConfigIt->second;
- if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
- AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
- if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
- source != AudioSource::SYS_RESERVED_INVALID) {
- mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
- }
+ setPortConfigFromConfig(&requestedPortConfig, config);
+
+ AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
+ if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
+ source != AudioSource::SYS_RESERVED_INVALID) {
+ mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
}
if (requestedPortConfig != portConfigIt->second) {
@@ -410,9 +426,19 @@
requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
portConfig, created);
} else if (requestedPortConfig.ext.getTag() == Tag::device) {
- return findOrCreateDevicePortConfig(
- requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
- portConfig, created);
+ if (const auto& p = requestedPortConfig;
+ p.sampleRate.has_value() && p.channelMask.has_value() &&
+ p.format.has_value()) {
+ AudioConfig config;
+ setConfigFromPortConfig(&config, requestedPortConfig);
+ return findOrCreateDevicePortConfig(
+ requestedPortConfig.ext.get<Tag::device>().device, &config,
+ portConfig, created);
+ } else {
+ return findOrCreateDevicePortConfig(
+ requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
+ portConfig, created);
+ }
}
ALOGW("%s: unsupported audio port config: %s",
__func__, requestedPortConfig.toString().c_str());
@@ -1002,6 +1028,9 @@
if (status == OK) {
auto portIt = mPorts.find(portId);
if (portIt != mPorts.end()) {
+ if (port->ext.getTag() == AudioPortExt::Tag::mix && portIt->second != *port) {
+ mDynamicMixPortIds.insert(portId);
+ }
portIt->second = *port;
} else {
ALOGW("%s, port(%d) returned successfully from the HAL but not it is not cached",
@@ -1050,4 +1079,15 @@
return OK;
}
+void Hal2AidlMapper::updateDynamicMixPorts() {
+ for (int32_t portId : mDynamicMixPortIds) {
+ if (auto it = mPorts.find(portId); it != mPorts.end()) {
+ updateAudioPort(portId, &it->second);
+ } else {
+ // This must not happen
+ ALOGE("%s, cannot find port for id=%d", __func__, portId);
+ }
+ }
+}
+
} // namespace android
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.h b/media/libaudiohal/impl/Hal2AidlMapper.h
index 21cfd5a..93ce233 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.h
+++ b/media/libaudiohal/impl/Hal2AidlMapper.h
@@ -126,6 +126,9 @@
status_t createOrUpdatePortConfig(
const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
::aidl::android::media::audio::common::AudioPortConfig* result, bool *created);
+ status_t createOrUpdatePortConfigRetry(
+ const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
+ ::aidl::android::media::audio::common::AudioPortConfig* result, bool *created);
void eraseConnectedPort(int32_t portId);
status_t findOrCreatePatch(
const std::set<int32_t>& sourcePortConfigIds,
@@ -185,6 +188,7 @@
status_t updateAudioPort(
int32_t portId, ::aidl::android::media::audio::common::AudioPort* port);
status_t updateRoutes();
+ void updateDynamicMixPorts();
Ports mPorts;
// Remote submix "template" ports (no address specified, no profiles).
@@ -202,6 +206,7 @@
ConnectedPorts mConnectedPorts;
std::pair<int32_t, ::aidl::android::media::audio::common::AudioPort>
mDisconnectedPortReplacement;
+ std::set<int32_t> mDynamicMixPortIds;
};
} // namespace android
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index 378d919..c2d7ee1 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -808,6 +808,7 @@
mOffloadMetadata.channelMask = VALUE_OR_RETURN_STATUS(
::aidl::android::legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
channel_mask, false /*isInput*/));
+ return OK;
}
return BAD_VALUE;
}))) {
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
index 71bb2ef..bb7e4c6 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
@@ -20,6 +20,7 @@
#define LOG_TAG "BundleContext"
#include <android-base/logging.h>
#include <audio_utils/power.h>
+#include <media/AidlConversionCppNdk.h>
#include <Utils.h>
#include "BundleContext.h"
@@ -36,9 +37,10 @@
const lvm::BundleEffectType& type)
: EffectContext(statusDepth, common), mType(type) {
LOG(DEBUG) << __func__ << type;
- int channelCount = ::aidl::android::hardware::audio::common::getChannelCount(
+
+ int inputChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
common.input.base.channelMask);
- mSamplesPerSecond = common.input.base.sampleRate * channelCount;
+ mSamplesPerSecond = common.input.base.sampleRate * inputChannelCount;
}
BundleContext::~BundleContext() {
@@ -50,9 +52,15 @@
std::lock_guard lg(mMutex);
// init with pre-defined preset NORMAL
for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
- mBandGainMdB[i] = lvm::kSoftPresets[0 /* normal */][i] * 100;
+ mBandGainmB[i] = lvm::kSoftPresets[0 /* normal */][i] * 100;
}
+ // Initialise control params
+ LVM_ControlParams_t controlParams;
+ RetCode retStatus = initControlParameter(controlParams);
+ RETURN_VALUE_IF(retStatus != RetCode::SUCCESS, RetCode::ERROR_ILLEGAL_PARAMETER,
+ " UnsupportedParams");
+
// allocate lvm instance
LVM_ReturnStatus_en status;
LVM_InstParams_t params = {.BufferMode = LVM_UNMANAGED_BUFFERS,
@@ -63,8 +71,6 @@
GOTO_IF_LVM_ERROR(status, deinit, "LVM_GetInstanceHandleFailed");
// set control
- LVM_ControlParams_t controlParams;
- initControlParameter(controlParams);
status = LVM_SetControlParameters(mInstance, &controlParams);
GOTO_IF_LVM_ERROR(status, deinit, "LVM_SetControlParametersFailed");
@@ -227,8 +233,8 @@
bool viEnabled = params.VirtualizerOperatingMode == LVM_MODE_ON;
if (eqEnabled) {
- for (size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
- float bandFactor = mBandGainMdB[i] / 1500.0;
+ for (unsigned int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
+ float bandFactor = mBandGainmB[i] / 1500.0;
float bandCoefficient = lvm::kBandEnergyCoefficient[i];
float bandEnergy = bandFactor * bandCoefficient * bandCoefficient;
if (bandEnergy > 0) energyContribution += bandEnergy;
@@ -236,9 +242,9 @@
// cross EQ coefficients
float bandFactorSum = 0;
- for (size_t i = 0; i < lvm::MAX_NUM_BANDS - 1; i++) {
- float bandFactor1 = mBandGainMdB[i] / 1500.0;
- float bandFactor2 = mBandGainMdB[i + 1] / 1500.0;
+ for (unsigned int i = 0; i < lvm::MAX_NUM_BANDS - 1; i++) {
+ float bandFactor1 = mBandGainmB[i] / 1500.0;
+ float bandFactor2 = mBandGainmB[i + 1] / 1500.0;
if (bandFactor1 > 0 && bandFactor2 > 0) {
float crossEnergy =
@@ -259,8 +265,8 @@
energyContribution += boostFactor * boostCoefficient * boostCoefficient;
if (eqEnabled) {
- for (size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
- float bandFactor = mBandGainMdB[i] / 1500.0;
+ for (unsigned int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
+ float bandFactor = mBandGainmB[i] / 1500.0;
float bandCrossCoefficient = lvm::kBassBoostEnergyCrossCoefficient[i];
float bandEnergy = boostFactor * bandFactor * bandCrossCoefficient;
if (bandEnergy > 0) energyBassBoost += bandEnergy;
@@ -312,7 +318,9 @@
device != AudioDeviceDescription{AudioDeviceType::OUT_CARKIT,
AudioDeviceDescription::CONNECTION_BT_SCO} &&
device != AudioDeviceDescription{AudioDeviceType::OUT_SPEAKER,
- AudioDeviceDescription::CONNECTION_BT_A2DP}) {
+ AudioDeviceDescription::CONNECTION_BT_A2DP} &&
+ device != AudioDeviceDescription{AudioDeviceType::OUT_SUBMIX,
+ AudioDeviceDescription::CONNECTION_VIRTUAL}) {
return false;
}
}
@@ -329,7 +337,9 @@
device != AudioDeviceDescription{AudioDeviceType::OUT_HEADPHONE,
AudioDeviceDescription::CONNECTION_BT_A2DP} &&
device != AudioDeviceDescription{AudioDeviceType::OUT_HEADSET,
- AudioDeviceDescription::CONNECTION_USB}) {
+ AudioDeviceDescription::CONNECTION_USB} &&
+ device != AudioDeviceDescription{AudioDeviceType::OUT_SUBMIX,
+ AudioDeviceDescription::CONNECTION_VIRTUAL}) {
return false;
}
}
@@ -469,6 +479,7 @@
RetCode BundleContext::setEqualizerBandLevels(const std::vector<Equalizer::BandLevel>& bandLevels) {
RETURN_VALUE_IF(bandLevels.size() > lvm::MAX_NUM_BANDS || bandLevels.empty(),
RetCode::ERROR_ILLEGAL_PARAMETER, "sizeExceedMax");
+
RetCode ret = updateControlParameter(bandLevels);
if (RetCode::SUCCESS == ret) {
mCurPresetIdx = lvm::PRESET_CUSTOM;
@@ -483,15 +494,13 @@
std::vector<Equalizer::BandLevel> bandLevels;
bandLevels.reserve(lvm::MAX_NUM_BANDS);
for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
- bandLevels.emplace_back(
- Equalizer::BandLevel{static_cast<int32_t>(i), mBandGainMdB[i]});
+ bandLevels.emplace_back(Equalizer::BandLevel{static_cast<int32_t>(i), mBandGainmB[i]});
}
return bandLevels;
}
std::vector<int32_t> BundleContext::getEqualizerCenterFreqs() {
std::vector<int32_t> freqs;
-
LVM_ControlParams_t params;
{
std::lock_guard lg(mMutex);
@@ -518,7 +527,7 @@
RETURN_VALUE_IF(!isBandLevelIndexInRange(bandLevels), RetCode::ERROR_ILLEGAL_PARAMETER,
"indexOutOfRange");
- std::array<int, lvm::MAX_NUM_BANDS> tempLevel(mBandGainMdB);
+ std::array<int, lvm::MAX_NUM_BANDS> tempLevel(mBandGainmB);
for (const auto& it : bandLevels) {
tempLevel[it.index] = it.levelMb;
}
@@ -539,8 +548,8 @@
RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, ¶ms),
RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
}
- mBandGainMdB = tempLevel;
- LOG(DEBUG) << __func__ << " update bandGain to " << ::android::internal::ToString(mBandGainMdB)
+ mBandGainmB = tempLevel;
+ LOG(DEBUG) << __func__ << " update bandGain to " << ::android::internal::ToString(mBandGainmB)
<< "mdB";
return RetCode::SUCCESS;
@@ -618,11 +627,30 @@
return RetCode::SUCCESS;
}
-void BundleContext::initControlParameter(LVM_ControlParams_t& params) const {
+RetCode BundleContext::initControlParameter(LVM_ControlParams_t& params) const {
+ int outputChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
+ mCommon.output.base.channelMask);
+ auto outputChannelMaskConv = aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+ mCommon.output.base.channelMask, /*isInput*/ false);
+ RETURN_VALUE_IF(!outputChannelMaskConv.ok(), RetCode::ERROR_ILLEGAL_PARAMETER,
+ " outputChannelMaskNotValid");
+
+ params.NrChannels = outputChannelCount;
+ params.ChMask = outputChannelMaskConv.value();
+ params.SampleRate = lvmFsForSampleRate(mCommon.input.base.sampleRate);
+
+ int inputChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
+ mCommon.input.base.channelMask);
+ if (inputChannelCount == 1) {
+ params.SourceFormat = LVM_MONO;
+ } else if (inputChannelCount == 2) {
+ params.SourceFormat = LVM_STEREO;
+ } else if (inputChannelCount > 2 && inputChannelCount <= LVM_MAX_CHANNELS) {
+ params.SourceFormat = LVM_MULTICHANNEL;
+ }
+
/* General parameters */
params.OperatingMode = LVM_MODE_ON;
- params.SampleRate = LVM_FS_44100;
- params.SourceFormat = LVM_STEREO;
params.SpeakerType = LVM_HEADPHONES;
/* Concert Sound parameters */
@@ -657,13 +685,7 @@
params.PSA_Enable = LVM_PSA_OFF;
params.PSA_PeakDecayRate = LVM_PSA_SPEED_MEDIUM;
- /* TE Control parameters */
- params.TE_OperatingMode = LVM_TE_OFF;
- params.TE_EffectLevel = 0;
-
- params.NrChannels = audio_channel_count_from_out_mask(AUDIO_CHANNEL_OUT_STEREO);
- params.ChMask = AUDIO_CHANNEL_OUT_STEREO;
- params.SourceFormat = LVM_STEREO;
+ return RetCode::SUCCESS;
}
void BundleContext::initHeadroomParameter(LVM_HeadroomParams_t& params) const {
@@ -832,13 +854,13 @@
LOG(DEBUG) << "Effect_process() processing last frame";
}
mNumberEffectsCalled = 0;
- LVM_UINT16 frames = samples * sizeof(float) / frameSize;
float* outTmp = (accumulate ? getWorkBuffer() : out);
/* Process the samples */
LVM_ReturnStatus_en lvmStatus;
{
std::lock_guard lg(mMutex);
- lvmStatus = LVM_Process(mInstance, in, outTmp, frames, 0);
+
+ lvmStatus = LVM_Process(mInstance, in, outTmp, inputFrameCount, 0);
if (lvmStatus != LVM_SUCCESS) {
LOG(ERROR) << __func__ << lvmStatus;
return {EX_UNSUPPORTED_OPERATION, 0, 0};
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
index 779d53a..809f402 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
@@ -41,15 +41,6 @@
RetCode disable();
RetCode disableOperatingMode();
- void setSampleRate(const int sampleRate) { mSampleRate = sampleRate; }
- int getSampleRate() const { return mSampleRate; }
-
- void setChannelMask(const aidl::android::media::audio::common::AudioChannelLayout& chMask) {
- mChMask = chMask;
- }
- aidl::android::media::audio::common::AudioChannelLayout getChannelMask() const {
- return mChMask;
- }
bool isDeviceSupportedBassBoost(
const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>&
devices);
@@ -105,9 +96,7 @@
LVM_Handle_t mInstance GUARDED_BY(mMutex);
aidl::android::media::audio::common::AudioDeviceDescription mVirtualizerForcedDevice;
- aidl::android::media::audio::common::AudioChannelLayout mChMask;
- int mSampleRate = LVM_FS_44100;
int mSamplesPerSecond = 0;
int mSamplesToExitCountEq = 0;
int mSamplesToExitCountBb = 0;
@@ -129,7 +118,7 @@
int mBassStrengthSaved = 0;
// Equalizer
int mCurPresetIdx = lvm::PRESET_CUSTOM; /* Current preset being used */
- std::array<int, lvm::MAX_NUM_BANDS> mBandGainMdB; /* band gain in millibels */
+ std::array<int, lvm::MAX_NUM_BANDS> mBandGainmB; /* band gain in millibels */
// Virtualizer
int mVirtStrengthSaved = 0; /* Conversion between Get/Set */
bool mVirtualizerTempDisabled = false;
@@ -139,7 +128,7 @@
float mVolume = 0;
bool mMuteEnabled = false; /* Must store as mute = -96dB level */
- void initControlParameter(LVM_ControlParams_t& params) const;
+ RetCode initControlParameter(LVM_ControlParams_t& params) const;
void initHeadroomParameter(LVM_HeadroomParams_t& params) const;
RetCode limitLevel();
static float VolToDb(float vol);
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index 5fb3966..da5346f 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -118,10 +118,15 @@
"libhardware_headers",
],
shared_libs: [
+ "libaudio_aidl_conversion_common_ndk",
+ "libaudioutils",
+ "libbinder",
"liblog",
+ "libstagefright_foundation",
],
cflags: [
"-Wthread-safety",
+ "-DBACKEND_NDK",
],
relative_install_path: "soundfx",
visibility: [
diff --git a/media/utils/include/mediautils/StaticStringView.h b/media/utils/include/mediautils/StaticStringView.h
index 14be240..e9a5deb 100644
--- a/media/utils/include/mediautils/StaticStringView.h
+++ b/media/utils/include/mediautils/StaticStringView.h
@@ -21,15 +21,15 @@
#pragma push_macro("EXPLICIT_CONVERSION_GENERATE_OPERATOR")
#undef EXPLICIT_CONVERSION_GENERATE_OPERATOR
-#define EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, op) \
- friend constexpr bool operator op(T lhs, T rhs) { \
- return operator op(static_cast<U>(lhs), static_cast<U>(rhs)); \
- } \
- friend constexpr bool operator op(T lhs, U rhs) { \
- return operator op(static_cast<U>(lhs), rhs); \
- } \
- friend constexpr bool operator op(U lhs, T rhs) { \
- return operator op(lhs, static_cast<U>(rhs)); \
+#define EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, op) \
+ friend constexpr bool operator op(T lhs, T rhs) { \
+ return static_cast<U>(lhs) op static_cast<U>(rhs); \
+ } \
+ friend constexpr bool operator op(T lhs, U rhs) { \
+ return static_cast<U>(lhs) op rhs; \
+ } \
+ friend constexpr bool operator op(U lhs, T rhs) { \
+ return lhs op static_cast<U>(rhs); \
}
#pragma push_macro("EXPLICIT_CONVERSION_GENERATE_COMPARISON_OPERATORS")
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 58e5311..2fd908f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -3225,7 +3225,8 @@
ALOGD("%s: no group matching with %s", __FUNCTION__, toString(attributes).c_str());
return BAD_VALUE;
}
- ALOGV("%s: group %d matching with %s", __FUNCTION__, group, toString(attributes).c_str());
+ ALOGV("%s: group %d matching with %s index %d",
+ __FUNCTION__, group, toString(attributes).c_str(), index);
status_t status = NO_ERROR;
IVolumeCurves &curves = getVolumeCurves(attributes);
VolumeSource vs = toVolumeSource(group);
@@ -3342,6 +3343,21 @@
status = volStatus;
}
}
+
+ // update voice volume if the an active call route exists
+ if (mCallRxSourceClient != nullptr && mCallRxSourceClient->isConnected()
+ && (curSrcDevices.find(
+ Volume::getDeviceForVolume({mCallRxSourceClient->sinkDevice()->type()}))
+ != curSrcDevices.end())) {
+ bool isVoiceVolSrc;
+ bool isBtScoVolSrc;
+ if (isVolumeConsistentForCalls(vs, {mCallRxSourceClient->sinkDevice()->type()},
+ isVoiceVolSrc, isBtScoVolSrc, __func__)
+ && (isVoiceVolSrc || isBtScoVolSrc)) {
+ setVoiceVolume(index, curves, isVoiceVolSrc, 0);
+ }
+ }
+
mpClientInterface->onAudioVolumeGroupChanged(group, 0 /*flags*/);
return status;
}
@@ -7815,26 +7831,16 @@
outputDesc->getMuteCount(volumeSource), outputDesc->isActive(volumeSource));
return NO_ERROR;
}
- VolumeSource callVolSrc = toVolumeSource(AUDIO_STREAM_VOICE_CALL, false);
- VolumeSource btScoVolSrc = toVolumeSource(AUDIO_STREAM_BLUETOOTH_SCO, false);
- bool isVoiceVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (callVolSrc == volumeSource);
- bool isBtScoVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (btScoVolSrc == volumeSource);
- bool isScoRequested = isScoRequestedForComm();
- bool isHAUsed = isHearingAidUsedForComm();
-
- // do not change in call volume if bluetooth is connected and vice versa
- // if sco and call follow same curves, bypass forceUseForComm
- if ((callVolSrc != btScoVolSrc) &&
- ((isVoiceVolSrc && isScoRequested) ||
- (isBtScoVolSrc && !(isScoRequested || isHAUsed))) &&
- !isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
- ALOGV("%s cannot set volume group %d volume when is%srequested for comm", __func__,
- volumeSource, isScoRequested ? " " : " not ");
+ bool isVoiceVolSrc;
+ bool isBtScoVolSrc;
+ if (!isVolumeConsistentForCalls(
+ volumeSource, deviceTypes, isVoiceVolSrc, isBtScoVolSrc, __func__)) {
// Do not return an error here as AudioService will always set both voice call
- // and bluetooth SCO volumes due to stream aliasing.
+ // and Bluetooth SCO volumes due to stream aliasing.
return NO_ERROR;
}
+
if (deviceTypes.empty()) {
deviceTypes = outputDesc->devices().types();
index = curves.getVolumeIndex(deviceTypes);
@@ -7859,21 +7865,51 @@
deviceTypes, delayMs, force, isVoiceVolSrc);
if (outputDesc == mPrimaryOutput && (isVoiceVolSrc || isBtScoVolSrc)) {
- float voiceVolume;
- // Force voice volume to max or mute for Bluetooth SCO as other attenuations are managed by the headset
- if (isVoiceVolSrc) {
- voiceVolume = (float)index/(float)curves.getVolumeIndexMax();
- } else {
- voiceVolume = index == 0 ? 0.0 : 1.0;
- }
- if (voiceVolume != mLastVoiceVolume) {
- mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
- mLastVoiceVolume = voiceVolume;
- }
+ setVoiceVolume(index, curves, isVoiceVolSrc, delayMs);
}
return NO_ERROR;
}
+void AudioPolicyManager::setVoiceVolume(
+ int index, IVolumeCurves &curves, bool isVoiceVolSrc, int delayMs) {
+ float voiceVolume;
+ // Force voice volume to max or mute for Bluetooth SCO as other attenuations are managed
+ // by the headset
+ if (isVoiceVolSrc) {
+ voiceVolume = (float)index/(float)curves.getVolumeIndexMax();
+ } else {
+ voiceVolume = index == 0 ? 0.0 : 1.0;
+ }
+ if (voiceVolume != mLastVoiceVolume) {
+ mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+ mLastVoiceVolume = voiceVolume;
+ }
+}
+
+bool AudioPolicyManager::isVolumeConsistentForCalls(VolumeSource volumeSource,
+ const DeviceTypeSet& deviceTypes,
+ bool& isVoiceVolSrc,
+ bool& isBtScoVolSrc,
+ const char* caller) {
+ const VolumeSource callVolSrc = toVolumeSource(AUDIO_STREAM_VOICE_CALL, false);
+ const VolumeSource btScoVolSrc = toVolumeSource(AUDIO_STREAM_BLUETOOTH_SCO, false);
+ const bool isScoRequested = isScoRequestedForComm();
+ const bool isHAUsed = isHearingAidUsedForComm();
+
+ isVoiceVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (callVolSrc == volumeSource);
+ isBtScoVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (btScoVolSrc == volumeSource);
+
+ if ((callVolSrc != btScoVolSrc) &&
+ ((isVoiceVolSrc && isScoRequested) ||
+ (isBtScoVolSrc && !(isScoRequested || isHAUsed))) &&
+ !isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
+ ALOGV("%s cannot set volume group %d volume when is%srequested for comm", caller,
+ volumeSource, isScoRequested ? " " : " not ");
+ return false;
+ }
+ return true;
+}
+
void AudioPolicyManager::applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc,
const DeviceTypeSet& deviceTypes,
int delayMs,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 5b9f6ad..8f8550c 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -575,6 +575,20 @@
DeviceTypeSet deviceTypes,
int delayMs = 0, bool force = false);
+ void setVoiceVolume(int index, IVolumeCurves &curves, bool isVoiceVolSrc, int delayMs);
+
+ // returns true if the supplied set of volume source and devices are consistent with
+ // call volume rules:
+ // if Bluetooth SCO and voice call use different volume curves:
+ // - do not apply voice call volume if Bluetooth SCO is used for call
+ // - do not apply Bluetooth SCO volume if SCO or Hearing Aid is not used for call.
+ // Also updates the booleans isVoiceVolSrc and isBtScoVolSrc according to the
+ // volume source supplied.
+ bool isVolumeConsistentForCalls(VolumeSource volumeSource,
+ const DeviceTypeSet& deviceTypes,
+ bool& isVoiceVolSrc,
+ bool& isBtScoVolSrc,
+ const char* caller);
// apply all stream volumes to the specified output and device
void applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc,
const DeviceTypeSet& deviceTypes,
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy b/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy
index a55c3eb..0c6aafd 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy
@@ -52,6 +52,9 @@
getdents64: 1
ppoll: 1
+clock_gettime: 1
+pipe2: 1
+
# Required by AddressSanitizer
gettid: 1
sched_yield: 1
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index 73a96e9..794bda0 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -74,10 +74,14 @@
name: "libresourcemanagerservice",
srcs: [
+ "DefaultResourceModel.cpp",
+ "ProcessPriorityReclaimPolicy.cpp",
"ResourceManagerMetrics.cpp",
"ResourceManagerService.cpp",
+ "ResourceManagerServiceNew.cpp",
"ResourceObserverService.cpp",
"ResourceManagerServiceUtils.cpp",
+ "ResourceTracker.cpp",
"ServiceLog.cpp",
"UidObserver.cpp",
@@ -97,6 +101,7 @@
"libstatssocket",
"libprotobuf-cpp-lite",
"libactivitymanager_aidl",
+ "aconfig_mediacodec_flags_c_lib",
],
static_libs: [
diff --git a/services/mediaresourcemanager/DefaultResourceModel.cpp b/services/mediaresourcemanager/DefaultResourceModel.cpp
new file mode 100644
index 0000000..7bad715
--- /dev/null
+++ b/services/mediaresourcemanager/DefaultResourceModel.cpp
@@ -0,0 +1,145 @@
+/*
+**
+** 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 "DefaultResourceModel"
+#include <utils/Log.h>
+
+#include "ResourceManagerServiceUtils.h"
+#include "DefaultResourceModel.h"
+#include "ResourceTracker.h"
+
+namespace android {
+
+DefaultResourceModel::DefaultResourceModel(
+ const std::shared_ptr<ResourceTracker>& resourceTracker,
+ bool supportsMultipleSecureCodecs,
+ bool supportsSecureWithNonSecureCodec)
+ : mSupportsMultipleSecureCodecs(supportsMultipleSecureCodecs),
+ mSupportsSecureWithNonSecureCodec(supportsSecureWithNonSecureCodec),
+ mResourceTracker(resourceTracker) {
+}
+
+DefaultResourceModel::~DefaultResourceModel() {
+}
+
+bool DefaultResourceModel::getAllClients(
+ const ReclaimRequestInfo& reclimRequestInfo,
+ std::vector<ClientInfo>& clients) {
+
+ clients.clear();
+ MediaResourceParcel mediaResource{.type = reclimRequestInfo.mResources[0].type,
+ .subType = reclimRequestInfo.mResources[0].subType};
+ ResourceRequestInfo resourceRequestInfo{reclimRequestInfo.mCallingPid, &mediaResource};
+
+ // Resolve the secure-unsecure codec conflicts if there is any.
+ switch (reclimRequestInfo.mResources[0].type) {
+ case MediaResource::Type::kSecureCodec:
+ // Looking to start a secure codec.
+ // #1. Make sure if multiple secure codecs can coexist
+ if (!mSupportsMultipleSecureCodecs) {
+ if (!mResourceTracker->getNonConflictingClients(resourceRequestInfo, clients)) {
+ // A higher priority process owns an instance of a secure codec.
+ // So this request can't be fulfilled.
+ return false;
+ }
+ }
+ // #2. Make sure a secure codec can coexist if there is an instance
+ // of non-secure codec running already.
+ if (!mSupportsSecureWithNonSecureCodec) {
+ mediaResource.type = MediaResource::Type::kNonSecureCodec;
+ if (!mResourceTracker->getNonConflictingClients(resourceRequestInfo, clients)) {
+ // A higher priority process owns an instance of a non-secure codec.
+ // So this request can't be fulfilled.
+ return false;
+ }
+ }
+ break;
+ case MediaResource::Type::kNonSecureCodec:
+ // Looking to start a non-secure codec.
+ // Make sure a non-secure codec can coexist if there is an instance
+ // of secure codec running already.
+ if (!mSupportsSecureWithNonSecureCodec) {
+ mediaResource.type = MediaResource::Type::kSecureCodec;
+ if (!mResourceTracker->getNonConflictingClients(resourceRequestInfo, clients)) {
+ // A higher priority process owns an instance of a secure codec.
+ // So this request can't be fulfilled.
+ return false;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!clients.empty()) {
+ // There is secure/unsecure codec co-existence conflict
+ // and we have only found processes with lower priority holding the
+ // resources. So, all of these need to be reclaimed.
+ return false;
+ }
+
+ // No more resource conflicts.
+ switch (reclimRequestInfo.mResources[0].type) {
+ case MediaResource::Type::kSecureCodec:
+ case MediaResource::Type::kNonSecureCodec:
+ // Handling Codec resource reclaim
+ return getCodecClients(reclimRequestInfo, clients);
+ case MediaResource::Type::kGraphicMemory:
+ case MediaResource::Type::kDrmSession:
+ // Handling DRM and GraphicMemory resource reclaim
+ mediaResource.id = reclimRequestInfo.mResources[0].id;
+ mediaResource.value = reclimRequestInfo.mResources[0].value;
+ return mResourceTracker->getAllClients(resourceRequestInfo, clients);
+ default:
+ break;
+ }
+
+ return !clients.empty();
+}
+
+bool DefaultResourceModel::getCodecClients(
+ const ReclaimRequestInfo& reclimRequestInfo,
+ std::vector<ClientInfo>& clients) {
+ MediaResourceParcel mediaResource;
+ ResourceRequestInfo resourceRequestInfo{reclimRequestInfo.mCallingPid, &mediaResource};
+
+ // 1. Look to find the client(s) with the other resources, for the given
+ // primary type.
+ MediaResource::SubType primarySubType = reclimRequestInfo.mResources[0].subType;
+ for (size_t index = 1; index < reclimRequestInfo.mResources.size(); index++) {
+ mediaResource.type = reclimRequestInfo.mResources[index].type;
+ mediaResource.subType = reclimRequestInfo.mResources[index].subType;
+ mResourceTracker->getAllClients(resourceRequestInfo, clients, primarySubType);
+ }
+
+ // 2. Get all clients of the same type.
+ mediaResource.type = reclimRequestInfo.mResources[0].type;
+ mediaResource.subType = reclimRequestInfo.mResources[0].subType;
+ mResourceTracker->getAllClients(resourceRequestInfo, clients);
+
+ // 3. Get all cliends of the different type.
+ MediaResourceType otherType =
+ (reclimRequestInfo.mResources[0].type == MediaResource::Type::kSecureCodec) ?
+ MediaResource::Type::kNonSecureCodec : MediaResource::Type::kSecureCodec;
+ mediaResource.type = otherType;
+ mResourceTracker->getAllClients(resourceRequestInfo, clients);
+
+ return !clients.empty();
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/DefaultResourceModel.h b/services/mediaresourcemanager/DefaultResourceModel.h
new file mode 100644
index 0000000..1891eda
--- /dev/null
+++ b/services/mediaresourcemanager/DefaultResourceModel.h
@@ -0,0 +1,73 @@
+/*
+**
+** 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_DEFAULTRESOURCEMODEL_H_
+#define ANDROID_MEDIA_DEFAULTRESOURCEMODEL_H_
+
+#include "IResourceModel.h"
+
+namespace android {
+
+class ResourceTracker;
+
+/*
+ * Implements the Default Resource Model that handles:
+ * - coexistence of secure codec with another secure/non-secure codecs
+ * - sharing resources among other codecs
+ */
+class DefaultResourceModel : public IResourceModel {
+public:
+ DefaultResourceModel(const std::shared_ptr<ResourceTracker>& resourceTracker,
+ bool supportsMultipleSecureCodecs = true,
+ bool supportsSecureWithNonSecureCodec = true);
+ virtual ~DefaultResourceModel();
+
+ /*
+ * Set the codec co-existence properties
+ */
+ void config(bool supportsMultipleSecureCodecs, bool supportsSecureWithNonSecureCodec) {
+ mSupportsMultipleSecureCodecs = supportsMultipleSecureCodecs;
+ mSupportsSecureWithNonSecureCodec = supportsSecureWithNonSecureCodec;
+ }
+
+ /*
+ * Get a list of all clients that holds the resources requested.
+ * This implementation uses the ResourceModel to select the clients.
+ *
+ * @param[in] reclaimRequestInfo Information about the Reclaim request
+ * @param[out] cliens The list of clients that hold the resources in question.
+ *
+ * @return true if there aren't any resource conflicts and false otherwise.
+ */
+ bool getAllClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ std::vector<ClientInfo>& clients) override;
+
+protected:
+ bool getCodecClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ std::vector<ClientInfo>& clients);
+
+protected:
+ // Keeping these protected to allow extending this implementation
+ // by other resource models.
+ bool mSupportsMultipleSecureCodecs;
+ bool mSupportsSecureWithNonSecureCodec;
+ std::shared_ptr<ResourceTracker> mResourceTracker;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_DEFAULTRESOURCEMODEL_H_
diff --git a/services/mediaresourcemanager/IReclaimPolicy.h b/services/mediaresourcemanager/IReclaimPolicy.h
new file mode 100644
index 0000000..dfbfc12
--- /dev/null
+++ b/services/mediaresourcemanager/IReclaimPolicy.h
@@ -0,0 +1,58 @@
+/*
+**
+** 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_IRECLAIMPOLICY_H_
+#define ANDROID_MEDIA_IRECLAIMPOLICY_H_
+
+#include <memory>
+#include <aidl/android/media/IResourceManagerClient.h>
+
+namespace android {
+
+struct ClientInfo;
+struct ReclaimRequestInfo;
+
+/*
+ * Interface that defines Reclaim Policy.
+ *
+ * This provides an interface to select/identify a client based on a specific
+ * Reclaim policy.
+ */
+class IReclaimPolicy {
+public:
+ IReclaimPolicy() {}
+
+ virtual ~IReclaimPolicy() {}
+
+ /*
+ * Based on the Reclaim policy, identify and return a client 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
+ */
+ virtual bool getClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients) = 0;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_IRECLAIMPOLICY_H_
diff --git a/services/mediaresourcemanager/IResourceModel.h b/services/mediaresourcemanager/IResourceModel.h
new file mode 100644
index 0000000..f865f54
--- /dev/null
+++ b/services/mediaresourcemanager/IResourceModel.h
@@ -0,0 +1,67 @@
+/*
+**
+** 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_IRESOURCEMODEL_H_
+#define ANDROID_MEDIA_IRESOURCEMODEL_H_
+
+#include <memory>
+#include <vector>
+
+#include <aidl/android/media/IResourceManagerClient.h>
+#include <aidl/android/media/MediaResourceParcel.h>
+
+namespace android {
+
+struct ClientInfo;
+struct ReclaimRequestInfo;
+
+/*
+ * Interface that defines Resource Model.
+ *
+ * This provides an interface that manages the resource model.
+ * The primary functionality of the implementation of this resource model is to:
+ * 1. Define a resource model for a device (or family of devices)
+ * For example (and not limited to):
+ * - Can a secure codec coexist with another secure or unsecured codec?
+ * - How many codecs can coexist?
+ * - Can one type of codecs (for example avc) coexist with another type of codec
+ * (for example hevc) independently? OR are they sharing the common
+ * resource pool?
+ * 2. Provide a list of clients that hold requesting resources.
+ */
+class IResourceModel {
+public:
+ IResourceModel() {}
+
+ virtual ~IResourceModel() {}
+
+ /*
+ * Get a list of all clients that holds the resources requested.
+ * This implementation uses the ResourceModel to select the clients.
+ *
+ * @param[in] reclaimRequestInfo Information about the Reclaim request
+ * @param[out] clients The list of clients that hold the resources in question.
+ *
+ * @return true if there aren't any resource conflicts and false otherwise.
+ */
+ virtual bool getAllClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ std::vector<ClientInfo>& clients) = 0;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_IRESOURCEMODEL_H_
diff --git a/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.cpp b/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.cpp
new file mode 100644
index 0000000..5b776a6
--- /dev/null
+++ b/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.cpp
@@ -0,0 +1,135 @@
+/*
+**
+** 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 "ProcessPriorityReclaimPolicy"
+#include <utils/Log.h>
+
+#include "ResourceTracker.h"
+#include "ResourceManagerService.h"
+#include "ProcessPriorityReclaimPolicy.h"
+
+namespace android {
+
+using aidl::android::media::IResourceManagerClient;
+
+ProcessPriorityReclaimPolicy::ProcessPriorityReclaimPolicy(
+ const std::shared_ptr<ResourceTracker>& resourceTracker)
+ : mResourceTracker(resourceTracker) {
+}
+
+ProcessPriorityReclaimPolicy::~ProcessPriorityReclaimPolicy() {
+}
+
+// Process priority (oom score) based reclaim:
+// - Find a process with lowest priority (than that of calling process).
+// - Find the bigegst client (with required resources) from that process.
+bool ProcessPriorityReclaimPolicy::getClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients) {
+ // NOTE: This is the behavior of the existing reclaim policy.
+ // We can alter it to select more than one client to reclaim from, depending
+ // on the reclaim polocy.
+
+ MediaResource::Type type = reclaimRequestInfo.mResources[0].type;
+ MediaResource::SubType subType = reclaimRequestInfo.mResources[0].subType;
+ // Find one client to reclaim the needed resources from.
+ // 1. Get the priority of the (reclaim) requesting process.
+ int callingPid = reclaimRequestInfo.mCallingPid;
+ int callingPriority = -1;
+ if (!mResourceTracker->getPriority(callingPid, &callingPriority)) {
+ ALOGE("%s: can't get process priority for pid %d", __func__, callingPid);
+ return false;
+ }
+
+ ClientInfo clientInfo;
+ // 2 Look to find the biggest client from the lowest priority process that
+ // has the other resources and with the given primary type.
+ bool found = false;
+ int lowestPriority = -1;
+ 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 = getBiggestClientFromLowestPriority(callingPid, callingPriority,
+ type, subType, primarySubType,
+ clients, clientInfo, lowestPriority);
+ }
+ // 3 If we haven't found a client yet, then select the biggest client of primary type.
+ if (!found) {
+ found = getBiggestClientFromLowestPriority(callingPid, callingPriority,
+ type, subType,
+ MediaResource::SubType::kUnspecifiedSubType,
+ clients, clientInfo, lowestPriority);
+ }
+ // 4 If we haven't found a client yet, then select the biggest client of different type.
+ // This is applicable for code 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 (!getBiggestClientFromLowestPriority(callingPid, callingPriority,
+ otherType, subType,
+ MediaResource::SubType::kUnspecifiedSubType,
+ clients, clientInfo, lowestPriority)) {
+ return false;
+ }
+ }
+
+ targetClients.emplace_back(clientInfo);
+ ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)",
+ __func__, callingPid, callingPriority, clientInfo.mPid, lowestPriority);
+
+ return true;
+}
+
+bool ProcessPriorityReclaimPolicy::getBiggestClientFromLowestPriority(
+ pid_t callingPid,
+ int callingPriority,
+ MediaResource::Type type, MediaResource::SubType subType,
+ MediaResource::SubType primarySubType,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& targetClient,
+ int& lowestPriority) {
+ // 1. Find the lowest priority process among all the clients with the
+ // requested resource type.
+ int lowestPriorityPid = -1;
+ lowestPriority = -1;
+ if (!mResourceTracker->getLowestPriorityPid(type, subType, primarySubType, clients,
+ lowestPriorityPid, lowestPriority)) {
+ ALOGD("%s: can't find a process with lower priority than that of the process[%d:%d]",
+ __func__, callingPid, callingPriority);
+ return false;
+ }
+
+ // 2. Make sure that the priority of the target process is less than
+ // requesting process.
+ if (lowestPriority <= callingPriority) {
+ ALOGD("%s: lowest priority %d vs caller priority %d",
+ __func__, lowestPriority, callingPriority);
+ return false;
+ }
+
+ // 3. Look to find the biggest client from that process for the given resources
+ return mResourceTracker->getBiggestClient(lowestPriorityPid, type, subType,
+ clients, targetClient, primarySubType);
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.h b/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.h
new file mode 100644
index 0000000..77bf7e1
--- /dev/null
+++ b/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.h
@@ -0,0 +1,89 @@
+/*
+**
+** 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_PROCESSPRIORITYRECLAIMPOLICY_H_
+#define ANDROID_MEDIA_PROCESSPRIORITYRECLAIMPOLICY_H_
+
+#include <media/MediaResource.h>
+#include "IReclaimPolicy.h"
+
+namespace android {
+
+class ResourceTracker;
+struct ClientInfo;
+
+/*
+ * Implementation of the Reclaim Policy based on the process priority.
+ *
+ * Find the lowest priority process (lower than the calling/requesting process’s priority)
+ * that has the required resources.
+ * From that process, find the biggest client and return the same for reclaiming.
+ * If there is a codec co-existence policy, that is addressed as below:
+ * - if these are any conflicting codecs, reclaim all those conflicting clients.
+ * If no conflicting codecs, the reclaim policy will select a client in the order of:
+ * - Find the biggest client from the lowest priority process that
+ * has the other resources and with the given primary type.
+ * - select the biggest client from the lower priority process that
+ * has the primary type.
+ * - If it's a codec reclaim request, then:
+ * - select the biggest client from the lower priority process that
+ * has the othe type (for example secure for a non-secure and vice versa).
+ */
+class ProcessPriorityReclaimPolicy : public IReclaimPolicy {
+public:
+ ProcessPriorityReclaimPolicy(const std::shared_ptr<ResourceTracker>& resourceTracker);
+
+ virtual ~ProcessPriorityReclaimPolicy();
+
+ /*
+ * Based on the process priority, identify and return a client 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:
+
+ // Get the biggest client with the given resources from the given list of clients.
+ // The client should belong to lowest possible priority than that of the
+ // calling/requesting process.
+ // returns true on success, false otherwise
+ //
+ bool getBiggestClientFromLowestPriority(
+ pid_t callingPid,
+ int callingPriority,
+ MediaResource::Type type,
+ MediaResource::SubType subType,
+ MediaResource::SubType primarySubType,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& targetClient,
+ int& lowestPriority);
+
+private:
+ std::shared_ptr<ResourceTracker> mResourceTracker;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_PROCESSPRIORITYRECLAIMPOLICY_H_
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 1953237..4bdb6e1 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -29,38 +29,64 @@
#include <mediautils/BatteryNotifier.h>
#include <mediautils/ProcessInfo.h>
#include <mediautils/SchedulingPolicyService.h>
+#include <com_android_media_codec_flags.h>
-#include "IMediaResourceMonitor.h"
#include "ResourceManagerMetrics.h"
+#include "ResourceManagerServiceNew.h"
#include "ResourceObserverService.h"
#include "ServiceLog.h"
+namespace CodecFeatureFlags = com::android::media::codec::flags;
+
namespace android {
-static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel>& resources) {
- static const char* const kServiceName = "media_resource_monitor";
- sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName));
- if (binder != NULL) {
- sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
- for (size_t i = 0; i < resources.size(); ++i) {
- switch (resources[i].subType) {
- case MediaResource::SubType::kHwAudioCodec:
- case MediaResource::SubType::kSwAudioCodec:
- service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
- break;
- case MediaResource::SubType::kHwVideoCodec:
- case MediaResource::SubType::kSwVideoCodec:
- service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
- break;
- case MediaResource::SubType::kHwImageCodec:
- case MediaResource::SubType::kSwImageCodec:
- service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_IMAGE_CODEC);
- break;
- case MediaResource::SubType::kUnspecifiedSubType:
- break;
+void ResourceManagerService::getResourceDump(std::string& resourceLog) const {
+ PidResourceInfosMap mapCopy;
+ std::map<int, int> overridePidMapCopy;
+ {
+ std::scoped_lock lock{mLock};
+ mapCopy = mMap; // Shadow copy, real copy will happen on write.
+ overridePidMapCopy = mOverridePidMap;
+ }
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ resourceLog.append(" Processes:\n");
+ for (const auto& [pid, infos] : mapCopy) {
+ snprintf(buffer, SIZE, " Pid: %d\n", pid);
+ resourceLog.append(buffer);
+ int priority = 0;
+ if (getPriority_l(pid, &priority)) {
+ snprintf(buffer, SIZE, " Priority: %d\n", priority);
+ } else {
+ snprintf(buffer, SIZE, " Priority: <unknown>\n");
+ }
+ resourceLog.append(buffer);
+
+ for (const auto& [infoKey, info] : infos) {
+ resourceLog.append(" Client:\n");
+ snprintf(buffer, SIZE, " Id: %lld\n", (long long)info.clientId);
+ resourceLog.append(buffer);
+
+ std::string clientName = info.name;
+ snprintf(buffer, SIZE, " Name: %s\n", clientName.c_str());
+ resourceLog.append(buffer);
+
+ 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(" Process Pid override:\n");
+ for (auto it = overridePidMapCopy.begin(); it != overridePidMapCopy.end(); ++it) {
+ snprintf(buffer, SIZE, " Original Pid: %d, Override Pid: %d\n",
+ it->first, it->second);
+ resourceLog.append(buffer);
+ }
}
binder_status_t ResourceManagerService::dump(int fd, const char** /*args*/, uint32_t /*numArgs*/) {
@@ -75,20 +101,20 @@
return PERMISSION_DENIED;
}
- PidResourceInfosMap mapCopy;
bool supportsMultipleSecureCodecs;
bool supportsSecureWithNonSecureCodec;
- std::map<int, int> overridePidMapCopy;
String8 serviceLog;
{
std::scoped_lock lock{mLock};
- mapCopy = mMap; // Shadow copy, real copy will happen on write.
supportsMultipleSecureCodecs = mSupportsMultipleSecureCodecs;
supportsSecureWithNonSecureCodec = mSupportsSecureWithNonSecureCodec;
serviceLog = mServiceLog->toString(" " /* linePrefix */);
- overridePidMapCopy = mOverridePidMap;
}
+ // Get all the resource (and overload pid) logs
+ std::string resourceLog;
+ getResourceDump(resourceLog);
+
const size_t SIZE = 256;
char buffer[SIZE];
snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this);
@@ -100,41 +126,8 @@
supportsSecureWithNonSecureCodec);
result.append(buffer);
- result.append(" Processes:\n");
- for (const auto& [pid, infos] : mapCopy) {
- snprintf(buffer, SIZE, " Pid: %d\n", pid);
- result.append(buffer);
- int priority = 0;
- if (getPriority_l(pid, &priority)) {
- snprintf(buffer, SIZE, " Priority: %d\n", priority);
- } else {
- snprintf(buffer, SIZE, " Priority: <unknown>\n");
- }
- result.append(buffer);
+ result.append(resourceLog.c_str());
- for (const auto& [infoKey, info] : infos) {
- result.append(" Client:\n");
- snprintf(buffer, SIZE, " Id: %lld\n", (long long)info.clientId);
- result.append(buffer);
-
- std::string clientName = info.name;
- snprintf(buffer, SIZE, " Name: %s\n", clientName.c_str());
- result.append(buffer);
-
- const ResourceList& resources = info.resources;
- result.append(" Resources:\n");
- for (auto it = resources.begin(); it != resources.end(); it++) {
- snprintf(buffer, SIZE, " %s\n", toString(it->second).c_str());
- result.append(buffer);
- }
- }
- }
- result.append(" Process Pid override:\n");
- for (auto it = overridePidMapCopy.begin(); it != overridePidMapCopy.end(); ++it) {
- snprintf(buffer, SIZE, " Original Pid: %d, Override Pid: %d\n",
- it->first, it->second);
- result.append(buffer);
- }
result.append(" Events logs (most recent at top):\n");
result.append(serviceLog);
@@ -212,9 +205,35 @@
std::shared_ptr<ResourceManagerService> ResourceManagerService::Create(
const sp<ProcessInfoInterface>& processInfo,
const sp<SystemCallbackInterface>& systemResource) {
- return ::ndk::SharedRefBase::make<ResourceManagerService>(processInfo, systemResource);
+ std::shared_ptr<ResourceManagerService> service = nullptr;
+ // If codec importance feature is on, create the refactored implementation.
+ if (CodecFeatureFlags::codec_importance()) {
+ service = ::ndk::SharedRefBase::make<ResourceManagerServiceNew>(processInfo,
+ systemResource);
+ } else {
+ service = ::ndk::SharedRefBase::make<ResourceManagerService>(processInfo,
+ systemResource);
+ }
+
+ if (service != nullptr) {
+ service->init();
+ }
+
+ return service;
}
+// TEST only function.
+std::shared_ptr<ResourceManagerService> ResourceManagerService::CreateNew(
+ const sp<ProcessInfoInterface>& processInfo,
+ const sp<SystemCallbackInterface>& systemResource) {
+ std::shared_ptr<ResourceManagerService> service =
+ ::ndk::SharedRefBase::make<ResourceManagerServiceNew>(processInfo, systemResource);
+ service->init();
+ return service;
+}
+
+void ResourceManagerService::init() {}
+
ResourceManagerService::~ResourceManagerService() {}
void ResourceManagerService::setObserverService(
@@ -472,6 +491,111 @@
}
}
+bool ResourceManagerService::getTargetClients(
+ int32_t callingPid,
+ const std::vector<MediaResourceParcel>& resources,
+ std::vector<ClientInfo>& targetClients) {
+ std::scoped_lock lock{mLock};
+ if (!mProcessInfo->isPidTrusted(callingPid)) {
+ pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
+ ALOGW("%s called with untrusted pid %d, using actual calling pid %d", __FUNCTION__,
+ callingPid, actualCallingPid);
+ callingPid = actualCallingPid;
+ }
+ const MediaResourceParcel *secureCodec = NULL;
+ const MediaResourceParcel *nonSecureCodec = NULL;
+ const MediaResourceParcel *graphicMemory = NULL;
+ const MediaResourceParcel *drmSession = NULL;
+ for (size_t i = 0; i < resources.size(); ++i) {
+ switch (resources[i].type) {
+ case MediaResource::Type::kSecureCodec:
+ secureCodec = &resources[i];
+ break;
+ case MediaResource::Type::kNonSecureCodec:
+ nonSecureCodec = &resources[i];
+ break;
+ case MediaResource::Type::kGraphicMemory:
+ graphicMemory = &resources[i];
+ break;
+ case MediaResource::Type::kDrmSession:
+ drmSession = &resources[i];
+ break;
+ default:
+ break;
+ }
+ }
+
+ // first pass to handle secure/non-secure codec conflict
+ if (secureCodec != NULL) {
+ MediaResourceParcel mediaResource{.type = MediaResource::Type::kSecureCodec,
+ .subType = secureCodec->subType};
+ ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
+ if (!mSupportsMultipleSecureCodecs) {
+ if (!getAllClients_l(resourceRequestInfo, targetClients)) {
+ return false;
+ }
+ }
+ if (!mSupportsSecureWithNonSecureCodec) {
+ mediaResource.type = MediaResource::Type::kNonSecureCodec;
+ if (!getAllClients_l(resourceRequestInfo, targetClients)) {
+ return false;
+ }
+ }
+ }
+ if (nonSecureCodec != NULL) {
+ if (!mSupportsSecureWithNonSecureCodec) {
+ MediaResourceParcel mediaResource{.type = MediaResource::Type::kSecureCodec,
+ .subType = nonSecureCodec->subType};
+ ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
+ if (!getAllClients_l(resourceRequestInfo, targetClients)) {
+ return false;
+ }
+ }
+ }
+
+ if (drmSession != NULL) {
+ ResourceRequestInfo resourceRequestInfo{callingPid, drmSession};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ if (targetClients.size() == 0) {
+ return false;
+ }
+ }
+
+ if (targetClients.size() == 0 && graphicMemory != nullptr) {
+ // if no secure/non-secure codec conflict, run second pass to handle other resources.
+ ResourceRequestInfo resourceRequestInfo{callingPid, graphicMemory};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ }
+
+ if (targetClients.size() == 0) {
+ // if we are here, run the third pass to free one codec with the same type.
+ if (secureCodec != nullptr) {
+ ResourceRequestInfo resourceRequestInfo{callingPid, secureCodec};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ }
+ if (nonSecureCodec != nullptr) {
+ ResourceRequestInfo resourceRequestInfo{callingPid, nonSecureCodec};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ }
+ }
+
+ if (targetClients.size() == 0) {
+ // if we are here, run the fourth pass to free one codec with the different type.
+ if (secureCodec != nullptr) {
+ MediaResource temp(MediaResource::Type::kNonSecureCodec, secureCodec->subType, 1);
+ ResourceRequestInfo resourceRequestInfo{callingPid, &temp};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ }
+ if (nonSecureCodec != nullptr) {
+ MediaResource temp(MediaResource::Type::kSecureCodec, nonSecureCodec->subType, 1);
+ ResourceRequestInfo resourceRequestInfo{callingPid, &temp};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ }
+ }
+
+ return !targetClients.empty();
+}
+
Status ResourceManagerService::reclaimResource(const ClientInfoParcel& clientInfo,
const std::vector<MediaResourceParcel>& resources, bool* _aidl_return) {
int32_t callingPid = clientInfo.pid;
@@ -481,105 +605,16 @@
mServiceLog->add(log);
*_aidl_return = false;
+ // Check if there are any resources to be reclaimed before processing.
+ if (resources.empty()) {
+ return Status::ok();
+ }
+
std::vector<ClientInfo> targetClients;
- {
- std::scoped_lock lock{mLock};
- if (!mProcessInfo->isPidTrusted(callingPid)) {
- pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
- ALOGW("%s called with untrusted pid %d, using actual calling pid %d", __FUNCTION__,
- callingPid, actualCallingPid);
- callingPid = actualCallingPid;
- }
- const MediaResourceParcel *secureCodec = NULL;
- const MediaResourceParcel *nonSecureCodec = NULL;
- const MediaResourceParcel *graphicMemory = NULL;
- const MediaResourceParcel *drmSession = NULL;
- for (size_t i = 0; i < resources.size(); ++i) {
- switch (resources[i].type) {
- case MediaResource::Type::kSecureCodec:
- secureCodec = &resources[i];
- break;
- case MediaResource::Type::kNonSecureCodec:
- nonSecureCodec = &resources[i];
- break;
- case MediaResource::Type::kGraphicMemory:
- graphicMemory = &resources[i];
- break;
- case MediaResource::Type::kDrmSession:
- drmSession = &resources[i];
- break;
- default:
- break;
- }
- }
-
- // first pass to handle secure/non-secure codec conflict
- if (secureCodec != NULL) {
- MediaResourceParcel mediaResource{.type = MediaResource::Type::kSecureCodec,
- .subType = secureCodec->subType};
- ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
- if (!mSupportsMultipleSecureCodecs) {
- if (!getAllClients_l(resourceRequestInfo, targetClients)) {
- return Status::ok();
- }
- }
- if (!mSupportsSecureWithNonSecureCodec) {
- mediaResource.type = MediaResource::Type::kNonSecureCodec;
- if (!getAllClients_l(resourceRequestInfo, targetClients)) {
- return Status::ok();
- }
- }
- }
- if (nonSecureCodec != NULL) {
- if (!mSupportsSecureWithNonSecureCodec) {
- MediaResourceParcel mediaResource{.type = MediaResource::Type::kSecureCodec,
- .subType = nonSecureCodec->subType};
- ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
- if (!getAllClients_l(resourceRequestInfo, targetClients)) {
- return Status::ok();
- }
- }
- }
-
- if (drmSession != NULL) {
- ResourceRequestInfo resourceRequestInfo{callingPid, drmSession};
- getClientForResource_l(resourceRequestInfo, targetClients);
- if (targetClients.size() == 0) {
- return Status::ok();
- }
- }
-
- if (targetClients.size() == 0 && graphicMemory != nullptr) {
- // if no secure/non-secure codec conflict, run second pass to handle other resources.
- ResourceRequestInfo resourceRequestInfo{callingPid, graphicMemory};
- getClientForResource_l(resourceRequestInfo, targetClients);
- }
-
- if (targetClients.size() == 0) {
- // if we are here, run the third pass to free one codec with the same type.
- if (secureCodec != nullptr) {
- ResourceRequestInfo resourceRequestInfo{callingPid, secureCodec};
- getClientForResource_l(resourceRequestInfo, targetClients);
- }
- if (nonSecureCodec != nullptr) {
- ResourceRequestInfo resourceRequestInfo{callingPid, nonSecureCodec};
- getClientForResource_l(resourceRequestInfo, targetClients);
- }
- }
-
- if (targetClients.size() == 0) {
- // if we are here, run the fourth pass to free one codec with the different type.
- if (secureCodec != nullptr) {
- MediaResource temp(MediaResource::Type::kNonSecureCodec, secureCodec->subType, 1);
- ResourceRequestInfo resourceRequestInfo{callingPid, &temp};
- getClientForResource_l(resourceRequestInfo, targetClients);
- }
- if (nonSecureCodec != nullptr) {
- MediaResource temp(MediaResource::Type::kSecureCodec, nonSecureCodec->subType, 1);
- ResourceRequestInfo resourceRequestInfo{callingPid, &temp};
- getClientForResource_l(resourceRequestInfo, targetClients);
- }
- }
+ if (!getTargetClients(callingPid, resources, targetClients)) {
+ // Nothing to reclaim from.
+ ALOGI("%s: There aren't any clients to reclaim from", __func__);
+ return Status::ok();
}
*_aidl_return = reclaimUnconditionallyFrom(targetClients);
@@ -686,6 +721,16 @@
return false;
}
+bool ResourceManagerService::overridePid_l(int32_t originalPid, int32_t newPid) {
+ mOverridePidMap.erase(originalPid);
+ if (newPid != -1) {
+ mOverridePidMap.emplace(originalPid, newPid);
+ return true;
+ }
+
+ return false;
+}
+
Status ResourceManagerService::overridePid(int originalPid, int newPid) {
String8 log = String8::format("overridePid(originalPid %d, newPid %d)",
originalPid, newPid);
@@ -705,9 +750,7 @@
{
std::scoped_lock lock{mLock};
- mOverridePidMap.erase(originalPid);
- if (newPid != -1) {
- mOverridePidMap.emplace(originalPid, newPid);
+ if (overridePid_l(originalPid, newPid)) {
mResourceManagerMetrics->addPid(newPid);
}
}
@@ -715,6 +758,29 @@
return Status::ok();
}
+bool ResourceManagerService::overrideProcessInfo_l(
+ const std::shared_ptr<IResourceManagerClient>& client,
+ int pid,
+ int procState,
+ int oomScore) {
+ removeProcessInfoOverride_l(pid);
+
+ if (!mProcessInfo->overrideProcessInfo(pid, procState, oomScore)) {
+ // Override value is rejected by ProcessInfo.
+ return false;
+ }
+
+ ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(pid),
+ .uid = 0,
+ .id = 0,
+ .name = "<unknown client>"};
+ auto deathNotifier = DeathNotifier::Create(
+ client, ref<ResourceManagerService>(), clientInfo, true);
+
+ mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{deathNotifier, client});
+ return true;
+}
+
Status ResourceManagerService::overrideProcessInfo(
const std::shared_ptr<IResourceManagerClient>& client, int pid, int procState,
int oomScore) {
@@ -735,23 +801,12 @@
}
std::scoped_lock lock{mLock};
- removeProcessInfoOverride_l(pid);
-
- if (!mProcessInfo->overrideProcessInfo(pid, procState, oomScore)) {
+ if (!overrideProcessInfo_l(client, pid, procState, oomScore)) {
// Override value is rejected by ProcessInfo.
return Status::fromServiceSpecificError(BAD_VALUE);
}
-
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(pid),
- .uid = 0,
- .id = 0,
- .name = "<unknown client>"};
- auto deathNotifier = DeathNotifier::Create(
- client, ref<ResourceManagerService>(), clientInfo, true);
-
- mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{deathNotifier, client});
-
return Status::ok();
+
}
void ResourceManagerService::removeProcessInfoOverride(int pid) {
@@ -857,11 +912,12 @@
return Status::ok();
}
-bool ResourceManagerService::getPriority_l(int pid, int* priority) {
+bool ResourceManagerService::getPriority_l(int pid, int* priority) const {
int newPid = pid;
- if (mOverridePidMap.find(pid) != mOverridePidMap.end()) {
- newPid = mOverridePidMap[pid];
+ std::map<int, int>::const_iterator found = mOverridePidMap.find(pid);
+ if (found != mOverridePidMap.end()) {
+ newPid = found->second;
ALOGD("getPriority_l: use override pid %d instead original pid %d",
newPid, pid);
}
@@ -1053,4 +1109,8 @@
return mResourceManagerMetrics->getCurrentConcurrentPixelCount(pid);
}
+void ResourceManagerService::notifyClientReleased(const ClientInfoParcel& clientInfo) {
+ mResourceManagerMetrics->notifyClientReleased(clientInfo);
+}
+
} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index e22a6b3..44ed005 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -73,7 +73,8 @@
const sp<SystemCallbackInterface> &systemResource);
virtual ~ResourceManagerService();
- void setObserverService(const std::shared_ptr<ResourceObserverService>& observerService);
+ virtual void setObserverService(
+ const std::shared_ptr<ResourceObserverService>& observerService);
// IResourceManagerService interface
Status config(const std::vector<MediaResourcePolicyParcel>& policies) override;
@@ -103,8 +104,6 @@
Status reclaimResourcesFromClientsPendingRemoval(int32_t pid) override;
- Status removeResource(const ClientInfoParcel& clientInfo, bool checkValid);
-
Status notifyClientCreated(const ClientInfoParcel& clientInfo) override;
Status notifyClientStarted(const ClientConfigParcel& clientConfig) override;
@@ -113,88 +112,140 @@
Status notifyClientConfigChanged(const ClientConfigParcel& clientConfig) override;
+protected:
+ // To get notifications when a resource is added for the first time.
+ void onFirstAdded(const MediaResourceParcel& res, uid_t uid);
+ // To get notifications when a resource has been removed at last.
+ void onLastRemoved(const MediaResourceParcel& res, uid_t uid);
+
+ // Reclaims resources from |clients|. Returns true if reclaim succeeded
+ // for all clients.
+ bool reclaimUnconditionallyFrom(const std::vector<ClientInfo>& targetClients);
+
+ // A helper function that returns true if the callingPid has higher priority than pid.
+ // Returns false otherwise.
+ bool isCallingPriorityHigher_l(int callingPid, int pid);
+
+ // To notify the metrics about client being released.
+ void notifyClientReleased(const ClientInfoParcel& clientInfo);
+
+ virtual Status removeResource(const ClientInfoParcel& clientInfo, bool checkValid);
+
private:
friend class ResourceManagerServiceTest;
friend class ResourceManagerServiceTestBase;
friend class DeathNotifier;
friend class OverrideProcessInfoDeathNotifier;
- // Reclaims resources from |clients|. Returns true if reclaim succeeded
- // for all clients.
- bool reclaimUnconditionallyFrom(
- const std::vector<ClientInfo>& targetClients);
-
- // 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);
-
- // 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);
-
// Gets the client who owns biggest piece of specified resource type from pid.
// Returns false with no change to client if there are no clients holding resources of this
// type.
- bool getBiggestClient_l(int pid, MediaResource::Type type, MediaResource::SubType subType,
+ bool getBiggestClient_l(int pid, MediaResource::Type type,
+ MediaResource::SubType subType,
ClientInfo& clientsInfo,
bool pendingRemovalOnly = false);
- // Same method as above, but with pendingRemovalOnly as true.
+
+ // A helper function that gets the biggest clients of the process pid that
+ // is marked to be (pending) removed and has the needed resources.
bool getBiggestClientPendingRemoval_l(int pid, MediaResource::Type type,
MediaResource::SubType subType,
ClientInfo& clientsInfo);
- // A helper function that returns true if the callingPid has higher priority than pid.
- // Returns false otherwise.
- bool isCallingPriorityHigher_l(int callingPid, int pid);
-
- // A helper function basically calls getLowestPriorityBiggestClient_l and adds
- // the result client to the given Vector.
+ // From the list of clients, pick/select client(s) based on the reclaim policy.
void getClientForResource_l(const ResourceRequestInfo& resourceRequestInfo,
std::vector<ClientInfo>& clientsInfo);
-
- void onFirstAdded(const MediaResourceParcel& res, uid_t uid);
- void onLastRemoved(const MediaResourceParcel& res, uid_t uid);
-
- // Get priority from process's pid
- bool getPriority_l(int pid, int* priority);
-
- void removeProcessInfoOverride(int pid);
-
- void removeProcessInfoOverride_l(int pid);
-
+ // A helper function that pushes Reclaim Atom (for metric collection).
void pushReclaimAtom(const ClientInfoParcel& clientInfo,
const std::vector<ClientInfo>& targetClients,
bool reclaimed);
- // Get the client for given pid and the clientId from the map
- std::shared_ptr<IResourceManagerClient> getClient(int pid, const int64_t& clientId) const;
+ // Remove the override info for the given process
+ void removeProcessInfoOverride_l(int pid);
- // Remove the client for given pid and the clientId from the map
- bool removeClient(int pid, const int64_t& clientId);
+ // Eventually we want to phase out this implementation of IResourceManagerService
+ // (ResourceManagerService) and replace that with the newer implementation
+ // (ResourceManagerServiceNew).
+ // So, marking the following methods as private virtual and for the newer implementation
+ // to override is the easiest way to maintain both implementation.
- // The following utility functions are used only for testing by ResourceManagerServiceTest
+ // Initializes the internal state of the ResourceManagerService
+ virtual void init();
+
+ // 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 std::vector<MediaResourceParcel>& resources,
+ std::vector<ClientInfo>& targetClients);
+
+ // 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.
+ virtual bool getAllClients_l(const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clientsInfo);
+
+ // 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.
+ virtual bool getLowestPriorityBiggestClient_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ ClientInfo& clientInfo);
+
+ // override the pid of given process
+ virtual bool overridePid_l(int32_t originalPid, int32_t newPid);
+
+ // override the process info of given process
+ virtual bool overrideProcessInfo_l(const std::shared_ptr<IResourceManagerClient>& client,
+ int pid, int procState, int oomScore);
+
+ // Get priority from process's pid
+ virtual bool getPriority_l(int pid, int* priority) const;
+
// 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);
+ virtual bool getLowestPriorityPid_l(MediaResource::Type type, MediaResource::SubType subType,
+ int* lowestPriorityPid, int* lowestPriority);
+
+ // Removes the pid from the override map.
+ virtual void removeProcessInfoOverride(int pid);
+
+ // Get the client for given pid and the clientId from the map
+ virtual std::shared_ptr<IResourceManagerClient> getClient(
+ 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);
+
+ // Get all the resource status for dump
+ virtual void getResourceDump(std::string& resourceLog) const;
+
+ // The following utility functions are used only for testing by ResourceManagerServiceTest
+ // START: TEST only functions
// Get the peak concurrent pixel count (associated with the video codecs) for the process.
long getPeakConcurrentPixelCount(int pid) const;
// Get the current concurrent pixel count (associated with the video codecs) for the process.
long getCurrentConcurrentPixelCount(int pid) const;
+ // To create object of type ResourceManagerServiceNew
+ static std::shared_ptr<ResourceManagerService> CreateNew(
+ const sp<ProcessInfoInterface>& processInfo,
+ const sp<SystemCallbackInterface>& systemResource);
+ // Returns a unmodifiable reference to the internal resource state as a map
+ virtual const std::map<int, ResourceInfos>& getResourceMap() const {
+ return mMap;
+ }
+ // END: TEST only functions
+protected:
mutable std::mutex mLock;
sp<ProcessInfoInterface> mProcessInfo;
sp<SystemCallbackInterface> mSystemCB;
sp<ServiceLog> mServiceLog;
- PidResourceInfosMap mMap;
bool mSupportsMultipleSecureCodecs;
bool mSupportsSecureWithNonSecureCodec;
int32_t mCpuBoostCount;
+
+private:
+ PidResourceInfosMap mMap;
struct ProcessInfoOverride {
std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
std::shared_ptr<IResourceManagerClient> client;
diff --git a/services/mediaresourcemanager/ResourceManagerServiceNew.cpp b/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
new file mode 100644
index 0000000..dde389a
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
@@ -0,0 +1,362 @@
+/*
+**
+** 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 "ResourceManagerServiceNew"
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <mediautils/ProcessInfo.h>
+
+#include "DefaultResourceModel.h"
+#include "ProcessPriorityReclaimPolicy.h"
+#include "ResourceManagerServiceNew.h"
+#include "ResourceTracker.h"
+#include "ServiceLog.h"
+
+namespace android {
+
+ResourceManagerServiceNew::ResourceManagerServiceNew(
+ const sp<ProcessInfoInterface>& processInfo,
+ const sp<SystemCallbackInterface>& systemResource) :
+ ResourceManagerService(processInfo, systemResource) {}
+
+ResourceManagerServiceNew::~ResourceManagerServiceNew() {}
+
+void ResourceManagerServiceNew::init() {
+ // Create the Resource Tracker
+ mResourceTracker = std::make_shared<ResourceTracker>(ref<ResourceManagerServiceNew>(),
+ mProcessInfo);
+ setUpResourceModels();
+ setUpReclaimPolicies();
+}
+
+void ResourceManagerServiceNew::setUpResourceModels() {
+ std::scoped_lock lock{mLock};
+ // Create/Configure the default resource model.
+ if (mDefaultResourceModel == nullptr) {
+ mDefaultResourceModel = std::make_unique<DefaultResourceModel>(
+ mResourceTracker,
+ mSupportsMultipleSecureCodecs,
+ mSupportsSecureWithNonSecureCodec);
+ } else {
+ DefaultResourceModel* resourceModel =
+ static_cast<DefaultResourceModel*>(mDefaultResourceModel.get());
+ resourceModel->config(mSupportsMultipleSecureCodecs, mSupportsSecureWithNonSecureCodec);
+ }
+}
+
+void ResourceManagerServiceNew::setUpReclaimPolicies() {
+ mReclaimPolicies.clear();
+ // Process priority (oom score) as the Default reclaim policy.
+ mReclaimPolicies.push_back(std::make_unique<ProcessPriorityReclaimPolicy>(mResourceTracker));
+}
+
+Status ResourceManagerServiceNew::config(const std::vector<MediaResourcePolicyParcel>& policies) {
+ Status status = ResourceManagerService::config(policies);
+ // Change in the config dictates update to the resource model.
+ setUpResourceModels();
+ return status;
+}
+
+void ResourceManagerServiceNew::setObserverService(
+ const std::shared_ptr<ResourceObserverService>& observerService) {
+ ResourceManagerService::setObserverService(observerService);
+ mResourceTracker->setResourceObserverService(observerService);
+}
+
+Status ResourceManagerServiceNew::addResource(
+ const ClientInfoParcel& clientInfo,
+ const std::shared_ptr<IResourceManagerClient>& client,
+ const std::vector<MediaResourceParcel>& resources) {
+ int32_t pid = clientInfo.pid;
+ int32_t uid = clientInfo.uid;
+ int64_t clientId = clientInfo.id;
+ String8 log = String8::format("addResource(pid %d, uid %d clientId %lld, resources %s)",
+ pid, uid, (long long) clientId, getString(resources).c_str());
+ mServiceLog->add(log);
+
+ std::scoped_lock lock{mLock};
+ mResourceTracker->addResource(clientInfo, client, resources);
+ notifyResourceGranted(pid, resources);
+
+ return Status::ok();
+}
+
+Status ResourceManagerServiceNew::removeResource(
+ const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources) {
+ int32_t pid = clientInfo.pid;
+ int32_t uid = clientInfo.uid;
+ int64_t clientId = clientInfo.id;
+ String8 log = String8::format("removeResource(pid %d, uid %d clientId %lld, resources %s)",
+ pid, uid, (long long) clientId, getString(resources).c_str());
+ mServiceLog->add(log);
+
+ std::scoped_lock lock{mLock};
+ mResourceTracker->removeResource(clientInfo, resources);
+ return Status::ok();
+}
+
+Status ResourceManagerServiceNew::removeClient(const ClientInfoParcel& clientInfo) {
+ removeResource(clientInfo, true /*checkValid*/);
+ return Status::ok();
+}
+
+Status ResourceManagerServiceNew::removeResource(const ClientInfoParcel& clientInfo,
+ bool checkValid) {
+ int32_t pid = clientInfo.pid;
+ int32_t uid = clientInfo.uid;
+ int64_t clientId = clientInfo.id;
+ String8 log = String8::format("removeResource(pid %d, uid %d clientId %lld)",
+ pid, uid, (long long) clientId);
+ mServiceLog->add(log);
+
+ std::scoped_lock lock{mLock};
+ if (mResourceTracker->removeResource(clientInfo, checkValid)) {
+ notifyClientReleased(clientInfo);
+ }
+ return Status::ok();
+}
+
+Status ResourceManagerServiceNew::reclaimResource(
+ const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources,
+ bool* _aidl_return) {
+ return ResourceManagerService::reclaimResource(clientInfo, resources, _aidl_return);
+}
+
+bool ResourceManagerServiceNew::overridePid_l(int32_t originalPid, int32_t newPid) {
+ return mResourceTracker->overridePid(originalPid, newPid);
+}
+
+Status ResourceManagerServiceNew::overridePid(int originalPid, int newPid) {
+ return ResourceManagerService::overridePid(originalPid, newPid);
+}
+
+bool ResourceManagerServiceNew::overrideProcessInfo_l(
+ const std::shared_ptr<IResourceManagerClient>& client,
+ int pid,
+ int procState,
+ int oomScore) {
+ return mResourceTracker->overrideProcessInfo(client, pid, procState, oomScore);
+}
+
+Status ResourceManagerServiceNew::overrideProcessInfo(
+ const std::shared_ptr<IResourceManagerClient>& client,
+ int pid,
+ int procState,
+ int oomScore) {
+ return ResourceManagerService::overrideProcessInfo(client, pid, procState, oomScore);
+}
+
+void ResourceManagerServiceNew::removeProcessInfoOverride(int pid) {
+ std::scoped_lock lock{mLock};
+
+ mResourceTracker->removeProcessInfoOverride(pid);
+}
+
+Status ResourceManagerServiceNew::markClientForPendingRemoval(const ClientInfoParcel& clientInfo) {
+ int32_t pid = clientInfo.pid;
+ int64_t clientId = clientInfo.id;
+ String8 log = String8::format(
+ "markClientForPendingRemoval(pid %d, clientId %lld)",
+ pid, (long long) clientId);
+ mServiceLog->add(log);
+
+ std::scoped_lock lock{mLock};
+ mResourceTracker->markClientForPendingRemoval(clientInfo);
+ return Status::ok();
+}
+
+Status ResourceManagerServiceNew::reclaimResourcesFromClientsPendingRemoval(int32_t pid) {
+ String8 log = String8::format("reclaimResourcesFromClientsPendingRemoval(pid %d)", pid);
+ mServiceLog->add(log);
+
+ std::vector<ClientInfo> targetClients;
+ {
+ std::scoped_lock lock{mLock};
+ mResourceTracker->getClientsMarkedPendingRemoval(pid, targetClients);
+ }
+
+ if (!targetClients.empty()) {
+ reclaimUnconditionallyFrom(targetClients);
+ }
+ return Status::ok();
+}
+
+Status ResourceManagerServiceNew::notifyClientCreated(const ClientInfoParcel& clientInfo) {
+ return ResourceManagerService::notifyClientCreated(clientInfo);
+}
+
+Status ResourceManagerServiceNew::notifyClientStarted(const ClientConfigParcel& clientConfig) {
+ return ResourceManagerService::notifyClientStarted(clientConfig);
+}
+
+Status ResourceManagerServiceNew::notifyClientStopped(const ClientConfigParcel& clientConfig) {
+ return ResourceManagerService::notifyClientStopped(clientConfig);
+}
+
+Status ResourceManagerServiceNew::notifyClientConfigChanged(
+ const ClientConfigParcel& clientConfig) {
+ return ResourceManagerService::notifyClientConfigChanged(clientConfig);
+}
+
+void ResourceManagerServiceNew::getResourceDump(std::string& resourceLog) const {
+ std::scoped_lock lock{mLock};
+ mResourceTracker->dump(resourceLog);
+}
+
+binder_status_t ResourceManagerServiceNew::dump(int fd, const char** args, uint32_t numArgs) {
+ return ResourceManagerService::dump(fd, args, numArgs);
+}
+
+bool ResourceManagerServiceNew::getTargetClients(
+ int callingPid,
+ const std::vector<MediaResourceParcel>& resources,
+ std::vector<ClientInfo>& targetClients) {
+ std::scoped_lock lock{mLock};
+ if (!mProcessInfo->isPidTrusted(callingPid)) {
+ pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
+ ALOGW("%s called with untrusted pid %d, using actual calling pid %d", __FUNCTION__,
+ callingPid, actualCallingPid);
+ callingPid = actualCallingPid;
+ }
+
+ // Use the Resource Model to get a list of all the clients that hold the
+ // needed/requested resources.
+ ReclaimRequestInfo reclaimRequestInfo{callingPid, resources};
+ std::vector<ClientInfo> clients;
+ if (!mDefaultResourceModel->getAllClients(reclaimRequestInfo, clients)) {
+ if (clients.empty()) {
+ ALOGI("%s: There aren't any clients with given resources. Nothing to reclaim",
+ __func__);
+ return false;
+ }
+ // Since there was a conflict, we need to reclaim all elements.
+ targetClients = std::move(clients);
+ } else {
+ // Select a client among those have the needed resources.
+ getClientForResource_l(reclaimRequestInfo, clients, targetClients);
+ }
+ return !targetClients.empty();
+}
+
+void ResourceManagerServiceNew::getClientForResource_l(
+ const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients) {
+ int callingPid = reclaimRequestInfo.mCallingPid;
+
+ // Before looking into other processes, check if we have clients marked for
+ // pending removal in the same process.
+ ClientInfo targetClient;
+ for (const MediaResourceParcel& resource : reclaimRequestInfo.mResources) {
+ if (mResourceTracker->getBiggestClientPendingRemoval(callingPid, resource.type,
+ resource.subType, targetClient)) {
+ targetClients.emplace_back(targetClient);
+ return;
+ }
+ }
+
+ // Run through all the reclaim policies until a client to reclaim from is identified.
+ for (std::unique_ptr<IReclaimPolicy>& reclaimPolicy : mReclaimPolicies) {
+ if (reclaimPolicy->getClients(reclaimRequestInfo, clients, targetClients)) {
+ return;
+ }
+ }
+}
+
+bool ResourceManagerServiceNew::getLowestPriorityBiggestClient_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ ClientInfo& clientInfo) {
+ //NOTE: This function is used only by the test: ResourceManagerServiceTest
+ if (resourceRequestInfo.mResource == nullptr) {
+ return false;
+ }
+
+ // Use the DefaultResourceModel to get all the clients with the resources requested.
+ std::vector<MediaResourceParcel> resources{*resourceRequestInfo.mResource};
+ ReclaimRequestInfo reclaimRequestInfo{resourceRequestInfo.mCallingPid, resources};
+ std::vector<ClientInfo> clients;
+ mDefaultResourceModel->getAllClients(reclaimRequestInfo, clients);
+
+ // Use the ProcessPriorityReclaimPolicy to select a client to reclaim from.
+ std::unique_ptr<IReclaimPolicy> reclaimPolicy
+ = std::make_unique<ProcessPriorityReclaimPolicy>(mResourceTracker);
+ std::vector<ClientInfo> targetClients;
+ if (reclaimPolicy->getClients(reclaimRequestInfo, clients, targetClients)) {
+ if (!targetClients.empty()) {
+ clientInfo = targetClients[0];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ResourceManagerServiceNew::getPriority_l(int pid, int* priority) const {
+ return mResourceTracker->getPriority(pid, priority);
+}
+
+bool ResourceManagerServiceNew::getLowestPriorityPid_l(
+ MediaResource::Type type, MediaResource::SubType subType,
+ int* lowestPriorityPid, int* lowestPriority) {
+ //NOTE: This function is used only by the test: ResourceManagerServiceTest
+ return mResourceTracker->getLowestPriorityPid(type, subType,
+ *lowestPriorityPid,
+ *lowestPriority);
+}
+
+bool ResourceManagerServiceNew::getAllClients_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clientsInfo) {
+ //NOTE: This function is used only by the test: ResourceManagerServiceTest
+ MediaResource::Type type = resourceRequestInfo.mResource->type;
+ // Get the list of all clients that has requested resources.
+ std::vector<ClientInfo> clients;
+ mResourceTracker->getAllClients(resourceRequestInfo, clients);
+
+ // Check is there any high priority process holding up the resources already.
+ for (const ClientInfo& info : clients) {
+ if (!isCallingPriorityHigher_l(resourceRequestInfo.mCallingPid, info.mPid)) {
+ // some higher/equal priority process owns the resource,
+ // this request can't be fulfilled.
+ ALOGE("%s: can't reclaim resource %s from pid %d", __func__, asString(type), info.mPid);
+ return false;
+ }
+ clientsInfo.emplace_back(info);
+ }
+ if (clientsInfo.size() == 0) {
+ ALOGV("%s: didn't find any resource %s", __func__, asString(type));
+ }
+ return true;
+}
+
+std::shared_ptr<IResourceManagerClient> ResourceManagerServiceNew::getClient(
+ int pid, const int64_t& clientId) const {
+ return mResourceTracker->getClient(pid, clientId);
+}
+
+bool ResourceManagerServiceNew::removeClient(int pid, const int64_t& clientId) {
+ return mResourceTracker->removeClient(pid, clientId);
+}
+
+const std::map<int, ResourceInfos>& ResourceManagerServiceNew::getResourceMap() const {
+ return mResourceTracker->getResourceMap();
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerServiceNew.h b/services/mediaresourcemanager/ResourceManagerServiceNew.h
new file mode 100644
index 0000000..20c3d6e
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceManagerServiceNew.h
@@ -0,0 +1,169 @@
+/*
+**
+** 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_RESOURCEMANAGERSERVICENEW_H
+#define ANDROID_MEDIA_RESOURCEMANAGERSERVICENEW_H
+
+#include "ResourceManagerService.h"
+
+namespace android {
+
+class IReclaimPolicy;
+class IResourceModel;
+class ResourceTracker;
+
+//
+// A newer implementation of IResourceManagerService, which
+// eventually will replace the older implementation in ResourceManagerService.
+//
+// To make the transition easier, this implementation overrides the
+// private virtual methods from ResourceManagerService.
+//
+// This implementation is devised to abstract and integrate:
+// - resources into an independent abstraction
+// - resource model as a separate interface (and implementation)
+// - reclaim policy as a separate interface (and implementation)
+//
+class ResourceManagerServiceNew : public ResourceManagerService {
+public:
+
+ explicit ResourceManagerServiceNew(const sp<ProcessInfoInterface>& processInfo,
+ const sp<SystemCallbackInterface>& systemResource);
+ virtual ~ResourceManagerServiceNew();
+
+ // IResourceManagerService interface
+ Status config(const std::vector<MediaResourcePolicyParcel>& policies) override;
+
+ Status addResource(const ClientInfoParcel& clientInfo,
+ const std::shared_ptr<IResourceManagerClient>& client,
+ const std::vector<MediaResourceParcel>& resources) override;
+
+ Status removeResource(const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources) override;
+
+ Status removeClient(const ClientInfoParcel& clientInfo) override;
+
+ Status reclaimResource(const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources,
+ bool* _aidl_return) override;
+
+ Status overridePid(int32_t originalPid, int32_t newPid) override;
+
+ Status overrideProcessInfo(const std::shared_ptr<IResourceManagerClient>& client,
+ int32_t pid, int32_t procState, int32_t oomScore) override;
+
+ Status markClientForPendingRemoval(const ClientInfoParcel& clientInfo) override;
+
+ Status reclaimResourcesFromClientsPendingRemoval(int32_t pid) override;
+
+ Status notifyClientCreated(const ClientInfoParcel& clientInfo) override;
+
+ Status notifyClientStarted(const ClientConfigParcel& clientConfig) override;
+
+ Status notifyClientStopped(const ClientConfigParcel& clientConfig) override;
+
+ Status notifyClientConfigChanged(const ClientConfigParcel& clientConfig) override;
+
+ binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+ friend class ResourceTracker;
+
+private:
+
+ // Set up the Resource models.
+ void setUpResourceModels();
+
+ // Set up the Reclaim Policies.
+ void setUpReclaimPolicies();
+
+ // From the list of clients, pick/select client(s) based on the reclaim policy.
+ void getClientForResource_l(
+ const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients);
+
+ // Initializes the internal state of the ResourceManagerService
+ void init() override;
+
+ void setObserverService(
+ const std::shared_ptr<ResourceObserverService>& observerService) 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 getTargetClients(
+ int32_t callingPid,
+ 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;
+
+ // override the process info of given process
+ bool overrideProcessInfo_l(const std::shared_ptr<IResourceManagerClient>& client,
+ int pid, int procState, int oomScore) override;
+
+ // 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(
+ 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;
+
+ // Get all the resource status for dump
+ void getResourceDump(std::string& resourceLog) const override;
+
+ // Returns a unmodifiable reference to the internal resource state as a map
+ const std::map<int, ResourceInfos>& getResourceMap() const override;
+
+ Status removeResource(const ClientInfoParcel& clientInfo, bool checkValid) override;
+
+private:
+ std::shared_ptr<ResourceTracker> mResourceTracker;
+ std::unique_ptr<IResourceModel> mDefaultResourceModel;
+ std::vector<std::unique_ptr<IReclaimPolicy>> mReclaimPolicies;
+};
+
+// ----------------------------------------------------------------------------
+} // namespace android
+
+#endif // ANDROID_MEDIA_RESOURCEMANAGERSERVICENEW_H
diff --git a/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp b/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
index de682f8..cd21327 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
@@ -19,6 +19,9 @@
#define LOG_TAG "ResourceManagerServiceUtils"
#include <utils/Log.h>
+#include <binder/IServiceManager.h>
+
+#include "IMediaResourceMonitor.h"
#include "ResourceManagerService.h"
#include "ResourceManagerServiceUtils.h"
@@ -202,4 +205,30 @@
return deathNotifier;
}
+void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel>& resources) {
+ static const char* const kServiceName = "media_resource_monitor";
+ sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName));
+ if (binder != NULL) {
+ sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
+ for (size_t i = 0; i < resources.size(); ++i) {
+ switch (resources[i].subType) {
+ case MediaResource::SubType::kHwAudioCodec:
+ case MediaResource::SubType::kSwAudioCodec:
+ service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
+ break;
+ case MediaResource::SubType::kHwVideoCodec:
+ case MediaResource::SubType::kSwVideoCodec:
+ service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
+ break;
+ case MediaResource::SubType::kHwImageCodec:
+ case MediaResource::SubType::kSwImageCodec:
+ service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_IMAGE_CODEC);
+ break;
+ case MediaResource::SubType::kUnspecifiedSubType:
+ break;
+ }
+ }
+ }
+}
+
} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerServiceUtils.h b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
index ac1e410..55ea149 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceUtils.h
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
@@ -18,6 +18,8 @@
#ifndef ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_
#define ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_
+#include <map>
+#include <memory>
#include <vector>
#include <aidl/android/media/BnResourceManagerService.h>
@@ -123,6 +125,16 @@
};
/*
+ * Resource Reclaim request info that encapsulates
+ * - the calling/requesting process pid.
+ * - the list of resources requesting (to be reclaimed from others)
+ */
+struct ReclaimRequestInfo {
+ int mCallingPid = -1;
+ const std::vector<::aidl::android::media::MediaResourceParcel>& mResources;
+};
+
+/*
* Resource request info that encapsulates
* - the calling/requesting process pid.
* - the resource requesting (to be reclaimed from others)
@@ -170,7 +182,7 @@
//Check whether a given resource (of type and subtype) is found in given resource parcel.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
- const MediaResourceParcel& resource);
+ const ::aidl::android::media::MediaResourceParcel& resource);
//Check whether a given resource (of type and subtype) is found in given resource list.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
@@ -193,7 +205,13 @@
ResourceInfos& infos);
// Merge resources from r2 into r1.
-void mergeResources(MediaResourceParcel& r1, const MediaResourceParcel& r2);
+void mergeResources(::aidl::android::media::MediaResourceParcel& r1,
+ const ::aidl::android::media::MediaResourceParcel& r2);
+
+// To notify the media_resource_monitor about the resource being granted.
+void notifyResourceGranted(
+ int pid,
+ const std::vector<::aidl::android::media::MediaResourceParcel>& resources);
} // namespace android
diff --git a/services/mediaresourcemanager/ResourceTracker.cpp b/services/mediaresourcemanager/ResourceTracker.cpp
new file mode 100644
index 0000000..8dc13cc
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceTracker.cpp
@@ -0,0 +1,720 @@
+/*
+**
+** 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 "ResourceTracker"
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <mediautils/ProcessInfo.h>
+#include "ResourceTracker.h"
+#include "ResourceManagerServiceNew.h"
+#include "ResourceObserverService.h"
+
+namespace android {
+
+inline bool isHwCodec(MediaResource::SubType subType) {
+ return subType == MediaResource::SubType::kHwImageCodec ||
+ subType == MediaResource::SubType::kHwVideoCodec;
+}
+
+// Check whether a given resource (of type and subtype) is found in given resource list
+// that also has the given Primary SubType.
+static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+ const ResourceList& resources, MediaResource::SubType primarySubType) {
+ 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)) {
+ foundResource = true;
+ } else if (it->second.subType == primarySubType) {
+ matchedPrimary = true;
+ } else if (isHwCodec(it->second.subType) == isHwCodec(primarySubType)) {
+ matchedPrimary = true;
+ }
+ if (matchedPrimary && foundResource) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// See if the given client is already in the list of clients.
+inline bool contains(const std::vector<ClientInfo>& clients, const int64_t& clientId) {
+ std::vector<ClientInfo>::const_iterator found =
+ std::find_if(clients.begin(), clients.end(),
+ [clientId](const ClientInfo& client) -> bool {
+ return client.mClientId == clientId;
+ });
+
+ return found != clients.end();
+}
+
+
+ResourceTracker::ResourceTracker(const std::shared_ptr<ResourceManagerServiceNew>& service,
+ const sp<ProcessInfoInterface>& processInfo) :
+ mService(service),
+ mProcessInfo(processInfo) {
+}
+
+ResourceTracker::~ResourceTracker() {
+}
+
+void ResourceTracker::setResourceObserverService(
+ const std::shared_ptr<ResourceObserverService>& observerService) {
+ mObserverService = observerService;
+}
+
+ResourceInfos& ResourceTracker::getResourceInfosForEdit(int pid) {
+ std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
+ // new pid
+ ResourceInfos infosForPid;
+ auto [it, inserted] = mMap.emplace(pid, infosForPid);
+ found = it;
+ }
+
+ return found->second;
+}
+
+bool ResourceTracker::addResource(const ClientInfoParcel& clientInfo,
+ const std::shared_ptr<IResourceManagerClient>& client,
+ const std::vector<MediaResourceParcel>& resources) {
+ int32_t pid = clientInfo.pid;
+ int32_t uid = clientInfo.uid;
+
+ if (!mProcessInfo->isPidUidTrusted(pid, uid)) {
+ pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ ALOGW("%s called with untrusted pid %d or uid %d, using calling pid %d, uid %d",
+ __func__, pid, uid, callingPid, callingUid);
+ pid = callingPid;
+ uid = callingUid;
+ }
+ ResourceInfos& infos = getResourceInfosForEdit(pid);
+ ResourceInfo& info = getResourceInfoForEdit(clientInfo, client, infos);
+ 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;
+ }
+ 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);
+ }
+ }
+ if (info.deathNotifier == nullptr && client != nullptr) {
+ info.deathNotifier = DeathNotifier::Create(client, mService, clientInfo);
+ }
+ if (mObserverService != nullptr && !resourceAdded.empty()) {
+ mObserverService->onResourceAdded(uid, pid, resourceAdded);
+ }
+
+ return !resourceAdded.empty();
+}
+
+bool ResourceTracker::removeResource(const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources) {
+ int32_t pid = clientInfo.pid;
+ int64_t clientId = clientInfo.id;
+
+ if (!mProcessInfo->isPidTrusted(pid)) {
+ pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ ALOGW("%s called with untrusted pid %d, using calling pid %d", __func__,
+ pid, callingPid);
+ pid = callingPid;
+ }
+ 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);
+ return false;
+ }
+
+ ResourceInfos& infos = found->second;
+ ResourceInfos::iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
+ ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
+ return false;
+ }
+
+ 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];
+ MediaResourceParcel actualRemoved = res;
+ if (resource.value > res.value) {
+ resource.value -= res.value;
+ } else {
+ onLastRemoved(res, info.uid);
+ actualRemoved.value = resource.value;
+ info.resources.erase(resType);
+ }
+
+ // 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);
+ }
+ }
+ }
+ if (mObserverService != nullptr && !resourceRemoved.empty()) {
+ mObserverService->onResourceRemoved(info.uid, pid, resourceRemoved);
+ }
+ return true;
+}
+
+bool ResourceTracker::removeResource(const ClientInfoParcel& clientInfo, bool validateCallingPid) {
+ int32_t pid = clientInfo.pid;
+ int64_t clientId = clientInfo.id;
+
+ if (validateCallingPid && !mProcessInfo->isPidTrusted(pid)) {
+ pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ ALOGW("%s called with untrusted pid %d, using calling pid %d", __func__,
+ pid, callingPid);
+ pid = callingPid;
+ }
+ 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);
+ return false;
+ }
+
+ ResourceInfos& infos = found->second;
+ ResourceInfos::iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
+ ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
+ return false;
+ }
+
+ const ResourceInfo& info = foundClient->second;
+ for (auto& [resType, resParcel] : info.resources) {
+ onLastRemoved(resParcel, info.uid);
+ }
+
+ if (mObserverService != nullptr && !info.resources.empty()) {
+ mObserverService->onResourceRemoved(info.uid, pid, info.resources);
+ }
+
+ infos.erase(foundClient);
+ return true;
+}
+
+std::shared_ptr<IResourceManagerClient> ResourceTracker::getClient(
+ int pid, const int64_t& clientId) const {
+ std::map<int, ResourceInfos>::const_iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
+ ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
+ return nullptr;
+ }
+
+ const ResourceInfos& infos = found->second;
+ ResourceInfos::const_iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
+ ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
+ return nullptr;
+ }
+
+ return foundClient->second.client;
+}
+
+bool ResourceTracker::removeClient(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);
+ return false;
+ }
+
+ ResourceInfos& infos = found->second;
+ ResourceInfos::iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
+ ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
+ return false;
+ }
+
+ infos.erase(foundClient);
+ return true;
+}
+
+bool ResourceTracker::markClientForPendingRemoval(const ClientInfoParcel& clientInfo) {
+ int32_t pid = clientInfo.pid;
+ int64_t clientId = clientInfo.id;
+
+ if (!mProcessInfo->isPidTrusted(pid)) {
+ pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ ALOGW("%s called with untrusted pid %d, using calling pid %d", __func__,
+ pid, callingPid);
+ pid = callingPid;
+ }
+ 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);
+ return false;
+ }
+
+ ResourceInfos& infos = found->second;
+ ResourceInfos::iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
+ ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
+ return false;
+ }
+
+ ResourceInfo& info = foundClient->second;
+ info.pendingRemoval = true;
+ return true;
+}
+
+bool ResourceTracker::getClientsMarkedPendingRemoval(int32_t pid,
+ std::vector<ClientInfo>& targetClients) {
+ if (!mProcessInfo->isPidTrusted(pid)) {
+ pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ ALOGW("%s called with untrusted pid %d, using calling pid %d", __func__, pid, callingPid);
+ pid = callingPid;
+ }
+
+ // Go through all the MediaResource types (and corresponding subtypes for
+ // each, if applicable) and see if the process (with given pid) holds any
+ // such resources that are marked as pending removal.
+ // Since the use-case of this function is to get all such resources (pending
+ // removal) and reclaim them all - the order in which we look for the
+ // resource type doesn't matter.
+ for (MediaResource::Type type : {MediaResource::Type::kSecureCodec,
+ MediaResource::Type::kNonSecureCodec,
+ MediaResource::Type::kGraphicMemory,
+ MediaResource::Type::kDrmSession}) {
+ switch (type) {
+ // Codec resources are segregated by audio, video and image domains.
+ case MediaResource::Type::kSecureCodec:
+ case MediaResource::Type::kNonSecureCodec:
+ for (MediaResource::SubType subType : {MediaResource::SubType::kHwAudioCodec,
+ MediaResource::SubType::kSwAudioCodec,
+ MediaResource::SubType::kHwVideoCodec,
+ MediaResource::SubType::kSwVideoCodec,
+ MediaResource::SubType::kHwImageCodec,
+ MediaResource::SubType::kSwImageCodec}) {
+ ClientInfo clientInfo;
+ if (getBiggestClientPendingRemoval(pid, type, subType, clientInfo)) {
+ if (!contains(targetClients, clientInfo.mClientId)) {
+ targetClients.emplace_back(clientInfo);
+ }
+ continue;
+ }
+ }
+ break;
+ // Non-codec resources are shared by audio, video and image codecs (no subtype).
+ default:
+ ClientInfo clientInfo;
+ MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
+ if (getBiggestClientPendingRemoval(pid, type, subType, clientInfo)) {
+ if (!contains(targetClients, clientInfo.mClientId)) {
+ targetClients.emplace_back(clientInfo);
+ }
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool ResourceTracker::overridePid(int originalPid, int newPid) {
+ mOverridePidMap.erase(originalPid);
+ if (newPid != -1) {
+ mOverridePidMap.emplace(originalPid, newPid);
+ return true;
+ }
+ return false;
+}
+
+bool ResourceTracker::overrideProcessInfo(const std::shared_ptr<IResourceManagerClient>& client,
+ int pid, int procState, int oomScore) {
+ removeProcessInfoOverride(pid);
+
+ if (!mProcessInfo->overrideProcessInfo(pid, procState, oomScore)) {
+ // Override value is rejected by ProcessInfo.
+ return false;
+ }
+
+ ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(pid),
+ .uid = 0,
+ .id = 0,
+ .name = "<unknown client>"};
+ std::shared_ptr<DeathNotifier> deathNotifier =
+ DeathNotifier::Create(client, mService, clientInfo, true);
+
+ mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{deathNotifier, client});
+
+ return true;
+}
+
+void ResourceTracker::removeProcessInfoOverride(int pid) {
+ auto it = mProcessInfoOverrideMap.find(pid);
+ if (it == mProcessInfoOverrideMap.end()) {
+ return;
+ }
+
+ mProcessInfo->removeProcessInfoOverride(pid);
+ mProcessInfoOverrideMap.erase(pid);
+}
+
+bool ResourceTracker::getAllClients(const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clients,
+ MediaResource::SubType primarySubType) {
+ MediaResource::Type type = resourceRequestInfo.mResource->type;
+ MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
+ bool foundClient = false;
+
+ for (auto& [pid, /* ResourceInfos */ infos] : mMap) {
+ for (auto& [id, /* ResourceInfo */ info] : infos) {
+ if (hasResourceType(type, subType, info.resources, primarySubType)) {
+ if (!contains(clients, info.clientId)) {
+ clients.emplace_back(info.pid, info.uid, info.clientId);
+ foundClient = true;
+ }
+ }
+ }
+ }
+
+ return foundClient;
+}
+
+bool ResourceTracker::getLowestPriorityPid(MediaResource::Type type, MediaResource::SubType subType,
+ int& lowestPriorityPid, int& lowestPriority) {
+ int pid = -1;
+ int priority = -1;
+ for (auto& [tempPid, /* ResourceInfos */ infos] : mMap) {
+ if (infos.size() == 0) {
+ // no client on this process.
+ continue;
+ }
+ if (!hasResourceType(type, subType, infos)) {
+ // doesn't have the requested resource type
+ continue;
+ }
+ int tempPriority = -1;
+ if (!getPriority(tempPid, &tempPriority)) {
+ ALOGV("%s: can't get priority of pid %d, skipped", __func__, tempPid);
+ // TODO: remove this pid from mMap?
+ continue;
+ }
+ if (pid == -1 || tempPriority > priority) {
+ // initial the value
+ pid = tempPid;
+ priority = tempPriority;
+ }
+ }
+
+ bool success = (pid != -1);
+
+ if (success) {
+ lowestPriorityPid = pid;
+ lowestPriority = priority;
+ }
+ return success;
+}
+
+bool ResourceTracker::getLowestPriorityPid(MediaResource::Type type, MediaResource::SubType subType,
+ MediaResource::SubType primarySubType,
+ const std::vector<ClientInfo>& clients,
+ int& lowestPriorityPid, int& lowestPriority) {
+ int pid = -1;
+ int priority = -1;
+ for (const ClientInfo& client : clients) {
+ const ResourceInfo* info = getResourceInfo(client.mPid, client.mClientId);
+ if (info == nullptr) {
+ continue;
+ }
+ if (!hasResourceType(type, subType, info->resources, primarySubType)) {
+ // doesn't have the requested resource type
+ continue;
+ }
+ int tempPriority = -1;
+ if (!getPriority(client.mPid, &tempPriority)) {
+ ALOGV("%s: can't get priority of pid %d, skipped", __func__, client.mPid);
+ // TODO: remove this pid from mMap?
+ continue;
+ }
+ if (pid == -1 || tempPriority > priority) {
+ // initial the value
+ pid = client.mPid;
+ priority = tempPriority;
+ }
+ }
+
+ bool success = (pid != -1);
+
+ if (success) {
+ lowestPriorityPid = pid;
+ lowestPriority = priority;
+ }
+ return success;
+}
+
+bool ResourceTracker::getBiggestClientPendingRemoval(int pid, MediaResource::Type type,
+ MediaResource::SubType subType,
+ ClientInfo& clientInfo) {
+ std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
+ return false;
+ }
+
+ uid_t uid = -1;
+ int64_t clientId = -1;
+ uint64_t largestValue = 0;
+ const ResourceInfos& infos = found->second;
+ for (const auto& [id, /* ResourceInfo */ info] : infos) {
+ const ResourceList& resources = info.resources;
+ // Skip if the client is not marked pending removal.
+ if (!info.pendingRemoval) {
+ continue;
+ }
+ for (auto it = resources.begin(); it != resources.end(); it++) {
+ const MediaResourceParcel& resource = it->second;
+ if (hasResourceType(type, subType, resource)) {
+ if (resource.value > largestValue) {
+ largestValue = resource.value;
+ clientId = info.clientId;
+ uid = info.uid;
+ }
+ }
+ }
+ }
+
+ if (clientId == -1) {
+ return false;
+ }
+
+ clientInfo.mPid = pid;
+ clientInfo.mUid = uid;
+ clientInfo.mClientId = clientId;
+ return true;
+}
+
+bool ResourceTracker::getBiggestClient(int targetPid,
+ MediaResource::Type type, MediaResource::SubType subType,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& clientInfo,
+ MediaResource::SubType primarySubType) {
+ 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;
+ }
+
+ 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) {
+ matchedPrimary = true;
+ } else if (isHwCodec(it->second.subType) == isHwCodec(primarySubType)) {
+ matchedPrimary = true;
+ }
+ }
+ // Primary type doesn't match, skip the client
+ if (!matchedPrimary) {
+ continue;
+ }
+ for (auto it = resources.begin(); it != resources.end(); it++) {
+ const MediaResourceParcel& resource = it->second;
+ 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;
+}
+
+void ResourceTracker::dump(std::string& resourceLogs) {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ resourceLogs.append(" Processes:\n");
+ for (const auto& [pid, /* ResourceInfos */ infos] : mMap) {
+ snprintf(buffer, SIZE, " Pid: %d\n", pid);
+ resourceLogs.append(buffer);
+ int priority = 0;
+ if (getPriority(pid, &priority)) {
+ snprintf(buffer, SIZE, " Priority: %d\n", priority);
+ } else {
+ snprintf(buffer, SIZE, " Priority: <unknown>\n");
+ }
+ resourceLogs.append(buffer);
+
+ for (const auto& [infoKey, /* ResourceInfo */ info] : infos) {
+ resourceLogs.append(" Client:\n");
+ snprintf(buffer, SIZE, " Id: %lld\n", (long long)info.clientId);
+ resourceLogs.append(buffer);
+
+ std::string clientName = info.name;
+ snprintf(buffer, SIZE, " Name: %s\n", clientName.c_str());
+ resourceLogs.append(buffer);
+
+ 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(" Process Pid override:\n");
+ for (const auto& [oldPid, newPid] : mOverridePidMap) {
+ snprintf(buffer, SIZE, " Original Pid: %d, Override Pid: %d\n", oldPid, newPid);
+ resourceLogs.append(buffer);
+ }
+}
+
+void ResourceTracker::onFirstAdded(const MediaResourceParcel& resource, uid_t uid) {
+ std::shared_ptr<ResourceManagerServiceNew> service = mService.lock();
+ if (service == nullptr) {
+ ALOGW("%s: ResourceManagerService is invalid!", __func__);
+ return;
+ }
+
+ service->onFirstAdded(resource, uid);
+}
+
+void ResourceTracker::onLastRemoved(const MediaResourceParcel& resource, uid_t uid) {
+ std::shared_ptr<ResourceManagerServiceNew> service = mService.lock();
+ if (service == nullptr) {
+ ALOGW("%s: ResourceManagerService is invalid!", __func__);
+ return;
+ }
+
+ service->onLastRemoved(resource, uid);
+}
+
+bool ResourceTracker::getPriority(int pid, int* priority) {
+ int newPid = pid;
+
+ if (mOverridePidMap.find(pid) != mOverridePidMap.end()) {
+ newPid = mOverridePidMap[pid];
+ ALOGD("%s: use override pid %d instead original pid %d", __func__, newPid, pid);
+ }
+
+ return mProcessInfo->getPriority(newPid, priority);
+}
+
+bool ResourceTracker::getNonConflictingClients(const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clients) {
+ MediaResource::Type type = resourceRequestInfo.mResource->type;
+ MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
+ for (auto& [pid, /* ResourceInfos */ infos] : mMap) {
+ for (const auto& [id, /* ResourceInfo */ info] : infos) {
+ if (hasResourceType(type, subType, info.resources)) {
+ if (!isCallingPriorityHigher(resourceRequestInfo.mCallingPid, pid)) {
+ // some higher/equal priority process owns the resource,
+ // this is a conflict.
+ ALOGE("%s: The resource (%s) request from pid %d is conflicting",
+ __func__, asString(type), pid);
+ clients.clear();
+ return false;
+ } else {
+ if (!contains(clients, info.clientId)) {
+ clients.emplace_back(info.pid, info.uid, info.clientId);
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+const ResourceInfo* ResourceTracker::getResourceInfo(int pid, const int64_t& clientId) const {
+ std::map<int, ResourceInfos>::const_iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
+ ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
+ return nullptr;
+ }
+
+ const ResourceInfos& infos = found->second;
+ ResourceInfos::const_iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
+ ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
+ return nullptr;
+ }
+
+ return &foundClient->second;
+}
+
+bool ResourceTracker::isCallingPriorityHigher(int callingPid, int pid) {
+ int callingPidPriority;
+ if (!getPriority(callingPid, &callingPidPriority)) {
+ return false;
+ }
+
+ int priority;
+ if (!getPriority(pid, &priority)) {
+ return false;
+ }
+
+ return (callingPidPriority < priority);
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ResourceTracker.h b/services/mediaresourcemanager/ResourceTracker.h
new file mode 100644
index 0000000..e5f33ec
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceTracker.h
@@ -0,0 +1,242 @@
+/*
+**
+** 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_RESOURCETRACKER_H_
+#define ANDROID_MEDIA_RESOURCETRACKER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+#include <media/MediaResource.h>
+#include <aidl/android/media/ClientInfoParcel.h>
+#include <aidl/android/media/IResourceManagerClient.h>
+#include <aidl/android/media/MediaResourceParcel.h>
+
+#include "ResourceManagerServiceUtils.h"
+
+namespace android {
+
+class DeathNotifier;
+class ResourceManagerServiceNew;
+class ResourceObserverService;
+struct ProcessInfoInterface;
+struct ResourceRequestInfo;
+struct ClientInfo;
+
+/*
+ * ResourceTracker abstracts the resources managed by the ResourceManager.
+ * It keeps track of the resource used by the clients (clientid) and by the process (pid)
+ */
+class ResourceTracker {
+public:
+ ResourceTracker(const std::shared_ptr<ResourceManagerServiceNew>& service,
+ const sp<ProcessInfoInterface>& processInfo);
+ ~ResourceTracker();
+
+ /**
+ * Add or update resources for |clientInfo|.
+ *
+ * If |clientInfo| is not tracked yet, it records its associated |client| and adds
+ * |resources| to the tracked resources. If |clientInfo| is already tracked,
+ * it updates the tracked resources by adding |resources| to them (|client| in
+ * this case is unused and unchecked).
+ *
+ * @param clientInfo Info of the calling client.
+ * @param client Interface for the client.
+ * @param resources An array of resources to be added.
+ *
+ * @return true upon successfully adding/updating the resources, false
+ * otherwise.
+ */
+ bool addResource(const aidl::android::media::ClientInfoParcel& clientInfo,
+ const std::shared_ptr<::aidl::android::media::IResourceManagerClient>& client,
+ const std::vector<::aidl::android::media::MediaResourceParcel>& resources);
+
+ // Remove a set of resources from the given client.
+ // returns true on success, false otherwise.
+ bool removeResource(const aidl::android::media::ClientInfoParcel& clientInfo,
+ const std::vector<::aidl::android::media::MediaResourceParcel>& resources);
+
+ /**
+ * Remove all resources tracked for |clientInfo|.
+ *
+ * If |validateCallingPid| is true, the (pid of the) calling process is validated that it
+ * is from a trusted process.
+ * Returns true on success (|clientInfo| was tracked and optionally the caller
+ * was a validated trusted process), false otherwise (|clientInfo| was not tracked,
+ * or the caller was not a trusted process)
+ */
+ bool removeResource(const aidl::android::media::ClientInfoParcel& clientInfo,
+ bool validateCallingPid);
+
+ // Mark the client for pending removal.
+ // Such clients are primary candidate for reclaim.
+ // returns true on success, false otherwise.
+ bool markClientForPendingRemoval(const aidl::android::media::ClientInfoParcel& clientInfo);
+
+ // Get a list of clients that belong to process with given pid and are maked to be
+ // pending removal by markClientForPendingRemoval.
+ // returns true on success, false otherwise.
+ bool getClientsMarkedPendingRemoval(int32_t pid, std::vector<ClientInfo>& targetClients);
+
+ // Override the pid of originalPid with newPid
+ // To remove the pid entry from the override list, set newPid as -1
+ // returns true on successful override, false otherwise.
+ bool overridePid(int originalPid, int newPid);
+
+ // Override the process info {state, oom score} of the process with pid.
+ // returns true on success, false otherwise.
+ bool overrideProcessInfo(
+ const std::shared_ptr<aidl::android::media::IResourceManagerClient>& client,
+ int pid, int procState, int oomScore);
+
+ // Remove the overridden process info.
+ void removeProcessInfoOverride(int pid);
+
+ // Find all clients that have given resources.
+ // If applicable, match the primary type too.
+ // The |clients| (list) isn't cleared by this function to allow calling this
+ // function multiple times for different resources.
+ // returns true upon finding at lease one client with the given resource request info,
+ // false otherwise (no clients)
+ bool getAllClients(
+ const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clients,
+ MediaResource::SubType primarySubType = MediaResource::SubType::kUnspecifiedSubType);
+
+ // Look for the lowest priority process with the given resources.
+ // Upon success lowestPriorityPid and lowestPriority are
+ // set accordingly and it returns true.
+ // If there isn't a lower priority process with the given resources, it will return false
+ // with out updating lowestPriorityPid and lowerPriority.
+ bool getLowestPriorityPid(MediaResource::Type type, MediaResource::SubType subType,
+ int& lowestPriorityPid, int& lowestPriority);
+
+ // Look for the lowest priority process with the given resources
+ // among the given client list.
+ // If applicable, match the primary type too.
+ // returns true on success, false otherwise.
+ bool getLowestPriorityPid(
+ MediaResource::Type type, MediaResource::SubType subType,
+ MediaResource::SubType primarySubType,
+ const std::vector<ClientInfo>& clients,
+ int& lowestPriorityPid, int& lowestPriority);
+
+ // Find the biggest client of the given process with given resources,
+ // that is marked as pending to be removed.
+ // returns true on success, false otherwise.
+ bool getBiggestClientPendingRemoval(
+ int pid, MediaResource::Type type,
+ MediaResource::SubType subType,
+ ClientInfo& clientInfo);
+
+ // Find the biggest client from the process pid, selecting them from the list of clients.
+ // If applicable, match the primary type too.
+ // Returns true when a client is found and clientInfo is updated accordingly.
+ // Upon failure to find a client, it will return false without updating
+ // clientInfo.
+ // Upon failure to find a client, it will return false.
+ bool getBiggestClient(
+ int targetPid,
+ MediaResource::Type type,
+ MediaResource::SubType subType,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& clientInfo,
+ MediaResource::SubType primarySubType = MediaResource::SubType::kUnspecifiedSubType);
+
+ // 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(
+ int pid, const int64_t& clientId) const;
+
+ // Removes the client from the given process(pid) with the given clientId.
+ // returns true on success, false otherwise.
+ bool removeClient(int pid, const int64_t& clientId);
+
+ // Set the resource observer service, to which to notify when the resources
+ // are added and removed.
+ void setResourceObserverService(
+ const std::shared_ptr<ResourceObserverService>& observerService);
+
+ // Dump all the resource allocations for all the processes into a given string
+ void dump(std::string& resourceLogs);
+
+ // get the priority of the process.
+ // If we can't get the priority of the process (with given pid), it will
+ // return false.
+ bool getPriority(int pid, int* priority);
+
+ // Check if the given resource request has conflicting clients.
+ // The resource conflict is defined by the ResourceModel (such as
+ // co-existence of secure codec with another secure or non-secure codec).
+ // But here, the ResourceTracker only looks for resources from lower
+ // priority processes.
+ // If is/are only higher or same priority process/es with the given resource,
+ // it will return false.
+ // Otherwise, adds all the clients to the list of clients and return true.
+ bool getNonConflictingClients(const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clients);
+
+ // Returns unmodifiable reference to the resource map.
+ const std::map<int, ResourceInfos>& getResourceMap() const {
+ return mMap;
+ }
+
+private:
+ // Get ResourceInfos associated with the given process.
+ // If none exists, this method will create and associate an empty object and return it.
+ ResourceInfos& getResourceInfosForEdit(int pid);
+
+ // A helper function that returns true if the callingPid has higher priority than pid.
+ // Returns false otherwise.
+ bool isCallingPriorityHigher(int callingPid, int pid);
+
+ // Locate the resource info corresponding to the process pid and
+ // the client clientId.
+ const ResourceInfo* getResourceInfo(int pid, const int64_t& clientId) const;
+
+ // Notify when a resource is added for the first time.
+ void onFirstAdded(const MediaResourceParcel& resource, uid_t uid);
+ // Notify when a resource is removed for the last time.
+ void onLastRemoved(const MediaResourceParcel& resource, uid_t uid);
+
+private:
+ // Structure that defines process info that needs to be overridden.
+ struct ProcessInfoOverride {
+ std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
+ std::shared_ptr<::aidl::android::media::IResourceManagerClient> client;
+ };
+
+ // Map of Resource information indexed through the process id.
+ std::map<int, ResourceInfos> mMap;
+ // A weak reference (to avoid cyclic dependency) to the ResourceManagerService.
+ // ResourceTracker uses this to communicate back with the ResourceManagerService.
+ std::weak_ptr<ResourceManagerServiceNew> mService;
+ // To notify the ResourceObserverService abour resources are added or removed.
+ std::shared_ptr<ResourceObserverService> mObserverService;
+ // Map of pid and their overrided id.
+ std::map<int, int> mOverridePidMap;
+ // Map of pid and their overridden process info.
+ std::map<pid_t, ProcessInfoOverride> mProcessInfoOverrideMap;
+ // Interface that gets process specific information.
+ sp<ProcessInfoInterface> mProcessInfo;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_RESOURCETRACKER_H_
diff --git a/services/mediaresourcemanager/fuzzer/Android.bp b/services/mediaresourcemanager/fuzzer/Android.bp
index a46d87a..b0db12b 100644
--- a/services/mediaresourcemanager/fuzzer/Android.bp
+++ b/services/mediaresourcemanager/fuzzer/Android.bp
@@ -46,6 +46,7 @@
"libstatspull",
"libstatssocket",
"libactivitymanager_aidl",
+ "aconfig_mediacodec_flags_c_lib",
],
fuzz_config: {
cc: [
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index f903c62..6a64823 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -12,7 +12,10 @@
name: "ResourceManagerService_test",
srcs: ["ResourceManagerService_test.cpp"],
test_suites: ["device-tests"],
- static_libs: ["libresourcemanagerservice"],
+ static_libs: [
+ "libresourcemanagerservice",
+ "aconfig_mediacodec_flags_c_lib",
+ ],
shared_libs: [
"libbinder",
"libbinder_ndk",
@@ -24,6 +27,7 @@
"libstatspull",
"libstatssocket",
"libactivitymanager_aidl",
+ "server_configurable_flags",
],
include_dirs: [
"frameworks/av/include",
@@ -62,6 +66,7 @@
static_libs: [
"libresourcemanagerservice",
"resourceobserver_aidl_interface-V1-ndk",
+ "aconfig_mediacodec_flags_c_lib",
],
shared_libs: [
"libbinder",
@@ -74,6 +79,7 @@
"libstatspull",
"libstatssocket",
"libactivitymanager_aidl",
+ "server_configurable_flags",
],
include_dirs: [
"frameworks/av/include",
diff --git a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
index 52d82b8..58dbb8d 100644
--- a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
+++ b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
@@ -198,8 +198,8 @@
return static_cast<TestClient*>(testClient.get());
}
- ResourceManagerServiceTestBase() {
- ALOGI("ResourceManagerServiceTestBase created");
+ ResourceManagerServiceTestBase(bool newRM = false) : mNewRM(newRM) {
+ ALOGI("ResourceManagerServiceTestBase created with %s RM", newRM ? "new" : "old");
}
void SetUp() override {
@@ -207,7 +207,11 @@
// silently ignored.
ABinderProcess_startThreadPool();
mSystemCB = new TestSystemCallback();
- mService = ResourceManagerService::Create(new TestProcessInfo, mSystemCB);
+ if (mNewRM) {
+ mService = ResourceManagerService::CreateNew(new TestProcessInfo, mSystemCB);
+ } 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);
@@ -244,6 +248,8 @@
EXPECT_EQ(client, info.client);
EXPECT_TRUE(isEqualResources(resources, info.resources));
}
+
+ bool mNewRM = false;
};
} // namespace android
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 8f05b13..9d4beef 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -77,8 +77,20 @@
}
public:
- ResourceManagerServiceTest() : ResourceManagerServiceTestBase() {}
+ ResourceManagerServiceTest(bool newRM = false) : ResourceManagerServiceTestBase(newRM) {}
+ void updateConfig(bool bSupportsMultipleSecureCodecs, bool bSupportsSecureWithNonSecureCodec) {
+ std::vector<MediaResourcePolicyParcel> policies;
+ policies.push_back(
+ MediaResourcePolicy(
+ IResourceManagerService::kPolicySupportsMultipleSecureCodecs,
+ bSupportsMultipleSecureCodecs ? "true" : "false"));
+ policies.push_back(
+ MediaResourcePolicy(
+ IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec,
+ bSupportsSecureWithNonSecureCodec ? "true" : "false"));
+ mService->config(policies);
+ }
// test set up
// ---------------------------------------------------------------------------------
@@ -129,7 +141,7 @@
resources3.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
mService->addResource(client3Info, mTestClient3, resources3);
- const PidResourceInfosMap &map = mService->mMap;
+ const PidResourceInfosMap &map = mService->getResourceMap();
EXPECT_EQ(2u, map.size());
const auto& mapIndex1 = map.find(kTestPid1);
EXPECT_TRUE(mapIndex1 != map.end());
@@ -159,7 +171,7 @@
// Expected result:
// 1) the client should have been added;
// 2) both resource entries should have been rejected, resource list should be empty.
- const PidResourceInfosMap &map = mService->mMap;
+ const PidResourceInfosMap &map = mService->getResourceMap();
EXPECT_EQ(1u, map.size());
const auto& mapIndex1 = map.find(kTestPid1);
EXPECT_TRUE(mapIndex1 != map.end());
@@ -213,29 +225,11 @@
EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
- std::vector<MediaResourcePolicyParcel> policies1;
- policies1.push_back(
- MediaResourcePolicy(
- IResourceManagerService::kPolicySupportsMultipleSecureCodecs,
- "true"));
- policies1.push_back(
- MediaResourcePolicy(
- IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec,
- "false"));
- mService->config(policies1);
+ updateConfig(true, false);
EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
EXPECT_FALSE(mService->mSupportsSecureWithNonSecureCodec);
- std::vector<MediaResourcePolicyParcel> policies2;
- policies2.push_back(
- MediaResourcePolicy(
- IResourceManagerService::kPolicySupportsMultipleSecureCodecs,
- "false"));
- policies2.push_back(
- MediaResourcePolicy(
- IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec,
- "true"));
- mService->config(policies2);
+ updateConfig(false, true);
EXPECT_FALSE(mService->mSupportsMultipleSecureCodecs);
EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
}
@@ -254,7 +248,7 @@
resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
mService->addResource(client1Info, mTestClient1, resources11);
- const PidResourceInfosMap &map = mService->mMap;
+ const PidResourceInfosMap &map = mService->getResourceMap();
EXPECT_EQ(1u, map.size());
const auto& mapIndex1 = map.find(kTestPid1);
EXPECT_TRUE(mapIndex1 != map.end());
@@ -299,7 +293,7 @@
resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
mService->addResource(client1Info, mTestClient1, resources11);
- const PidResourceInfosMap &map = mService->mMap;
+ const PidResourceInfosMap &map = mService->getResourceMap();
EXPECT_EQ(1u, map.size());
const auto& mapIndex1 = map.find(kTestPid1);
EXPECT_TRUE(mapIndex1 != map.end());
@@ -339,8 +333,7 @@
// ### secure codec can't coexist and secure codec can coexist with non-secure codec ###
{
addResource();
- mService->mSupportsMultipleSecureCodecs = false;
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(false, true);
// priority too low to reclaim resource
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(kLowPriorityPid),
@@ -374,7 +367,7 @@
.name = "none"};
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
@@ -402,7 +395,7 @@
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
@@ -428,7 +421,7 @@
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
mService->markClientForPendingRemoval(client2Info);
@@ -466,7 +459,7 @@
.name = "none"};
mService->removeClient(client2Info);
- const PidResourceInfosMap &map = mService->mMap;
+ const PidResourceInfosMap &map = mService->getResourceMap();
EXPECT_EQ(2u, map.size());
const ResourceInfos &infos1 = map.at(kTestPid1);
const ResourceInfos &infos2 = map.at(kTestPid2);
@@ -520,8 +513,7 @@
// ### secure codec can't coexist and secure codec can coexist with non-secure codec ###
{
addResource();
- mService->mSupportsMultipleSecureCodecs = false;
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(false, true);
// priority too low
CHECK_STATUS_FALSE(mService->reclaimResource(lowPriorityClient, resources, &result));
@@ -546,8 +538,7 @@
// ### secure codecs can't coexist and secure codec can't coexist with non-secure codec ###
{
addResource();
- mService->mSupportsMultipleSecureCodecs = false;
- mService->mSupportsSecureWithNonSecureCodec = false;
+ updateConfig(false, false);
// priority too low
CHECK_STATUS_FALSE(mService->reclaimResource(lowPriorityClient, resources, &result));
@@ -567,8 +558,7 @@
// ### secure codecs can coexist but secure codec can't coexist with non-secure codec ###
{
addResource();
- mService->mSupportsMultipleSecureCodecs = true;
- mService->mSupportsSecureWithNonSecureCodec = false;
+ updateConfig(true, false);
// priority too low
CHECK_STATUS_FALSE(mService->reclaimResource(lowPriorityClient, resources, &result));
@@ -599,8 +589,7 @@
// ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
{
addResource();
- mService->mSupportsMultipleSecureCodecs = true;
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
// priority too low
CHECK_STATUS_FALSE(mService->reclaimResource(lowPriorityClient, resources, &result));
@@ -630,8 +619,7 @@
// ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
{
addResource();
- mService->mSupportsMultipleSecureCodecs = true;
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
@@ -677,7 +665,7 @@
// ### secure codec can't coexist with non-secure codec ###
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = false;
+ updateConfig(true, false);
// priority too low
CHECK_STATUS_FALSE(mService->reclaimResource(lowPriorityClient, resources, &result));
@@ -703,7 +691,7 @@
// ### secure codec can coexist with non-secure codec ###
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
// priority too low
CHECK_STATUS_FALSE(mService->reclaimResource(lowPriorityClient, resources, &result));
@@ -733,7 +721,7 @@
// ### secure codec can coexist with non-secure codec ###
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
@@ -1512,6 +1500,11 @@
}
};
+class ResourceManagerServiceNewTest : public ResourceManagerServiceTest {
+public:
+ ResourceManagerServiceNewTest(bool newRM = true) : ResourceManagerServiceTest(newRM) {}
+};
+
TEST_F(ResourceManagerServiceTest, config) {
testConfig();
}
@@ -1598,4 +1591,91 @@
testConcurrentCodecs();
}
+/////// test cases for ResourceManagerServiceNew ////
+TEST_F(ResourceManagerServiceNewTest, config) {
+ testConfig();
+}
+
+TEST_F(ResourceManagerServiceNewTest, addResource) {
+ addResource();
+}
+
+TEST_F(ResourceManagerServiceNewTest, combineResource) {
+ testCombineResource();
+}
+
+TEST_F(ResourceManagerServiceNewTest, combineResourceNegative) {
+ testCombineResourceWithNegativeValues();
+}
+
+TEST_F(ResourceManagerServiceNewTest, removeResource) {
+ testRemoveResource();
+}
+
+TEST_F(ResourceManagerServiceNewTest, removeClient) {
+ testRemoveClient();
+}
+
+TEST_F(ResourceManagerServiceNewTest, reclaimResource) {
+ testReclaimResourceSecure();
+ testReclaimResourceNonSecure();
+}
+
+TEST_F(ResourceManagerServiceNewTest, getAllClients_l) {
+ testGetAllClients();
+}
+
+TEST_F(ResourceManagerServiceNewTest, getLowestPriorityBiggestClient_l) {
+ testGetLowestPriorityBiggestClient();
+}
+
+TEST_F(ResourceManagerServiceNewTest, getLowestPriorityPid_l) {
+ testGetLowestPriorityPid();
+}
+
+TEST_F(ResourceManagerServiceNewTest, isCallingPriorityHigher_l) {
+ testIsCallingPriorityHigher();
+}
+
+TEST_F(ResourceManagerServiceNewTest, batteryStats) {
+ testBatteryStats();
+}
+
+TEST_F(ResourceManagerServiceNewTest, cpusetBoost) {
+ testCpusetBoost();
+}
+
+TEST_F(ResourceManagerServiceNewTest, overridePid) {
+ testOverridePid();
+}
+
+TEST_F(ResourceManagerServiceNewTest, markClientForPendingRemoval) {
+ testMarkClientForPendingRemoval();
+}
+
+TEST_F(ResourceManagerServiceNewTest, reclaimResources_withVideoCodec_reclaimsOnlyVideoCodec) {
+ testReclaimResources_withVideoCodec_reclaimsOnlyVideoCodec();
+}
+
+TEST_F(ResourceManagerServiceNewTest, reclaimResources_withAudioCodec_reclaimsOnlyAudioCodec) {
+ testReclaimResources_withAudioCodec_reclaimsOnlyAudioCodec();
+}
+
+TEST_F(ResourceManagerServiceNewTest, reclaimResources_withImageCodec_reclaimsOnlyImageCodec) {
+ testReclaimResources_withImageCodec_reclaimsOnlyImageCodec();
+}
+
+TEST_F(ResourceManagerServiceNewTest, reclaimResources_whenPartialResourceMatch_reclaims) {
+ testReclaimResources_whenPartialResourceMatch_reclaims();
+}
+
+TEST_F(ResourceManagerServiceNewTest,
+ reclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources) {
+ testReclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources();
+}
+
+TEST_F(ResourceManagerServiceNewTest, concurrentCodecs) {
+ testConcurrentCodecs();
+}
+
} // namespace android