Merge "camera: delay initialization of lazy camera providers" into main
diff --git a/camera/tests/fuzzer/camera_Parameters_fuzzer.cpp b/camera/tests/fuzzer/camera_Parameters_fuzzer.cpp
index e59f76c..8371905 100644
--- a/camera/tests/fuzzer/camera_Parameters_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_Parameters_fuzzer.cpp
@@ -22,6 +22,8 @@
#include <utils/String16.h>
#include <camera/StringUtils.h>
+#include <functional>
+
using namespace std;
using namespace android;
diff --git a/camera/tests/fuzzer/camera_c2CaptureRequest_fuzzer.cpp b/camera/tests/fuzzer/camera_c2CaptureRequest_fuzzer.cpp
index 494ec1b..5ad9530 100644
--- a/camera/tests/fuzzer/camera_c2CaptureRequest_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_c2CaptureRequest_fuzzer.cpp
@@ -44,7 +44,7 @@
}
for (size_t idx = 0; idx < physicalCameraSettingsSize; ++idx) {
- string id = fdp.ConsumeRandomLengthString();
+ string id = fdp.ConsumeRandomLengthString(kMaxBytes);
if (fdp.ConsumeBool()) {
parcelCamCaptureReq.writeString16(toString16(id));
}
@@ -120,7 +120,11 @@
}
}
- invokeReadWriteParcelsp<CaptureRequest>(captureRequest);
+ if (fdp.ConsumeBool()) {
+ invokeReadWriteParcelsp<CaptureRequest>(captureRequest);
+ } else {
+ invokeNewReadWriteParcelsp<CaptureRequest>(captureRequest, fdp);
+ }
invokeReadWriteNullParcelsp<CaptureRequest>(captureRequest);
parcelCamCaptureReq.setDataPosition(0);
captureRequest->readFromParcel(&parcelCamCaptureReq);
diff --git a/camera/tests/fuzzer/camera_c2SubmitInfo_fuzzer.cpp b/camera/tests/fuzzer/camera_c2SubmitInfo_fuzzer.cpp
index dc40b0f..c588f11 100644
--- a/camera/tests/fuzzer/camera_c2SubmitInfo_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_c2SubmitInfo_fuzzer.cpp
@@ -27,6 +27,10 @@
SubmitInfo submitInfo;
submitInfo.mRequestId = fdp.ConsumeIntegral<int32_t>();
submitInfo.mLastFrameNumber = fdp.ConsumeIntegral<int64_t>();
- invokeReadWriteParcel<SubmitInfo>(&submitInfo);
+ if (fdp.ConsumeBool()) {
+ invokeReadWriteParcel<SubmitInfo>(&submitInfo);
+ } else {
+ invokeNewReadWriteParcel<SubmitInfo>(&submitInfo, fdp);
+ }
return 0;
}
diff --git a/camera/tests/fuzzer/camera_vendorTagDescriptor_fuzzer.cpp b/camera/tests/fuzzer/camera_vendorTagDescriptor_fuzzer.cpp
index e14d9ce..3131f1d 100644
--- a/camera/tests/fuzzer/camera_vendorTagDescriptor_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_vendorTagDescriptor_fuzzer.cpp
@@ -29,6 +29,8 @@
constexpr int32_t kRangeMin = 0;
constexpr int32_t kRangeMax = 1000;
constexpr int32_t kVendorTagDescriptorId = -1;
+constexpr int8_t kMinLoopIterations = 1;
+constexpr int8_t kMaxLoopIterations = 50;
extern "C" {
@@ -95,39 +97,63 @@
initVendorTagDescriptor();
sp<VendorTagDescriptor> vdesc = new VendorTagDescriptor();
- vdesc->copyFrom(*mVendorTagDescriptor);
- VendorTagDescriptor::setAsGlobalVendorTagDescriptor(mVendorTagDescriptor);
- VendorTagDescriptor::getGlobalVendorTagDescriptor();
- int32_t tagCount = mVendorTagDescriptor->getTagCount();
- if (tagCount > 0) {
- uint32_t tagArray[tagCount];
- mVendorTagDescriptor->getTagArray(tagArray);
- uint32_t tag;
- for (int32_t i = 0; i < tagCount; ++i) {
- tag = tagArray[i];
- get_local_camera_metadata_section_name_vendor_id(tag, kVendorTagDescriptorId);
- get_local_camera_metadata_tag_name_vendor_id(tag, kVendorTagDescriptorId);
- get_local_camera_metadata_tag_type_vendor_id(tag, kVendorTagDescriptorId);
- mVendorTagDescriptor->getSectionIndex(tag);
- }
- mVendorTagDescriptor->getAllSectionNames();
+ int8_t count = mFDP->ConsumeIntegralInRange<int8_t>(kMinLoopIterations, kMaxLoopIterations);
+ while (--count > 0) {
+ auto callVendorTagDescriptor = mFDP->PickValueInArray<const std::function<void()>>({
+ [&]() {
+ int32_t tagCount = mVendorTagDescriptor->getTagCount();
+ if (tagCount > 0) {
+ uint32_t tagArray[tagCount];
+ mVendorTagDescriptor->getTagArray(tagArray);
+ uint32_t tag;
+ for (int32_t i = 0; i < tagCount; ++i) {
+ tag = tagArray[i];
+ get_local_camera_metadata_section_name_vendor_id(
+ tag, kVendorTagDescriptorId);
+ get_local_camera_metadata_tag_name_vendor_id(tag,
+ kVendorTagDescriptorId);
+ get_local_camera_metadata_tag_type_vendor_id(tag,
+ kVendorTagDescriptorId);
+ mVendorTagDescriptor->getSectionIndex(tag);
+ }
+ }
+ },
+ [&]() {
+ if (mVendorTagDescriptor->getTagCount() > 0) {
+ mVendorTagDescriptor->getAllSectionNames();
+ }
+ },
+ [&]() { vdesc->copyFrom(*mVendorTagDescriptor); },
+ [&]() {
+ VendorTagDescriptor::setAsGlobalVendorTagDescriptor(mVendorTagDescriptor);
+ },
+ [&]() { VendorTagDescriptor::getGlobalVendorTagDescriptor(); },
+ [&]() {
+ String8 name((mFDP->ConsumeRandomLengthString()).c_str());
+ String8 section((mFDP->ConsumeRandomLengthString()).c_str());
+ uint32_t lookupTag;
+ mVendorTagDescriptor->lookupTag(name, section, &lookupTag);
+ },
+ [&]() {
+ int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
+ int32_t verbosity = mFDP->ConsumeIntegralInRange<int32_t>(kRangeMin, kRangeMax);
+ int32_t indentation =
+ mFDP->ConsumeIntegralInRange<int32_t>(kRangeMin, kRangeMax);
+ mVendorTagDescriptor->dump(fd, verbosity, indentation);
+ close(fd);
+ },
+ });
+ callVendorTagDescriptor();
}
- String8 name((mFDP->ConsumeRandomLengthString()).c_str());
- String8 section((mFDP->ConsumeRandomLengthString()).c_str());
- uint32_t lookupTag;
- mVendorTagDescriptor->lookupTag(name, section, &lookupTag);
-
- int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
- int32_t verbosity = mFDP->ConsumeIntegralInRange<int32_t>(kRangeMin, kRangeMax);
- int32_t indentation = mFDP->ConsumeIntegralInRange<int32_t>(kRangeMin, kRangeMax);
- mVendorTagDescriptor->dump(fd, verbosity, indentation);
-
- invokeReadWriteParcelsp<VendorTagDescriptor>(mVendorTagDescriptor);
+ // Do not keep invokeReadWrite() APIs in while loop to avoid possible OOM.
+ if (mFDP->ConsumeBool()) {
+ invokeReadWriteParcelsp<VendorTagDescriptor>(mVendorTagDescriptor);
+ } else {
+ invokeNewReadWriteParcelsp<VendorTagDescriptor>(mVendorTagDescriptor, *mFDP);
+ }
VendorTagDescriptor::clearGlobalVendorTagDescriptor();
- vdesc.clear();
- close(fd);
}
void VendorTagDescriptorFuzzer::invokeVendorTagDescriptorCache() {
@@ -135,36 +161,52 @@
uint64_t id = mFDP->ConsumeIntegral<uint64_t>();
initVendorTagDescriptor();
- mVendorTagDescriptorCache->addVendorDescriptor(id, mVendorTagDescriptor);
- VendorTagDescriptorCache::setAsGlobalVendorTagCache(mVendorTagDescriptorCache);
- VendorTagDescriptorCache::getGlobalVendorTagCache();
- sp<VendorTagDescriptor> tagDesc;
- mVendorTagDescriptorCache->getVendorTagDescriptor(id, &tagDesc);
-
- int32_t tagCount = mVendorTagDescriptorCache->getTagCount(id);
- if (tagCount > 0) {
- uint32_t tagArray[tagCount];
- mVendorTagDescriptorCache->getTagArray(tagArray, id);
- uint32_t tag;
- for (int32_t i = 0; i < tagCount; ++i) {
- tag = tagArray[i];
- get_local_camera_metadata_section_name_vendor_id(tag, id);
- get_local_camera_metadata_tag_name_vendor_id(tag, id);
- get_local_camera_metadata_tag_type_vendor_id(tag, id);
- }
+ int8_t count = mFDP->ConsumeIntegralInRange<int8_t>(kMinLoopIterations, kMaxLoopIterations);
+ while (--count > 0) {
+ auto callVendorTagDescriptorCache = mFDP->PickValueInArray<const std::function<void()>>({
+ [&]() { mVendorTagDescriptorCache->addVendorDescriptor(id, mVendorTagDescriptor); },
+ [&]() {
+ VendorTagDescriptorCache::setAsGlobalVendorTagCache(mVendorTagDescriptorCache);
+ },
+ [&]() { VendorTagDescriptorCache::getGlobalVendorTagCache(); },
+ [&]() {
+ sp<VendorTagDescriptor> tagDesc;
+ mVendorTagDescriptorCache->getVendorTagDescriptor(id, &tagDesc);
+ },
+ [&]() {
+ int32_t tagCount = mVendorTagDescriptorCache->getTagCount(id);
+ if (tagCount > 0) {
+ uint32_t tagArray[tagCount];
+ mVendorTagDescriptorCache->getTagArray(tagArray, id);
+ uint32_t tag;
+ for (int32_t i = 0; i < tagCount; ++i) {
+ tag = tagArray[i];
+ get_local_camera_metadata_section_name_vendor_id(tag, id);
+ get_local_camera_metadata_tag_name_vendor_id(tag, id);
+ get_local_camera_metadata_tag_type_vendor_id(tag, id);
+ }
+ }
+ },
+ [&]() {
+ int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
+ int32_t verbosity = mFDP->ConsumeIntegralInRange<int>(kRangeMin, kRangeMax);
+ int32_t indentation = mFDP->ConsumeIntegralInRange<int>(kRangeMin, kRangeMax);
+ mVendorTagDescriptorCache->dump(fd, verbosity, indentation);
+ close(fd);
+ },
+ [&]() { VendorTagDescriptorCache::isVendorCachePresent(id); },
+ [&]() { mVendorTagDescriptorCache->getVendorIdsAndTagDescriptors(); },
+ });
+ callVendorTagDescriptorCache();
}
- int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
- int32_t verbosity = mFDP->ConsumeIntegralInRange<int>(kRangeMin, kRangeMax);
- int32_t indentation = mFDP->ConsumeIntegralInRange<int>(kRangeMin, kRangeMax);
- mVendorTagDescriptorCache->dump(fd, verbosity, indentation);
-
- invokeReadWriteParcelsp<VendorTagDescriptorCache>(mVendorTagDescriptorCache);
- VendorTagDescriptorCache::isVendorCachePresent(id);
- mVendorTagDescriptorCache->getVendorIdsAndTagDescriptors();
+ // Do not keep invokeReadWrite() APIs in while loop to avoid possible OOM.
+ if (mFDP->ConsumeBool()) {
+ invokeReadWriteParcelsp<VendorTagDescriptorCache>(mVendorTagDescriptorCache);
+ } else {
+ invokeNewReadWriteParcelsp<VendorTagDescriptorCache>(mVendorTagDescriptorCache, *mFDP);
+ }
mVendorTagDescriptorCache->clearGlobalVendorTagCache();
- tagDesc.clear();
- close(fd);
}
void VendorTagDescriptorFuzzer::invokeVendorTagErrorConditions() {
@@ -177,26 +219,39 @@
VendorTagDescriptor::createDescriptorFromOps(/*vOps*/ NULL, vDesc);
} else {
VendorTagDescriptor::createDescriptorFromOps(&vOps, vDesc);
- int32_t tagCount = vDesc->getTagCount();
- uint32_t badTag = mFDP->ConsumeIntegral<uint32_t>();
- uint32_t badTagArray[tagCount + 1];
- vDesc->getTagArray(badTagArray);
- vDesc->getSectionName(badTag);
- vDesc->getTagName(badTag);
- vDesc->getTagType(badTag);
- VendorTagDescriptor::clearGlobalVendorTagDescriptor();
- VendorTagDescriptor::getGlobalVendorTagDescriptor();
- VendorTagDescriptor::setAsGlobalVendorTagDescriptor(vDesc);
+
+ int8_t count = mFDP->ConsumeIntegralInRange<int8_t>(kMinLoopIterations, kMaxLoopIterations);
+ while (--count > 0) {
+ int32_t tagCount = vDesc->getTagCount();
+ uint32_t badTag = mFDP->ConsumeIntegral<uint32_t>();
+ uint32_t badTagArray[tagCount + 1];
+ auto callVendorTagErrorConditions =
+ mFDP->PickValueInArray<const std::function<void()>>({
+ [&]() { vDesc->getTagArray(badTagArray); },
+ [&]() { vDesc->getSectionName(badTag); },
+ [&]() { vDesc->getTagName(badTag); },
+ [&]() { vDesc->getTagType(badTag); },
+ [&]() { VendorTagDescriptor::clearGlobalVendorTagDescriptor(); },
+ [&]() { VendorTagDescriptor::getGlobalVendorTagDescriptor(); },
+ [&]() { VendorTagDescriptor::setAsGlobalVendorTagDescriptor(vDesc); },
+ });
+ callVendorTagErrorConditions();
+ }
invokeReadWriteNullParcelsp<VendorTagDescriptor>(vDesc);
- vDesc.clear();
}
+ vDesc.clear();
}
void VendorTagDescriptorFuzzer::process(const uint8_t* data, size_t size) {
mFDP = new FuzzedDataProvider(data, size);
- invokeVendorTagDescriptor();
- invokeVendorTagDescriptorCache();
- invokeVendorTagErrorConditions();
+ while (mFDP->remaining_bytes()) {
+ auto invokeVendorTagDescriptorFuzzer = mFDP->PickValueInArray<const std::function<void()>>({
+ [&]() { invokeVendorTagDescriptor(); },
+ [&]() { invokeVendorTagDescriptorCache(); },
+ [&]() { invokeVendorTagErrorConditions(); },
+ });
+ invokeVendorTagDescriptorFuzzer();
+ }
delete mFDP;
}
diff --git a/media/aconfig/Android.bp b/media/aconfig/Android.bp
index 96bf4f5..ee25c03 100644
--- a/media/aconfig/Android.bp
+++ b/media/aconfig/Android.bp
@@ -1,22 +1,49 @@
+// deprecated
aconfig_declarations {
name: "aconfig_mediacodec_flags",
package: "com.android.media.codec.flags",
srcs: ["mediacodec_flags.aconfig"],
}
+// deprecated
java_aconfig_library {
name: "aconfig_mediacodec_flags_java_lib",
aconfig_declarations: "aconfig_mediacodec_flags",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+// deprecated
cc_aconfig_library {
name: "aconfig_mediacodec_flags_c_lib",
min_sdk_version: "30",
vendor_available: true,
+ double_loadable: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
+ aconfig_declarations: "aconfig_mediacodec_flags",
+}
+
+aconfig_declarations {
+ name: "aconfig_codec_fwk_flags",
+ package: "android.media.codec",
+ srcs: ["codec_fwk.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.media.codec-aconfig-java",
+ aconfig_declarations: "aconfig_codec_fwk_flags",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+cc_aconfig_library {
+ name: "android.media.codec-aconfig-cc",
+ min_sdk_version: "30",
+ vendor_available: true,
apex_available: [
"//apex_available:platform",
"com.android.media.swcodec",
],
- aconfig_declarations: "aconfig_mediacodec_flags",
+ aconfig_declarations: "aconfig_codec_fwk_flags",
}
diff --git a/media/aconfig/codec_fwk.aconfig b/media/aconfig/codec_fwk.aconfig
new file mode 100644
index 0000000..06aceeb
--- /dev/null
+++ b/media/aconfig/codec_fwk.aconfig
@@ -0,0 +1,33 @@
+# Codec framework feature flags.
+#
+# !!! Please add flags in alphabetical order. !!!
+
+package: "android.media.codec"
+
+flag {
+ name: "aidl_hal_input_surface"
+ namespace: "codec_fwk"
+ description: "Feature flags for enabling AIDL HAL InputSurface handling"
+ bug: "201479783"
+}
+
+flag {
+ name: "dynamic_color_aspects"
+ namespace: "codec_fwk"
+ description: "Feature flag for dynamic color aspect support"
+ bug: "297914560"
+}
+
+flag {
+ name: "hlg_editing"
+ namespace: "codec_fwk"
+ description: "Feature flag for HLG editing support"
+ bug: "316397061"
+}
+
+flag {
+ name: "null_output_surface"
+ namespace: "codec_fwk"
+ description: "Feature flag for null output Surface support"
+ bug: "297920102"
+}
diff --git a/media/aconfig/mediacodec_flags.aconfig b/media/aconfig/mediacodec_flags.aconfig
index c82ad4d..be0fc5c 100644
--- a/media/aconfig/mediacodec_flags.aconfig
+++ b/media/aconfig/mediacodec_flags.aconfig
@@ -1,5 +1,10 @@
package: "com.android.media.codec.flags"
+# ******************************************************************
+# !!! DO NOT ADD FURTHER FLAGS TO THIS FILE !!!
+# !!! USE codec_fwk.aconfig INSTEAD !!!
+# ******************************************************************
+
flag {
name: "large_audio_frame"
namespace: "codec_fwk"
diff --git a/media/audio/aconfig/Android.bp b/media/audio/aconfig/Android.bp
index 08840e4..af97dac 100644
--- a/media/audio/aconfig/Android.bp
+++ b/media/audio/aconfig/Android.bp
@@ -68,6 +68,12 @@
aconfig_declarations: "com.android.media.audio-aconfig",
}
+// For CTS usage
+java_aconfig_library {
+ name: "com.android.media.audioserver-aconfig-java",
+ aconfig_declarations: "com.android.media.audioserver-aconfig",
+}
+
// Framework available flags to follow
// Care must be taken to avoid namespace conflicts.
// These flags are accessible outside of the platform! Limit usage to @FlaggedApi wherever possible
@@ -76,21 +82,21 @@
name: "android.media.audio-aconfig",
package: "android.media.audio",
srcs: ["audio_framework.aconfig"],
- visibility: ["//visibility:private"],
+ visibility: ["//frameworks/base/api"],
}
aconfig_declarations {
name: "android.media.audiopolicy-aconfig",
package: "android.media.audiopolicy",
srcs: ["audiopolicy_framework.aconfig"],
- visibility: ["//visibility:private"],
+ visibility: ["//frameworks/base/api"],
}
aconfig_declarations {
name: "android.media.midi-aconfig",
package: "android.media.midi",
srcs: ["midi_flags.aconfig"],
- visibility: ["//visibility:private"],
+ visibility: ["//frameworks/base/api"],
}
java_aconfig_library {
diff --git a/media/audio/aconfig/audio_framework.aconfig b/media/audio/aconfig/audio_framework.aconfig
index 34c026a..c5663cd 100644
--- a/media/audio/aconfig/audio_framework.aconfig
+++ b/media/audio/aconfig/audio_framework.aconfig
@@ -53,3 +53,12 @@
bug: "298463873"
}
+flag {
+ name: "sco_managed_by_audio"
+ namespace: "media_audio"
+ description: "\
+Enable new implementation of headset profile device connection and\
+SCO audio activation."
+ bug: "265057196"
+}
+
diff --git a/media/audio/aconfig/audiopolicy_framework.aconfig b/media/audio/aconfig/audiopolicy_framework.aconfig
index e38737b..b41c1c3 100644
--- a/media/audio/aconfig/audiopolicy_framework.aconfig
+++ b/media/audio/aconfig/audiopolicy_framework.aconfig
@@ -18,3 +18,10 @@
description: "Enable Fade Manager Configuration support to determine fade properties"
bug: "307354764"
}
+
+flag {
+ name: "multi_zone_audio"
+ namespace: "media_audio"
+ description: "Enable multi-zone audio support in audio product strategies."
+ bug: "316643994"
+}
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/codec2/Android.mk b/media/codec2/Android.mk
deleted file mode 100644
index 82d739f..0000000
--- a/media/codec2/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-# =============================================================================
-# DOCUMENTATION GENERATION
-# =============================================================================
-C2_ROOT := $(call my-dir)
-
-C2_DOCS_ROOT := $(OUT_DIR)/target/common/docs/codec2
-
-C2_OUT_TEMP := $(PRODUCT_OUT)/gen/ETC/Codec2-docs_intermediates
-
-C2_DOXY := $(or $(shell command -v doxygen),\
- $(shell command -v /Applications/Doxygen.app/Contents/Resources/doxygen))
-
-.PHONY: check-doxygen
-check-doxygen:
-ifndef C2_DOXY
- $(error 'doxygen is not available')
-endif
-
-$(C2_OUT_TEMP)/doxy-api.config: $(C2_ROOT)/docs/doxygen.config
- # only document include directory, no internal sections
- sed 's/\(^INPUT *=.*\)/\1include\//; \
- s/\(^INTERNAL_DOCS *= *\).*/\1NO/; \
- s/\(^ENABLED_SECTIONS *=.*\)INTERNAL\(.*\).*/\1\2/; \
- s:\(^OUTPUT_DIRECTORY *= \)out:\1'$(OUT_DIR)':;' \
- $(C2_ROOT)/docs/doxygen.config > $@
-
-$(C2_OUT_TEMP)/doxy-internal.config: $(C2_ROOT)/docs/doxygen.config
- sed 's:\(^OUTPUT_DIRECTORY *= \)out\(.*\)api:\1'$(OUT_DIR)'\2internal:;' \
- $(C2_ROOT)/docs/doxygen.config > $@
-
-.PHONY: docs-api
-docs-api: $(C2_OUT_TEMP)/doxy-api.config check-doxygen
- echo API docs are building in $(C2_DOCS_ROOT)/api
- rm -rf $(C2_DOCS_ROOT)/api
- mkdir -p $(C2_DOCS_ROOT)/api
- $(C2_DOXY) $(C2_OUT_TEMP)/doxy-api.config
-
-.PHONY: docs-internal
-docs-internal: $(C2_OUT_TEMP)/doxy-internal.config check-doxygen
- echo Internal docs are building in $(C2_DOCS_ROOT)/internal
- rm -rf $(C2_DOCS_ROOT)/internal
- mkdir -p $(C2_DOCS_ROOT)/internal
- $(C2_DOXY) $(C2_OUT_TEMP)/doxy-internal.config
-
-.PHONY: docs-all
-docs-all: docs-api docs-internal
-
-include $(call all-makefiles-under,$(call my-dir))
diff --git a/media/codec2/components/OWNERS b/media/codec2/components/OWNERS
new file mode 100644
index 0000000..453999a
--- /dev/null
+++ b/media/codec2/components/OWNERS
@@ -0,0 +1 @@
+kyslov@google.com
\ No newline at end of file
diff --git a/media/codec2/components/aom/C2SoftAomEnc.cpp b/media/codec2/components/aom/C2SoftAomEnc.cpp
index 71909e5..7c9d3e8 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.cpp
+++ b/media/codec2/components/aom/C2SoftAomEnc.cpp
@@ -338,6 +338,19 @@
}
c2_status_t C2SoftAomEnc::onStop() {
+ IntfImpl::Lock lock = mIntf->lock();
+ std::shared_ptr<C2StreamRequestSyncFrameTuning::output> requestSync = mIntf->getRequestSync_l();
+ lock.unlock();
+ if (requestSync != mRequestSync) {
+ // we can handle IDR immediately
+ if (requestSync->value) {
+ // unset request
+ C2StreamRequestSyncFrameTuning::output clearSync(0u, C2_FALSE);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ mIntf->config({ &clearSync }, C2_MAY_BLOCK, &failures);
+ }
+ mRequestSync = requestSync;
+ }
onRelease();
return C2_OK;
}
diff --git a/media/codec2/docs/doxygen.config b/media/codec2/docs/doxygen.config
index 5c3bea3..ab8b53b 100644
--- a/media/codec2/docs/doxygen.config
+++ b/media/codec2/docs/doxygen.config
@@ -162,7 +162,7 @@
# will be relative from the directory where doxygen is started.
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-STRIP_FROM_PATH = frameworks/av/media/libstagefright/codec2
+STRIP_FROM_PATH = frameworks/av/media/codec2
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
# path mentioned in the documentation of a class, which tells the reader which
@@ -781,7 +781,7 @@
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
-INPUT = frameworks/av/media/libstagefright/codec2/
+INPUT = frameworks/av/media/codec2/
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -897,7 +897,7 @@
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
-INPUT_FILTER = frameworks/av/media/libstagefright/codec2/docs/doxyfilter.sh
+INPUT_FILTER = frameworks/av/media/codec2/docs/doxyfilter.sh
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis. Doxygen will compare the file name with each pattern and apply the
diff --git a/media/codec2/doxygen.sh b/media/codec2/doxygen.sh
new file mode 100755
index 0000000..ca5aeed
--- /dev/null
+++ b/media/codec2/doxygen.sh
@@ -0,0 +1,87 @@
+#!/bin/bash
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# =============================================================================
+# DOCUMENTATION GENERATION
+# =============================================================================
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+ echo "error: Android build is not set up. Run this command after lunch." >&2
+ exit 2
+fi
+
+OUT_DIR=$ANDROID_BUILD_TOP/out
+
+# Codec 2.0 source and target paths
+C2_ROOT=$(dirname "$0")
+C2_DOCS_ROOT=$OUT_DIR/target/common/docs/codec2
+C2_OUT_TEMP=$ANDROID_PRODUCT_OUT/gen/ETC/Codec2-docs_intermediates
+
+# Doxygen path
+DOXY=$(which doxygen)
+DOXY_MAC="/Applications/Doxygen.app/Contents/Resources/doxygen"
+if [ -z "$DOXY" -a -x "$DOXY_MAC" ]; then
+ DOXY=$DOXY_MAC
+fi
+
+if [ -z "$DOXY" ]; then
+ echo "error: doxygen is not available" >&2
+ exit 2
+fi
+
+# Create doxygen config
+# ---------------------
+gen_doxy() {
+ local variant=$1
+ local variant_lc=$(echo $variant | tr A-Z a-z)
+ mkdir -p $C2_OUT_TEMP
+ if [ "$variant_lc" == "api" ]; then
+ # only document include directory, no internal sections
+ sed 's/\(^INPUT *=.*\)/\1core\/include\//;
+ s/\(^INTERNAL_DOCS *= *\).*/\1NO/;
+ s/\(^ENABLED_SECTIONS *=.*\)INTERNAL\(.*\).*/\1\2/;
+ s:\(^OUTPUT_DIRECTORY *= \)out\(.*\)api:\1'$OUT_DIR'\2'$variant_lc':;' \
+ $C2_ROOT/docs/doxygen.config > $C2_OUT_TEMP/doxy-$variant_lc.config
+
+ ls -la $C2_OUT_TEMP/doxy-$variant_lc.config
+ else
+ sed 's:\(^OUTPUT_DIRECTORY *= \)out\(.*\)api:\1'$OUT_DIR'\2'$variant_lc':;' \
+ $C2_ROOT/docs/doxygen.config > $C2_OUT_TEMP/doxy-$variant_lc.config
+ fi
+
+ echo $variant docs are building in $C2_DOCS_ROOT/$variant_lc
+ rm -rf $C2_DOCS_ROOT/$variant_lc
+ mkdir -p $C2_DOCS_ROOT/$variant_lc
+ pushd $ANDROID_BUILD_TOP
+ $DOXY $C2_OUT_TEMP/doxy-$variant_lc.config
+ popd
+}
+
+usage() {
+ echo "usage: $(basename "$0") [target]"
+ echo " where target can be one of:"
+ echo " all: build both API and internal docs (default)"
+ echo " api: build API docs only"
+ echo " internal: build internal docs which include implementation details"
+}
+
+TARGET=${1:-all}
+case "$TARGET" in
+ api) gen_doxy API;;
+ internal) gen_doxy Internal;;
+ all) gen_doxy API; gen_doxy Internal;;
+ -h) usage; exit 0;;
+ *) echo "unknown target '$TARGET'" >&2; usage; exit 2;;
+esac
diff --git a/media/codec2/hal/aidl/Android.bp b/media/codec2/hal/aidl/Android.bp
index 7a9af18..48b6e21 100644
--- a/media/codec2/hal/aidl/Android.bp
+++ b/media/codec2/hal/aidl/Android.bp
@@ -24,7 +24,7 @@
shared_libs: [
"android.hardware.common-V2-ndk",
"android.hardware.media.bufferpool@2.0",
- "android.hardware.media.bufferpool2-V1-ndk",
+ "android.hardware.media.bufferpool2-V2-ndk",
"android.hardware.media.c2-V1-ndk",
"libbinder_ndk",
"libbase",
@@ -84,7 +84,7 @@
shared_libs: [
"android.hardware.common-V2-ndk",
- "android.hardware.media.bufferpool2-V1-ndk",
+ "android.hardware.media.bufferpool2-V2-ndk",
"android.hardware.media.c2-V1-ndk",
"libbase",
"libbinder_ndk",
diff --git a/media/codec2/hal/aidl/BufferTypes.cpp b/media/codec2/hal/aidl/BufferTypes.cpp
index bc4948b..a0e6aa5 100644
--- a/media/codec2/hal/aidl/BufferTypes.cpp
+++ b/media/codec2/hal/aidl/BufferTypes.cpp
@@ -302,7 +302,7 @@
"invalid receiver connection id (0).";
return bufferpool2::ResultStatus::CRITICAL_ERROR;
} else {
- if (isNewConnection) {
+ if (foundConnection == mConnections.end()) {
foundConnection = mConnections.try_emplace(
connectionId, receiverConnectionId, now).first;
} else {
diff --git a/media/codec2/hal/aidl/Component.cpp b/media/codec2/hal/aidl/Component.cpp
index 4c2d5d3..8da9861 100644
--- a/media/codec2/hal/aidl/Component.cpp
+++ b/media/codec2/hal/aidl/Component.cpp
@@ -51,8 +51,10 @@
struct Component::Listener : public C2Component::Listener {
Listener(const std::shared_ptr<Component>& component) :
- mComponent(component),
- mListener(component->mListener) {
+ mComponent(component),
+ mListener(component->mListener) {
+ CHECK(component);
+ CHECK(component->mListener);
}
virtual void onError_nb(
@@ -289,30 +291,22 @@
const IComponent::BlockPoolAllocator &allocator,
IComponent::BlockPool *blockPool) {
std::shared_ptr<C2BlockPool> c2BlockPool;
- static constexpr IComponent::BlockPoolAllocator::Tag ALLOCATOR_ID =
- IComponent::BlockPoolAllocator::allocatorId;
- static constexpr IComponent::BlockPoolAllocator::Tag IGBA =
- IComponent::BlockPoolAllocator::allocator;
c2_status_t status = C2_OK;
::android::C2PlatformAllocatorDesc allocatorParam;
- switch (allocator.getTag()) {
- case ALLOCATOR_ID: {
- allocatorParam.allocatorId =
- allocator.get<IComponent::BlockPoolAllocator::allocatorId>();
- }
- break;
- case IGBA: {
- allocatorParam.allocatorId = ::android::C2PlatformAllocatorStore::IGBA;
- allocatorParam.igba =
- allocator.get<IComponent::BlockPoolAllocator::allocator>().igba;
+ allocatorParam.allocatorId = allocator.allocatorId;
+ switch (allocator.allocatorId) {
+ case ::android::C2PlatformAllocatorStore::IGBA: {
+ allocatorParam.igba = allocator.gbAllocator->igba;
allocatorParam.waitableFd.reset(
- allocator.get<IComponent::BlockPoolAllocator::allocator>()
- .waitableFd.dup().release());
+ allocator.gbAllocator->waitableFd.dup().release());
}
break;
- default:
- return ScopedAStatus::fromServiceSpecificError(C2_CORRUPTED);
+ default: {
+ // no-op
+ }
+ break;
}
+
#ifdef __ANDROID_APEX__
status = ::android::CreateCodec2BlockPool(
allocatorParam,
@@ -428,6 +422,8 @@
mInit = res;
}
+ // b/321902635, mListener should not be null.
+ CHECK(mListener);
mDeathRecipient = ::ndk::ScopedAIBinder_DeathRecipient(
AIBinder_DeathRecipient_new(OnBinderDied));
mDeathContext = new DeathContext{ref<Component>()};
diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp
index f0a1490..3f687b5 100644
--- a/media/codec2/hal/aidl/ComponentStore.cpp
+++ b/media/codec2/hal/aidl/ComponentStore.cpp
@@ -210,6 +210,8 @@
c2_status_t status =
mStore->createComponent(name, &c2component);
+ ALOGD("createComponent(): listener(%d)", bool(listener));
+
if (status == C2_OK) {
#ifndef __ANDROID_APEX__
c2component = GetFilterWrapper()->maybeWrapComponent(c2component);
@@ -218,7 +220,8 @@
std::shared_ptr<Component> comp =
SharedRefBase::make<Component>(c2component, listener, ref<ComponentStore>(), pool);
*component = comp;
- if (!component) {
+ if (!component || !comp) {
+ ALOGE("createComponent(): component cannot be returned");
status = C2_CORRUPTED;
} else {
reportComponentBirth(comp.get());
diff --git a/media/codec2/hal/client/Android.bp b/media/codec2/hal/client/Android.bp
index 0b5b940..af6f4ae 100644
--- a/media/codec2/hal/client/Android.bp
+++ b/media/codec2/hal/client/Android.bp
@@ -43,7 +43,7 @@
"android.hardware.media.c2@1.0",
"android.hardware.media.c2@1.1",
"android.hardware.media.c2@1.2",
- "android.hardware.media.bufferpool2-V1-ndk",
+ "android.hardware.media.bufferpool2-V2-ndk",
"android.hardware.media.c2-V1-ndk",
"libbase",
"libbinder",
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index 85b5ec8..9ed9458 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -2072,6 +2072,8 @@
id = id == C2PlatformAllocatorStore::BUFFERQUEUE ?
C2PlatformAllocatorStore::IGBA : id;
+ c2_aidl::IComponent::BlockPoolAllocator allocator;
+ allocator.allocatorId = id;
if (id == C2PlatformAllocatorStore::IGBA) {
std::shared_ptr<AidlGraphicBufferAllocator> gba =
mGraphicBufferAllocators->create();
@@ -2081,12 +2083,11 @@
if (status != C2_OK) {
return status;
}
- c2_aidl::IComponent::BlockPoolAllocator allocator;
- allocator.set<c2_aidl::IComponent::BlockPoolAllocator::allocator>();
- allocator.get<c2_aidl::IComponent::BlockPoolAllocator::allocator>().igba =
+ c2_aidl::IComponent::GbAllocator gbAllocator;
+ gbAllocator.waitableFd = std::move(waitableFd);
+ gbAllocator.igba =
c2_aidl::IGraphicBufferAllocator::fromBinder(gba->asBinder());
- allocator.get<c2_aidl::IComponent::BlockPoolAllocator::allocator>().waitableFd =
- std::move(waitableFd);
+ allocator.gbAllocator = std::move(gbAllocator);
::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(
allocator, &aidlBlockPool);
status = GetC2Status(transStatus, "createBlockPool");
@@ -2096,7 +2097,7 @@
mGraphicBufferAllocators->setCurrentId(aidlBlockPool.blockPoolId);
} else {
::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(
- static_cast<int32_t>(id), &aidlBlockPool);
+ allocator, &aidlBlockPool);
status = GetC2Status(transStatus, "createBlockPool");
if (status != C2_OK) {
return status;
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/Android.bp b/media/codec2/hal/hidl/1.0/vts/functional/Android.bp
index 1c5c7d6..2054fe6 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/Android.bp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/Android.bp
@@ -44,6 +44,7 @@
"res/bbb_opus_stereo_128kbps_48000hz.info",
"res/bbb_opus_stereo_128kbps_48000hz.opus",
"res/bbb_raw_1ch_8khz_s32le.info",
+ "res/bbb_raw_1ch_8khz_s32le_largeframe.info",
"res/bbb_raw_1ch_8khz_s32le.raw",
"res/bbb_vorbis_stereo_128kbps_48000hz.info",
"res/bbb_vorbis_stereo_128kbps_48000hz.vorbis",
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index c7c04c5..0c30d95 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -32,7 +32,11 @@
#include <codec2/hidl/client.h>
#include "media_c2_hidl_test_common.h"
-using DecodeTestParameters = std::tuple<std::string, std::string, uint32_t, bool>;
+
+using DecodeTestParameters = std::tuple<std::string /*instance_name*/,
+ std::string /*component_name*/,
+ uint32_t /*stream_index*/,
+ bool /*signal end-of-stream nor not*/>;
static std::vector<DecodeTestParameters> gDecodeTestParameters;
using CsdFlushTestParameters = std::tuple<std::string, std::string, bool>;
@@ -56,6 +60,7 @@
{"g711-mlaw", "bbb_g711mulaw_1ch_8khz.raw", "bbb_g711mulaw_1ch_8khz.info"},
{"gsm", "bbb_gsm_1ch_8khz_13kbps.raw", "bbb_gsm_1ch_8khz_13kbps.info"},
{"raw", "bbb_raw_1ch_8khz_s32le.raw", "bbb_raw_1ch_8khz_s32le.info"},
+ {"raw", "bbb_raw_1ch_8khz_s32le.raw", "bbb_raw_1ch_8khz_s32le_largeframe.info"},
{"flac", "bbb_flac_stereo_680kbps_48000hz.flac", "bbb_flac_stereo_680kbps_48000hz.info"},
};
@@ -137,6 +142,9 @@
struct outputMetaData {
uint64_t timestampUs;
uint32_t rangeLength;
+ // The following is used only if C2AccessUnitInfos::output
+ // is present as part of C2Buffer.
+ std::vector<C2AccessUnitInfosStruct> largeFrameInfo;
};
// callback function to process onWorkDone received by Listener
void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
@@ -161,8 +169,18 @@
.capacity();
// List of timestamp values and output size to calculate timestamp
if (mTimestampDevTest) {
- outputMetaData meta = {mTimestampUs, rangeLength};
+ outputMetaData meta = {mTimestampUs, rangeLength, {}};
oBufferMetaData.push_back(meta);
+ std::shared_ptr<const C2AccessUnitInfos::output> inBufferInfo =
+ std::static_pointer_cast<const C2AccessUnitInfos::output>(
+ work->worklets.front()->output.buffers[0]->getInfo(
+ C2AccessUnitInfos::output::PARAM_TYPE));
+ if (inBufferInfo) {
+ for (int nMeta = 0; nMeta < inBufferInfo->flexCount(); nMeta++) {
+ oBufferMetaData.back().largeFrameInfo.push_back(
+ inBufferInfo->m.values[nMeta]);
+ }
+ }
}
}
bool mCsd = false;
@@ -203,6 +221,12 @@
std::string mInfoFile;
size_t mStreamIndex = 0;
+ // These are used only with large frame codec
+ // Specifies the maximum output size in bytes.
+ uint32_t mMaxOutputSize;
+ //Specifies the threshold output size in bytes.
+ uint32_t mOutputThresholdSize;
+
protected:
static void description(const std::string& description) {
RecordProperty("description", description);
@@ -249,6 +273,96 @@
ALOGV("Component Valid");
}
+bool isLargeAudioFrameSupported(const std::shared_ptr<android::Codec2Client::Component> &comp,
+ std::vector<C2FieldSupportedValues>& supportedValues) {
+ C2LargeFrame::output largeFrameParams;
+ std::vector<C2FieldSupportedValuesQuery> validValueInfos = {
+ C2FieldSupportedValuesQuery::Current(
+ C2ParamField(&largeFrameParams, &C2LargeFrame::maxSize)),
+ C2FieldSupportedValuesQuery::Current(
+ C2ParamField(&largeFrameParams,
+ &C2LargeFrame::thresholdSize))};
+ c2_status_t c2err = comp->querySupportedValues(validValueInfos, C2_DONT_BLOCK);
+ if (c2err != C2_OK || validValueInfos.size() != 2) {
+ return false;
+ }
+ supportedValues.clear();
+ for (int i = 0; i < 2; i++) {
+ if (validValueInfos[i].values.type == C2FieldSupportedValues::EMPTY) {
+ return false;
+ }
+ supportedValues.push_back(validValueInfos[i].values);
+ }
+ return true;
+}
+
+c2_status_t configureLargeFrameParams(const std::shared_ptr<android::Codec2Client::Component> &comp,
+ uint32_t& maxOutput, uint32_t& outputThreshold,
+ const std::vector<C2FieldSupportedValues>& supportedValues) {
+
+ if (supportedValues.empty()) {
+ ALOGE("Error: No supported values in large audio frame params");
+ return C2_BAD_VALUE;
+ }
+
+ auto boundBySupportedValues = [](const C2FieldSupportedValues& supportedValues, uint32_t& value)
+ -> c2_status_t {
+ uint32_t oBufMin = 0, oBufMax = 0;
+ switch (supportedValues.type) {
+ case C2FieldSupportedValues::type_t::RANGE:
+ {
+ const auto& range = supportedValues.range;
+ oBufMax = (uint32_t)(range.max).ref<uint32_t>();
+ oBufMin = (uint32_t)(range.min).ref<uint32_t>();
+ value = (value > oBufMax) ? oBufMax :
+ (value < oBufMin) ? oBufMin : value;
+ break;
+ }
+
+ case C2FieldSupportedValues::type_t::VALUES:
+ {
+ uint32_t lastValue;
+ for (const C2Value::Primitive& prim : supportedValues.values) {
+ lastValue = (uint32_t)prim.ref<uint32_t>();
+ if (lastValue > value) {
+ value = lastValue;
+ break;
+ }
+ }
+ if (value > lastValue) {
+ value = lastValue;
+ }
+ break;
+ }
+
+ default:
+ return C2_BAD_VALUE;
+ }
+ return C2_OK;
+ };
+ c2_status_t c2_err = boundBySupportedValues(supportedValues[0], maxOutput);
+ if (c2_err != C2_OK) {
+ return c2_err;
+ }
+ c2_err = boundBySupportedValues(supportedValues[1], outputThreshold);
+ if (c2_err != C2_OK) {
+ return c2_err;
+ }
+ if (outputThreshold > maxOutput) {
+ outputThreshold = maxOutput;
+ }
+ ALOGV("Setting large frame format : Max: %d - Threshold: %d", maxOutput, outputThreshold);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ C2LargeFrame::output largeFrameParams(0u, maxOutput, outputThreshold);
+ std::vector<C2Param*> configParam{&largeFrameParams};
+ c2_status_t status = comp->config(configParam, C2_DONT_BLOCK, &failures);
+ if (status != C2_OK || failures.size() != 0u) {
+ ALOGE("Large frame Audio configuration failed for maxSize: %d, thresholdSize: %d",
+ maxOutput, outputThreshold);
+ }
+ return status;
+}
+
// Set Default config param.
bool setupConfigParam(const std::shared_ptr<android::Codec2Client::Component>& component,
int32_t* bitStreamInfo) {
@@ -317,6 +431,10 @@
typedef std::unique_lock<std::mutex> ULock;
int frameID = offset;
int maxRetry = 0;
+ std::shared_ptr<C2Buffer> buffer;
+ std::vector<C2FieldSupportedValues> largeFrameValues;
+ bool isComponentSupportsLargeAudioFrame = isLargeAudioFrameSupported(component,
+ largeFrameValues);
while (1) {
if (frameID == (int)Info->size() || frameID == (offset + range)) break;
uint32_t flags = 0;
@@ -376,7 +494,17 @@
memcpy(view.base(), data, size);
- work->input.buffers.emplace_back(new LinearBuffer(block));
+ buffer.reset(new LinearBuffer(block));
+ if (!(*Info)[frameID].largeFrameInfo.empty() && isComponentSupportsLargeAudioFrame) {
+ const std::vector<C2AccessUnitInfosStruct>& meta =
+ (*Info)[frameID].largeFrameInfo;
+ ALOGV("Large Audio frame supported for %s, frameID: %d, size: %zu",
+ component->getName().c_str(), frameID, meta.size());
+ const std::shared_ptr<C2AccessUnitInfos::input> largeFrame =
+ C2AccessUnitInfos::input::AllocShared(meta.size(), 0u, meta);
+ buffer->setInfo(largeFrame);
+ }
+ work->input.buffers.push_back(buffer);
free(data);
}
work->worklets.clear();
@@ -403,9 +531,37 @@
auto itOut = oBufferMetaData.begin();
EXPECT_EQ(*itIn, itOut->timestampUs);
uint64_t expectedTimeStamp = *itIn;
- while (itOut != oBufferMetaData.end()) {
+ bool err= false;
+ while (!err && itOut != oBufferMetaData.end()) {
EXPECT_EQ(expectedTimeStamp, itOut->timestampUs);
if (expectedTimeStamp != itOut->timestampUs) break;
+ if (!itOut->largeFrameInfo.empty()) {
+ // checking large audio frame metadata
+ if (itOut->largeFrameInfo[0].timestamp != itOut->timestampUs) {
+ ALOGE("Metadata first time stamp doesn't match");
+ err = true;
+ break;
+ }
+ uint64_t totalSize = 0;
+ uint64_t sampleSize = 0;
+ int64_t nextTimestamp = itOut->timestampUs;
+ for (auto& meta : itOut->largeFrameInfo) {
+ if (nextTimestamp != meta.timestamp) {
+ ALOGE("Metadata timestamp error: expect: %lld, got: %lld",
+ (long long)nextTimestamp, (long long)meta.timestamp);
+ err = true;
+ break;
+ }
+ totalSize += meta.size;
+ sampleSize = (meta.size / (nChannels * 2));
+ nextTimestamp += sampleSize * 1000000ll / nSampleRate;
+ }
+ if (totalSize != itOut->rangeLength) {
+ ALOGE("Metadata size error: expected:%lld, got: %d",
+ (long long)totalSize, itOut->rangeLength);
+ err = true;
+ }
+ }
// buffer samples = ((total bytes) / (ac * (bits per sample / 8))
samplesReceived += ((itOut->rangeLength) / (nChannels * 2));
expectedTimeStamp = samplesReceived * 1000000ll / nSampleRate;
@@ -453,7 +609,8 @@
android::Vector<FrameInfo> Info;
int32_t numCsds = populateInfoVector(mInfoFile, &Info, mTimestampDevTest, &mTimestampUslist);
- ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << mInfoFile;
+ ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << mInfoFile <<
+ " #CSD " << numCsds;
// Reset total no of frames received
mFramesReceived = 0;
@@ -474,10 +631,23 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
std::ifstream eleStream;
eleStream.open(mInputFile, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true);
+
ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
mFlushedIndices, mLinearPool, eleStream, &Info, 0,
(int)Info.size(), signalEOS));
@@ -529,6 +699,18 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
// request EOS for thumbnail
@@ -611,6 +793,18 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
// flush
std::list<std::unique_ptr<C2Work>> flushedWork;
@@ -681,6 +875,7 @@
uint32_t flags = 0;
uint32_t vtsFlags = 0;
uint32_t timestamp = 0;
+ uint32_t nLargeFrames = 0;
bool codecConfig = false;
// This test introduces empty CSD after every 20th frame
// and empty input frames at an interval of 5 frames.
@@ -688,6 +883,7 @@
if (!(frameId % 5)) {
vtsFlags = !(frameId % 20) ? (1 << VTS_BIT_FLAG_CSD_FRAME) : 0;
bytesCount = 0;
+ Info.push_back({bytesCount, vtsFlags, timestamp, {}});
} else {
if (!(eleInfo >> bytesCount)) break;
eleInfo >> flags;
@@ -695,8 +891,20 @@
ASSERT_NE(vtsFlags, 0xFF) << "unrecognized flag entry in info file: " << mInfoFile;
eleInfo >> timestamp;
codecConfig = (vtsFlags & (1 << VTS_BIT_FLAG_CSD_FRAME)) != 0;
+ Info.push_back({bytesCount, vtsFlags, timestamp, {}});
+ if ((vtsFlags & (1 << VTS_BIT_FLAG_LARGE_AUDIO_FRAME)) != 0) {
+ eleInfo >> nLargeFrames;
+ // this is a large audio frame.
+ while(nLargeFrames-- > 0) {
+ eleInfo >> bytesCount;
+ eleInfo >> flags;
+ eleInfo >> timestamp;
+ vtsFlags = mapInfoFlagstoVtsFlags(flags);
+ Info.editItemAt(Info.size() - 1).largeFrameInfo.push_back(
+ {(uint32_t)bytesCount, vtsFlags, timestamp});
+ }
+ }
}
- Info.push_back({bytesCount, vtsFlags, timestamp});
frameId++;
}
eleInfo.close();
@@ -711,6 +919,18 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
eleStream.open(mInputFile, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true);
@@ -766,7 +986,18 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
-
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
std::ifstream eleStream;
eleStream.open(mInputFile, std::ifstream::binary);
@@ -864,4 +1095,4 @@
::testing::InitGoogleTest(&argc, argv);
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
-}
+}
\ No newline at end of file
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml
index 6c04683..9b9c62f 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml
+++ b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml
@@ -38,6 +38,8 @@
<option name="push-file" key="bbb_opus_stereo_128kbps_48000hz.info" value="/data/local/tmp/media/bbb_opus_stereo_128kbps_48000hz.info" />
<option name="push-file" key="bbb_opus_stereo_128kbps_48000hz.opus" value="/data/local/tmp/media/bbb_opus_stereo_128kbps_48000hz.opus" />
<option name="push-file" key="bbb_raw_1ch_8khz_s32le.info" value="/data/local/tmp/media/bbb_raw_1ch_8khz_s32le.info" />
+ <option name="push-file" key="bbb_raw_1ch_8khz_s32le_largeframe.info"
+ value="/data/local/tmp/media/bbb_raw_1ch_8khz_s32le_largeframe.info" />
<option name="push-file" key="bbb_raw_1ch_8khz_s32le.raw" value="/data/local/tmp/media/bbb_raw_1ch_8khz_s32le.raw" />
<option name="push-file" key="bbb_vorbis_stereo_128kbps_48000hz.info" value="/data/local/tmp/media/bbb_vorbis_stereo_128kbps_48000hz.info" />
<option name="push-file" key="bbb_vorbis_stereo_128kbps_48000hz.vorbis" value="/data/local/tmp/media/bbb_vorbis_stereo_128kbps_48000hz.vorbis" />
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
index a72f7bd..92b0bf5 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
@@ -235,12 +235,13 @@
uint32_t flags = 0;
uint32_t vtsFlags = 0;
uint32_t timestamp = 0;
+ uint32_t nLargeFrames = 0;
while (1) {
if (!(eleInfo >> bytesCount)) break;
eleInfo >> flags;
vtsFlags = mapInfoFlagstoVtsFlags(flags);
if (vtsFlags == 0xFF) {
- ALOGE("unrecognized flag entry in info file %s", info.c_str());
+ ALOGE("unrecognized flag(0x%x) entry in info file %s", flags, info.c_str());
return -1;
}
eleInfo >> timestamp;
@@ -250,7 +251,18 @@
if (timestampDevTest && !codecConfig && !nonDisplayFrame) {
timestampUslist->push_back(timestamp);
}
- frameInfo->push_back({bytesCount, vtsFlags, timestamp});
+ frameInfo->push_back({bytesCount, vtsFlags, timestamp, {}});
+ if (vtsFlags & (1 << VTS_BIT_FLAG_LARGE_AUDIO_FRAME)) {
+ eleInfo >> nLargeFrames;
+ while(nLargeFrames-- > 0) {
+ eleInfo >> bytesCount;
+ eleInfo >> flags;
+ eleInfo >> timestamp;
+ vtsFlags = mapInfoFlagstoVtsFlags(flags);
+ frameInfo->editItemAt(frameInfo->size() - 1).largeFrameInfo.push_back(
+ {vtsFlags, static_cast<uint32_t>(bytesCount), timestamp});
+ }
+ }
}
ALOGV("numCsds : %d", numCsds);
eleInfo.close();
@@ -285,5 +297,6 @@
else if (infoFlags == 0x1) return (1 << VTS_BIT_FLAG_SYNC_FRAME);
else if (infoFlags == 0x10) return (1 << VTS_BIT_FLAG_NO_SHOW_FRAME);
else if (infoFlags == 0x20) return (1 << VTS_BIT_FLAG_CSD_FRAME);
+ else if (infoFlags == 0x40) return (1 << VTS_BIT_FLAG_LARGE_AUDIO_FRAME);
return 0xFF;
}
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
index eda7b99..708fe15 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
+++ b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
@@ -54,12 +54,16 @@
VTS_BIT_FLAG_SYNC_FRAME = 1,
VTS_BIT_FLAG_NO_SHOW_FRAME = 2,
VTS_BIT_FLAG_CSD_FRAME = 3,
+ VTS_BIT_FLAG_LARGE_AUDIO_FRAME = 4,
};
struct FrameInfo {
int bytesCount;
uint32_t vtsFlags;
int64_t timestamp;
+ // This is used when access-units are marked with
+ // VTS_BIT_FLAG_LARGE_AUDIO_FRAME
+ std::vector<C2AccessUnitInfosStruct> largeFrameInfo;
};
template <typename... T>
@@ -86,7 +90,6 @@
virtual void onWorkDone(const std::weak_ptr<android::Codec2Client::Component>& comp,
std::list<std::unique_ptr<C2Work>>& workItems) override {
/* TODO */
- ALOGD("onWorkDone called");
(void)comp;
if (callBack) callBack(workItems);
}
@@ -103,7 +106,6 @@
uint32_t errorCode) override {
/* TODO */
(void)comp;
- ALOGD("onError called");
if (errorCode != 0) ALOGE("Error : %u", errorCode);
}
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le_largeframe.info b/media/codec2/hal/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le_largeframe.info
new file mode 100644
index 0000000..291e323
--- /dev/null
+++ b/media/codec2/hal/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le_largeframe.info
@@ -0,0 +1,5 @@
+16384 64 0 1 16384 1 0
+49152 64 1024000 3 16384 1 1024000 16384 1 2048000 16384 1 3072000
+32768 64 4096000 2 16384 1 4096000 16384 1 5120000
+49152 64 6144000 3 16384 1 6144000 16384 1 7168000 16384 1 8192000
+10924 64 9216000 1 10924 1 9216000
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index df89510..f8fd425 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -739,7 +739,7 @@
ASSERT_NE(vtsFlags, 0xFF) << "unrecognized flag entry in info file: " << mInfoFile;
eleInfo >> timestamp;
timestamp += timestampOffset;
- Info.push_back({bytesCount, vtsFlags, timestamp});
+ Info.push_back({bytesCount, vtsFlags, timestamp, {}});
bool codecConfig = (vtsFlags & (1 << VTS_BIT_FLAG_CSD_FRAME)) != 0;
bool nonDisplayFrame = (vtsFlags & (1 << VTS_BIT_FLAG_NO_SHOW_FRAME)) != 0;
@@ -978,7 +978,7 @@
eleInfo >> timestamp;
codecConfig = (vtsFlags & (1 << VTS_BIT_FLAG_CSD_FRAME)) != 0;
}
- Info.push_back({bytesCount, vtsFlags, timestamp});
+ Info.push_back({bytesCount, vtsFlags, timestamp, {}});
frameId++;
}
eleInfo.close();
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 6b45e0e..6e6d3f7 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1604,8 +1604,14 @@
padding = 0;
}
if (delay || padding) {
- // We need write access to the buffers, and we're already in
- // array mode.
+ // We need write access to the buffers, so turn them into array mode.
+ // TODO: b/321930152 - define SkipCutOutputBuffers that takes output from
+ // component, runs it through SkipCutBuffer and allocate local buffer to be
+ // used by fwk. Make initSkipCutBuffer() return OutputBuffers similar to
+ // toArrayMode().
+ if (!output->buffers->isArrayMode()) {
+ output->buffers = output->buffers->toArrayMode(numOutputSlots);
+ }
output->buffers->initSkipCutBuffer(delay, padding, sampleRate, channelCount);
}
}
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index af2683b..9f57bfd 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -84,7 +84,7 @@
"libbase",
"libdmabufheap",
"android.hardware.media.bufferpool@2.0",
- "android.hardware.media.bufferpool2-V1-ndk",
+ "android.hardware.media.bufferpool2-V2-ndk",
],
local_include_dirs: [
@@ -102,7 +102,7 @@
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
"android.hardware.media.bufferpool@2.0",
- "android.hardware.media.bufferpool2-V1-ndk",
+ "android.hardware.media.bufferpool2-V2-ndk",
"android.hardware.media.c2-V1-ndk",
"libbase",
"libbinder_ndk",
@@ -162,11 +162,12 @@
"android.hardware.graphics.bufferqueue@2.0",
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
- "android.hardware.media.bufferpool2-V1-ndk",
+ "android.hardware.media.bufferpool2-V2-ndk",
"android.hardware.media.c2-V1-ndk",
],
shared_libs: [
+ "libbinder",
"libbinder_ndk",
"libui",
"libdl",
diff --git a/media/libaaudio/include/aaudio/AAudioTesting.h b/media/libaaudio/include/aaudio/AAudioTesting.h
index 01d97b6..d67ec70 100644
--- a/media/libaaudio/include/aaudio/AAudioTesting.h
+++ b/media/libaaudio/include/aaudio/AAudioTesting.h
@@ -49,12 +49,6 @@
};
typedef int32_t aaudio_policy_t;
-// Internal error codes. Only used by the framework.
-enum {
- AAUDIO_INTERNAL_ERROR_BASE = -1000,
- AAUDIO_ERROR_STANDBY,
-};
-
/**
* Control whether AAudioStreamBuilder_openStream() will use the new MMAP data path
* or the older "Legacy" data path.
diff --git a/media/libaaudio/src/core/AudioGlobal.h b/media/libaaudio/src/core/AudioGlobal.h
index 6c22744..8af49b4 100644
--- a/media/libaaudio/src/core/AudioGlobal.h
+++ b/media/libaaudio/src/core/AudioGlobal.h
@@ -22,6 +22,14 @@
namespace aaudio {
+// Internal error codes. Only used by the framework.
+enum {
+ AAUDIO_INTERNAL_ERROR_BASE = -1000,
+ AAUDIO_ERROR_STANDBY,
+ AAUDIO_ERROR_ALREADY_CLOSED,
+
+};
+
aaudio_policy_t AudioGlobal_getMMapPolicy();
aaudio_result_t AudioGlobal_setMMapPolicy(aaudio_policy_t policy);
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index d59afef..30efeb0 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -248,3 +248,30 @@
srcs: ["test_idle_disconnected_shared_stream.cpp"],
shared_libs: ["libaaudio"],
}
+
+cc_test {
+ name: "test_multiple_close_simultaneously",
+ defaults: [
+ "latest_android_media_audio_common_types_cpp_shared",
+ "libaaudio_tests_defaults",
+ ],
+ srcs: ["test_multiple_close_simultaneously.cpp"],
+ shared_libs: [
+ "aaudio-aidl-cpp",
+ "framework-permission-aidl-cpp",
+ "libaaudio",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+ // This test will run 1 minute to ensure there is no crash happen.
+ // In that case, set the timeout as 2 minutes to allow the test to complete.
+ test_options: {
+ test_runner_options: [
+ {
+ name: "native-test-timeout",
+ value: "2m",
+ }
+ ],
+ },
+}
diff --git a/media/libaaudio/tests/test_multiple_close_simultaneously.cpp b/media/libaaudio/tests/test_multiple_close_simultaneously.cpp
new file mode 100644
index 0000000..f6351b6
--- /dev/null
+++ b/media/libaaudio/tests/test_multiple_close_simultaneously.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "test_multiple_close_simultaneously"
+
+#include <chrono>
+#include <condition_variable>
+#include <shared_mutex>
+#include <string>
+#include <thread>
+
+#include <gtest/gtest.h>
+
+#include <binder/IBinder.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <aaudio/AAudio.h>
+#include <aaudio/IAAudioService.h>
+#include <aaudio/StreamRequest.h>
+#include <aaudio/StreamParameters.h>
+
+using namespace android;
+using namespace aaudio;
+
+#define AAUDIO_SERVICE_NAME "media.aaudio"
+
+static constexpr int THREAD_NUM = 2;
+static constexpr auto TEST_DURATION = std::chrono::minutes(1);
+
+static std::string sError;
+static bool sTestPassed = true;
+
+struct Signal {
+ std::atomic_int value{0};
+ std::shared_mutex lock;
+ std::condition_variable_any cv;
+};
+
+class AAudioServiceDeathRecipient : public IBinder::DeathRecipient {
+public:
+ void binderDied(const wp<IBinder>& who __unused) override {
+ sError = "AAudioService is dead";
+ ALOGE("%s", sError.c_str());
+ sTestPassed = false;
+ }
+};
+
+sp<IAAudioService> getAAudioService(const sp<IBinder::DeathRecipient>& recipient) {
+ auto sm = defaultServiceManager();
+ if (sm == nullptr) {
+ sError = "Cannot get service manager";
+ ALOGE("%s", sError.c_str());
+ return nullptr;
+ }
+ sp<IBinder> binder = sm->waitForService(String16(AAUDIO_SERVICE_NAME));
+ if (binder == nullptr) {
+ sError = "Cannot get aaudio service";
+ ALOGE("%s", sError.c_str());
+ return nullptr;
+ }
+ if (binder->linkToDeath(recipient) != NO_ERROR) {
+ sError = "Cannot link to binder death";
+ ALOGE("%s", sError.c_str());
+ return nullptr;
+ }
+ return interface_cast<IAAudioService>(binder);
+}
+
+void openAndMultipleClose(const sp<IAAudioService>& aaudioService) {
+ auto start = std::chrono::system_clock::now();
+ bool hasFailedOpening = false;
+ while (sTestPassed && std::chrono::system_clock::now() - start < TEST_DURATION) {
+ StreamRequest inRequest;
+ StreamParameters outParams;
+ int32_t handle = 0;
+ inRequest.attributionSource.uid = getuid();
+ inRequest.attributionSource.pid = getpid();
+ inRequest.attributionSource.token = sp<BBinder>::make();
+ auto status = aaudioService->openStream(inRequest, &outParams, &handle);
+ if (!status.isOk()) {
+ sError = "Cannot open stream, it can be caused by service death";
+ ALOGE("%s", sError.c_str());
+ sTestPassed = false;
+ break;
+ }
+ if (handle <= 0) {
+ sError = "Cannot get stream handle after open, returned handle"
+ + std::to_string(handle);
+ ALOGE("%s", sError.c_str());
+ sTestPassed = false;
+ break;
+ }
+ hasFailedOpening = false;
+
+ Signal isReady;
+ Signal startWork;
+ Signal isCompleted;
+ std::unique_lock readyLock(isReady.lock);
+ std::unique_lock completedLock(isCompleted.lock);
+ for (int i = 0; i < THREAD_NUM; ++i) {
+ std::thread closeStream([aaudioService, handle, &isReady, &startWork, &isCompleted] {
+ isReady.value++;
+ isReady.cv.notify_one();
+ {
+ std::shared_lock<std::shared_mutex> _l(startWork.lock);
+ startWork.cv.wait(_l, [&startWork] { return startWork.value.load() == 1; });
+ }
+ int32_t result;
+ aaudioService->closeStream(handle, &result);
+ isCompleted.value++;
+ isCompleted.cv.notify_one();
+ });
+ closeStream.detach();
+ }
+ isReady.cv.wait(readyLock, [&isReady] { return isReady.value == THREAD_NUM; });
+ {
+ std::unique_lock startWorkLock(startWork.lock);
+ startWork.value.store(1);
+ }
+ startWork.cv.notify_all();
+ isCompleted.cv.wait_for(completedLock,
+ std::chrono::milliseconds(1000),
+ [&isCompleted] { return isCompleted.value == THREAD_NUM; });
+ if (isCompleted.value != THREAD_NUM) {
+ sError = "Close is not completed within 1 second";
+ ALOGE("%s", sError.c_str());
+ sTestPassed = false;
+ break;
+ }
+ }
+}
+
+TEST(test_multiple_close_simultaneously, open_multiple_close) {
+ const auto recipient = sp<AAudioServiceDeathRecipient>::make();
+ auto aaudioService = getAAudioService(recipient);
+ ASSERT_NE(nullptr, aaudioService) << sError;
+ openAndMultipleClose(aaudioService);
+ ASSERT_TRUE(sTestPassed) << sError;
+}
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 15b03cb..565427b 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -1704,10 +1704,14 @@
__func__, mPortId, deviceId, mSelectedDeviceId, mRoutedDeviceId);
if (mSelectedDeviceId != deviceId) {
mSelectedDeviceId = deviceId;
- if (mStatus == NO_ERROR && mSelectedDeviceId != mRoutedDeviceId) {
+ if (mStatus == NO_ERROR) {
+ // allow track invalidation when track is not playing to propagate
+ // the updated mSelectedDeviceId
if (isPlaying_l()) {
- android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
- mProxy->interrupt();
+ if (mSelectedDeviceId != mRoutedDeviceId) {
+ android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ mProxy->interrupt();
+ }
} else {
// if the track is idle, try to restore now and
// defer to next start if not possible
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/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 3aec2cb..db9a9b1 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -985,7 +985,7 @@
if (mModule == nullptr) return NO_INIT;
{
std::lock_guard l(mLock);
- mMapper.resetUnusedPatchesAndPortConfigs();
+ mMapper.resetUnusedPatchesPortConfigsAndPorts();
}
ModuleDebug debug{ .simulateDeviceConnections = enabled };
status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
index a807669..39999a5 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -187,16 +187,7 @@
IEffect::OpenEffectReturn openReturn;
RETURN_STATUS_IF_ERROR(
statusTFromBinderStatus(mEffect->open(common, std::nullopt, &openReturn)));
-
- if (mIsProxyEffect) {
- mStatusQ = std::static_pointer_cast<EffectProxy>(mEffect)->getStatusMQ();
- mInputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getInputMQ();
- mOutputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getOutputMQ();
- } else {
- mStatusQ = std::make_shared<StatusMQ>(openReturn.statusMQ);
- mInputQ = std::make_shared<DataMQ>(openReturn.inputDataMQ);
- mOutputQ = std::make_shared<DataMQ>(openReturn.outputDataMQ);
- }
+ updateMqs(openReturn);
if (status_t status = updateEventFlags(); status != OK) {
ALOGV("%s closing at status %d", __func__, status);
@@ -213,6 +204,18 @@
return *static_cast<int32_t*>(pReplyData) = OK;
}
+void EffectConversionHelperAidl::updateMqs(const IEffect::OpenEffectReturn& ret) {
+ if (mIsProxyEffect) {
+ mStatusQ = std::static_pointer_cast<EffectProxy>(mEffect)->getStatusMQ();
+ mInputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getInputMQ();
+ mOutputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getOutputMQ();
+ } else {
+ mStatusQ = std::make_shared<StatusMQ>(ret.statusMQ);
+ mInputQ = std::make_shared<DataMQ>(ret.inputDataMQ);
+ mOutputQ = std::make_shared<DataMQ>(ret.outputDataMQ);
+ }
+}
+
status_t EffectConversionHelperAidl::handleGetConfig(uint32_t cmdSize __unused,
const void* pCmdData __unused,
uint32_t* replySize, void* pReplyData) {
@@ -505,5 +508,13 @@
return desc;
}
+status_t EffectConversionHelperAidl::reopen() {
+ IEffect::OpenEffectReturn openReturn;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->reopen(&openReturn)));
+
+ updateMqs(openReturn);
+ return OK;
+}
+
} // namespace effect
} // namespace android
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.h b/media/libaudiohal/impl/EffectConversionHelperAidl.h
index 5db334c..8b9efb3 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.h
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.h
@@ -47,6 +47,7 @@
bool isBypassingOrTunnel() const;
::aidl::android::hardware::audio::effect::Descriptor getDescriptor() const;
+ status_t reopen();
protected:
const int32_t mSessionId;
@@ -108,6 +109,8 @@
std::shared_ptr<android::hardware::EventFlag> mEfGroup = nullptr;
status_t updateEventFlags();
+ void updateMqs(const ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn& ret);
+
status_t handleInit(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
void* pReplyData);
status_t handleSetConfig(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
index f26444c..2836727 100644
--- a/media/libaudiohal/impl/EffectHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -56,6 +56,7 @@
using ::aidl::android::hardware::audio::effect::Descriptor;
using ::aidl::android::hardware::audio::effect::IEffect;
using ::aidl::android::hardware::audio::effect::IFactory;
+using ::aidl::android::hardware::audio::effect::kEventFlagDataMqUpdate;
using ::aidl::android::hardware::audio::effect::State;
namespace android {
@@ -165,26 +166,37 @@
// write to input FMQ here, wait for statusMQ STATUS_OK, and read from output FMQ
status_t EffectHalAidl::process() {
+ const std::string effectName = mConversion->getDescriptor().common.name;
State state = State::INIT;
if (mConversion->isBypassing() || !mEffect->getState(&state).isOk() ||
state != State::PROCESSING) {
- ALOGI("%s skipping %s process because it's %s", __func__,
- mConversion->getDescriptor().common.name.c_str(),
+ ALOGI("%s skipping %s process because it's %s", __func__, effectName.c_str(),
mConversion->isBypassing()
? "bypassing"
: aidl::android::hardware::audio::effect::toString(state).c_str());
return -ENODATA;
}
+ // check if the DataMq needs any update, timeout at 1ns to avoid being blocked
+ auto efGroup = mConversion->getEventFlagGroup();
+ if (!efGroup) {
+ ALOGE("%s invalid efGroup", __func__);
+ return INVALID_OPERATION;
+ }
+
+ if (uint32_t efState = 0;
+ ::android::OK == efGroup->wait(kEventFlagDataMqUpdate, &efState, 1 /* ns */,
+ true /* retry */)) {
+ ALOGI("%s %s receive dataMQUpdate eventFlag from HAL", __func__, effectName.c_str());
+ mConversion->reopen();
+ }
auto statusQ = mConversion->getStatusMQ();
auto inputQ = mConversion->getInputMQ();
auto outputQ = mConversion->getOutputMQ();
- auto efGroup = mConversion->getEventFlagGroup();
if (!statusQ || !statusQ->isValid() || !inputQ || !inputQ->isValid() || !outputQ ||
- !outputQ->isValid() || !efGroup) {
- ALOGE("%s invalid FMQ [Status %d I %d O %d] efGroup %p", __func__,
- statusQ ? statusQ->isValid() : 0, inputQ ? inputQ->isValid() : 0,
- outputQ ? outputQ->isValid() : 0, efGroup.get());
+ !outputQ->isValid()) {
+ ALOGE("%s invalid FMQ [Status %d I %d O %d]", __func__, statusQ ? statusQ->isValid() : 0,
+ inputQ ? inputQ->isValid() : 0, outputQ ? outputQ->isValid() : 0);
return INVALID_OPERATION;
}
@@ -225,8 +237,8 @@
return INVALID_OPERATION;
}
- ALOGD("%s %s consumed %zu produced %zu", __func__,
- mConversion->getDescriptor().common.name.c_str(), floatsToWrite, floatsToRead);
+ ALOGD("%s %s consumed %zu produced %zu", __func__, effectName.c_str(), floatsToWrite,
+ floatsToRead);
return OK;
}
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
index d4024a2..2b7f298 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.cpp
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -730,7 +730,7 @@
this, __func__, ioHandle, device.toString().c_str(),
flags.toString().c_str(), toString(source).c_str(),
config->toString().c_str(), mixPortConfig->toString().c_str());
- resetUnusedPatchesAndPortConfigs();
+ resetUnusedPatchesPortConfigsAndPorts();
const AudioConfig initialConfig = *config;
// Find / create AudioPortConfigs for the device port and the mix port,
// then find / create a patch between them, and open a stream on the mix port.
@@ -858,7 +858,7 @@
result = BAD_VALUE;
}
}
- resetUnusedPortConfigs();
+ resetUnusedPortConfigsAndPorts();
return result;
}
@@ -875,7 +875,7 @@
ALOGE("%s: port config id %d not found", __func__, portConfigId);
}
-void Hal2AidlMapper::resetUnusedPatchesAndPortConfigs() {
+void Hal2AidlMapper::resetUnusedPatchesPortConfigsAndPorts() {
// Since patches can be created independently of streams via 'createOrUpdatePatch',
// here we only clean up patches for released streams.
std::set<int32_t> patchesToRelease;
@@ -889,11 +889,11 @@
it = mStreams.erase(it);
}
}
- // 'releaseAudioPatches' also resets unused port configs.
+ // 'releaseAudioPatches' also resets unused port configs and ports.
releaseAudioPatches(patchesToRelease);
}
-void Hal2AidlMapper::resetUnusedPortConfigs() {
+void Hal2AidlMapper::resetUnusedPortConfigsAndPorts() {
// The assumption is that port configs are used to create patches
// (or to open streams, but that involves creation of patches, too). Thus,
// orphaned port configs can and should be reset.
@@ -934,6 +934,7 @@
}
status_t Hal2AidlMapper::setDevicePortConnectedState(const AudioPort& devicePort, bool connected) {
+ resetUnusedPatchesPortConfigsAndPorts();
if (connected) {
AudioDevice matchDevice = devicePort.ext.get<AudioPortExt::device>().device;
std::optional<AudioPort> templatePort;
@@ -968,7 +969,6 @@
}
templatePort = portsIt->second;
}
- resetUnusedPatchesAndPortConfigs();
// Use the ID of the "template" port, use all the information from the provided port.
AudioPort connectedPort = devicePort;
@@ -995,7 +995,6 @@
ALOGD("%s: device port for device %s found in the module %s",
__func__, matchDevice.toString().c_str(), mInstance.c_str());
}
- resetUnusedPatchesAndPortConfigs();
// Disconnection of remote submix out with address "0" is a special case. We need to replace
// the connected port entry with the "augmented template".
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.h b/media/libaudiohal/impl/Hal2AidlMapper.h
index 93ce233..f937173 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.h
+++ b/media/libaudiohal/impl/Hal2AidlMapper.h
@@ -91,7 +91,7 @@
::aidl::android::media::audio::common::AudioPortConfig* portConfig,
Cleanups* cleanups = nullptr);
status_t releaseAudioPatch(int32_t patchId);
- void resetUnusedPatchesAndPortConfigs();
+ void resetUnusedPatchesPortConfigsAndPorts();
status_t setDevicePortConnectedState(
const ::aidl::android::media::audio::common::AudioPort& devicePort, bool connected);
@@ -184,7 +184,7 @@
status_t releaseAudioPatches(const std::set<int32_t>& patchIds);
void resetPatch(int32_t patchId) { (void)releaseAudioPatch(patchId); }
void resetPortConfig(int32_t portConfigId);
- void resetUnusedPortConfigs();
+ void resetUnusedPortConfigsAndPorts();
status_t updateAudioPort(
int32_t portId, ::aidl::android::media::audio::common::AudioPort* port);
status_t updateRoutes();
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index c2d7ee1..5f525d7 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -234,7 +234,9 @@
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
if (!mStream) return NO_INIT;
- return mStream->dump(fd, Args(args).args(), args.size());
+ status_t status = mStream->dump(fd, Args(args).args(), args.size());
+ mStreamPowerLog.dump(fd);
+ return status;
}
status_t StreamHalAidl::start() {
diff --git a/media/libeffects/downmix/Android.bp b/media/libeffects/downmix/Android.bp
index 37633ae..b56872c 100644
--- a/media/libeffects/downmix/Android.bp
+++ b/media/libeffects/downmix/Android.bp
@@ -69,6 +69,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/downmix/aidl/DownmixContext.cpp b/media/libeffects/downmix/aidl/DownmixContext.cpp
index 13e0e5a..5fb44b5 100644
--- a/media/libeffects/downmix/aidl/DownmixContext.cpp
+++ b/media/libeffects/downmix/aidl/DownmixContext.cpp
@@ -111,7 +111,6 @@
}
IEffect::Status DownmixContext::downmixProcess(float* in, float* out, int samples) {
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << samples;
IEffect::Status status = {EX_ILLEGAL_ARGUMENT, 0, 0};
if (in == nullptr || out == nullptr ||
@@ -132,7 +131,6 @@
bool accumulate = false;
int frames = samples * sizeof(float) / getInputFrameSize();
if (mType == Downmix::Type::STRIP) {
- int inputChannelCount = getChannelCount(mChMask);
while (frames) {
if (accumulate) {
out[0] = std::clamp(out[0] + in[0], -1.f, 1.f);
@@ -141,7 +139,7 @@
out[0] = in[0];
out[1] = in[1];
}
- in += inputChannelCount;
+ in += mInputChannelCount;
out += 2;
frames--;
}
@@ -153,8 +151,11 @@
return status;
}
}
- LOG(DEBUG) << __func__ << " done processing";
- return {STATUS_OK, samples, samples};
+ int producedSamples = (samples / mInputChannelCount) << 1;
+ LOG(DEBUG) << __func__ << " done processing " << samples << " samples, generated "
+ << producedSamples << " frameSize: " << getInputFrameSize() << " - "
+ << getOutputFrameSize();
+ return {STATUS_OK, samples, producedSamples};
}
void DownmixContext::init_params(const Parameter::Common& common) {
diff --git a/media/libeffects/downmix/aidl/EffectDownmix.cpp b/media/libeffects/downmix/aidl/EffectDownmix.cpp
index 702a6f0..c82c23b 100644
--- a/media/libeffects/downmix/aidl/EffectDownmix.cpp
+++ b/media/libeffects/downmix/aidl/EffectDownmix.cpp
@@ -71,42 +71,6 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus DownmixImpl::setParameterCommon(const Parameter& param) {
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
-
- auto tag = param.getTag();
- switch (tag) {
- case Parameter::common:
- RETURN_IF(mContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
- EX_ILLEGAL_ARGUMENT, "setCommFailed");
- break;
- case Parameter::deviceDescription:
- RETURN_IF(mContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
- RetCode::SUCCESS,
- EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
- break;
- case Parameter::mode:
- RETURN_IF(mContext->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
- EX_ILLEGAL_ARGUMENT, "setModeFailed");
- break;
- case Parameter::source:
- RETURN_IF(mContext->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
- EX_ILLEGAL_ARGUMENT, "setSourceFailed");
- break;
- case Parameter::volumeStereo:
- RETURN_IF(mContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
- RetCode::SUCCESS,
- EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
- break;
- default: {
- LOG(ERROR) << __func__ << " unsupportedParameterTag " << toString(tag);
- return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
- "commonParamNotSupported");
- }
- }
- return ndk::ScopedAStatus::ok();
-}
-
ndk::ScopedAStatus DownmixImpl::commandImpl(CommandId command) {
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
switch (command) {
@@ -206,6 +170,43 @@
return RetCode::SUCCESS;
}
+void DownmixImpl::process() {
+ /**
+ * wait for the EventFlag without lock, it's ok because the mEfGroup pointer will not change
+ * in the life cycle of workerThread (threadLoop).
+ */
+ uint32_t efState = 0;
+ if (!mEventFlag || ::android::OK != mEventFlag->wait(kEventFlagNotEmpty, &efState)) {
+ LOG(ERROR) << getEffectName() << __func__ << ": StatusEventFlag invalid";
+ }
+
+ {
+ std::lock_guard lg(mImplMutex);
+ RETURN_VALUE_IF(!mImplContext, void(), "nullContext");
+ auto statusMQ = mImplContext->getStatusFmq();
+ auto inputMQ = mImplContext->getInputDataFmq();
+ auto outputMQ = mImplContext->getOutputDataFmq();
+ auto buffer = mImplContext->getWorkBuffer();
+ if (!inputMQ || !outputMQ) {
+ return;
+ }
+
+ const auto availableToRead = inputMQ->availableToRead();
+ const auto availableToWrite = outputMQ->availableToWrite() *
+ mImplContext->getInputFrameSize() /
+ mImplContext->getOutputFrameSize();
+ auto processSamples = std::min(availableToRead, availableToWrite);
+ if (processSamples) {
+ inputMQ->read(buffer, processSamples);
+ IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
+ outputMQ->write(buffer, status.fmqProduced);
+ statusMQ->writeBlocking(&status, 1);
+ LOG(VERBOSE) << getEffectName() << __func__ << ": done processing, effect consumed "
+ << status.fmqConsumed << " produced " << status.fmqProduced;
+ }
+ }
+}
+
// Processing method running in EffectWorker thread.
IEffect::Status DownmixImpl::effectProcessImpl(float* in, float* out, int sampleToProcess) {
if (!mContext) {
diff --git a/media/libeffects/downmix/aidl/EffectDownmix.h b/media/libeffects/downmix/aidl/EffectDownmix.h
index 812d26b..54557dc 100644
--- a/media/libeffects/downmix/aidl/EffectDownmix.h
+++ b/media/libeffects/downmix/aidl/EffectDownmix.h
@@ -34,21 +34,26 @@
LOG(DEBUG) << __func__;
}
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
- ndk::ScopedAStatus setParameterCommon(const Parameter& param) override;
- ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
- ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
- Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
- std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
- RetCode releaseContext() override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process)
+ REQUIRES(mImplMutex) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> getContext() override { return mContext; }
std::string getEffectName() override { return kEffectName; }
+ // downmix override the process because of different input/output sample size requirement
+ void process() override;
+
private:
- std::shared_ptr<DownmixContext> mContext;
- ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific);
+ std::shared_ptr<DownmixContext> mContext GUARDED_BY(mImplMutex);
+ ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/dynamicsproc/Android.bp b/media/libeffects/dynamicsproc/Android.bp
index 9e154cf..e93a4e6 100644
--- a/media/libeffects/dynamicsproc/Android.bp
+++ b/media/libeffects/dynamicsproc/Android.bp
@@ -95,6 +95,6 @@
],
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
index 85ea53a..1fedea4 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
@@ -211,11 +211,12 @@
RETURN_IF(common.input.base.format.pcm != common.output.base.format.pcm ||
common.input.base.format.pcm != PcmType::FLOAT_32_BIT,
EX_ILLEGAL_ARGUMENT, "dataMustBe32BitsFloat");
+ std::lock_guard lg(mImplMutex);
RETURN_OK_IF(mState != State::INIT);
- auto context = createContext(common);
- RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
+ mImplContext = createContext(common);
+ RETURN_IF(!mContext || !mImplContext, EX_NULL_POINTER, "createContextFailed");
+ mEventFlag = mImplContext->getStatusEventFlag();
- RETURN_IF_ASTATUS_NOT_OK(setParameterCommon(common), "setCommParamErr");
if (specific.has_value()) {
RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
} else {
@@ -227,8 +228,8 @@
}
mState = State::IDLE;
- context->dupeFmq(ret);
- RETURN_IF(createThread(context, getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
+ mContext->dupeFmq(ret);
+ RETURN_IF(createThread(getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
"FailedToCreateWorker");
return ndk::ScopedAStatus::ok();
}
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
index 1e1e72e..4897888 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
@@ -39,22 +39,25 @@
ndk::ScopedAStatus open(const Parameter::Common& common,
const std::optional<Parameter::Specific>& specific,
OpenEffectReturn* ret) override;
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
- ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
- ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
- Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
- std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
- RetCode releaseContext() override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process)
+ REQUIRES(mImplMutex) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> getContext() override { return mContext; }
std::string getEffectName() override { return kEffectName; }
private:
- std::shared_ptr<DynamicsProcessingContext> mContext;
+ std::shared_ptr<DynamicsProcessingContext> mContext GUARDED_BY(mImplMutex);
ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
bool isParamInRange(const Parameter::Specific& specific);
};
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
index f3a3860..042b063 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
@@ -63,6 +63,9 @@
}
RetCode DynamicsProcessingContext::setCommon(const Parameter::Common& common) {
+ if(auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
+ return ret;
+ }
mCommon = common;
init();
LOG(INFO) << __func__ << common.toString();
@@ -312,7 +315,9 @@
void DynamicsProcessingContext::init() {
std::lock_guard lg(mMutex);
- mState = DYNAMICS_PROCESSING_STATE_INITIALIZED;
+ if (mState == DYNAMICS_PROCESSING_STATE_UNINITIALIZED) {
+ mState = DYNAMICS_PROCESSING_STATE_INITIALIZED;
+ }
mChannelCount = static_cast<int>(::aidl::android::hardware::audio::common::getChannelCount(
mCommon.input.base.channelMask));
}
diff --git a/media/libeffects/hapticgenerator/Android.bp b/media/libeffects/hapticgenerator/Android.bp
index cc19a80..7d96b53 100644
--- a/media/libeffects/hapticgenerator/Android.bp
+++ b/media/libeffects/hapticgenerator/Android.bp
@@ -84,6 +84,6 @@
],
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
index fe9616a..53dcd49 100644
--- a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
+++ b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
@@ -33,16 +33,18 @@
LOG(DEBUG) << __func__;
}
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
- ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
- ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
- Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
- std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
- RetCode releaseContext() override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process)
+ REQUIRES(mImplMutex) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> getContext() override { return mContext; }
std::string getEffectName() override { return kEffectName; }
private:
diff --git a/media/libeffects/loudness/Android.bp b/media/libeffects/loudness/Android.bp
index 05bbec3..46e4669 100644
--- a/media/libeffects/loudness/Android.bp
+++ b/media/libeffects/loudness/Android.bp
@@ -69,6 +69,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h
index 5b9e924..e2e716c 100644
--- a/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h
+++ b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h
@@ -33,22 +33,25 @@
LOG(DEBUG) << __func__;
}
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
- ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
- ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
- Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
- std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
- RetCode releaseContext() override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process)
+ REQUIRES(mImplMutex) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> getContext() override { return mContext; }
std::string getEffectName() override { return kEffectName; }
private:
- std::shared_ptr<LoudnessEnhancerContext> mContext;
+ std::shared_ptr<LoudnessEnhancerContext> mContext GUARDED_BY(mImplMutex);
ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
index 3148d36..257e972 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
@@ -425,10 +425,6 @@
return mContext;
}
-std::shared_ptr<EffectContext> EffectBundleAidl::getContext() {
- return mContext;
-}
-
RetCode EffectBundleAidl::releaseContext() {
if (mContext) {
GlobalSession::getGlobalSession().releaseSession(mType, mContext->getSessionId());
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
index ec1abe8..429e941 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
@@ -36,41 +36,47 @@
~EffectBundleAidl() override;
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
- ndk::ScopedAStatus setParameterCommon(const Parameter& param) override;
- ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
- ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
- Parameter::Specific* specific) override;
+ ndk::ScopedAStatus setParameterCommon(const Parameter& param) REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
- std::shared_ptr<EffectContext> getContext() override;
- RetCode releaseContext() override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+ REQUIRES(mImplMutex) override;
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
std::string getEffectName() override { return *mEffectName; }
private:
- std::shared_ptr<BundleContext> mContext;
+ std::shared_ptr<BundleContext> mContext GUARDED_BY(mImplMutex);
const Descriptor* mDescriptor;
const std::string* mEffectName;
lvm::BundleEffectType mType = lvm::BundleEffectType::EQUALIZER;
IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
- ndk::ScopedAStatus setParameterBassBoost(const Parameter::Specific& specific);
- ndk::ScopedAStatus getParameterBassBoost(const BassBoost::Id& id,
- Parameter::Specific* specific);
+ ndk::ScopedAStatus setParameterBassBoost(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
+ ndk::ScopedAStatus getParameterBassBoost(const BassBoost::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
- ndk::ScopedAStatus setParameterEqualizer(const Parameter::Specific& specific);
- ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Id& id,
- Parameter::Specific* specific);
- ndk::ScopedAStatus setParameterVolume(const Parameter::Specific& specific);
- ndk::ScopedAStatus getParameterVolume(const Volume::Id& id, Parameter::Specific* specific);
- ndk::ScopedAStatus setParameterVirtualizer(const Parameter::Specific& specific);
+ ndk::ScopedAStatus setParameterEqualizer(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
+ ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
+ ndk::ScopedAStatus setParameterVolume(const Parameter::Specific& specific) REQUIRES(mImplMutex);
+ ndk::ScopedAStatus getParameterVolume(const Volume::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
+ ndk::ScopedAStatus setParameterVirtualizer(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
ndk::ScopedAStatus getParameterVirtualizer(const Virtualizer::Id& id,
- Parameter::Specific* specific);
+ Parameter::Specific* specific) REQUIRES(mImplMutex);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index da5346f..62837b9 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -120,7 +120,6 @@
shared_libs: [
"libaudio_aidl_conversion_common_ndk",
"libaudioutils",
- "libbinder",
"liblog",
"libstagefright_foundation",
],
@@ -130,7 +129,7 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
@@ -161,6 +160,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
index b49d109..f9afe69 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
@@ -358,10 +358,6 @@
return mContext;
}
-std::shared_ptr<EffectContext> EffectReverb::getContext() {
- return mContext;
-}
-
RetCode EffectReverb::releaseContext() {
if (mContext) {
mContext.reset();
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h
index d7d2bbd..e0771a1 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h
@@ -30,35 +30,41 @@
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
- ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
- ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
- Parameter::Specific* specific) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
- std::shared_ptr<EffectContext> getContext() override;
- RetCode releaseContext() override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+ REQUIRES(mImplMutex) override;
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
std::string getEffectName() override { return *mEffectName; }
private:
- std::shared_ptr<ReverbContext> mContext;
+ std::shared_ptr<ReverbContext> mContext GUARDED_BY(mImplMutex);
const Descriptor* mDescriptor;
const std::string* mEffectName;
lvm::ReverbEffectType mType;
IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
- ndk::ScopedAStatus setParameterPresetReverb(const Parameter::Specific& specific);
+ ndk::ScopedAStatus setParameterPresetReverb(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
ndk::ScopedAStatus getParameterPresetReverb(const PresetReverb::Id& id,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
- ndk::ScopedAStatus setParameterEnvironmentalReverb(const Parameter::Specific& specific);
+ ndk::ScopedAStatus setParameterEnvironmentalReverb(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
ndk::ScopedAStatus getParameterEnvironmentalReverb(const EnvironmentalReverb::Id& id,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/Android.bp b/media/libeffects/preprocessing/Android.bp
index 564eb36..994b061 100644
--- a/media/libeffects/preprocessing/Android.bp
+++ b/media/libeffects/preprocessing/Android.bp
@@ -89,6 +89,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp b/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
index e8ae8b3..7552804 100644
--- a/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
+++ b/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
@@ -412,10 +412,6 @@
return mContext;
}
-std::shared_ptr<EffectContext> EffectPreProcessing::getContext() {
- return mContext;
-}
-
RetCode EffectPreProcessing::releaseContext() {
if (mContext) {
PreProcessingSession::getPreProcessingSession().releaseSession(mType,
diff --git a/media/libeffects/preprocessing/aidl/EffectPreProcessing.h b/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
index fad848a..9ce5597 100644
--- a/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
+++ b/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
@@ -31,41 +31,51 @@
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
- ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
- ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
- Parameter::Specific* specific) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
- std::shared_ptr<EffectContext> getContext() override;
- RetCode releaseContext() override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+ REQUIRES(mImplMutex) override;
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
std::string getEffectName() override { return *mEffectName; }
private:
- std::shared_ptr<PreProcessingContext> mContext;
+ std::shared_ptr<PreProcessingContext> mContext GUARDED_BY(mImplMutex);
const Descriptor* mDescriptor;
const std::string* mEffectName;
PreProcessingEffectType mType;
- ndk::ScopedAStatus setParameterAcousticEchoCanceler(const Parameter::Specific& specific);
+ ndk::ScopedAStatus setParameterAcousticEchoCanceler(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
ndk::ScopedAStatus getParameterAcousticEchoCanceler(const AcousticEchoCanceler::Id& id,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
- ndk::ScopedAStatus setParameterAutomaticGainControlV1(const Parameter::Specific& specific);
+ ndk::ScopedAStatus setParameterAutomaticGainControlV1(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
ndk::ScopedAStatus getParameterAutomaticGainControlV1(const AutomaticGainControlV1::Id& id,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
- ndk::ScopedAStatus setParameterAutomaticGainControlV2(const Parameter::Specific& specific);
+ ndk::ScopedAStatus setParameterAutomaticGainControlV2(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
ndk::ScopedAStatus getParameterAutomaticGainControlV2(const AutomaticGainControlV2::Id& id,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
- ndk::ScopedAStatus setParameterNoiseSuppression(const Parameter::Specific& specific);
+ ndk::ScopedAStatus setParameterNoiseSuppression(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
ndk::ScopedAStatus getParameterNoiseSuppression(const NoiseSuppression::Id& id,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp b/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
index c1e4eda..2c44e5c 100644
--- a/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
+++ b/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
@@ -141,6 +141,9 @@
}
RetCode PreProcessingContext::setCommon(const Parameter::Common& common) {
+ if(auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
+ return ret;
+ }
mCommon = common;
updateConfigs(common);
return RetCode::SUCCESS;
diff --git a/media/libeffects/visualizer/Android.bp b/media/libeffects/visualizer/Android.bp
index a8b665b..66ceadf 100644
--- a/media/libeffects/visualizer/Android.bp
+++ b/media/libeffects/visualizer/Android.bp
@@ -70,6 +70,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/visualizer/aidl/Visualizer.h b/media/libeffects/visualizer/aidl/Visualizer.h
index ec725db..b48c85e 100644
--- a/media/libeffects/visualizer/aidl/Visualizer.h
+++ b/media/libeffects/visualizer/aidl/Visualizer.h
@@ -35,23 +35,25 @@
LOG(DEBUG) << __func__;
}
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
- ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
- ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
- Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
- std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
- RetCode releaseContext() override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process)
+ REQUIRES(mImplMutex) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> getContext() override { return mContext; }
std::string getEffectName() override { return kEffectName; }
private:
static const std::vector<Range::VisualizerRange> kRanges;
- std::shared_ptr<VisualizerContext> mContext;
+ std::shared_ptr<VisualizerContext> mContext GUARDED_BY(mImplMutex);
ndk::ScopedAStatus getParameterVisualizer(const Visualizer::Tag& tag,
- Parameter::Specific* specific);
+ Parameter::Specific* specific) REQUIRES(mImplMutex);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libmediaplayerservice/fuzzer/Android.bp b/media/libmediaplayerservice/fuzzer/Android.bp
index b511372..74b0a85 100644
--- a/media/libmediaplayerservice/fuzzer/Android.bp
+++ b/media/libmediaplayerservice/fuzzer/Android.bp
@@ -110,6 +110,17 @@
"libresourcemanagerservice",
"libmediametricsservice",
"mediametricsservice-aidl-cpp",
+ "libcameraservice",
+ "android.hardware.camera.common@1.0",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.camera.provider@2.5",
+ "android.hardware.camera.provider@2.6",
+ "android.hardware.camera.provider@2.7",
+ "android.hardware.camera.provider-V3-ndk",
+ "android.hardware.camera.device@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.4",
+ "libaudiohal@7.0",
],
header_libs: [
"libaudiohal_headers",
@@ -124,14 +135,19 @@
],
defaults: [
"libmediaplayerserviceFuzzer_defaults",
+ "libmediaplayerservice_defaults",
],
static_libs: [
"libplayerservice_datasource",
],
shared_libs: [
+ "libmediaplayerservice",
"libdatasource",
"libdrmframework",
+ "libstagefright_httplive",
+ "libmediaextractorservice",
],
+ include_dirs: ["frameworks/av/services/mediaextractor"],
}
cc_fuzz {
diff --git a/media/libmediaplayerservice/fuzzer/mediarecorder_fuzzer.cpp b/media/libmediaplayerservice/fuzzer/mediarecorder_fuzzer.cpp
index fdac1a1..2518c21 100644
--- a/media/libmediaplayerservice/fuzzer/mediarecorder_fuzzer.cpp
+++ b/media/libmediaplayerservice/fuzzer/mediarecorder_fuzzer.cpp
@@ -15,22 +15,22 @@
*
*/
-#include <media/stagefright/foundation/AString.h>
-#include "fuzzer/FuzzedDataProvider.h"
-
#include <AudioFlinger.h>
#include <MediaPlayerService.h>
#include <ResourceManagerService.h>
-#include <fakeservicemanager/FakeServiceManager.h>
#include <StagefrightRecorder.h>
#include <camera/Camera.h>
#include <camera/android/hardware/ICamera.h>
+#include <fakeservicemanager/FakeServiceManager.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <media/stagefright/PersistentSurface.h>
+#include <media/stagefright/foundation/AString.h>
#include <mediametricsservice/MediaMetricsService.h>
#include <thread>
+#include "CameraService.h"
+#include "fuzzer/FuzzedDataProvider.h"
using namespace std;
using namespace android;
@@ -46,32 +46,27 @@
AUDIO_SOURCE_VOICE_RECOGNITION, AUDIO_SOURCE_VOICE_COMMUNICATION,
AUDIO_SOURCE_REMOTE_SUBMIX, AUDIO_SOURCE_UNPROCESSED,
AUDIO_SOURCE_VOICE_PERFORMANCE, AUDIO_SOURCE_ECHO_REFERENCE,
- AUDIO_SOURCE_FM_TUNER, AUDIO_SOURCE_HOTWORD};
+ AUDIO_SOURCE_FM_TUNER, AUDIO_SOURCE_HOTWORD,
+ AUDIO_SOURCE_ULTRASOUND};
+
+constexpr output_format kOutputFormat[] = {
+ OUTPUT_FORMAT_DEFAULT, OUTPUT_FORMAT_THREE_GPP,
+ OUTPUT_FORMAT_MPEG_4, OUTPUT_FORMAT_AUDIO_ONLY_START,
+ OUTPUT_FORMAT_RAW_AMR, OUTPUT_FORMAT_AMR_NB,
+ OUTPUT_FORMAT_AMR_WB, OUTPUT_FORMAT_AAC_ADTS,
+ OUTPUT_FORMAT_AUDIO_ONLY_END, OUTPUT_FORMAT_RTP_AVP,
+ OUTPUT_FORMAT_MPEG2TS, OUTPUT_FORMAT_WEBM,
+ OUTPUT_FORMAT_HEIF, OUTPUT_FORMAT_OGG,
+ OUTPUT_FORMAT_LIST_END};
+
+constexpr video_encoder kVideoEncoder[] = {
+ VIDEO_ENCODER_DEFAULT, VIDEO_ENCODER_H263, VIDEO_ENCODER_H264,
+ VIDEO_ENCODER_MPEG_4_SP, VIDEO_ENCODER_VP8, VIDEO_ENCODER_HEVC,
+ VIDEO_ENCODER_DOLBY_VISION, VIDEO_ENCODER_AV1, VIDEO_ENCODER_LIST_END};
constexpr audio_microphone_direction_t kSupportedMicrophoneDirections[] = {
MIC_DIRECTION_UNSPECIFIED, MIC_DIRECTION_FRONT, MIC_DIRECTION_BACK, MIC_DIRECTION_EXTERNAL};
-struct RecordingConfig {
- output_format outputFormat;
- audio_encoder audioEncoder;
- video_encoder videoEncoder;
-};
-
-const struct RecordingConfig kRecordingConfigList[] = {
- {OUTPUT_FORMAT_AMR_NB, AUDIO_ENCODER_AMR_NB, VIDEO_ENCODER_DEFAULT},
- {OUTPUT_FORMAT_AMR_WB, AUDIO_ENCODER_AMR_WB, VIDEO_ENCODER_DEFAULT},
- {OUTPUT_FORMAT_AAC_ADTS, AUDIO_ENCODER_AAC, VIDEO_ENCODER_DEFAULT},
- {OUTPUT_FORMAT_AAC_ADTS, AUDIO_ENCODER_HE_AAC, VIDEO_ENCODER_DEFAULT},
- {OUTPUT_FORMAT_AAC_ADTS, AUDIO_ENCODER_AAC_ELD, VIDEO_ENCODER_DEFAULT},
- {OUTPUT_FORMAT_OGG, AUDIO_ENCODER_OPUS, VIDEO_ENCODER_DEFAULT},
- {OUTPUT_FORMAT_RTP_AVP, AUDIO_ENCODER_DEFAULT, VIDEO_ENCODER_DEFAULT},
- {OUTPUT_FORMAT_MPEG2TS, AUDIO_ENCODER_AAC, VIDEO_ENCODER_H264},
- {OUTPUT_FORMAT_WEBM, AUDIO_ENCODER_VORBIS, VIDEO_ENCODER_VP8},
- {OUTPUT_FORMAT_THREE_GPP, AUDIO_ENCODER_DEFAULT, VIDEO_ENCODER_MPEG_4_SP},
- {OUTPUT_FORMAT_MPEG_4, AUDIO_ENCODER_AAC, VIDEO_ENCODER_H264},
- {OUTPUT_FORMAT_MPEG_4, AUDIO_ENCODER_DEFAULT, VIDEO_ENCODER_MPEG_4_SP},
- {OUTPUT_FORMAT_MPEG_4, AUDIO_ENCODER_DEFAULT, VIDEO_ENCODER_HEVC}};
-
const string kParametersList[] = {"max-duration",
"max-filesize",
"interleave-duration-us",
@@ -104,14 +99,16 @@
"rtp-param-ext-cvo-degrees",
"video-param-request-i-frame",
"rtp-param-set-socket-dscp",
- "rtp-param-set-socket-network"};
+ "rtp-param-set-socket-network",
+ "rtp-param-set-socket-ecn",
+ "rtp-param-remote-ip",
+ "rtp-param-set-socket-network",
+ "log-session-id"};
-constexpr int32_t kMaxSleepTimeInMs = 100;
-constexpr int32_t kMinSleepTimeInMs = 0;
constexpr int32_t kMinVideoSize = 2;
constexpr int32_t kMaxVideoSize = 8192;
-constexpr int32_t kNumRecordMin = 1;
-constexpr int32_t kNumRecordMax = 10;
+const char kOutputFile[] = "OutputFile";
+const char kNextOutputFile[] = "NextOutputFile";
class TestAudioDeviceCallback : public AudioSystem::AudioDeviceCallback {
public:
@@ -194,8 +191,7 @@
int32_t max;
mStfRecorder->getMaxAmplitude(&max);
- int32_t deviceId = mFdp.ConsumeIntegral<int32_t>();
- mStfRecorder->setInputDevice(deviceId);
+ int32_t deviceId;
mStfRecorder->getRoutedDeviceId(&deviceId);
vector<android::media::MicrophoneInfoFw> activeMicrophones{};
@@ -213,101 +209,189 @@
sp<IGraphicBufferProducer> buffer = mStfRecorder->querySurfaceMediaSource();
}
-void MediaRecorderClientFuzzer::dumpInfo() {
- int32_t dumpFd = memfd_create("DumpFile", MFD_ALLOW_SEALING);
- Vector<String16> args;
- args.push_back(String16(mFdp.ConsumeRandomLengthString().c_str()));
- mStfRecorder->dump(dumpFd, args);
- close(dumpFd);
-}
-
-void MediaRecorderClientFuzzer::setConfig() {
- mStfRecorder->setOutputFile(mMediaRecorderOutputFd);
- mStfRecorder->setAudioSource(mFdp.PickValueInArray(kSupportedAudioSources));
- mStfRecorder->setVideoSource(mFdp.PickValueInArray(kSupportedVideoSources));
- mStfRecorder->setPreferredMicrophoneDirection(
- mFdp.PickValueInArray(kSupportedMicrophoneDirections));
- mStfRecorder->setPrivacySensitive(mFdp.ConsumeBool());
- bool isPrivacySensitive;
- mStfRecorder->isPrivacySensitive(&isPrivacySensitive);
- mStfRecorder->setVideoSize(mFdp.ConsumeIntegralInRange<int32_t>(kMinVideoSize, kMaxVideoSize),
- mFdp.ConsumeIntegralInRange<int32_t>(kMinVideoSize, kMaxVideoSize));
- mStfRecorder->setVideoFrameRate(mFdp.ConsumeIntegral<int32_t>());
- mStfRecorder->enableAudioDeviceCallback(mFdp.ConsumeBool());
- mStfRecorder->setPreferredMicrophoneFieldDimension(mFdp.ConsumeFloatingPoint<float>());
- mStfRecorder->setClientName(String16(mFdp.ConsumeRandomLengthString().c_str()));
-
- int32_t Idx = mFdp.ConsumeIntegralInRange<int32_t>(0, size(kRecordingConfigList) - 1);
- mStfRecorder->setOutputFormat(kRecordingConfigList[Idx].outputFormat);
- mStfRecorder->setAudioEncoder(kRecordingConfigList[Idx].audioEncoder);
- mStfRecorder->setVideoEncoder(kRecordingConfigList[Idx].videoEncoder);
-
- int32_t nextOutputFd = memfd_create("NextOutputFile", MFD_ALLOW_SEALING);
- mStfRecorder->setNextOutputFile(nextOutputFd);
- close(nextOutputFd);
-
- for (Idx = 0; Idx < size(kParametersList); ++Idx) {
- if (mFdp.ConsumeBool()) {
- int32_t value = mFdp.ConsumeIntegral<int32_t>();
- mStfRecorder->setParameters(
- String8((kParametersList[Idx] + "=" + to_string(value)).c_str()));
- }
+template <typename FuncWrapper>
+void callMediaAPI(FuncWrapper funcWrapper, FuzzedDataProvider* fdp) {
+ if (fdp->ConsumeBool()) {
+ funcWrapper();
}
}
-MediaRecorderClientFuzzer::MediaRecorderClientFuzzer(const uint8_t *data, size_t size)
- : mFdp(data, size), mMediaRecorderOutputFd(memfd_create("OutputFile", MFD_ALLOW_SEALING)) {
+void MediaRecorderClientFuzzer::setConfig() {
+ callMediaAPI(
+ [this]() {
+ mSurfaceControl = mComposerClient.createSurface(
+ String8(mFdp.ConsumeRandomLengthString().c_str()) /* name */,
+ mFdp.ConsumeIntegral<uint32_t>() /* width */,
+ mFdp.ConsumeIntegral<uint32_t>() /* height */,
+ mFdp.ConsumeIntegral<int32_t>() /* pixel-format */,
+ mFdp.ConsumeIntegral<int32_t>() /* flags */);
+ if (mSurfaceControl) {
+ mSurface = mSurfaceControl->getSurface();
+ mStfRecorder->setPreviewSurface(mSurface->getIGraphicBufferProducer());
+ }
+ },
+ &mFdp);
+
+ callMediaAPI([this]() { mStfRecorder->setInputDevice(mFdp.ConsumeIntegral<int32_t>()); },
+ &mFdp);
+
+ callMediaAPI(
+ [this]() {
+ sp<TestMediaRecorderClient> listener = sp<TestMediaRecorderClient>::make();
+ mStfRecorder->setListener(listener);
+ },
+ &mFdp);
+
+ callMediaAPI(
+ [this]() {
+ sp<TestCamera> testCamera = sp<TestCamera>::make();
+ sp<Camera> camera = Camera::create(testCamera);
+ mStfRecorder->setCamera(camera->remote(), camera->getRecordingProxy());
+ },
+ &mFdp);
+
+ callMediaAPI(
+ [this]() {
+ sp<PersistentSurface> persistentSurface = sp<PersistentSurface>::make();
+ mStfRecorder->setInputSurface(persistentSurface);
+ },
+ &mFdp);
+
+ callMediaAPI(
+ [this]() {
+ sp<TestAudioDeviceCallback> callback = sp<TestAudioDeviceCallback>::make();
+ mStfRecorder->setAudioDeviceCallback(callback);
+ mStfRecorder->setOutputFile(mMediaRecorderOutputFd);
+ },
+ &mFdp);
+
+ callMediaAPI(
+ [this]() {
+ mStfRecorder->setAudioSource(mFdp.PickValueInArray(kSupportedAudioSources));
+ },
+ &mFdp);
+
+ callMediaAPI(
+ [this]() {
+ mStfRecorder->setVideoSource(mFdp.PickValueInArray(kSupportedVideoSources));
+ },
+ &mFdp);
+
+ callMediaAPI(
+ [this]() {
+ mStfRecorder->setPreferredMicrophoneDirection(
+ mFdp.PickValueInArray(kSupportedMicrophoneDirections));
+ },
+ &mFdp);
+
+ callMediaAPI([this]() { mStfRecorder->setPrivacySensitive(mFdp.ConsumeBool()); }, &mFdp);
+
+ callMediaAPI(
+ [this]() {
+ bool isPrivacySensitive;
+ mStfRecorder->isPrivacySensitive(&isPrivacySensitive);
+ },
+ &mFdp);
+
+ callMediaAPI(
+ [this]() {
+ mStfRecorder->setVideoSize(mFdp.ConsumeIntegralInRange<int32_t>(
+ kMinVideoSize, kMaxVideoSize) /* width */,
+ mFdp.ConsumeIntegralInRange<int32_t>(
+ kMinVideoSize, kMaxVideoSize) /* height */);
+ },
+ &mFdp);
+
+ callMediaAPI([this]() { mStfRecorder->setVideoFrameRate(mFdp.ConsumeIntegral<int32_t>()); },
+ &mFdp);
+
+ callMediaAPI([this]() { mStfRecorder->enableAudioDeviceCallback(mFdp.ConsumeBool()); }, &mFdp);
+
+ callMediaAPI(
+ [this]() {
+ mStfRecorder->setPreferredMicrophoneFieldDimension(
+ mFdp.ConsumeFloatingPoint<float>());
+ },
+ &mFdp);
+
+ callMediaAPI(
+ [this]() {
+ mStfRecorder->setClientName(String16(mFdp.ConsumeRandomLengthString().c_str()));
+ },
+ &mFdp);
+
+ callMediaAPI(
+ [this]() {
+ output_format OutputFormat = mFdp.PickValueInArray(kOutputFormat);
+ audio_encoder AudioEncoderFormat =
+ (audio_encoder)mFdp.ConsumeIntegralInRange<int32_t>(AUDIO_ENCODER_DEFAULT,
+ AUDIO_ENCODER_LIST_END);
+ video_encoder VideoEncoderFormat = mFdp.PickValueInArray(kVideoEncoder);
+ if (OutputFormat == OUTPUT_FORMAT_AMR_NB) {
+ AudioEncoderFormat =
+ mFdp.ConsumeBool() ? AUDIO_ENCODER_DEFAULT : AUDIO_ENCODER_AMR_NB;
+ } else if (OutputFormat == OUTPUT_FORMAT_AMR_WB) {
+ AudioEncoderFormat = AUDIO_ENCODER_AMR_WB;
+ } else if (OutputFormat == OUTPUT_FORMAT_AAC_ADIF ||
+ OutputFormat == OUTPUT_FORMAT_AAC_ADTS ||
+ OutputFormat == OUTPUT_FORMAT_MPEG2TS) {
+ AudioEncoderFormat = (audio_encoder)mFdp.ConsumeIntegralInRange<int32_t>(
+ AUDIO_ENCODER_AAC, AUDIO_ENCODER_AAC_ELD);
+ if (OutputFormat == OUTPUT_FORMAT_MPEG2TS) {
+ VideoEncoderFormat = VIDEO_ENCODER_H264;
+ }
+ }
+ mStfRecorder->setOutputFormat(OutputFormat);
+ mStfRecorder->setAudioEncoder(AudioEncoderFormat);
+ mStfRecorder->setVideoEncoder(VideoEncoderFormat);
+ },
+ &mFdp);
+
+ callMediaAPI(
+ [this]() {
+ int32_t nextOutputFd = memfd_create(kNextOutputFile, MFD_ALLOW_SEALING);
+ mStfRecorder->setNextOutputFile(nextOutputFd);
+ close(nextOutputFd);
+ },
+ &mFdp);
+
+ callMediaAPI(
+ [this]() {
+ for (int32_t idx = 0; idx < size(kParametersList); ++idx) {
+ if (mFdp.ConsumeBool()) {
+ int32_t value = mFdp.ConsumeIntegral<int32_t>();
+ mStfRecorder->setParameters(
+ String8((kParametersList[idx] + "=" + to_string(value)).c_str()));
+ }
+ }
+ },
+ &mFdp);
+}
+
+MediaRecorderClientFuzzer::MediaRecorderClientFuzzer(const uint8_t* data, size_t size)
+ : mFdp(data, size), mMediaRecorderOutputFd(memfd_create(kOutputFile, MFD_ALLOW_SEALING)) {
AttributionSourceState attributionSource;
attributionSource.packageName = mFdp.ConsumeRandomLengthString().c_str();
attributionSource.token = sp<BBinder>::make();
mStfRecorder = make_unique<StagefrightRecorder>(attributionSource);
-
- mSurfaceControl = mComposerClient.createSurface(
- String8(mFdp.ConsumeRandomLengthString().c_str()), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<int32_t>(),
- mFdp.ConsumeIntegral<int32_t>());
- if (mSurfaceControl) {
- mSurface = mSurfaceControl->getSurface();
- mStfRecorder->setPreviewSurface(mSurface->getIGraphicBufferProducer());
- }
-
- sp<TestMediaRecorderClient> listener = sp<TestMediaRecorderClient>::make();
- mStfRecorder->setListener(listener);
-
- sp<TestCamera> testCamera = sp<TestCamera>::make();
- sp<Camera> camera = Camera::create(testCamera);
- mStfRecorder->setCamera(camera->remote(), camera->getRecordingProxy());
-
- sp<PersistentSurface> persistentSurface = sp<PersistentSurface>::make();
- mStfRecorder->setInputSurface(persistentSurface);
-
- sp<TestAudioDeviceCallback> callback = sp<TestAudioDeviceCallback>::make();
- mStfRecorder->setAudioDeviceCallback(callback);
}
void MediaRecorderClientFuzzer::process() {
- setConfig();
-
mStfRecorder->init();
mStfRecorder->prepare();
- size_t numRecord = mFdp.ConsumeIntegralInRange<size_t>(kNumRecordMin, kNumRecordMax);
- for (size_t Idx = 0; Idx < numRecord; ++Idx) {
- mStfRecorder->start();
- this_thread::sleep_for(chrono::milliseconds(
- mFdp.ConsumeIntegralInRange<int32_t>(kMinSleepTimeInMs, kMaxSleepTimeInMs)));
- mStfRecorder->pause();
- this_thread::sleep_for(chrono::milliseconds(
- mFdp.ConsumeIntegralInRange<int32_t>(kMinSleepTimeInMs, kMaxSleepTimeInMs)));
- mStfRecorder->resume();
- this_thread::sleep_for(chrono::milliseconds(
- mFdp.ConsumeIntegralInRange<int32_t>(kMinSleepTimeInMs, kMaxSleepTimeInMs)));
- mStfRecorder->stop();
+ while (mFdp.remaining_bytes()) {
+ auto invokeMediaPLayerApi = mFdp.PickValueInArray<const std::function<void()>>({
+ [&]() { setConfig(); },
+ [&]() { mStfRecorder->start(); },
+ [&]() { mStfRecorder->pause(); },
+ [&]() { mStfRecorder->resume(); },
+ [&]() { mStfRecorder->stop(); },
+ [&]() { getConfig(); },
+ [&]() { mStfRecorder->close(); },
+ [&]() { mStfRecorder->reset(); },
+ });
+ invokeMediaPLayerApi();
}
- dumpInfo();
- getConfig();
-
- mStfRecorder->close();
- mStfRecorder->reset();
}
extern "C" int LLVMFuzzerInitialize(int /* *argc */, char /* ***argv */) {
@@ -320,6 +404,7 @@
MediaPlayerService::instantiate();
AudioFlinger::instantiate();
ResourceManagerService::instantiate();
+ CameraService::instantiate();
fakeServiceManager->addService(String16(MediaMetricsService::kServiceName),
new MediaMetricsService());
return 0;
diff --git a/media/libmediaplayerservice/fuzzer/metadataretriever_fuzzer.cpp b/media/libmediaplayerservice/fuzzer/metadataretriever_fuzzer.cpp
index a7cb689..857223d 100644
--- a/media/libmediaplayerservice/fuzzer/metadataretriever_fuzzer.cpp
+++ b/media/libmediaplayerservice/fuzzer/metadataretriever_fuzzer.cpp
@@ -15,6 +15,8 @@
*
*/
+#include <MediaExtractorService.h>
+#include <MediaPlayerService.h>
#include <StagefrightMetadataRetriever.h>
#include <binder/ProcessState.h>
#include <datasource/FileSource.h>
@@ -54,58 +56,96 @@
MEDIA_MIMETYPE_CONTAINER_MPEG2PS, MEDIA_MIMETYPE_CONTAINER_HEIF,
MEDIA_MIMETYPE_TEXT_3GPP, MEDIA_MIMETYPE_TEXT_SUBRIP,
MEDIA_MIMETYPE_TEXT_VTT, MEDIA_MIMETYPE_TEXT_CEA_608,
- MEDIA_MIMETYPE_TEXT_CEA_708, MEDIA_MIMETYPE_DATA_TIMED_ID3};
+ MEDIA_MIMETYPE_TEXT_CEA_708, MEDIA_MIMETYPE_DATA_TIMED_ID3,
+ MEDIA_MIMETYPE_IMAGE_AVIF, MEDIA_MIMETYPE_AUDIO_MPEGH_MHA1,
+ MEDIA_MIMETYPE_AUDIO_MPEGH_MHM1, MEDIA_MIMETYPE_AUDIO_MPEGH_BL_L3,
+ MEDIA_MIMETYPE_AUDIO_MPEGH_BL_L4, MEDIA_MIMETYPE_AUDIO_MPEGH_LC_L3,
+ MEDIA_MIMETYPE_AUDIO_MPEGH_LC_L4, MEDIA_MIMETYPE_AUDIO_DTS,
+ MEDIA_MIMETYPE_AUDIO_DTS_HD, MEDIA_MIMETYPE_AUDIO_DTS_HD_MA,
+ MEDIA_MIMETYPE_AUDIO_DTS_UHD, MEDIA_MIMETYPE_AUDIO_DTS_UHD_P1,
+ MEDIA_MIMETYPE_AUDIO_DTS_UHD_P2, MEDIA_MIMETYPE_AUDIO_EVRC,
+ MEDIA_MIMETYPE_AUDIO_EVRCB, MEDIA_MIMETYPE_AUDIO_EVRCWB,
+ MEDIA_MIMETYPE_AUDIO_EVRCNW, MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS,
+ MEDIA_MIMETYPE_AUDIO_APTX, MEDIA_MIMETYPE_AUDIO_DRA,
+ MEDIA_MIMETYPE_AUDIO_DOLBY_MAT, MEDIA_MIMETYPE_AUDIO_DOLBY_TRUEHD,
+ MEDIA_MIMETYPE_AUDIO_DOLBY_MAT_1_0,MEDIA_MIMETYPE_AUDIO_AAC_MP4,
+ MEDIA_MIMETYPE_AUDIO_DOLBY_MAT_2_0,MEDIA_MIMETYPE_AUDIO_DOLBY_MAT_2_1,
+ MEDIA_MIMETYPE_AUDIO_AAC_MAIN, MEDIA_MIMETYPE_AUDIO_AAC_LC,
+ MEDIA_MIMETYPE_AUDIO_AAC_SSR, MEDIA_MIMETYPE_AUDIO_AAC_LTP,
+ MEDIA_MIMETYPE_AUDIO_AAC_HE_V1, MEDIA_MIMETYPE_AUDIO_AAC_SCALABLE,
+ MEDIA_MIMETYPE_AUDIO_AAC_ERLC, MEDIA_MIMETYPE_AUDIO_AAC_ADTS_MAIN,
+ MEDIA_MIMETYPE_AUDIO_AAC_HE_V2, MEDIA_MIMETYPE_AUDIO_AAC_ADTS_HE_V1,
+ MEDIA_MIMETYPE_AUDIO_AAC_XHE, MEDIA_MIMETYPE_AUDIO_AAC_ADTS_HE_V2,
+ MEDIA_MIMETYPE_AUDIO_AAC_LD, MEDIA_MIMETYPE_AUDIO_AAC_ADTS_LC,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_SSR, MEDIA_MIMETYPE_AUDIO_AAC_ADTS_LTP,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADIF, MEDIA_MIMETYPE_AUDIO_IEC60958,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_ERLC,MEDIA_MIMETYPE_AUDIO_AAC_ADTS_LD,
+ MEDIA_MIMETYPE_AUDIO_AAC_ELD, MEDIA_MIMETYPE_AUDIO_AAC_LATM_HE_V1,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_XHE, MEDIA_MIMETYPE_AUDIO_AAC_LATM_LC,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_ELD, MEDIA_MIMETYPE_AUDIO_AAC_LATM_HE_V2,
+ MEDIA_MIMETYPE_AUDIO_IEC61937,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_SCALABLE,};
+
+constexpr size_t kMaxSize = 100;
class MetadataRetrieverFuzzer {
public:
MetadataRetrieverFuzzer(const uint8_t *data, size_t size)
- : mFdp(data, size),
- mMdRetriever(new StagefrightMetadataRetriever()),
- mDataSourceFd(memfd_create("InputFile", MFD_ALLOW_SEALING)) {}
- ~MetadataRetrieverFuzzer() { close(mDataSourceFd); }
+ : mFdp(data, size), mMdRetriever(new StagefrightMetadataRetriever()) {}
bool setDataSource(const uint8_t *data, size_t size);
void getData();
private:
FuzzedDataProvider mFdp;
sp<StagefrightMetadataRetriever> mMdRetriever = nullptr;
- const int32_t mDataSourceFd;
+ int32_t mDataSourceFd;
};
void MetadataRetrieverFuzzer::getData() {
- int64_t timeUs = mFdp.ConsumeIntegral<int64_t>();
- int32_t option = mFdp.ConsumeIntegral<int32_t>();
- int32_t colorFormat = mFdp.ConsumeIntegral<int32_t>();
- bool metaOnly = mFdp.ConsumeBool();
- mMdRetriever->getFrameAtTime(timeUs, option, colorFormat, metaOnly);
-
- int32_t index = mFdp.ConsumeIntegral<int32_t>();
- colorFormat = mFdp.ConsumeIntegral<int32_t>();
- metaOnly = mFdp.ConsumeBool();
- bool thumbnail = mFdp.ConsumeBool();
- mMdRetriever->getImageAtIndex(index, colorFormat, metaOnly, thumbnail);
-
- index = mFdp.ConsumeIntegral<int32_t>();
- colorFormat = mFdp.ConsumeIntegral<int32_t>();
- int32_t left = mFdp.ConsumeIntegral<int32_t>();
- int32_t top = mFdp.ConsumeIntegral<int32_t>();
- int32_t right = mFdp.ConsumeIntegral<int32_t>();
- int32_t bottom = mFdp.ConsumeIntegral<int32_t>();
- mMdRetriever->getImageRectAtIndex(index, colorFormat, left, top, right, bottom);
-
- index = mFdp.ConsumeIntegral<int32_t>();
- colorFormat = mFdp.ConsumeIntegral<int32_t>();
- metaOnly = mFdp.ConsumeBool();
- mMdRetriever->getFrameAtIndex(index, colorFormat, metaOnly);
-
- mMdRetriever->extractAlbumArt();
-
- int32_t keyCode = mFdp.ConsumeIntegral<int32_t>();
- mMdRetriever->extractMetadata(keyCode);
+ while (mFdp.remaining_bytes()) {
+ auto invokeMediaApi = mFdp.PickValueInArray<const std::function<void()>>({
+ [&]() {
+ mMdRetriever->getFrameAtTime(mFdp.ConsumeIntegral<int64_t>() /* timeUs */,
+ mFdp.ConsumeIntegral<int32_t>() /* option */,
+ mFdp.ConsumeIntegral<int32_t>() /* colorFormat */,
+ mFdp.ConsumeBool() /* metaOnly */);
+ },
+ [&]() {
+ mMdRetriever->getImageAtIndex(mFdp.ConsumeIntegral<int32_t>() /* index */,
+ mFdp.ConsumeIntegral<int32_t>() /* colorFormat */,
+ mFdp.ConsumeBool() /* metaOnly */,
+ mFdp.ConsumeBool() /* thumbnail */);
+ },
+ [&]() {
+ mMdRetriever->getImageRectAtIndex(
+ mFdp.ConsumeIntegral<int32_t>() /* index */,
+ mFdp.ConsumeIntegral<int32_t>() /* colorFormat */,
+ mFdp.ConsumeIntegral<int32_t>() /* left */,
+ mFdp.ConsumeIntegral<int32_t>() /* top */,
+ mFdp.ConsumeIntegral<int32_t>() /* right */,
+ mFdp.ConsumeIntegral<int32_t>() /* bottom */);
+ },
+ [&]() {
+ mMdRetriever->getFrameAtIndex(mFdp.ConsumeIntegral<int32_t>() /* index */,
+ mFdp.ConsumeIntegral<int32_t>() /* colorFormat */,
+ mFdp.ConsumeBool() /* metaOnly */);
+ },
+ [&]() { mMdRetriever->extractAlbumArt(); },
+ [&]() {
+ mMdRetriever->extractMetadata(mFdp.ConsumeIntegral<int32_t>() /* keyCode */);
+ },
+ });
+ invokeMediaApi();
+ }
}
bool MetadataRetrieverFuzzer::setDataSource(const uint8_t *data, size_t size) {
status_t status = -1;
+ std::unique_ptr<std::FILE, decltype(&fclose)> fp(tmpfile(), &fclose);
+ mDataSourceFd = fileno(fp.get());
+ if (mDataSourceFd < 0) {
+ return false;
+ }
enum DataSourceChoice {FromHttp, FromFd, FromFileSource, kMaxValue = FromFileSource};
switch (mFdp.ConsumeEnum<DataSourceChoice>()) {
@@ -114,7 +154,7 @@
mHeaders.add(String8(mFdp.ConsumeRandomLengthString().c_str()),
String8(mFdp.ConsumeRandomLengthString().c_str()));
- uint32_t dataBlobSize = mFdp.ConsumeIntegralInRange<uint16_t>(0, size);
+ uint32_t dataBlobSize = mFdp.ConsumeIntegralInRange<uint16_t>(0, min(kMaxSize,size));
vector<uint8_t> uriSuffix = mFdp.ConsumeBytes<uint8_t>(dataBlobSize);
string uri("data:");
@@ -146,6 +186,12 @@
return true;
}
+extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) {
+ MediaPlayerService::instantiate();
+ MediaExtractorService::instantiate();
+ return 0;
+}
+
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
MetadataRetrieverFuzzer mrtFuzzer(data, size);
ProcessState::self()->startThreadPool();
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 0af9d12..712b405 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -137,7 +137,7 @@
cflags: [
"-DDISABLE_AUDIO_SYSTEM_OFFLOAD",
],
- }
+ },
},
}
@@ -273,7 +273,7 @@
"VideoFrameSchedulerBase.cpp",
"VideoFrameScheduler.cpp",
"VideoRenderQualityTracker.cpp",
- ],
+ ],
shared_libs: [
"libstagefright_framecapture_utils",
@@ -330,7 +330,7 @@
"libmedia_ndkformatpriv",
],
- header_libs:[
+ header_libs: [
"libmediadrm_headers",
"libnativeloader-headers",
"libstagefright_xmlparser_headers",
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 46a3587..3c80f28 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -318,8 +318,8 @@
return Status::fromStatus(STATUS_INVALID_OPERATION);
}
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(this)};
+ .uid = static_cast<int32_t>(mUid),
+ .id = getId(this)};
service->removeClient(clientInfo);
*_aidl_return = true;
return Status::ok();
@@ -396,6 +396,10 @@
mCodecName = name;
}
+ inline void setImportance(int importance) {
+ mImportance = importance;
+ }
+
private:
// To get the binder interface to ResourceManagerService.
void getService() {
@@ -435,12 +439,30 @@
mGetServiceFuture = std::async(std::launch::async, [this] { getService(); });
}
+ /**
+ * Get the ClientInfo to communicate with the ResourceManager.
+ *
+ * ClientInfo includes:
+ * - {pid, uid} of the process
+ * - identifier for the client
+ * - name of the client/codec
+ * - importance associated with the client
+ */
+ inline ClientInfoParcel getClientInfo() const {
+ ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
+ .uid = static_cast<int32_t>(mUid),
+ .id = getId(mClient),
+ .name = mCodecName,
+ .importance = mImportance};
+ return std::move(clientInfo);
+ }
private:
- std::mutex mLock;
- pid_t mPid;
- uid_t mUid;
- bool mBinderDied = false;
+ std::mutex mLock;
+ bool mBinderDied = false;
+ pid_t mPid;
+ uid_t mUid;
+ int mImportance = 0;
std::string mCodecName;
/**
* Reconnecting with the ResourceManagerService, after its binder interface dies,
@@ -548,11 +570,7 @@
std::vector<MediaResourceParcel> resources;
std::copy(mMediaResourceParcel.begin(), mMediaResourceParcel.end(),
std::back_inserter(resources));
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- mService->addResource(clientInfo, mClient, resources);
+ mService->addResource(getClientInfo(), mClient, resources);
}
void MediaCodec::ResourceManagerServiceProxy::BinderDiedCallback(void* cookie) {
@@ -585,11 +603,7 @@
}
std::vector<MediaResourceParcel> resources;
resources.push_back(resource);
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->addResource(clientInfo, mClient, resources);
+ service->addResource(getClientInfo(), mClient, resources);
mMediaResourceParcel.emplace(resource);
}
@@ -603,11 +617,7 @@
}
std::vector<MediaResourceParcel> resources;
resources.push_back(resource);
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->removeResource(clientInfo, resources);
+ service->removeResource(getClientInfo(), resources);
mMediaResourceParcel.erase(resource);
}
@@ -618,11 +628,7 @@
ALOGW("Service isn't available");
return;
}
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->removeClient(clientInfo);
+ service->removeClient(getClientInfo());
mMediaResourceParcel.clear();
}
@@ -633,11 +639,7 @@
ALOGW("Service isn't available");
return;
}
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->markClientForPendingRemoval(clientInfo);
+ service->markClientForPendingRemoval(getClientInfo());
mMediaResourceParcel.clear();
}
@@ -650,11 +652,7 @@
return false;
}
bool success;
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- Status status = service->reclaimResource(clientInfo, resources, &success);
+ Status status = service->reclaimResource(getClientInfo(), resources, &success);
return status.isOk() && success;
}
@@ -665,11 +663,7 @@
ALOGW("Service isn't available");
return;
}
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->notifyClientCreated(clientInfo);
+ service->notifyClientCreated(getClientInfo());
}
void MediaCodec::ResourceManagerServiceProxy::notifyClientStarted(
@@ -680,10 +674,7 @@
ALOGW("Service isn't available");
return;
}
- clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
- clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
- clientConfig.clientInfo.id = getId(mClient);
- clientConfig.clientInfo.name = mCodecName;
+ clientConfig.clientInfo = getClientInfo();
service->notifyClientStarted(clientConfig);
}
@@ -695,10 +686,7 @@
ALOGW("Service isn't available");
return;
}
- clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
- clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
- clientConfig.clientInfo.id = getId(mClient);
- clientConfig.clientInfo.name = mCodecName;
+ clientConfig.clientInfo = getClientInfo();
service->notifyClientStopped(clientConfig);
}
@@ -710,10 +698,7 @@
ALOGW("Service isn't available");
return;
}
- clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
- clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
- clientConfig.clientInfo.id = getId(mClient);
- clientConfig.clientInfo.name = mCodecName;
+ clientConfig.clientInfo = getClientInfo();
service->notifyClientConfigChanged(clientConfig);
}
@@ -1714,6 +1699,21 @@
}
}
+void MediaCodec::updateCodecImportance(const sp<AMessage>& msg) {
+ // Update the codec importance.
+ int32_t importance = 0;
+ if (msg->findInt32(KEY_IMPORTANCE, &importance)) {
+ // Ignoring the negative importance.
+ if (importance >= 0) {
+ // Notify RM about the change in the importance.
+ mResourceManagerProxy->setImportance(importance);
+ ClientConfigParcel clientConfig;
+ initClientConfigParcel(clientConfig);
+ mResourceManagerProxy->notifyClientConfigChanged(clientConfig);
+ }
+ }
+}
+
constexpr const char *MediaCodec::asString(TunnelPeekState state, const char *default_string){
switch(state) {
case TunnelPeekState::kLegacyMode:
@@ -2222,23 +2222,9 @@
static void mapFormat(AString componentName, const sp<AMessage> &format, const char *kind,
bool reverse);
-status_t MediaCodec::configure(
- const sp<AMessage> &format,
- const sp<Surface> &nativeWindow,
- const sp<ICrypto> &crypto,
- uint32_t flags) {
- return configure(format, nativeWindow, crypto, NULL, flags);
-}
-
-status_t MediaCodec::configure(
- const sp<AMessage> &format,
- const sp<Surface> &surface,
- const sp<ICrypto> &crypto,
- const sp<IDescrambler> &descrambler,
- uint32_t flags) {
-
- sp<AMessage> msg = new AMessage(kWhatConfigure, this);
+mediametrics_handle_t MediaCodec::createMediaMetrics(const sp<AMessage>& format, uint32_t flags) {
mediametrics_handle_t nextMetricsHandle = mediametrics_create(kCodecKeyName);
+ bool isEncoder = (flags & CONFIGURE_FLAG_ENCODE);
// TODO: validity check log-session-id: it should be a 32-hex-digit.
format->findString("log-session-id", &mLogSessionId);
@@ -2253,8 +2239,7 @@
if (format->findInt32("level", &level)) {
mediametrics_setInt32(nextMetricsHandle, kCodecLevel, level);
}
- mediametrics_setInt32(nextMetricsHandle, kCodecEncoder,
- (flags & CONFIGURE_FLAG_ENCODE) ? 1 : 0);
+ mediametrics_setInt32(nextMetricsHandle, kCodecEncoder, isEncoder);
if (!mLogSessionId.empty()) {
mediametrics_setCString(nextMetricsHandle, kCodecLogSessionId, mLogSessionId.c_str());
@@ -2333,7 +2318,7 @@
}
}
- if (flags & CONFIGURE_FLAG_ENCODE) {
+ if (isEncoder) {
int8_t enableShaping = property_get_bool(enableMediaFormatShapingProperty,
enableMediaFormatShapingDefault);
if (!enableShaping) {
@@ -2378,6 +2363,31 @@
updateLowLatency(format);
+ return nextMetricsHandle;
+}
+
+status_t MediaCodec::configure(
+ const sp<AMessage> &format,
+ const sp<Surface> &nativeWindow,
+ const sp<ICrypto> &crypto,
+ uint32_t flags) {
+ return configure(format, nativeWindow, crypto, NULL, flags);
+}
+
+status_t MediaCodec::configure(
+ const sp<AMessage> &format,
+ const sp<Surface> &surface,
+ const sp<ICrypto> &crypto,
+ const sp<IDescrambler> &descrambler,
+ uint32_t flags) {
+
+ // Update the codec importance.
+ updateCodecImportance(format);
+
+ // Create and set up metrics for this codec.
+ mediametrics_handle_t nextMetricsHandle = createMediaMetrics(format, flags);
+
+ sp<AMessage> msg = new AMessage(kWhatConfigure, this);
msg->setMessage("format", format);
msg->setInt32("flags", flags);
msg->setObject("surface", surface);
@@ -6589,6 +6599,7 @@
return NO_INIT;
}
updateLowLatency(params);
+ updateCodecImportance(params);
mapFormat(mComponentName, params, nullptr, false);
updateTunnelPeek(params);
mCodec->signalSetParameters(params);
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
index f16e635..604dcb0 100644
--- a/media/libstagefright/SurfaceUtils.cpp
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -298,6 +298,11 @@
ALOGE("error pushing blank frames: lock failed: %s (%d)", strerror(-err), -err);
break;
}
+ if (img == nullptr) {
+ (void)buf->unlock(); // Since lock() was successful.
+ ALOGE("error pushing blank frames: lock succeeded: buf mapping is nullptr");
+ break;
+ }
*img = 0;
diff --git a/media/libstagefright/colorconversion/fuzzer/Android.bp b/media/libstagefright/colorconversion/fuzzer/Android.bp
index 76b054a..237e715 100644
--- a/media/libstagefright/colorconversion/fuzzer/Android.bp
+++ b/media/libstagefright/colorconversion/fuzzer/Android.bp
@@ -47,9 +47,15 @@
],
fuzz_config: {
cc: [
- "android-media-fuzzing-reports@google.com",
+ "android-fwk-video@google.com",
],
- componentid: 155276,
+ componentid: 42195,
+ hotlists: ["4593311"],
+ description: "The fuzzer targets the APIs of libstagefright_color_conversion",
+ vector: "local_no_privileges_required",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index baa5b7e..2f94e5e 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -320,6 +320,9 @@
status_t reclaim(bool force = false);
friend struct ResourceManagerClient;
+ // to create the metrics associated with this codec.
+ mediametrics_handle_t createMediaMetrics(const sp<AMessage>& format, uint32_t flags);
+
private:
enum State {
UNINITIALIZED,
@@ -462,6 +465,7 @@
void resetMetricsFields();
void updateEphemeralMediametrics(mediametrics_handle_t item);
void updateLowLatency(const sp<AMessage> &msg);
+ void updateCodecImportance(const sp<AMessage>& msg);
void onGetMetrics(const sp<AMessage>& msg);
constexpr const char *asString(TunnelPeekState state, const char *default_string="?");
void updateTunnelPeek(const sp<AMessage> &msg);
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 7334639..f4c40e1 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -794,6 +794,7 @@
inline constexpr char KEY_HDR10_PLUS_INFO[] = "hdr10-plus-info";
inline constexpr char KEY_HEIGHT[] = "height";
inline constexpr char KEY_I_FRAME_INTERVAL[] = "i-frame-interval";
+inline constexpr char KEY_IMPORTANCE[] = "importance";
inline constexpr char KEY_INTRA_REFRESH_PERIOD[] = "intra-refresh-period";
inline constexpr char KEY_IS_ADTS[] = "is-adts";
inline constexpr char KEY_IS_AUTOSELECT[] = "is-autoselect";
@@ -809,6 +810,9 @@
inline constexpr char KEY_MAX_FPS_TO_ENCODER[] = "max-fps-to-encoder";
inline constexpr char KEY_MAX_HEIGHT[] = "max-height";
inline constexpr char KEY_MAX_INPUT_SIZE[] = "max-input-size";
+inline constexpr char KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE[] = "buffer-batch-max-output-size";
+inline constexpr char KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE[] =
+ "buffer-batch-threshold-output-size";
inline constexpr char KEY_MAX_OUTPUT_CHANNEL_COUNT[] = "max-output-channel-count";
inline constexpr char KEY_MAX_PTS_GAP_TO_ENCODER[] = "max-pts-gap-to-encoder";
inline constexpr char KEY_MAX_WIDTH[] = "max-width";
diff --git a/media/module/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml b/media/module/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml
index c3a0ced..f8906dc 100644
--- a/media/module/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml
+++ b/media/module/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml
@@ -15,6 +15,7 @@
-->
<configuration description="Unit test configuration for {MODULE}">
<option name="test-suite-tag" value="TranscoderTests" />
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="false" />
<option name="push-file" key="TranscodingTestAssets" value="/data/local/tmp/TranscodingTestAssets" />
diff --git a/media/module/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp b/media/module/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
index 88c3fd3..fed8fc9 100644
--- a/media/module/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
+++ b/media/module/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
@@ -20,6 +20,7 @@
#define LOG_TAG "VideoTrackTranscoderTests"
#include <android-base/logging.h>
+#include <android/binder_process.h>
#include <fcntl.h>
#include <gtest/gtest.h>
#include <media/MediaSampleReaderNDK.h>
@@ -221,5 +222,6 @@
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
}
diff --git a/media/mtp/tests/MtpFuzzer/MtpMockHandle.h b/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
index 111485c..aa632a4 100644
--- a/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
+++ b/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
@@ -45,18 +45,18 @@
pkt.size());
// packet is bigger than what the caller can handle,
- if (pkt.size() > len) {
+ if (pkt.size() - mPacketOffset > len) {
memcpy(data, pkt.data() + mPacketOffset, len);
mPacketOffset += len;
readAmt = len;
// packet is equal or smaller than the caller buffer
} else {
- memcpy(data, pkt.data() + mPacketOffset, pkt.size());
+ memcpy(data, pkt.data() + mPacketOffset, pkt.size() - mPacketOffset);
mPacketNumber++;
mPacketOffset = 0;
- readAmt = pkt.size();
+ readAmt = pkt.size() - mPacketOffset;
}
return readAmt;
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 161b5e3..a26681e 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -428,6 +428,7 @@
EXPORT const char* AMEDIAFORMAT_KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
EXPORT const char* AMEDIAFORMAT_KEY_HEIGHT = "height";
EXPORT const char* AMEDIAFORMAT_KEY_ICC_PROFILE = "icc-profile";
+EXPORT const char* AMEDIAFORMAT_KEY_IMPORTANCE = "importance";
EXPORT const char* AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
EXPORT const char* AMEDIAFORMAT_KEY_IS_ADTS = "is-adts";
EXPORT const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT = "is-autoselect";
@@ -449,6 +450,10 @@
EXPORT const char* AMEDIAFORMAT_KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
+EXPORT const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE =
+ "buffer-batch-max-output-size";
+EXPORT const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE =
+ "buffer-batch-threshold-output-size";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_PTS_GAP_TO_ENCODER = "max-pts-gap-to-encoder";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";
EXPORT const char* AMEDIAFORMAT_KEY_MIME = "mime";
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index b2cdf8d..cc1dd9f 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -168,6 +168,7 @@
extern const char* AMEDIAFORMAT_KEY_GRID_ROWS __INTRODUCED_IN(28);
extern const char* AMEDIAFORMAT_KEY_HDR_STATIC_INFO __INTRODUCED_IN(28);
extern const char* AMEDIAFORMAT_KEY_HEIGHT __INTRODUCED_IN(21);
+extern const char* AMEDIAFORMAT_KEY_IMPORTANCE __INTRODUCED_IN(35);
extern const char* AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD __INTRODUCED_IN(28);
extern const char* AMEDIAFORMAT_KEY_IS_ADTS __INTRODUCED_IN(21);
extern const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT __INTRODUCED_IN(21);
@@ -186,6 +187,8 @@
extern const char* AMEDIAFORMAT_KEY_MAX_B_FRAMES __INTRODUCED_IN(34);
extern const char* AMEDIAFORMAT_KEY_MAX_HEIGHT __INTRODUCED_IN(21);
extern const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE __INTRODUCED_IN(21);
+extern const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE __INTRODUCED_IN(35);
+extern const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE __INTRODUCED_IN(35);
extern const char* AMEDIAFORMAT_KEY_MAX_WIDTH __INTRODUCED_IN(21);
extern const char* AMEDIAFORMAT_KEY_MIME __INTRODUCED_IN(21);
extern const char* AMEDIAFORMAT_KEY_MPEG_USER_DATA __INTRODUCED_IN(28);
diff --git a/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/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index aafe3cd..bdbd4d6 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -311,7 +311,8 @@
}
mPatchPanel = IAfPatchPanel::create(sp<IAfPatchPanelCallback>::fromExisting(this));
- mMelReporter = sp<MelReporter>::make(sp<IAfMelReporterCallback>::fromExisting(this));
+ mMelReporter = sp<MelReporter>::make(sp<IAfMelReporterCallback>::fromExisting(this),
+ mPatchPanel);
}
status_t AudioFlinger::setAudioHalPids(const std::vector<pid_t>& pids) {
@@ -4482,7 +4483,7 @@
if (effect->state() == IAfEffectModule::ACTIVE ||
effect->state() == IAfEffectModule::STOPPING) {
++started;
- effect->start();
+ effect->start_l();
}
}
dstChain->mutex().unlock();
@@ -4585,7 +4586,7 @@
// removeEffect_l() has stopped the effect if it was active so it must be restarted
if (effect->state() == IAfEffectModule::ACTIVE ||
effect->state() == IAfEffectModule::STOPPING) {
- effect->start();
+ effect->start_l();
}
}
diff --git a/services/audioflinger/DeviceEffectManager.cpp b/services/audioflinger/DeviceEffectManager.cpp
index 201d147..feae97e 100644
--- a/services/audioflinger/DeviceEffectManager.cpp
+++ b/services/audioflinger/DeviceEffectManager.cpp
@@ -143,7 +143,7 @@
if (lStatus == NO_ERROR) {
lStatus = effect->addHandle(handle.get());
if (lStatus == NO_ERROR) {
- lStatus = effect->init(patches);
+ lStatus = effect->init_l(patches);
if (lStatus == NAME_NOT_FOUND) {
lStatus = NO_ERROR;
}
diff --git a/services/audioflinger/DeviceEffectManager.h b/services/audioflinger/DeviceEffectManager.h
index 7045c8b..287d838 100644
--- a/services/audioflinger/DeviceEffectManager.h
+++ b/services/audioflinger/DeviceEffectManager.h
@@ -139,7 +139,7 @@
// check if effects should be suspended or restored when a given effect is enable or disabled
void checkSuspendOnEffectEnabled(const sp<IAfEffectBase>& effect __unused,
bool enabled __unused, bool threadLocked __unused) final {}
- void resetVolume() final {}
+ void resetVolume_l() final REQUIRES(audio_utils::EffectChain_Mutex) {}
product_strategy_t strategy() const final { return static_cast<product_strategy_t>(0); }
int32_t activeTrackCnt() const final { return 0; }
void onEffectEnable(const sp<IAfEffectBase>& effect __unused) final {}
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 3147433..a02657e 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -570,10 +570,10 @@
: EffectBase(callback, desc, id, sessionId, pinned),
// clear mConfig to ensure consistent initial value of buffer framecount
// in case buffers are associated by setInBuffer() or setOutBuffer()
- // prior to configure().
+ // prior to configure_l().
mConfig{{}, {}},
mStatus(NO_INIT),
- mMaxDisableWaitCnt(1), // set by configure(), should be >= 1
+ mMaxDisableWaitCnt(1), // set by configure_l(), should be >= 1
mDisableWaitCnt(0), // set by process() and updateState()
mOffloaded(false),
mIsOutput(false)
@@ -588,13 +588,13 @@
if (mStatus != NO_ERROR) {
return;
}
- lStatus = init();
+ lStatus = init_l();
if (lStatus < 0) {
mStatus = lStatus;
goto Error;
}
- setOffloaded(callback->isOffload(), callback->io());
+ setOffloaded_l(callback->isOffload(), callback->io());
ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface.get());
return;
@@ -616,7 +616,7 @@
}
-bool EffectModule::updateState() {
+bool EffectModule::updateState_l() {
audio_utils::lock_guard _l(mutex());
bool started = false;
@@ -632,7 +632,7 @@
0,
mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
}
- if (start_l() == NO_ERROR) {
+ if (start_ll() == NO_ERROR) {
mState = ACTIVE;
started = true;
} else {
@@ -641,8 +641,8 @@
break;
case STOPPING:
// volume control for offload and direct threads must take effect immediately.
- if (stop_l() == NO_ERROR
- && !(isVolumeControl() && isOffloadedOrDirect())) {
+ if (stop_ll() == NO_ERROR
+ && !(isVolumeControl() && isOffloadedOrDirect_l())) {
mDisableWaitCnt = mMaxDisableWaitCnt;
} else {
mDisableWaitCnt = 1; // will cause immediate transition to IDLE
@@ -836,9 +836,9 @@
mEffectInterface->command(EFFECT_CMD_RESET, 0, NULL, &replySize, &reply);
}
-status_t EffectModule::configure()
+status_t EffectModule::configure_l()
{
- ALOGVV("configure() started");
+ ALOGVV("%s started", __func__);
status_t status;
uint32_t size;
audio_channel_mask_t channelMask;
@@ -879,7 +879,7 @@
mConfig.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
// Don't use sample rate for thread if effect isn't offloadable.
- if (callback->isOffloadOrDirect() && !isOffloaded()) {
+ if (callback->isOffloadOrDirect() && !isOffloaded_l()) {
mConfig.inputCfg.samplingRate = DEFAULT_OUTPUT_SAMPLE_RATE;
ALOGV("Overriding effect input as 48kHz");
} else {
@@ -909,9 +909,9 @@
mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount;
mIsOutput = callback->isOutput();
- ALOGV("configure() %p chain %p buffer %p framecount %zu",
- this, callback->chain().promote().get(),
- mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount);
+ ALOGV("%s %p chain %p buffer %p framecount %zu", __func__, this,
+ callback->chain().promote().get(), mConfig.inputCfg.buffer.raw,
+ mConfig.inputCfg.buffer.frameCount);
status_t cmdStatus;
size = sizeof(int);
@@ -1012,11 +1012,11 @@
exit:
// TODO: consider clearing mConfig on error.
mStatus = status;
- ALOGVV("configure ended");
+ ALOGVV("%s ended", __func__);
return status;
}
-status_t EffectModule::init()
+status_t EffectModule::init_l()
{
audio_utils::lock_guard _l(mutex());
if (mEffectInterface == 0) {
@@ -1048,21 +1048,21 @@
}
}
-// start() must be called with PlaybackThread::mutex() or EffectChain::mutex() held
-status_t EffectModule::start()
+// start_l() must be called with EffectChain::mutex() held
+status_t EffectModule::start_l()
{
status_t status;
{
audio_utils::lock_guard _l(mutex());
- status = start_l();
+ status = start_ll();
}
if (status == NO_ERROR) {
- getCallback()->resetVolume();
+ getCallback()->resetVolume_l();
}
return status;
}
-status_t EffectModule::start_l()
+status_t EffectModule::start_ll()
{
if (mEffectInterface == 0) {
return NO_INIT;
@@ -1086,13 +1086,13 @@
return status;
}
-status_t EffectModule::stop()
+status_t EffectModule::stop_l()
{
audio_utils::lock_guard _l(mutex());
- return stop_l();
+ return stop_ll();
}
-status_t EffectModule::stop_l()
+status_t EffectModule::stop_ll()
{
if (mEffectInterface == 0) {
return NO_INIT;
@@ -1103,11 +1103,11 @@
status_t cmdStatus = NO_ERROR;
uint32_t size = sizeof(status_t);
- if (isVolumeControl() && isOffloadedOrDirect()) {
+ if (isVolumeControl() && isOffloadedOrDirect_l()) {
// We have the EffectChain and EffectModule lock, permit a reentrant call to setVolume:
// resetVolume_l --> setVolume_l --> EffectModule::setVolume
mSetVolumeReentrantTid = gettid();
- getCallback()->resetVolume();
+ getCallback()->resetVolume_l();
mSetVolumeReentrantTid = INVALID_PID;
}
@@ -1162,7 +1162,7 @@
std::vector<uint8_t>* reply)
{
audio_utils::lock_guard _l(mutex());
- ALOGVV("command(), cmdCode: %d, mEffectInterface: %p", cmdCode, mEffectInterface.get());
+ ALOGVV("%s, cmdCode: %d, mEffectInterface: %p", __func__, cmdCode, mEffectInterface.get());
if (mState == DESTROYED || mEffectInterface == 0) {
return NO_INIT;
@@ -1258,20 +1258,20 @@
}
}
-bool EffectModule::isOffloadedOrDirect() const
+bool EffectModule::isOffloadedOrDirect_l() const
{
return getCallback()->isOffloadOrDirect();
}
-bool EffectModule::isVolumeControlEnabled() const
+bool EffectModule::isVolumeControlEnabled_l() const
{
- return (isVolumeControl() && (isOffloadedOrDirect() ? isEnabled() : isProcessEnabled()));
+ return (isVolumeControl() && (isOffloadedOrDirect_l() ? isEnabled() : isProcessEnabled()));
}
void EffectModule::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
ALOGVV("setInBuffer %p",(&buffer));
- // mConfig.inputCfg.buffer.frameCount may be zero if configure() is not called yet.
+ // mConfig.inputCfg.buffer.frameCount may be zero if configure_l() is not called yet.
if (buffer != 0) {
mConfig.inputCfg.buffer.raw = buffer->audioBuffer()->raw;
buffer->setFrameCount(mConfig.inputCfg.buffer.frameCount);
@@ -1317,7 +1317,7 @@
void EffectModule::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
ALOGVV("setOutBuffer %p",(&buffer));
- // mConfig.outputCfg.buffer.frameCount may be zero if configure() is not called yet.
+ // mConfig.outputCfg.buffer.frameCount may be zero if configure_l() is not called yet.
if (buffer != 0) {
mConfig.outputCfg.buffer.raw = buffer->audioBuffer()->raw;
buffer->setFrameCount(mConfig.outputCfg.buffer.frameCount);
@@ -1356,8 +1356,7 @@
}
}
-status_t EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
-{
+status_t EffectModule::setVolume(uint32_t* left, uint32_t* right, bool controller) {
AutoLockReentrant _l(mutex(), mSetVolumeReentrantTid);
if (mStatus != NO_ERROR) {
return mStatus;
@@ -1480,7 +1479,7 @@
return status;
}
-status_t EffectModule::setOffloaded(bool offloaded, audio_io_handle_t io)
+status_t EffectModule::setOffloaded_l(bool offloaded, audio_io_handle_t io)
{
audio_utils::lock_guard _l(mutex());
if (mStatus != NO_ERROR) {
@@ -1509,11 +1508,11 @@
}
mOffloaded = false;
}
- ALOGV("setOffloaded() offloaded %d io %d status %d", offloaded, io, status);
+ ALOGV("%s offloaded %d io %d status %d", __func__, offloaded, io, status);
return status;
}
-bool EffectModule::isOffloaded() const
+bool EffectModule::isOffloaded_l() const
{
audio_utils::lock_guard _l(mutex());
return mOffloaded;
@@ -1537,8 +1536,7 @@
return IAfEffectModule::isSpatializer(&mDescriptor.type);
}
-status_t EffectModule::setHapticIntensity(int id, os::HapticScale intensity)
-{
+status_t EffectModule::setHapticIntensity_l(int id, os::HapticScale intensity) {
if (mStatus != NO_ERROR) {
return mStatus;
}
@@ -1563,8 +1561,7 @@
return status;
}
-status_t EffectModule::setVibratorInfo(const media::AudioVibratorInfo& vibratorInfo)
-{
+status_t EffectModule::setVibratorInfo_l(const media::AudioVibratorInfo& vibratorInfo) {
if (mStatus != NO_ERROR) {
return mStatus;
}
@@ -1593,8 +1590,8 @@
return status;
}
-status_t EffectModule::getConfigs(
- audio_config_base_t* inputCfg, audio_config_base_t* outputCfg, bool* isOutput) const {
+status_t EffectModule::getConfigs_l(audio_config_base_t* inputCfg, audio_config_base_t* outputCfg,
+ bool* isOutput) const {
audio_utils::lock_guard _l(mutex());
if (mConfig.inputCfg.mask == 0 || mConfig.outputCfg.mask == 0) {
return NO_INIT;
@@ -1609,7 +1606,7 @@
return NO_ERROR;
}
-status_t EffectModule::sendMetadata(const std::vector<playback_track_metadata_v7_t>& metadata) {
+status_t EffectModule::sendMetadata_ll(const std::vector<playback_track_metadata_v7_t>& metadata) {
if (mStatus != NO_ERROR) {
return mStatus;
}
@@ -1948,7 +1945,7 @@
audio_config_base_t inputCfg = AUDIO_CONFIG_BASE_INITIALIZER;
audio_config_base_t outputCfg = AUDIO_CONFIG_BASE_INITIALIZER;
bool isOutput;
- status_t status = effectModule->getConfigs(&inputCfg, &outputCfg, &isOutput);
+ status_t status = effectModule->getConfigs_l(&inputCfg, &outputCfg, &isOutput);
if (status == NO_ERROR) {
constexpr bool isInput = false; // effects always use 'OUT' channel masks.
_config->inputCfg = VALUE_OR_RETURN_STATUS_AS_OUT(
@@ -2214,7 +2211,7 @@
return 0;
}
-std::vector<int> EffectChain::getEffectIds() const
+std::vector<int> EffectChain::getEffectIds_l() const
{
std::vector<int> ids;
audio_utils::lock_guard _l(mutex());
@@ -2244,8 +2241,7 @@
}
// Must be called with EffectChain::mutex() locked
-void EffectChain::process_l()
-{
+void EffectChain::process_l() {
// never process effects when:
// - on an OFFLOAD thread
// - no more tracks are on the session and the effect tail has been rendered
@@ -2288,7 +2284,7 @@
}
bool doResetVolume = false;
for (size_t i = 0; i < size; i++) {
- doResetVolume = mEffects[i]->updateState() || doResetVolume;
+ doResetVolume = mEffects[i]->updateState_l() || doResetVolume;
}
if (doResetVolume) {
resetVolume_l();
@@ -2342,14 +2338,14 @@
numSamples * sizeof(float), &halBuffer);
if (result != OK) return result;
- effect->configure();
+ effect->configure_l();
effect->setInBuffer(halBuffer);
// auxiliary effects output samples to chain input buffer for further processing
// by insert effects
effect->setOutBuffer(mInBuffer);
} else {
- ssize_t idx_insert = getInsertIndex(desc);
+ ssize_t idx_insert = getInsertIndex_ll(desc);
if (idx_insert < 0) {
return INVALID_OPERATION;
}
@@ -2357,7 +2353,7 @@
size_t previousSize = mEffects.size();
mEffects.insertAt(effect, idx_insert);
- effect->configure();
+ effect->configure_l();
// - By default:
// All effects read samples from chain input buffer.
@@ -2372,9 +2368,9 @@
effect->setOutBuffer(mOutBuffer);
if (idx_insert == 0) {
if (previousSize != 0) {
- mEffects[1]->configure();
+ mEffects[1]->configure_l();
mEffects[1]->setInBuffer(mOutBuffer);
- mEffects[1]->updateAccessMode(); // reconfig if neeeded.
+ mEffects[1]->updateAccessMode_l(); // reconfig if needed.
}
effect->setInBuffer(mInBuffer);
} else {
@@ -2384,9 +2380,9 @@
effect->setInBuffer(mInBuffer);
if (idx_insert == static_cast<ssize_t>(previousSize)) {
if (idx_insert != 0) {
- mEffects[idx_insert-1]->configure();
+ mEffects[idx_insert-1]->configure_l();
mEffects[idx_insert-1]->setOutBuffer(mInBuffer);
- mEffects[idx_insert - 1]->updateAccessMode(); // reconfig if neeeded.
+ mEffects[idx_insert - 1]->updateAccessMode_l(); // reconfig if needed.
}
effect->setOutBuffer(mOutBuffer);
} else {
@@ -2396,21 +2392,21 @@
ALOGV("%s effect %p, added in chain %p at rank %zu",
__func__, effect.get(), this, idx_insert);
}
- effect->configure();
+ effect->configure_l();
return NO_ERROR;
}
std::optional<size_t> EffectChain::findVolumeControl_l(size_t from, size_t to) const {
for (size_t i = std::min(to, mEffects.size()); i > from; i--) {
- if (mEffects[i - 1]->isVolumeControlEnabled()) {
+ if (mEffects[i - 1]->isVolumeControlEnabled_l()) {
return i - 1;
}
}
return std::nullopt;
}
-ssize_t EffectChain::getInsertIndex(const effect_descriptor_t& desc) {
+ssize_t EffectChain::getInsertIndex_ll(const effect_descriptor_t& desc) {
// Insert effects are inserted at the end of mEffects vector as they are processed
// after track and auxiliary effects.
// Insert effect order as a function of indicated preference:
@@ -2498,7 +2494,7 @@
// the middle of a read from audio HAL
if (mEffects[i]->state() == EffectModule::ACTIVE ||
mEffects[i]->state() == EffectModule::STOPPING) {
- mEffects[i]->stop();
+ mEffects[i]->stop_l();
}
if (release) {
mEffects[i]->release_l();
@@ -2506,9 +2502,9 @@
if (type != EFFECT_FLAG_TYPE_AUXILIARY) {
if (i == size - 1 && i != 0) {
- mEffects[i - 1]->configure();
+ mEffects[i - 1]->configure_l();
mEffects[i - 1]->setOutBuffer(mOutBuffer);
- mEffects[i - 1]->updateAccessMode(); // reconfig if neeeded.
+ mEffects[i - 1]->updateAccessMode_l(); // reconfig if needed.
}
}
mEffects.removeAt(i);
@@ -2517,9 +2513,9 @@
// is updated if needed (can switch from HAL channel mask to mixer channel mask)
if (type != EFFECT_FLAG_TYPE_AUXILIARY // TODO(b/284522658) breaks for aux FX, why?
&& i == 0 && size > 1) {
- mEffects[0]->configure();
+ mEffects[0]->configure_l();
mEffects[0]->setInBuffer(mInBuffer);
- mEffects[0]->updateAccessMode(); // reconfig if neeeded.
+ mEffects[0]->updateAccessMode_l(); // reconfig if needed.
}
ALOGV("removeEffect_l() effect %p, removed from chain %p at rank %zu", effect.get(),
@@ -2569,14 +2565,19 @@
bool EffectChain::hasVolumeControlEnabled_l() const {
for (const auto &effect : mEffects) {
- if (effect->isVolumeControlEnabled()) return true;
+ if (effect->isVolumeControlEnabled_l()) return true;
}
return false;
}
-// setVolume_l() must be called with IAfThreadBase::mutex() or EffectChain::mutex() held
-bool EffectChain::setVolume_l(uint32_t *left, uint32_t *right, bool force)
-{
+// setVolume() must be called without EffectChain::mutex()
+bool EffectChain::setVolume(uint32_t* left, uint32_t* right, bool force) {
+ audio_utils::lock_guard _l(mutex());
+ return setVolume_l(left, right, force);
+}
+
+// setVolume_l() must be called with EffectChain::mutex() held
+bool EffectChain::setVolume_l(uint32_t* left, uint32_t* right, bool force) {
uint32_t newLeft = *left;
uint32_t newRight = *right;
const size_t size = mEffects.size();
@@ -2651,7 +2652,7 @@
return volumeControlIndex.has_value();
}
-// resetVolume_l() must be called with IAfThreadBase::mutex() or EffectChain::mutex() held
+// resetVolume_l() must be called with EffectChain::mutex() held
void EffectChain::resetVolume_l()
{
if ((mLeftVolume != UINT_MAX) && (mRightVolume != UINT_MAX)) {
@@ -2677,11 +2678,11 @@
{
audio_utils::lock_guard _l(mutex());
for (size_t i = 0; i < mEffects.size(); ++i) {
- mEffects[i]->setHapticIntensity(id, intensity);
+ mEffects[i]->setHapticIntensity_l(id, intensity);
}
}
-void EffectChain::syncHalEffectsState()
+void EffectChain::syncHalEffectsState_l()
{
audio_utils::lock_guard _l(mutex());
for (size_t i = 0; i < mEffects.size(); i++) {
@@ -2750,7 +2751,7 @@
}
if (desc->mRefCount++ == 0) {
- sp<IAfEffectModule> effect = getEffectIfEnabled(type);
+ sp<IAfEffectModule> effect = getEffectIfEnabled_l(type);
if (effect != 0) {
desc->mEffect = effect;
effect->setSuspended(true);
@@ -2803,7 +2804,7 @@
}
if (desc->mRefCount++ == 0) {
Vector< sp<IAfEffectModule> > effects;
- getSuspendEligibleEffects(effects);
+ getSuspendEligibleEffects_l(effects);
for (size_t i = 0; i < effects.size(); i++) {
setEffectSuspended_l(&effects[i]->desc().type, true);
}
@@ -2844,8 +2845,7 @@
#endif //OPENSL_ES_H_
/* static */
-bool EffectChain::isEffectEligibleForBtNrecSuspend(const effect_uuid_t *type)
-{
+bool EffectChain::isEffectEligibleForBtNrecSuspend_l(const effect_uuid_t* type) {
// Only NS and AEC are suspended when BtNRec is off
if ((memcmp(type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) ||
(memcmp(type, FX_IID_NS, sizeof(effect_uuid_t)) == 0)) {
@@ -2854,7 +2854,7 @@
return false;
}
-bool EffectChain::isEffectEligibleForSuspend(const effect_descriptor_t& desc)
+bool EffectChain::isEffectEligibleForSuspend_l(const effect_descriptor_t& desc)
{
// auxiliary effects and visualizer are never suspended on output mix
if ((mSessionId == AUDIO_SESSION_OUTPUT_MIX) &&
@@ -2867,26 +2867,24 @@
return true;
}
-void EffectChain::getSuspendEligibleEffects(
+void EffectChain::getSuspendEligibleEffects_l(
Vector< sp<IAfEffectModule> > &effects)
{
effects.clear();
for (size_t i = 0; i < mEffects.size(); i++) {
- if (isEffectEligibleForSuspend(mEffects[i]->desc())) {
+ if (isEffectEligibleForSuspend_l(mEffects[i]->desc())) {
effects.add(mEffects[i]);
}
}
}
-sp<IAfEffectModule> EffectChain::getEffectIfEnabled(const effect_uuid_t *type)
+sp<IAfEffectModule> EffectChain::getEffectIfEnabled_l(const effect_uuid_t *type)
{
sp<IAfEffectModule> effect = getEffectFromType_l(type);
return effect != 0 && effect->isEnabled() ? effect : 0;
}
-void EffectChain::checkSuspendOnEffectEnabled(const sp<IAfEffectModule>& effect,
- bool enabled)
-{
+void EffectChain::checkSuspendOnEffectEnabled_l(const sp<IAfEffectModule>& effect, bool enabled) {
ssize_t index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow);
if (enabled) {
if (index < 0) {
@@ -2895,18 +2893,17 @@
if (index < 0) {
return;
}
- if (!isEffectEligibleForSuspend(effect->desc())) {
+ if (!isEffectEligibleForSuspend_l(effect->desc())) {
return;
}
setEffectSuspended_l(&effect->desc().type, enabled);
index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow);
if (index < 0) {
- ALOGW("checkSuspendOnEffectEnabled() Fx should be suspended here!");
+ ALOGW("%s Fx should be suspended here!", __func__);
return;
}
}
- ALOGV("checkSuspendOnEffectEnabled() enable suspending fx %08x",
- effect->desc().type.timeLow);
+ ALOGV("%s enable suspending fx %08x", __func__, effect->desc().type.timeLow);
sp<SuspendedEffectDesc> desc = mSuspendedEffects.valueAt(index);
// if effect is requested to suspended but was not yet enabled, suspend it now.
if (desc->mEffect == 0) {
@@ -2918,8 +2915,7 @@
if (index < 0) {
return;
}
- ALOGV("checkSuspendOnEffectEnabled() disable restoring fx %08x",
- effect->desc().type.timeLow);
+ ALOGV("%s disable restoring fx %08x", __func__, effect->desc().type.timeLow);
sp<SuspendedEffectDesc> desc = mSuspendedEffects.valueAt(index);
desc->mEffect.clear();
effect->setSuspended(false);
@@ -3028,9 +3024,9 @@
for (const auto& effect : mEffects) {
if (spatializedMetadata.has_value()
&& IAfEffectModule::isSpatializer(&effect->desc().type)) {
- effect->sendMetadata(spatializedMetadata.value());
+ effect->sendMetadata_ll(spatializedMetadata.value());
} else {
- effect->sendMetadata(allMetadata);
+ effect->sendMetadata_ll(allMetadata);
}
}
}
@@ -3248,8 +3244,9 @@
t->setVolumeForOutput_l(left, right);
}
-void EffectChain::EffectCallback::checkSuspendOnEffectEnabled(
- const sp<IAfEffectBase>& effect, bool enabled, bool threadLocked) {
+void EffectChain::EffectCallback::checkSuspendOnEffectEnabled(const sp<IAfEffectBase>& effect,
+ bool enabled, bool threadLocked)
+ NO_THREAD_SAFETY_ANALYSIS {
const sp<IAfThreadBase> t = thread().promote();
if (t == nullptr) {
return;
@@ -3261,7 +3258,7 @@
return;
}
// in EffectChain context, an EffectBase is always from an EffectModule so static cast is safe
- c->checkSuspendOnEffectEnabled(effect->asEffectModule(), enabled);
+ c->checkSuspendOnEffectEnabled_l(effect->asEffectModule(), enabled);
}
void EffectChain::EffectCallback::onEffectEnable(const sp<IAfEffectBase>& effect) {
@@ -3293,7 +3290,7 @@
return true;
}
-void EffectChain::EffectCallback::resetVolume() {
+void EffectChain::EffectCallback::resetVolume_l() {
sp<IAfEffectChain> c = chain().promote();
if (c == nullptr) {
return;
@@ -3354,7 +3351,7 @@
return status;
}
-status_t DeviceEffectProxy::init(
+status_t DeviceEffectProxy::init_l(
const std::map <audio_patch_handle_t, IAfPatchPanel::Patch>& patches) {
//For all audio patches
//If src or sink device match
@@ -3458,7 +3455,7 @@
} else {
mHalEffect->setDevices({mDevice});
}
- mHalEffect->configure();
+ mHalEffect->configure_l();
}
*handle = new EffectHandle(mHalEffect, nullptr, nullptr, 0 /*priority*/,
mNotifyFramesProcessed);
@@ -3747,7 +3744,7 @@
if (effect == nullptr) {
return;
}
- effect->start();
+ effect->start_l();
}
void DeviceEffectProxy::ProxyCallback::onEffectDisable(
@@ -3756,7 +3753,7 @@
if (effect == nullptr) {
return;
}
- effect->stop();
+ effect->stop_l();
}
} // namespace android
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 8583d47..6e34e9b 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -78,11 +78,11 @@
{ return (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK)
== EFFECT_FLAG_VOLUME_MONITOR; }
- status_t setEnabled(bool enabled, bool fromHandle) override;
- status_t setEnabled_l(bool enabled) final;
+ status_t setEnabled(bool enabled, bool fromHandle) override EXCLUDES_EffectBase_Mutex;
+ status_t setEnabled_l(bool enabled) final REQUIRES(audio_utils::EffectBase_Mutex);
bool isEnabled() const final;
- void setSuspended(bool suspended) final;
- bool suspended() const final;
+ void setSuspended(bool suspended) final EXCLUDES_EffectBase_Mutex;
+ bool suspended() const final EXCLUDES_EffectBase_Mutex;
status_t command(int32_t __unused,
const std::vector<uint8_t>& __unused,
@@ -99,36 +99,40 @@
return mCallback.load();
}
- status_t addHandle(IAfEffectHandle *handle) final;
- ssize_t disconnectHandle(IAfEffectHandle *handle, bool unpinIfLast) final;
- ssize_t removeHandle(IAfEffectHandle *handle) final;
- ssize_t removeHandle_l(IAfEffectHandle *handle) final;
- IAfEffectHandle* controlHandle_l() final;
- bool purgeHandles() final;
+ status_t addHandle(IAfEffectHandle* handle) final EXCLUDES_EffectBase_Mutex;
+ ssize_t disconnectHandle(IAfEffectHandle* handle,
+ bool unpinIfLast) final EXCLUDES_EffectBase_Mutex;
+ ssize_t removeHandle(IAfEffectHandle* handle) final EXCLUDES_EffectBase_Mutex;
+ ssize_t removeHandle_l(IAfEffectHandle* handle) final REQUIRES(audio_utils::EffectBase_Mutex);
+ IAfEffectHandle* controlHandle_l() final REQUIRES(audio_utils::EffectBase_Mutex);
+ bool purgeHandles() final EXCLUDES_EffectBase_Mutex;
- void checkSuspendOnEffectEnabled(bool enabled, bool threadLocked) final;
+ void checkSuspendOnEffectEnabled(bool enabled, bool threadLocked) final;
- bool isPinned() const final { return mPinned; }
- void unPin() final { mPinned = false; }
+ bool isPinned() const final { return mPinned; }
+ void unPin() final { mPinned = false; }
- audio_utils::mutex& mutex() const final { return mMutex; }
+ audio_utils::mutex& mutex() const final
+ RETURN_CAPABILITY(android::audio_utils::EffectBase_Mutex) {
+ return mMutex;
+ }
- status_t updatePolicyState() final;
+ status_t updatePolicyState() final EXCLUDES_EffectBase_Mutex;
sp<IAfEffectModule> asEffectModule() override { return nullptr; }
sp<IAfDeviceEffectProxy> asDeviceEffectProxy() override { return nullptr; }
- void dump(int fd, const Vector<String16>& args) const override;
+ void dump(int fd, const Vector<String16>& args) const override;
protected:
- bool isInternal_l() const {
- for (auto handle : mHandles) {
- if (handle->client() != nullptr) {
- return false;
- }
- }
- return true;
- }
+ bool isInternal_l() const REQUIRES(audio_utils::EffectBase_Mutex) {
+ for (auto handle : mHandles) {
+ if (handle->client() != nullptr) {
+ return false;
+ }
+ }
+ return true;
+ }
bool mPinned = false;
@@ -150,7 +154,10 @@
// Audio policy effect state management
// Mutex protecting transactions with audio policy manager as mutex() cannot
// be held to avoid cross deadlocks with audio policy mutex
- audio_utils::mutex& policyMutex() const { return mPolicyMutex; }
+ audio_utils::mutex& policyMutex() const
+ RETURN_CAPABILITY(android::audio_utils::EffectBase_PolicyMutex) {
+ return mPolicyMutex;
+ }
mutable audio_utils::mutex mPolicyMutex{audio_utils::MutexOrder::kEffectBase_PolicyMutex};
// Effect is registered in APM or not
bool mPolicyRegistered = false;
@@ -175,25 +182,23 @@
int id,
audio_session_t sessionId,
bool pinned,
- audio_port_handle_t deviceId);
- ~EffectModule() override;
+ audio_port_handle_t deviceId) REQUIRES(audio_utils::EffectChain_Mutex);
+ ~EffectModule() override REQUIRES(audio_utils::EffectChain_Mutex);
- void process() final;
- bool updateState() final;
- status_t command(int32_t cmdCode,
- const std::vector<uint8_t>& cmdData,
- int32_t maxReplySize,
- std::vector<uint8_t>* reply) final;
+ void process() final EXCLUDES_EffectBase_Mutex;
+ bool updateState_l() final REQUIRES(audio_utils::EffectChain_Mutex) EXCLUDES_EffectBase_Mutex;
+ status_t command(int32_t cmdCode, const std::vector<uint8_t>& cmdData, int32_t maxReplySize,
+ std::vector<uint8_t>* reply) final EXCLUDES_EffectBase_Mutex;
- void reset_l() final;
- status_t configure() final;
- status_t init() final;
+ void reset_l() final REQUIRES(audio_utils::EffectBase_Mutex);
+ status_t configure_l() final REQUIRES(audio_utils::EffectChain_Mutex);
+ status_t init_l() final REQUIRES(audio_utils::EffectChain_Mutex) EXCLUDES_EffectBase_Mutex;
uint32_t status() const final {
return mStatus;
}
bool isProcessEnabled() const final;
- bool isOffloadedOrDirect() const final;
- bool isVolumeControlEnabled() const final;
+ bool isOffloadedOrDirect_l() const final REQUIRES(audio_utils::EffectChain_Mutex);
+ bool isVolumeControlEnabled_l() const final REQUIRES(audio_utils::EffectChain_Mutex);
void setInBuffer(const sp<EffectBufferHalInterface>& buffer) final;
int16_t *inBuffer() const final {
return mInBuffer != 0 ? reinterpret_cast<int16_t*>(mInBuffer->ptr()) : NULL;
@@ -203,36 +208,42 @@
return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
}
// Updates the access mode if it is out of date. May issue a new effect configure.
- void updateAccessMode() final {
- if (requiredEffectBufferAccessMode() != mConfig.outputCfg.accessMode) {
- configure();
- }
- }
- status_t setDevices(const AudioDeviceTypeAddrVector &devices) final;
- status_t setInputDevice(const AudioDeviceTypeAddr &device) final;
+ void updateAccessMode_l() final REQUIRES(audio_utils::EffectChain_Mutex) {
+ if (requiredEffectBufferAccessMode() != mConfig.outputCfg.accessMode) {
+ configure_l();
+ }
+ }
+ status_t setDevices(const AudioDeviceTypeAddrVector& devices) final EXCLUDES_EffectBase_Mutex;
+ status_t setInputDevice(const AudioDeviceTypeAddr& device) final EXCLUDES_EffectBase_Mutex;
status_t setVolume(uint32_t *left, uint32_t *right, bool controller) final;
- status_t setMode(audio_mode_t mode) final;
- status_t setAudioSource(audio_source_t source) final;
- status_t start() final;
- status_t stop() final;
+ status_t setMode(audio_mode_t mode) final EXCLUDES_EffectBase_Mutex;
+ status_t setAudioSource(audio_source_t source) final EXCLUDES_EffectBase_Mutex;
+ status_t start_l() final REQUIRES(audio_utils::EffectChain_Mutex) EXCLUDES_EffectBase_Mutex;
+ status_t stop_l() final REQUIRES(audio_utils::EffectChain_Mutex) EXCLUDES_EffectBase_Mutex;
- status_t setOffloaded(bool offloaded, audio_io_handle_t io) final;
- bool isOffloaded() const final;
- void addEffectToHal_l() final;
- void release_l() final;
+ status_t setOffloaded_l(bool offloaded, audio_io_handle_t io) final
+ REQUIRES(audio_utils::EffectChain_Mutex) EXCLUDES_EffectBase_Mutex;
+ bool isOffloaded_l() const final
+ REQUIRES(audio_utils::EffectChain_Mutex) EXCLUDES_EffectBase_Mutex;
+ void addEffectToHal_l() final REQUIRES(audio_utils::EffectChain_Mutex);
+ void release_l() final REQUIRES(audio_utils::EffectChain_Mutex);
sp<IAfEffectModule> asEffectModule() final { return this; }
bool isHapticGenerator() const final;
bool isSpatializer() const final;
- status_t setHapticIntensity(int id, os::HapticScale intensity) final;
- status_t setVibratorInfo(const media::AudioVibratorInfo& vibratorInfo) final;
- status_t sendMetadata(const std::vector<playback_track_metadata_v7_t>& metadata) final;
+ status_t setHapticIntensity_l(int id, os::HapticScale intensity) final
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectBase_Mutex;
+ status_t setVibratorInfo_l(const media::AudioVibratorInfo& vibratorInfo) final
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectBase_Mutex;
+ status_t sendMetadata_ll(const std::vector<playback_track_metadata_v7_t>& metadata) final
+ REQUIRES(audio_utils::ThreadBase_Mutex,
+ audio_utils::EffectChain_Mutex) EXCLUDES_EffectBase_Mutex;
- status_t getConfigs(audio_config_base_t* inputCfg,
- audio_config_base_t* outputCfg,
- bool* isOutput) const final;
+ status_t getConfigs_l(audio_config_base_t* inputCfg, audio_config_base_t* outputCfg,
+ bool* isOutput) const final
+ REQUIRES(audio_utils::EffectHandle_Mutex) EXCLUDES_EffectBase_Mutex;
void dump(int fd, const Vector<String16>& args) const final;
@@ -243,9 +254,9 @@
DISALLOW_COPY_AND_ASSIGN(EffectModule);
- status_t start_l();
- status_t stop_l();
- status_t removeEffectFromHal_l();
+ status_t start_ll() REQUIRES(audio_utils::EffectChain_Mutex, audio_utils::EffectBase_Mutex);
+ status_t stop_ll() REQUIRES(audio_utils::EffectChain_Mutex, audio_utils::EffectBase_Mutex);
+ status_t removeEffectFromHal_l() REQUIRES(audio_utils::EffectChain_Mutex);
status_t sendSetAudioDevicesCommand(const AudioDeviceTypeAddrVector &devices, uint32_t cmdCode);
effect_buffer_access_e requiredEffectBufferAccessMode() const {
return mConfig.inputCfg.buffer.raw == mConfig.outputCfg.buffer.raw
@@ -368,7 +379,9 @@
private:
DISALLOW_COPY_AND_ASSIGN(EffectHandle);
- audio_utils::mutex& mutex() const { return mMutex; }
+ audio_utils::mutex& mutex() const RETURN_CAPABILITY(android::audio_utils::EffectHandle_Mutex) {
+ return mMutex;
+ }
// protects IEffect method calls
mutable audio_utils::mutex mMutex{audio_utils::MutexOrder::kEffectHandle_Mutex};
const wp<IAfEffectBase> mEffect; // pointer to controlled EffectModule
@@ -401,34 +414,43 @@
public:
EffectChain(const sp<IAfThreadBase>& thread, audio_session_t sessionId);
- void process_l() final;
+ void process_l() final REQUIRES(audio_utils::EffectChain_Mutex);
- audio_utils::mutex& mutex() const final { return mMutex; }
+ audio_utils::mutex& mutex() const final RETURN_CAPABILITY(audio_utils::EffectChain_Mutex) {
+ return mMutex;
+ }
- status_t createEffect_l(sp<IAfEffectModule>& effect,
- effect_descriptor_t *desc,
- int id,
- audio_session_t sessionId,
- bool pinned) final;
- status_t addEffect_l(const sp<IAfEffectModule>& handle) final;
- status_t addEffect_ll(const sp<IAfEffectModule>& handle) final;
- size_t removeEffect_l(const sp<IAfEffectModule>& handle, bool release = false) final;
+ status_t createEffect_l(sp<IAfEffectModule>& effect, effect_descriptor_t* desc, int id,
+ audio_session_t sessionId, bool pinned) final
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectChain_Mutex;
+ status_t addEffect_l(const sp<IAfEffectModule>& handle) final
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectChain_Mutex;
+ status_t addEffect_ll(const sp<IAfEffectModule>& handle) final
+ REQUIRES(audio_utils::ThreadBase_Mutex, audio_utils::EffectChain_Mutex);
+ size_t removeEffect_l(const sp<IAfEffectModule>& handle, bool release = false) final
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectChain_Mutex;
audio_session_t sessionId() const final { return mSessionId; }
void setSessionId(audio_session_t sessionId) final { mSessionId = sessionId; }
- sp<IAfEffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor) const final;
- sp<IAfEffectModule> getEffectFromId_l(int id) const final;
- sp<IAfEffectModule> getEffectFromType_l(const effect_uuid_t *type) const final;
- std::vector<int> getEffectIds() const final;
+ sp<IAfEffectModule> getEffectFromDesc_l(effect_descriptor_t* descriptor) const final
+ REQUIRES(audio_utils::ThreadBase_Mutex);
+ sp<IAfEffectModule> getEffectFromId_l(int id) const final
+ REQUIRES(audio_utils::ThreadBase_Mutex);
+ sp<IAfEffectModule> getEffectFromType_l(const effect_uuid_t* type) const final
+ REQUIRES(audio_utils::ThreadBase_Mutex);
+ std::vector<int> getEffectIds_l() const final REQUIRES(audio_utils::ThreadBase_Mutex);
// FIXME use float to improve the dynamic range
- bool setVolume_l(uint32_t *left, uint32_t *right, bool force = false) final;
- void resetVolume_l() final;
- void setDevices_l(const AudioDeviceTypeAddrVector &devices) final;
- void setInputDevice_l(const AudioDeviceTypeAddr &device) final;
- void setMode_l(audio_mode_t mode) final;
- void setAudioSource_l(audio_source_t source) final;
+ bool setVolume(uint32_t* left, uint32_t* right,
+ bool force = false) final EXCLUDES_EffectChain_Mutex;
+ void resetVolume_l() final REQUIRES(audio_utils::EffectChain_Mutex);
+ void setDevices_l(const AudioDeviceTypeAddrVector& devices) final
+ REQUIRES(audio_utils::ThreadBase_Mutex);
+ void setInputDevice_l(const AudioDeviceTypeAddr& device) final
+ REQUIRES(audio_utils::ThreadBase_Mutex);
+ void setMode_l(audio_mode_t mode) final REQUIRES(audio_utils::ThreadBase_Mutex);
+ void setAudioSource_l(audio_source_t source) final REQUIRES(audio_utils::ThreadBase_Mutex);
void setInBuffer(const sp<EffectBufferHalInterface>& buffer) final {
mInBuffer = buffer;
@@ -459,21 +481,22 @@
// suspend or restore effects of the specified type. The number of suspend requests is counted
// and restore occurs once all suspend requests are cancelled.
- void setEffectSuspended_l(const effect_uuid_t *type,
- bool suspend) final;
+ void setEffectSuspended_l(const effect_uuid_t* type, bool suspend) final
+ REQUIRES(audio_utils::ThreadBase_Mutex);
// suspend all eligible effects
- void setEffectSuspendedAll_l(bool suspend) final;
+ void setEffectSuspendedAll_l(bool suspend) final REQUIRES(audio_utils::ThreadBase_Mutex);
// check if effects should be suspended or restored when a given effect is enable or disabled
- void checkSuspendOnEffectEnabled(
- const sp<IAfEffectModule>& effect, bool enabled) final;
+ void checkSuspendOnEffectEnabled_l(const sp<IAfEffectModule>& effect, bool enabled) final
+ REQUIRES(audio_utils::ThreadBase_Mutex);
- void clearInputBuffer() final;
+ void clearInputBuffer() final EXCLUDES_EffectChain_Mutex;
// At least one non offloadable effect in the chain is enabled
- bool isNonOffloadableEnabled() const final;
- bool isNonOffloadableEnabled_l() const final;
+ bool isNonOffloadableEnabled() const final EXCLUDES_EffectChain_Mutex;
+ bool isNonOffloadableEnabled_l() const final REQUIRES(audio_utils::EffectChain_Mutex);
- void syncHalEffectsState() final;
+ void syncHalEffectsState_l()
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectChain_Mutex final;
// flags is an ORed set of audio_output_flags_t which is updated on return.
void checkOutputFlagCompatibility(audio_output_flags_t *flags) const final;
@@ -492,12 +515,13 @@
// isCompatibleWithThread_l() must be called with thread->mutex() held
bool isCompatibleWithThread_l(const sp<IAfThreadBase>& thread) const final
- REQUIRES(audio_utils::ThreadBase_Mutex);
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectChain_Mutex;
// Requires either IAfThreadBase::mutex() or EffectChain::mutex() held
bool containsHapticGeneratingEffect_l() final;
- void setHapticIntensity_l(int id, os::HapticScale intensity) final;
+ void setHapticIntensity_l(int id, os::HapticScale intensity) final
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectChain_Mutex;
sp<EffectCallbackInterface> effectCallback() const final { return mEffectCallback; }
@@ -519,9 +543,11 @@
const std::optional<const std::vector<playback_track_metadata_v7_t>> spatializedMetadata)
final REQUIRES(audio_utils::ThreadBase_Mutex);
- void setThread(const sp<IAfThreadBase>& thread) final;
+ void setThread(const sp<IAfThreadBase>& thread) final EXCLUDES_EffectChain_Mutex;
-private:
+ private:
+ bool setVolume_l(uint32_t* left, uint32_t* right, bool force = false)
+ REQUIRES(audio_utils::EffectChain_Mutex);
// For transaction consistency, please consider holding the EffectChain lock before
// calling the EffectChain::EffectCallback methods, excepting
@@ -568,9 +594,10 @@
void setVolumeForOutput(float left, float right) const override;
// check if effects should be suspended/restored when a given effect is enable/disabled
- void checkSuspendOnEffectEnabled(const sp<IAfEffectBase>& effect,
- bool enabled, bool threadLocked) override;
- void resetVolume() override;
+ void checkSuspendOnEffectEnabled(const sp<IAfEffectBase>& effect, bool enabled,
+ bool threadLocked) override;
+ void resetVolume_l() override
+ REQUIRES(audio_utils::ThreadBase_Mutex, audio_utils::EffectChain_Mutex);
product_strategy_t strategy() const override;
int32_t activeTrackCnt() const override;
void onEffectEnable(const sp<IAfEffectBase>& effect) override;
@@ -610,27 +637,34 @@
// get a list of effect modules to suspend when an effect of the type
// passed is enabled.
- void getSuspendEligibleEffects(Vector<sp<IAfEffectModule>> &effects);
+ void getSuspendEligibleEffects_l(Vector<sp<IAfEffectModule>>& effects)
+ REQUIRES(audio_utils::ThreadBase_Mutex);
// get an effect module if it is currently enable
- sp<IAfEffectModule> getEffectIfEnabled(const effect_uuid_t *type);
+ sp<IAfEffectModule> getEffectIfEnabled_l(const effect_uuid_t* type)
+ REQUIRES(audio_utils::ThreadBase_Mutex);
// true if the effect whose descriptor is passed can be suspended
// OEMs can modify the rules implemented in this method to exclude specific effect
// types or implementations from the suspend/restore mechanism.
- bool isEffectEligibleForSuspend(const effect_descriptor_t& desc);
+ bool isEffectEligibleForSuspend_l(const effect_descriptor_t& desc)
+ REQUIRES(audio_utils::ThreadBase_Mutex);
- static bool isEffectEligibleForBtNrecSuspend(const effect_uuid_t *type);
+ static bool isEffectEligibleForBtNrecSuspend_l(const effect_uuid_t* type)
+ REQUIRES(audio_utils::ThreadBase_Mutex);
- void clearInputBuffer_l();
+ void clearInputBuffer_l() REQUIRES(audio_utils::EffectChain_Mutex);
// true if any effect module within the chain has volume control
- bool hasVolumeControlEnabled_l() const;
+ bool hasVolumeControlEnabled_l() const REQUIRES(audio_utils::EffectChain_Mutex);
- void setVolumeForOutput_l(uint32_t left, uint32_t right);
+ void setVolumeForOutput_l(uint32_t left, uint32_t right)
+ REQUIRES(audio_utils::EffectChain_Mutex);
- ssize_t getInsertIndex(const effect_descriptor_t& desc);
+ ssize_t getInsertIndex_ll(const effect_descriptor_t& desc)
+ REQUIRES(audio_utils::ThreadBase_Mutex, audio_utils::EffectChain_Mutex);
- std::optional<size_t> findVolumeControl_l(size_t from, size_t to) const;
+ std::optional<size_t> findVolumeControl_l(size_t from, size_t to) const
+ REQUIRES(audio_utils::EffectChain_Mutex);
// mutex protecting effect list
mutable audio_utils::mutex mMutex{audio_utils::MutexOrder::kEffectChain_Mutex};
@@ -674,11 +708,11 @@
status_t setEnabled(bool enabled, bool fromHandle) final;
sp<IAfDeviceEffectProxy> asDeviceEffectProxy() final { return this; }
- status_t init(const std::map<audio_patch_handle_t,
- IAfPatchPanel::Patch>& patches) final;
+ status_t init_l(const std::map<audio_patch_handle_t, IAfPatchPanel::Patch>& patches) final
+ REQUIRES(audio_utils::DeviceEffectManager_Mutex) EXCLUDES_EffectBase_Mutex;
status_t onCreatePatch(audio_patch_handle_t patchHandle,
- const IAfPatchPanel::Patch& patch) final;
+ const IAfPatchPanel::Patch& patch) final;
status_t onUpdatePatch(audio_patch_handle_t oldPatchHandle, audio_patch_handle_t newPatchHandle,
const IAfPatchPanel::Patch& patch) final;
@@ -696,10 +730,8 @@
audio_channel_mask_t channelMask() const final;
uint32_t channelCount() const final;
- status_t command(int32_t cmdCode,
- const std::vector<uint8_t>& cmdData,
- int32_t maxReplySize,
- std::vector<uint8_t>* reply) final;
+ status_t command(int32_t cmdCode, const std::vector<uint8_t>& cmdData, int32_t maxReplySize,
+ std::vector<uint8_t>* reply) final EXCLUDES_DeviceEffectProxy_ProxyMutex;
void dump2(int fd, int spaces) const final;
@@ -745,7 +777,7 @@
void checkSuspendOnEffectEnabled(const sp<IAfEffectBase>& effect __unused,
bool enabled __unused, bool threadLocked __unused) override {}
- void resetVolume() override {}
+ void resetVolume_l() override REQUIRES(audio_utils::EffectChain_Mutex) {}
product_strategy_t strategy() const override { return static_cast<product_strategy_t>(0); }
int32_t activeTrackCnt() const override { return 0; }
void onEffectEnable(const sp<IAfEffectBase>& effect __unused) override;
@@ -765,13 +797,16 @@
};
status_t checkPort(const IAfPatchPanel::Patch& patch,
- const struct audio_port_config *port, sp<IAfEffectHandle> *handle);
+ const struct audio_port_config* port, sp<IAfEffectHandle>* handle);
const AudioDeviceTypeAddr mDevice;
const sp<DeviceEffectManagerCallback> mManagerCallback;
const sp<ProxyCallback> mMyCallback;
- audio_utils::mutex& proxyMutex() const { return mProxyMutex; }
+ audio_utils::mutex& proxyMutex() const
+ RETURN_CAPABILITY(android::audio_utils::DeviceEffectProxy_ProxyMutex) {
+ return mProxyMutex;
+ }
mutable audio_utils::mutex mProxyMutex{
audio_utils::MutexOrder::kDeviceEffectProxy_ProxyMutex};
std::map<audio_patch_handle_t, sp<IAfEffectHandle>> mEffectHandles; // protected by mProxyMutex
diff --git a/services/audioflinger/IAfEffect.h b/services/audioflinger/IAfEffect.h
index 56076a3..82436a3 100644
--- a/services/audioflinger/IAfEffect.h
+++ b/services/audioflinger/IAfEffect.h
@@ -80,7 +80,7 @@
// Methods usually implemented with help from EffectChain: pay attention to mutex locking order
virtual product_strategy_t strategy() const = 0;
virtual int32_t activeTrackCnt() const = 0;
- virtual void resetVolume() = 0;
+ virtual void resetVolume_l() REQUIRES(audio_utils::EffectChain_Mutex) = 0;
virtual wp<IAfEffectChain> chain() const = 0;
virtual bool isAudioPolicyReady() const = 0;
};
@@ -106,43 +106,45 @@
virtual bool isOffloadable() const = 0;
virtual bool isImplementationSoftware() const = 0;
virtual bool isProcessImplemented() const = 0;
- virtual bool isVolumeControl() const = 0;
+ virtual bool isVolumeControl() const REQUIRES(audio_utils::EffectChain_Mutex) = 0;
virtual bool isVolumeMonitor() const = 0;
virtual bool isEnabled() const = 0;
virtual bool isPinned() const = 0;
virtual void unPin() = 0;
- virtual status_t updatePolicyState() = 0;
- virtual bool purgeHandles() = 0;
+ virtual status_t updatePolicyState() EXCLUDES_EffectBase_Mutex = 0;
+ virtual bool purgeHandles() EXCLUDES_EffectBase_Mutex = 0;
virtual void checkSuspendOnEffectEnabled(bool enabled, bool threadLocked) = 0;
// mCallback is atomic so this can be lock-free.
virtual void setCallback(const sp<EffectCallbackInterface>& callback) = 0;
virtual sp<EffectCallbackInterface> getCallback() const = 0;
- virtual status_t addHandle(IAfEffectHandle *handle) = 0;
- virtual ssize_t removeHandle(IAfEffectHandle *handle) = 0;
+ virtual status_t addHandle(IAfEffectHandle* handle) EXCLUDES_EffectBase_Mutex = 0;
+ virtual ssize_t removeHandle(IAfEffectHandle* handle) EXCLUDES_EffectBase_Mutex = 0;
virtual sp<IAfEffectModule> asEffectModule() = 0;
virtual sp<IAfDeviceEffectProxy> asDeviceEffectProxy() = 0;
- virtual status_t command(int32_t cmdCode,
- const std::vector<uint8_t>& cmdData,
- int32_t maxReplySize,
- std::vector<uint8_t>* reply) = 0;
+ virtual status_t command(int32_t cmdCode, const std::vector<uint8_t>& cmdData,
+ int32_t maxReplySize, std::vector<uint8_t>* reply)
+ EXCLUDES(audio_utils::EffectBase_Mutex) = 0;
virtual void dump(int fd, const Vector<String16>& args) const = 0;
private:
- virtual status_t setEnabled(bool enabled, bool fromHandle) = 0;
- virtual status_t setEnabled_l(bool enabled) = 0;
- virtual void setSuspended(bool suspended) = 0;
- virtual bool suspended() const = 0;
+ virtual status_t setEnabled(bool enabled, bool fromHandle) EXCLUDES_EffectBase_Mutex = 0;
+ virtual status_t setEnabled_l(bool enabled) REQUIRES(audio_utils::EffectBase_Mutex) = 0;
+ virtual void setSuspended(bool suspended) EXCLUDES_EffectBase_Mutex = 0;
+ virtual bool suspended() const EXCLUDES_EffectBase_Mutex = 0;
- virtual ssize_t disconnectHandle(IAfEffectHandle *handle, bool unpinIfLast) = 0;
- virtual ssize_t removeHandle_l(IAfEffectHandle *handle) = 0;
- virtual IAfEffectHandle* controlHandle_l() = 0;
+ virtual ssize_t disconnectHandle(IAfEffectHandle* handle,
+ bool unpinIfLast) EXCLUDES_EffectBase_Mutex = 0;
+ virtual ssize_t removeHandle_l(IAfEffectHandle* handle)
+ REQUIRES(audio_utils::EffectBase_Mutex) = 0;
+ virtual IAfEffectHandle* controlHandle_l() REQUIRES(audio_utils::EffectBase_Mutex) = 0;
- virtual audio_utils::mutex& mutex() const = 0;
+ virtual audio_utils::mutex& mutex() const
+ RETURN_CAPABILITY(android::audio_utils::EffectBase_Mutex) = 0;
};
class IAfEffectModule : public virtual IAfEffectBase {
@@ -162,45 +164,51 @@
virtual status_t setDevices(const AudioDeviceTypeAddrVector &devices) = 0;
virtual status_t setInputDevice(const AudioDeviceTypeAddr &device) = 0;
virtual status_t setVolume(uint32_t *left, uint32_t *right, bool controller) = 0;
- virtual status_t setOffloaded(bool offloaded, audio_io_handle_t io) = 0;
- virtual bool isOffloaded() const = 0;
+ virtual status_t setOffloaded_l(bool offloaded, audio_io_handle_t io) = 0;
+ virtual bool isOffloaded_l() const = 0;
virtual status_t setAudioSource(audio_source_t source) = 0;
virtual status_t setMode(audio_mode_t mode) = 0;
- virtual status_t start() = 0;
- virtual status_t getConfigs(audio_config_base_t* inputCfg,
- audio_config_base_t* outputCfg,
- bool* isOutput) const = 0;
+ virtual status_t start_l() = 0;
+ virtual status_t getConfigs_l(audio_config_base_t* inputCfg, audio_config_base_t* outputCfg,
+ bool* isOutput) const
+ REQUIRES(audio_utils::EffectHandle_Mutex) EXCLUDES_EffectBase_Mutex = 0;
static bool isHapticGenerator(const effect_uuid_t* type);
virtual bool isHapticGenerator() const = 0;
static bool isSpatializer(const effect_uuid_t* type);
virtual bool isSpatializer() const = 0;
- virtual status_t setHapticIntensity(int id, os::HapticScale intensity) = 0;
- virtual status_t setVibratorInfo(const media::AudioVibratorInfo& vibratorInfo) = 0;
- virtual status_t sendMetadata(const std::vector<playback_track_metadata_v7_t>& metadata) = 0;
+ virtual status_t setHapticIntensity_l(int id, os::HapticScale intensity)
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectBase_Mutex = 0;
+ virtual status_t setVibratorInfo_l(const media::AudioVibratorInfo& vibratorInfo)
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectBase_Mutex = 0;
+ virtual status_t sendMetadata_ll(const std::vector<playback_track_metadata_v7_t>& metadata)
+ REQUIRES(audio_utils::ThreadBase_Mutex,
+ audio_utils::EffectChain_Mutex) EXCLUDES_EffectBase_Mutex = 0;
private:
virtual void process() = 0;
- virtual bool updateState() = 0;
- virtual void reset_l() = 0;
- virtual status_t configure() = 0;
- virtual status_t init() = 0;
+ virtual bool updateState_l()
+ REQUIRES(audio_utils::EffectChain_Mutex) EXCLUDES_EffectBase_Mutex = 0;
+ virtual void reset_l() REQUIRES(audio_utils::EffectChain_Mutex) = 0;
+ virtual status_t configure_l() REQUIRES(audio_utils::EffectChain_Mutex) = 0;
+ virtual status_t init_l()
+ REQUIRES(audio_utils::EffectChain_Mutex) EXCLUDES_EffectBase_Mutex = 0;
virtual uint32_t status() const = 0;
virtual bool isProcessEnabled() const = 0;
- virtual bool isOffloadedOrDirect() const = 0;
- virtual bool isVolumeControlEnabled() const = 0;
+ virtual bool isOffloadedOrDirect_l() const REQUIRES(audio_utils::EffectChain_Mutex) = 0;
+ virtual bool isVolumeControlEnabled_l() const REQUIRES(audio_utils::EffectChain_Mutex) = 0;
virtual void setInBuffer(const sp<EffectBufferHalInterface>& buffer) = 0;
virtual void setOutBuffer(const sp<EffectBufferHalInterface>& buffer) = 0;
virtual int16_t *outBuffer() const = 0;
// Updates the access mode if it is out of date. May issue a new effect configure.
- virtual void updateAccessMode() = 0;
+ virtual void updateAccessMode_l() = 0;
- virtual status_t stop() = 0;
+ virtual status_t stop_l() = 0;
virtual void addEffectToHal_l() = 0;
virtual void release_l() = 0;
};
@@ -220,33 +228,41 @@
// a session is stopped or removed to allow effect tail to be rendered
static constexpr int kProcessTailDurationMs = 1000;
- virtual void process_l() = 0;
+ virtual void process_l() REQUIRES(audio_utils::EffectChain_Mutex) = 0;
- virtual audio_utils::mutex& mutex() const = 0;
+ virtual audio_utils::mutex& mutex() const RETURN_CAPABILITY(audio_utils::EffectChain_Mutex) = 0;
- virtual status_t createEffect_l(sp<IAfEffectModule>& effect,
- effect_descriptor_t *desc,
- int id,
- audio_session_t sessionId,
- bool pinned) = 0;
+ virtual status_t createEffect_l(sp<IAfEffectModule>& effect, effect_descriptor_t* desc, int id,
+ audio_session_t sessionId, bool pinned)
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectChain_Mutex = 0;
- virtual status_t addEffect_l(const sp<IAfEffectModule>& handle) = 0;
- virtual status_t addEffect_ll(const sp<IAfEffectModule>& handle) = 0;
- virtual size_t removeEffect_l(const sp<IAfEffectModule>& handle, bool release = false) = 0;
+ virtual status_t addEffect_l(const sp<IAfEffectModule>& handle)
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectChain_Mutex = 0;
+ virtual status_t addEffect_ll(const sp<IAfEffectModule>& handle)
+ REQUIRES(audio_utils::ThreadBase_Mutex, audio_utils::EffectChain_Mutex) = 0;
+ virtual size_t removeEffect_l(const sp<IAfEffectModule>& handle,
+ bool release = false) EXCLUDES_EffectChain_Mutex = 0;
virtual audio_session_t sessionId() const = 0;
virtual void setSessionId(audio_session_t sessionId) = 0;
- virtual sp<IAfEffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor) const = 0;
- virtual sp<IAfEffectModule> getEffectFromId_l(int id) const = 0;
- virtual sp<IAfEffectModule> getEffectFromType_l(const effect_uuid_t *type) const = 0;
- virtual std::vector<int> getEffectIds() const = 0;
- virtual bool setVolume_l(uint32_t *left, uint32_t *right, bool force = false) = 0;
- virtual void resetVolume_l() = 0;
- virtual void setDevices_l(const AudioDeviceTypeAddrVector &devices) = 0;
- virtual void setInputDevice_l(const AudioDeviceTypeAddr &device) = 0;
- virtual void setMode_l(audio_mode_t mode) = 0;
- virtual void setAudioSource_l(audio_source_t source) = 0;
+ virtual sp<IAfEffectModule> getEffectFromDesc_l(effect_descriptor_t* descriptor) const
+ REQUIRES(audio_utils::ThreadBase_Mutex) = 0;
+ virtual sp<IAfEffectModule> getEffectFromId_l(int id) const
+ REQUIRES(audio_utils::ThreadBase_Mutex) = 0;
+ virtual sp<IAfEffectModule> getEffectFromType_l(const effect_uuid_t* type) const
+ REQUIRES(audio_utils::ThreadBase_Mutex) = 0;
+ virtual std::vector<int> getEffectIds_l() const = 0;
+ virtual bool setVolume(uint32_t* left, uint32_t* right,
+ bool force = false) EXCLUDES_EffectChain_Mutex = 0;
+ virtual void resetVolume_l() REQUIRES(audio_utils::EffectChain_Mutex) = 0;
+ virtual void setDevices_l(const AudioDeviceTypeAddrVector& devices)
+ REQUIRES(audio_utils::ThreadBase_Mutex) = 0;
+ virtual void setInputDevice_l(const AudioDeviceTypeAddr& device)
+ REQUIRES(audio_utils::ThreadBase_Mutex) = 0;
+ virtual void setMode_l(audio_mode_t mode) REQUIRES(audio_utils::ThreadBase_Mutex) = 0;
+ virtual void setAudioSource_l(audio_source_t source)
+ REQUIRES(audio_utils::ThreadBase_Mutex) = 0;
virtual void setInBuffer(const sp<EffectBufferHalInterface>& buffer) = 0;
virtual float *inBuffer() const = 0;
@@ -266,20 +282,21 @@
// suspend or restore effects of the specified type. The number of suspend requests is counted
// and restore occurs once all suspend requests are cancelled.
- virtual void setEffectSuspended_l(
- const effect_uuid_t *type, bool suspend) = 0;
+ virtual void setEffectSuspended_l(const effect_uuid_t* type, bool suspend) = 0;
// suspend all eligible effects
virtual void setEffectSuspendedAll_l(bool suspend) = 0;
// check if effects should be suspended or restored when a given effect is enable or disabled
- virtual void checkSuspendOnEffectEnabled(const sp<IAfEffectModule>& effect, bool enabled) = 0;
+ virtual void checkSuspendOnEffectEnabled_l(const sp<IAfEffectModule>& effect, bool enabled)
+ REQUIRES(audio_utils::ThreadBase_Mutex) REQUIRES(audio_utils::ThreadBase_Mutex) = 0;
- virtual void clearInputBuffer() = 0;
+ virtual void clearInputBuffer() EXCLUDES_EffectChain_Mutex = 0;
// At least one non offloadable effect in the chain is enabled
- virtual bool isNonOffloadableEnabled() const = 0;
- virtual bool isNonOffloadableEnabled_l() const = 0;
+ virtual bool isNonOffloadableEnabled() const EXCLUDES_EffectChain_Mutex = 0;
+ virtual bool isNonOffloadableEnabled_l() const REQUIRES(audio_utils::EffectChain_Mutex) = 0;
- virtual void syncHalEffectsState() = 0;
+ virtual void syncHalEffectsState_l()
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectChain_Mutex = 0;
// flags is an ORed set of audio_output_flags_t which is updated on return.
virtual void checkOutputFlagCompatibility(audio_output_flags_t *flags) const = 0;
@@ -297,16 +314,18 @@
virtual bool isBitPerfectCompatible() const = 0;
// isCompatibleWithThread_l() must be called with thread->mLock held
- virtual bool isCompatibleWithThread_l(const sp<IAfThreadBase>& thread) const = 0;
+ virtual bool isCompatibleWithThread_l(const sp<IAfThreadBase>& thread) const
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectChain_Mutex = 0;
virtual bool containsHapticGeneratingEffect_l() = 0;
- virtual void setHapticIntensity_l(int id, os::HapticScale intensity) = 0;
+ virtual void setHapticIntensity_l(int id, os::HapticScale intensity)
+ REQUIRES(audio_utils::ThreadBase_Mutex) EXCLUDES_EffectChain_Mutex = 0;
virtual sp<EffectCallbackInterface> effectCallback() const = 0;
virtual wp<IAfThreadBase> thread() const = 0;
- virtual void setThread(const sp<IAfThreadBase>& thread) = 0;
+ virtual void setThread(const sp<IAfThreadBase>& thread) EXCLUDES_EffectChain_Mutex = 0;
virtual bool isFirstEffect(int id) const = 0;
@@ -360,9 +379,8 @@
const sp<DeviceEffectManagerCallback>& callback,
effect_descriptor_t *desc, int id, bool notifyFramesProcessed);
- virtual status_t init(
- const std::map<audio_patch_handle_t,
- IAfPatchPanel::Patch>& patches) = 0;
+ virtual status_t init_l(const std::map<audio_patch_handle_t, IAfPatchPanel::Patch>& patches)
+ REQUIRES(audio_utils::DeviceEffectManager_Mutex) EXCLUDES_EffectBase_Mutex = 0;
virtual const AudioDeviceTypeAddr& device() const = 0;
virtual status_t onCreatePatch(
diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h
index 46a67e8..d701288 100644
--- a/services/audioflinger/IAfThread.h
+++ b/services/audioflinger/IAfThread.h
@@ -279,7 +279,7 @@
// integrity of the chains during the process.
// Also sets the parameter 'effectChains' to current value of mEffectChains.
virtual void lockEffectChains_l(Vector<sp<IAfEffectChain>>& effectChains)
- REQUIRES(mutex()) = 0;
+ REQUIRES(mutex()) EXCLUDES_EffectChain_Mutex = 0;
// unlock effect chains after process
virtual void unlockEffectChains(const Vector<sp<IAfEffectChain>>& effectChains)
EXCLUDES_ThreadBase_Mutex = 0;
diff --git a/services/audioflinger/MelReporter.cpp b/services/audioflinger/MelReporter.cpp
index 41c5096..1d38306 100644
--- a/services/audioflinger/MelReporter.cpp
+++ b/services/audioflinger/MelReporter.cpp
@@ -307,6 +307,22 @@
}
+void MelReporter::applyAllAudioPatches() {
+ ALOGV("%s", __func__);
+
+ std::vector<IAfPatchPanel::Patch> patchesCopy;
+ {
+ audio_utils::lock_guard _laf(mAfMelReporterCallback->mutex());
+ for (const auto& patch : mAfPatchPanel->patches_l()) {
+ patchesCopy.emplace_back(patch.second);
+ }
+ }
+
+ for (const auto& patch : patchesCopy) {
+ onCreateAudioPatch(patch.mHalHandle, patch);
+ }
+}
+
std::optional<audio_patch_handle_t> MelReporter::activePatchStreamHandle_l(
audio_io_handle_t streamHandle) {
for(const auto& patchIt : mActiveMelPatches) {
diff --git a/services/audioflinger/MelReporter.h b/services/audioflinger/MelReporter.h
index 235dd11..0aeb225 100644
--- a/services/audioflinger/MelReporter.h
+++ b/services/audioflinger/MelReporter.h
@@ -27,8 +27,6 @@
namespace android {
-constexpr static int kMaxTimestampDeltaInSec = 120;
-
class IAfMelReporterCallback : public virtual RefBase {
public:
virtual audio_utils::mutex& mutex() const
@@ -45,8 +43,10 @@
class MelReporter : public PatchCommandThread::PatchCommandListener,
public IMelReporterCallback {
public:
- explicit MelReporter(const sp<IAfMelReporterCallback>& afMelReporterCallback)
- : mAfMelReporterCallback(afMelReporterCallback) {}
+ MelReporter(const sp<IAfMelReporterCallback>& afMelReporterCallback,
+ const sp<IAfPatchPanel>& afPatchPanel)
+ : mAfMelReporterCallback(afMelReporterCallback),
+ mAfPatchPanel(afPatchPanel) {}
void onFirstRef() override;
@@ -80,9 +80,10 @@
// IMelReporterCallback methods
void stopMelComputationForDeviceId(audio_port_handle_t deviceId) final
- EXCLUDES_MelReporter_Mutex;
+ EXCLUDES_AudioFlinger_Mutex EXCLUDES_MelReporter_Mutex;
void startMelComputationForDeviceId(audio_port_handle_t deviceId) final
- EXCLUDES_MelReporter_Mutex;
+ EXCLUDES_AudioFlinger_Mutex EXCLUDES_MelReporter_Mutex;
+ void applyAllAudioPatches() final EXCLUDES_AudioFlinger_Mutex EXCLUDES_MelReporter_Mutex;
// PatchCommandListener methods
void onCreateAudioPatch(audio_patch_handle_t handle,
@@ -131,6 +132,7 @@
bool useHalSoundDoseInterface_l() REQUIRES(mutex());
const sp<IAfMelReporterCallback> mAfMelReporterCallback;
+ const sp<IAfPatchPanel> mAfPatchPanel;
/* const */ sp<SoundDoseManager> mSoundDoseManager; // set onFirstRef
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 244a262..671e27f 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1691,7 +1691,7 @@
std::move(mAfThreadCallback->getDefaultVibratorInfo_l());
if (defaultVibratorInfo) {
// Only set the vibrator info when it is a valid one.
- effect->setVibratorInfo(*defaultVibratorInfo);
+ effect->setVibratorInfo_l(*defaultVibratorInfo);
}
}
// create effect handle and connect it to effect module
@@ -1793,7 +1793,7 @@
std::vector<int> ThreadBase::getEffectIds_l(audio_session_t sessionId) const
{
sp<IAfEffectChain> chain = getEffectChain_l(sessionId);
- return chain != nullptr ? chain->getEffectIds() : std::vector<int>{};
+ return chain != nullptr ? chain->getEffectIds_l() : std::vector<int>{};
}
// PlaybackThread::addEffect_ll() must be called with AudioFlinger::mutex() and
@@ -1825,7 +1825,7 @@
return BAD_VALUE;
}
- effect->setOffloaded(mType == OFFLOAD, mId);
+ effect->setOffloaded_l(mType == OFFLOAD, mId);
status_t status = chain->addEffect_l(effect);
if (status != NO_ERROR) {
@@ -1862,22 +1862,20 @@
}
}
-void ThreadBase::lockEffectChains_l(
- Vector<sp<IAfEffectChain>>& effectChains)
-NO_THREAD_SAFETY_ANALYSIS // calls EffectChain::lock()
+void ThreadBase::lockEffectChains_l(Vector<sp<IAfEffectChain>>& effectChains)
+ NO_THREAD_SAFETY_ANALYSIS // calls EffectChain::lock()
{
effectChains = mEffectChains;
- for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->mutex().lock();
+ for (const auto& effectChain : effectChains) {
+ effectChain->mutex().lock();
}
}
-void ThreadBase::unlockEffectChains(
- const Vector<sp<IAfEffectChain>>& effectChains)
-NO_THREAD_SAFETY_ANALYSIS // calls EffectChain::unlock()
+void ThreadBase::unlockEffectChains(const Vector<sp<IAfEffectChain>>& effectChains)
+ NO_THREAD_SAFETY_ANALYSIS // calls EffectChain::unlock()
{
- for (size_t i = 0; i < effectChains.size(); i++) {
- effectChains[i]->mutex().unlock();
+ for (const auto& effectChain : effectChains) {
+ effectChain->mutex().unlock();
}
}
@@ -5501,7 +5499,7 @@
sp<IAfEffectChain> chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
if (chain != 0) {
uint32_t v = (uint32_t)(masterVolume * (1 << 24));
- chain->setVolume_l(&v, &v);
+ chain->setVolume(&v, &v);
masterVolume = (float)((v + (1 << 23)) >> 24);
chain.clear();
}
@@ -5836,7 +5834,7 @@
mixedTracks++;
- // track->mainBuffer() != mSinkBuffer or mMixerBuffer means
+ // track->mainBuffer() != mSinkBuffer and mMixerBuffer means
// there is an effect chain connected to the track
chain.clear();
if (track->mainBuffer() != mSinkBuffer &&
@@ -5940,7 +5938,7 @@
track->setFinalVolume(vrf, vlf);
// Delegate volume control to effect in track effect chain if needed
- if (chain != 0 && chain->setVolume_l(&vl, &vr)) {
+ if (chain != 0 && chain->setVolume(&vl, &vr)) {
// Do not ramp volume if volume is controlled by effect
param = AudioMixer::VOLUME;
// Update remaining floating point volume levels
@@ -6680,8 +6678,8 @@
// Convert volumes from float to 8.24
uint32_t vl = (uint32_t)(left * (1 << 24));
uint32_t vr = (uint32_t)(right * (1 << 24));
- // Direct/Offload effect chains set output volume in setVolume_l().
- (void)mEffectChains[0]->setVolume_l(&vl, &vr);
+ // Direct/Offload effect chains set output volume in setVolume().
+ (void)mEffectChains[0]->setVolume(&vl, &vr);
} else {
// otherwise we directly set the volume.
setVolumeForOutput_l(left, right);
@@ -9748,7 +9746,7 @@
// make sure enabled pre processing effects state is communicated to the HAL as we
// just moved them to a new input stream.
- chain->syncHalEffectsState();
+ chain->syncHalEffectsState_l();
mEffectChains.add(chain);
@@ -10733,7 +10731,7 @@
chain->setThread(this);
chain->setInBuffer(nullptr);
chain->setOutBuffer(nullptr);
- chain->syncHalEffectsState();
+ chain->syncHalEffectsState_l();
mEffectChains.add(chain);
checkSuspendOnAddEffectChain_l(chain);
@@ -11026,7 +11024,7 @@
// only one effect chain can be present on DirectOutputThread, so if
// there is one, the track is connected to it
if (!mEffectChains.isEmpty()) {
- mEffectChains[0]->setVolume_l(&vol, &vol);
+ mEffectChains[0]->setVolume(&vol, &vol);
volume = (float)vol / (1 << 24);
}
// Try to use HW volume control and fall back to SW control if not implemented
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 8491e43..a6888c0 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -436,9 +436,11 @@
// ThreadBase mutex before processing the mixer and effects. This guarantees the
// integrity of the chains during the process.
// Also sets the parameter 'effectChains' to current value of mEffectChains.
- void lockEffectChains_l(Vector<sp<IAfEffectChain>>& effectChains) final REQUIRES(mutex());
+ void lockEffectChains_l(Vector<sp<IAfEffectChain>>& effectChains) final
+ REQUIRES(audio_utils::ThreadBase_Mutex) ACQUIRE(audio_utils::EffectChain_Mutex);
// unlock effect chains after process
- void unlockEffectChains(const Vector<sp<IAfEffectChain>>& effectChains) final;
+ void unlockEffectChains(const Vector<sp<IAfEffectChain>>& effectChains) final
+ RELEASE(audio_utils::EffectChain_Mutex);
// get a copy of mEffectChains vector
Vector<sp<IAfEffectChain>> getEffectChains_l() const final REQUIRES(mutex()) {
return mEffectChains;
diff --git a/services/audioflinger/afutils/Vibrator.cpp b/services/audioflinger/afutils/Vibrator.cpp
index 25fcc6a..ab15a09 100644
--- a/services/audioflinger/afutils/Vibrator.cpp
+++ b/services/audioflinger/afutils/Vibrator.cpp
@@ -44,6 +44,10 @@
}
os::HapticScale onExternalVibrationStart(const sp<os::ExternalVibration>& externalVibration) {
+ if (externalVibration->getAudioAttributes().flags & AUDIO_FLAG_MUTE_HAPTIC) {
+ ALOGD("%s, mute haptic according to audio attributes flag", __func__);
+ return os::HapticScale::MUTE;
+ }
const sp<os::IExternalVibratorService> evs = getExternalVibratorService();
if (evs != nullptr) {
int32_t ret;
diff --git a/services/audioflinger/sounddose/SoundDoseManager.cpp b/services/audioflinger/sounddose/SoundDoseManager.cpp
index bf72661..6797e3d 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.cpp
+++ b/services/audioflinger/sounddose/SoundDoseManager.cpp
@@ -231,6 +231,13 @@
ALOGI("%s: could not find port id for device %s", __func__, adt.toString().c_str());
return AUDIO_PORT_HANDLE_NONE;
}
+ const auto btDeviceIt = mBluetoothDevicesWithCsd.find(std::make_pair(address, type));
+ if (btDeviceIt != mBluetoothDevicesWithCsd.end()) {
+ if (!btDeviceIt->second) {
+ ALOGI("%s: bt device %s does not support sound dose", __func__, adt.toString().c_str());
+ return AUDIO_PORT_HANDLE_NONE;
+ }
+ }
return deviceIt->second;
}
@@ -583,8 +590,19 @@
}
void SoundDoseManager::setComputeCsdOnAllDevices(bool computeCsdOnAllDevices) {
- const std::lock_guard _l(mLock);
- mComputeCsdOnAllDevices = computeCsdOnAllDevices;
+ bool changed = false;
+ {
+ const std::lock_guard _l(mLock);
+ if (mHalSoundDose.size() != 0) {
+ // when using the HAL path we cannot enforce to deliver values for all devices
+ changed = mUseFrameworkMel != computeCsdOnAllDevices;
+ mUseFrameworkMel = computeCsdOnAllDevices;
+ }
+ mComputeCsdOnAllDevices = computeCsdOnAllDevices;
+ }
+ if (changed && computeCsdOnAllDevices) {
+ mMelReporterCallback->applyAllAudioPatches();
+ }
}
bool SoundDoseManager::isComputeCsdForcedOnAllDevices() const {
diff --git a/services/audioflinger/sounddose/SoundDoseManager.h b/services/audioflinger/sounddose/SoundDoseManager.h
index 0c49a80..52a3fd6 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.h
+++ b/services/audioflinger/sounddose/SoundDoseManager.h
@@ -39,6 +39,8 @@
virtual void stopMelComputationForDeviceId(audio_port_handle_t deviceId) = 0;
virtual void startMelComputationForDeviceId(audio_port_handle_t deviceId) = 0;
+
+ virtual void applyAllAudioPatches() = 0;
};
class SoundDoseManager : public audio_utils::MelProcessor::MelCallback {
diff --git a/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp b/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
index 1151647..e79b05e 100644
--- a/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
+++ b/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
@@ -44,6 +44,7 @@
public:
MOCK_METHOD(void, startMelComputationForDeviceId, (audio_port_handle_t), (override));
MOCK_METHOD(void, stopMelComputationForDeviceId, (audio_port_handle_t), (override));
+ MOCK_METHOD(void, applyAllAudioPatches, (), (override));
};
class MelAggregatorMock : public audio_utils::MelAggregator {
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index b164159..9ececea 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -285,7 +285,8 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId,
- uid_t uid) = 0;
+ uid_t uid,
+ bool internal = false) = 0;
virtual status_t stopAudioSource(audio_port_handle_t portId) = 0;
virtual status_t setMasterMono(bool mono) = 0;
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 7119b85..fe90a1e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -222,7 +222,8 @@
const struct audio_port_config &config,
const sp<DeviceDescriptor>& srcDevice,
audio_stream_type_t stream, product_strategy_t strategy,
- VolumeSource volumeSource);
+ VolumeSource volumeSource,
+ bool isInternal);
~SourceClientDescriptor() override = default;
@@ -248,6 +249,7 @@
void setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput, bool closeOutput = false);
wp<HwAudioOutputDescriptor> hwOutput() const { return mHwOutput; }
void setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput);
+ bool isInternal() const override { return mIsInternal; }
using ClientDescriptor::dump;
void dump(String8 *dst, int spaces) const override;
@@ -268,34 +270,17 @@
* behavior of AudioDeviceCallback.
*/
bool mCloseOutput = false;
-};
-
-/**
- * @brief The InternalSourceClientDescriptor class
- * Specialized Client Descriptor for either a raw patch created from @see createAudioPatch API
- * or for internal audio patches managed by APM (e.g. phone call patches).
- * Whatever the bridge created (software or hardware), we need a client to track the activity
- * and manage volumes.
- * The Audio Patch requested sink is expressed as a preferred device which allows to route
- * the SwOutput. Then APM will performs checks on the UID (against UID of Audioserver) of the
- * requester to prevent rerouting SwOutput involved in raw patches.
- */
-class InternalSourceClientDescriptor: public SourceClientDescriptor
-{
-public:
- InternalSourceClientDescriptor(
- audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes,
- const struct audio_port_config &config, const sp<DeviceDescriptor>& srcDevice,
- const sp<DeviceDescriptor>& sinkDevice,
- product_strategy_t strategy, VolumeSource volumeSource) :
- SourceClientDescriptor(
- portId, uid, attributes, config, srcDevice, AUDIO_STREAM_PATCH, strategy,
- volumeSource)
- {
- setPreferredDeviceId(sinkDevice->getId());
- }
- bool isInternal() const override { return true; }
- ~InternalSourceClientDescriptor() override = default;
+ /**
+ * True for specialized Client Descriptor for either a raw patch created from
+ * @see createAudioPatch API or for internal audio patches managed by APM
+ * (e.g. phone call patches).
+ * Whatever the bridge created (software or hardware), we need a client to track the activity
+ * and manage volumes.
+ * The Audio Patch requested sink is expressed as a preferred device which allows to route
+ * the SwOutput. Then APM will performs checks on the UID (against UID of Audioserver) of the
+ * requester to prevent rerouting SwOutput involved in raw patches.
+ */
+ bool mIsInternal = false;
};
class SourceClientCollection :
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index 8b6866e..2aee501 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -96,12 +96,12 @@
SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid,
audio_attributes_t attributes, const struct audio_port_config &config,
const sp<DeviceDescriptor>& srcDevice, audio_stream_type_t stream,
- product_strategy_t strategy, VolumeSource volumeSource) :
+ product_strategy_t strategy, VolumeSource volumeSource, bool isInternal) :
TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
{config.sample_rate, config.channel_mask, config.format}, AUDIO_PORT_HANDLE_NONE,
stream, strategy, volumeSource, AUDIO_OUTPUT_FLAG_NONE, false,
{} /* Sources do not support secondary outputs*/, nullptr),
- mSrcDevice(srcDevice)
+ mSrcDevice(srcDevice), mIsInternal(isInternal)
{
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 252470b..46e4d60 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -782,7 +782,11 @@
.ext.device.type = AUDIO_DEVICE_IN_TELEPHONY_RX, .ext.device.address = ""
};
const auto aa = mEngine->getAttributesForStreamType(AUDIO_STREAM_VOICE_CALL);
- mCallRxSourceClient = startAudioSourceInternal(&source, &aa, 0/*uid*/);
+
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+ status_t status = startAudioSource(&source, &aa, &portId, 0 /*uid*/, true /*internal*/);
+ ALOGE_IF(status != OK, "%s: failed to start audio source (%d)", __func__, status);
+ mCallRxSourceClient = mAudioSources.valueFor(portId);
ALOGE_IF(mCallRxSourceClient == nullptr,
"%s failed to start Telephony Rx AudioSource", __func__);
}
@@ -815,9 +819,11 @@
struct audio_port_config source = {};
srcDevice->toAudioPortConfig(&source);
- mCallTxSourceClient = new InternalSourceClientDescriptor(
- callTxSourceClientPortId, mUidCached, aa, source, srcDevice, sinkDevice,
- mCommunnicationStrategy, toVolumeSource(aa));
+ mCallTxSourceClient = new SourceClientDescriptor(
+ callTxSourceClientPortId, mUidCached, aa, source, srcDevice, AUDIO_STREAM_PATCH,
+ mCommunnicationStrategy, toVolumeSource(aa), true);
+ mCallTxSourceClient->setPreferredDeviceId(sinkDevice->getId());
+
audio_patch_handle_t patchHandle = AUDIO_PATCH_HANDLE_NONE;
status_t status = connectAudioSourceToSink(
mCallTxSourceClient, sinkDevice, patchBuilder.patch(), patchHandle, mUidCached,
@@ -1628,7 +1634,8 @@
*isSpatialized = false;
if (mSpatializerOutput != nullptr
- && canBeSpatializedInt(attr, config, devices.toTypeAddrVector())) {
+ && canBeSpatializedInt(attr, config, devices.toTypeAddrVector())
+ && prefMixerConfigInfo == nullptr) {
*isSpatialized = true;
return mSpatializerOutput->mIoHandle;
}
@@ -4873,9 +4880,11 @@
audio_attributes_t attributes = attributes_initializer(AUDIO_USAGE_MEDIA);
const struct audio_port_config *source = &patch->sources[0];
sp<SourceClientDescriptor> sourceDesc =
- new InternalSourceClientDescriptor(
- portId, uid, attributes, *source, srcDevice, sinkDevice,
- mEngine->getProductStrategyForAttributes(attributes), toVolumeSource(attributes));
+ new SourceClientDescriptor(
+ portId, uid, attributes, *source, srcDevice, AUDIO_STREAM_PATCH,
+ mEngine->getProductStrategyForAttributes(attributes), toVolumeSource(attributes),
+ true);
+ sourceDesc->setPreferredDeviceId(sinkDevice->getId());
status_t status =
connectAudioSourceToSink(sourceDesc, sinkDevice, patch, *handle, uid, 0 /* delayMs */);
@@ -5542,7 +5551,7 @@
status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId,
- uid_t uid)
+ uid_t uid, bool internal)
{
ALOGV("%s", __FUNCTION__);
*portId = AUDIO_PORT_HANDLE_NONE;
@@ -5575,7 +5584,7 @@
new SourceClientDescriptor(*portId, uid, *attributes, *source, srcDevice,
mEngine->getStreamTypeForAttributes(*attributes),
mEngine->getProductStrategyForAttributes(*attributes),
- toVolumeSource(*attributes));
+ toVolumeSource(*attributes), internal);
status_t status = connectAudioSource(sourceDesc);
if (status == NO_ERROR) {
@@ -5584,18 +5593,6 @@
return status;
}
-sp<SourceClientDescriptor> AudioPolicyManager::startAudioSourceInternal(
- const struct audio_port_config *source, const audio_attributes_t *attributes, uid_t uid)
-{
- ALOGV("%s", __FUNCTION__);
- audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
-
- status_t status = startAudioSource(source, attributes, &portId, uid);
- ALOGE_IF(status != OK, "%s: failed to start audio source (%d)", __func__, status);
- return mAudioSources.valueFor(portId);
-}
-
-
status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
{
ALOGV("%s handle %d", __FUNCTION__, sourceDesc->portId());
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 61be09f..ea60c2b 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -339,7 +339,8 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId,
- uid_t uid);
+ uid_t uid,
+ bool internal = false);
virtual status_t stopAudioSource(audio_port_handle_t portId);
virtual status_t setMasterMono(bool mono);
@@ -1055,9 +1056,6 @@
bool isMsdPatch(const audio_patch_handle_t &handle) const;
private:
- sp<SourceClientDescriptor> startAudioSourceInternal(
- const struct audio_port_config *source, const audio_attributes_t *attributes,
- uid_t uid);
void onNewAudioModulesAvailableInt(DeviceVector *newDevices);
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index e316bce..575e0fb 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -101,7 +101,7 @@
"android.frameworks.cameraservice.device-V2-ndk",
"android.hardware.camera.common-V1-ndk",
"android.hardware.camera.device-V3-ndk",
- "android.hardware.camera.metadata-V2-ndk",
+ "android.hardware.camera.metadata-V3-ndk",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.6",
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 70110bd..be5ed4e 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -1823,18 +1823,13 @@
auto& c = mCameraCharacteristics;
auto entry = c.find(ANDROID_SENSOR_READOUT_TIMESTAMP);
- if (entry.count != 0) {
- ALOGE("%s: CameraCharacteristics must not contain ANDROID_SENSOR_READOUT_TIMESTAMP!",
- __FUNCTION__);
+ if (entry.count == 0) {
+ uint8_t defaultReadoutTimestamp = readoutTimestampSupported ?
+ ANDROID_SENSOR_READOUT_TIMESTAMP_HARDWARE :
+ ANDROID_SENSOR_READOUT_TIMESTAMP_NOT_SUPPORTED;
+ res = c.update(ANDROID_SENSOR_READOUT_TIMESTAMP, &defaultReadoutTimestamp, 1);
}
- uint8_t readoutTimestamp = ANDROID_SENSOR_READOUT_TIMESTAMP_NOT_SUPPORTED;
- if (readoutTimestampSupported) {
- readoutTimestamp = ANDROID_SENSOR_READOUT_TIMESTAMP_HARDWARE;
- }
-
- res = c.update(ANDROID_SENSOR_READOUT_TIMESTAMP, &readoutTimestamp, 1);
-
return res;
}
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
index d3b874d..13c500f 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
@@ -339,6 +339,16 @@
mBatchSizeLimitEnabled = (deviceVersion >= CAMERA_DEVICE_API_VERSION_1_2);
+ camera_metadata_entry readoutSupported = mDeviceInfo.find(ANDROID_SENSOR_READOUT_TIMESTAMP);
+ if (readoutSupported.count == 0) {
+ ALOGW("%s: Could not find value corresponding to ANDROID_SENSOR_READOUT_TIMESTAMP. "
+ "Assuming true.", __FUNCTION__);
+ mSensorReadoutTimestampSupported = true;
+ } else {
+ mSensorReadoutTimestampSupported =
+ readoutSupported.data.u8[0] == ANDROID_SENSOR_READOUT_TIMESTAMP_HARDWARE;
+ }
+
return initializeCommonLocked();
}
@@ -452,7 +462,7 @@
mOverrideToPortrait, mActivePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
- camera3::notify(states, msg);
+ camera3::notify(states, msg, mSensorReadoutTimestampSupported);
}
return ::ndk::ScopedAStatus::ok();
@@ -623,7 +633,8 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers);
*session = new AidlCamera3OfflineSession(mId, inputStream, offlineStreamSet,
- std::move(bufferRecords), offlineReqs, offlineStates, offlineSession);
+ std::move(bufferRecords), offlineReqs, offlineStates,
+ offlineSession, mSensorReadoutTimestampSupported);
// Delete all streams that has been transferred to offline session
Mutex::Autolock l(mLock);
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
index 90e2f97..f0a5f7e 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
@@ -289,6 +289,9 @@
// capture requests.
bool mBatchSizeLimitEnabled = false;
+ // Whether the HAL supports reporting sensor readout timestamp
+ bool mSensorReadoutTimestampSupported = true;
+
}; // class AidlCamera3Device
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
index b55e0da..f8308df 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
@@ -177,7 +177,7 @@
/*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
- camera3::notify(states, msg);
+ camera3::notify(states, msg, mSensorReadoutTimestampSupported);
}
return ::ndk::ScopedAStatus::ok();
}
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.h
index 33b638c..f8fdeb9 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.h
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.h
@@ -105,19 +105,20 @@
};
// initialize by Camera3Device.
- explicit AidlCamera3OfflineSession(const std::string& id,
- const sp<camera3::Camera3Stream>& inputStream,
- const camera3::StreamSet& offlineStreamSet,
- camera3::BufferRecords&& bufferRecords,
+ explicit AidlCamera3OfflineSession(
+ const std::string& id, const sp<camera3::Camera3Stream>& inputStream,
+ const camera3::StreamSet& offlineStreamSet, camera3::BufferRecords&& bufferRecords,
const camera3::InFlightRequestMap& offlineReqs,
const Camera3OfflineStates& offlineStates,
std::shared_ptr<aidl::android::hardware::camera::device::ICameraOfflineSession>
- offlineSession) :
- Camera3OfflineSession(id, inputStream, offlineStreamSet, std::move(bufferRecords),
- offlineReqs, offlineStates),
- mSession(offlineSession) {
- mCallbacks = ndk::SharedRefBase::make<AidlCameraDeviceCallbacks>(this);
- };
+ offlineSession,
+ bool sensorReadoutTimestampSupported)
+ : Camera3OfflineSession(id, inputStream, offlineStreamSet, std::move(bufferRecords),
+ offlineReqs, offlineStates),
+ mSession(offlineSession),
+ mSensorReadoutTimestampSupported(sensorReadoutTimestampSupported) {
+ mCallbacks = ndk::SharedRefBase::make<AidlCameraDeviceCallbacks>(this);
+ };
/**
* End of CameraOfflineSessionBase interface
@@ -130,6 +131,8 @@
std::shared_ptr<AidlCameraDeviceCallbacks> mCallbacks;
+ bool mSensorReadoutTimestampSupported;
+
virtual void closeSessionLocked() override;
virtual void releaseSessionLocked() override;
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.cpp
index 6be9e70..3fc070b 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.cpp
@@ -67,7 +67,8 @@
}
void notify(CaptureOutputStates& states,
- const aidl::android::hardware::camera::device::NotifyMsg& msg) {
+ const aidl::android::hardware::camera::device::NotifyMsg& msg,
+ bool hasReadoutTimestamp) {
using ErrorCode = aidl::android::hardware::camera::device::ErrorCode;
using Tag = aidl::android::hardware::camera::device::NotifyMsg::Tag;
@@ -110,8 +111,9 @@
m.type = CAMERA_MSG_SHUTTER;
m.message.shutter.frame_number = msg.get<Tag::shutter>().frameNumber;
m.message.shutter.timestamp = msg.get<Tag::shutter>().timestamp;
- m.message.shutter.readout_timestamp_valid = true;
- m.message.shutter.readout_timestamp = msg.get<Tag::shutter>().readoutTimestamp;
+ m.message.shutter.readout_timestamp_valid = hasReadoutTimestamp;
+ m.message.shutter.readout_timestamp =
+ hasReadoutTimestamp ? msg.get<Tag::shutter>().readoutTimestamp : 0LL;
break;
}
notify(states, &m);
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.h
index e795624..d3a8ede 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.h
@@ -79,11 +79,8 @@
&physicalCameraMetadata);
void notify(CaptureOutputStates& states,
- const aidl::android::hardware::camera::device::NotifyMsg& msg,
- bool hasReadoutTime, uint64_t readoutTime);
-
- void notify(CaptureOutputStates& states,
- const aidl::android::hardware::camera::device::NotifyMsg& msg);
+ const aidl::android::hardware::camera::device::NotifyMsg& msg,
+ bool hasReadoutTimestamp);
void requestStreamBuffers(RequestBufferStates& states,
const std::vector<aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
diff --git a/services/camera/virtualcamera/VirtualCameraDevice.cc b/services/camera/virtualcamera/VirtualCameraDevice.cc
index 84f721b..768dffb 100644
--- a/services/camera/virtualcamera/VirtualCameraDevice.cc
+++ b/services/camera/virtualcamera/VirtualCameraDevice.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -28,6 +28,7 @@
#include "VirtualCameraSession.h"
#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
+#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
#include "aidl/android/hardware/camera/common/Status.h"
#include "aidl/android/hardware/camera/device/CameraMetadata.h"
#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
@@ -44,7 +45,10 @@
using ::aidl::android::companion::virtualcamera::Format;
using ::aidl::android::companion::virtualcamera::IVirtualCameraCallback;
+using ::aidl::android::companion::virtualcamera::LensFacing;
+using ::aidl::android::companion::virtualcamera::SensorOrientation;
using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
+using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
using ::aidl::android::hardware::camera::common::CameraResourceCost;
using ::aidl::android::hardware::camera::common::Status;
using ::aidl::android::hardware::camera::device::CameraMetadata;
@@ -64,11 +68,15 @@
// Prefix of camera name - "device@1.1/virtual/{numerical_id}"
const char* kDevicePathPrefix = "device@1.1/virtual/";
-constexpr std::chrono::nanoseconds kMinFrameDuration30Fps = 1s / 30;
constexpr int32_t kMaxJpegSize = 3 * 1024 * 1024 /*3MiB*/;
constexpr MetadataBuilder::ControlRegion kDefaultEmptyControlRegion{};
+const std::array<int32_t, 3> kOutputFormats{
+ ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
+ ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,
+ ANDROID_SCALER_AVAILABLE_FORMATS_BLOB};
+
struct Resolution {
Resolution(const int w, const int h) : width(w), height(h) {
}
@@ -103,24 +111,34 @@
return Resolution(itMax->width, itMax->height);
}
-std::set<Resolution> getUniqueResolutions(
+// Returns a map of unique resolution to maximum maxFps for all streams with
+// that resolution.
+std::map<Resolution, int> getResolutionToMaxFpsMap(
const std::vector<SupportedStreamConfiguration>& configs) {
- std::set<Resolution> uniqueResolutions;
- std::transform(configs.begin(), configs.end(),
- std::inserter(uniqueResolutions, uniqueResolutions.begin()),
- [](const SupportedStreamConfiguration& config) {
- return Resolution(config.width, config.height);
- });
- return uniqueResolutions;
+ std::map<Resolution, int> resolutionToMaxFpsMap;
+
+ for (const SupportedStreamConfiguration& config : configs) {
+ Resolution resolution(config.width, config.height);
+ if (resolutionToMaxFpsMap.find(resolution) == resolutionToMaxFpsMap.end()) {
+ resolutionToMaxFpsMap[resolution] = config.maxFps;
+ } else {
+ int currentMaxFps = resolutionToMaxFpsMap[resolution];
+ resolutionToMaxFpsMap[resolution] = std::max(currentMaxFps, config.maxFps);
+ }
+ }
+
+ return resolutionToMaxFpsMap;
}
// TODO(b/301023410) - Populate camera characteristics according to camera configuration.
std::optional<CameraMetadata> initCameraCharacteristics(
- const std::vector<SupportedStreamConfiguration>& supportedInputConfig) {
+ const std::vector<SupportedStreamConfiguration>& supportedInputConfig,
+ const SensorOrientation sensorOrientation, const LensFacing lensFacing) {
if (!std::all_of(supportedInputConfig.begin(), supportedInputConfig.end(),
[](const SupportedStreamConfiguration& config) {
return isFormatSupportedForInput(
- config.width, config.height, config.pixelFormat);
+ config.width, config.height, config.pixelFormat,
+ config.maxFps);
})) {
ALOGE("%s: input configuration contains unsupported format", __func__);
return std::nullopt;
@@ -131,8 +149,9 @@
.setSupportedHardwareLevel(
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL)
.setFlashAvailable(false)
- .setLensFacing(ANDROID_LENS_FACING_EXTERNAL)
- .setSensorOrientation(0)
+ .setLensFacing(
+ static_cast<camera_metadata_enum_android_lens_facing>(lensFacing))
+ .setSensorOrientation(static_cast<int32_t>(sensorOrientation))
.setAvailableFaceDetectModes({ANDROID_STATISTICS_FACE_DETECT_MODE_OFF})
.setAvailableMaxDigitalZoom(1.0)
.setControlAvailableModes({ANDROID_CONTROL_MODE_AUTO})
@@ -166,45 +185,24 @@
// TODO(b/301023410) Add also all "standard" resolutions we can rescale the
// streams to (all standard resolutions with same aspect ratio).
- // Add IMPLEMENTATION_DEFINED format for all supported input resolutions.
- std::set<Resolution> uniqueResolutions =
- getUniqueResolutions(supportedInputConfig);
- std::transform(
- uniqueResolutions.begin(), uniqueResolutions.end(),
- std::back_inserter(outputConfigurations),
- [](const Resolution& resolution) {
- return MetadataBuilder::StreamConfiguration{
- .width = resolution.width,
- .height = resolution.height,
- .format = ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
- .minFrameDuration = kMinFrameDuration30Fps,
- .minStallDuration = 0s};
- });
+ std::map<Resolution, int> resolutionToMaxFpsMap =
+ getResolutionToMaxFpsMap(supportedInputConfig);
- // Add all supported configuration with explicit pixel format.
- std::transform(supportedInputConfig.begin(), supportedInputConfig.end(),
- std::back_inserter(outputConfigurations),
- [](const SupportedStreamConfiguration& config) {
- return MetadataBuilder::StreamConfiguration{
- .width = config.width,
- .height = config.height,
- .format = static_cast<int>(config.pixelFormat),
- .minFrameDuration = kMinFrameDuration30Fps,
- .minStallDuration = 0s};
- });
-
- // TODO(b/301023410) We currently don't support rescaling for still capture,
- // so only announce BLOB support for formats exactly matching the input.
- std::transform(uniqueResolutions.begin(), uniqueResolutions.end(),
- std::back_inserter(outputConfigurations),
- [](const Resolution& resolution) {
- return MetadataBuilder::StreamConfiguration{
- .width = resolution.width,
- .height = resolution.height,
- .format = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB,
- .minFrameDuration = kMinFrameDuration30Fps,
- .minStallDuration = 0s};
- });
+ // Add configurations for all unique input resolutions and output formats.
+ for (int32_t format : kOutputFormats) {
+ std::transform(
+ resolutionToMaxFpsMap.begin(), resolutionToMaxFpsMap.end(),
+ std::back_inserter(outputConfigurations), [format](const auto& entry) {
+ Resolution resolution = entry.first;
+ int maxFps = entry.second;
+ return MetadataBuilder::StreamConfiguration{
+ .width = resolution.width,
+ .height = resolution.height,
+ .format = format,
+ .minFrameDuration = std::chrono::nanoseconds(1s) / maxFps,
+ .minStallDuration = 0s};
+ });
+ }
ALOGV("Adding %zu output configurations", outputConfigurations.size());
builder.setAvailableOutputStreamConfigurations(outputConfigurations);
@@ -221,14 +219,13 @@
} // namespace
VirtualCameraDevice::VirtualCameraDevice(
- const uint32_t cameraId,
- const std::vector<SupportedStreamConfiguration>& supportedInputConfig,
- std::shared_ptr<IVirtualCameraCallback> virtualCameraClientCallback)
+ const uint32_t cameraId, const VirtualCameraConfiguration& configuration)
: mCameraId(cameraId),
- mVirtualCameraClientCallback(virtualCameraClientCallback),
- mSupportedInputConfigurations(supportedInputConfig) {
- std::optional<CameraMetadata> metadata =
- initCameraCharacteristics(mSupportedInputConfigurations);
+ mVirtualCameraClientCallback(configuration.virtualCameraCallback),
+ mSupportedInputConfigurations(configuration.supportedStreamConfigs) {
+ std::optional<CameraMetadata> metadata = initCameraCharacteristics(
+ mSupportedInputConfigurations, configuration.sensorOrientation,
+ configuration.lensFacing);
if (metadata.has_value()) {
mCameraCharacteristics = *metadata;
} else {
@@ -286,6 +283,11 @@
bool VirtualCameraDevice::isStreamCombinationSupported(
const StreamConfiguration& streamConfiguration) const {
+ if (streamConfiguration.streams.empty()) {
+ ALOGE("%s: Querying empty configuration", __func__);
+ return false;
+ }
+
for (const Stream& stream : streamConfiguration.streams) {
ALOGV("%s: Configuration queried: %s", __func__, stream.toString().c_str());
diff --git a/services/camera/virtualcamera/VirtualCameraDevice.h b/services/camera/virtualcamera/VirtualCameraDevice.h
index 402de6c..10d52af 100644
--- a/services/camera/virtualcamera/VirtualCameraDevice.h
+++ b/services/camera/virtualcamera/VirtualCameraDevice.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -22,6 +22,7 @@
#include "aidl/android/companion/virtualcamera/IVirtualCameraCallback.h"
#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
+#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
#include "aidl/android/hardware/camera/device/BnCameraDevice.h"
namespace android {
@@ -35,12 +36,8 @@
public:
explicit VirtualCameraDevice(
uint32_t cameraId,
- const std::vector<
- aidl::android::companion::virtualcamera::SupportedStreamConfiguration>&
- supportedInputConfig,
- std::shared_ptr<
- ::aidl::android::companion::virtualcamera::IVirtualCameraCallback>
- virtualCameraClientCallback = nullptr);
+ const aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
+ configuration);
virtual ~VirtualCameraDevice() override = default;
diff --git a/services/camera/virtualcamera/VirtualCameraProvider.cc b/services/camera/virtualcamera/VirtualCameraProvider.cc
index 25a43d6..e4a68f5 100644
--- a/services/camera/virtualcamera/VirtualCameraProvider.cc
+++ b/services/camera/virtualcamera/VirtualCameraProvider.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -33,8 +33,7 @@
namespace companion {
namespace virtualcamera {
-using ::aidl::android::companion::virtualcamera::IVirtualCameraCallback;
-using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
+using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
using ::aidl::android::hardware::camera::common::Status;
using ::aidl::android::hardware::camera::common::VendorTagSection;
@@ -155,10 +154,9 @@
}
std::shared_ptr<VirtualCameraDevice> VirtualCameraProvider::createCamera(
- const std::vector<SupportedStreamConfiguration>& supportedInputConfig,
- std::shared_ptr<IVirtualCameraCallback> virtualCameraClientCallback) {
- auto camera = ndk::SharedRefBase::make<VirtualCameraDevice>(
- sNextId++, supportedInputConfig, virtualCameraClientCallback);
+ const VirtualCameraConfiguration& configuration) {
+ auto camera =
+ ndk::SharedRefBase::make<VirtualCameraDevice>(sNextId++, configuration);
std::shared_ptr<ICameraProviderCallback> callback;
{
const std::lock_guard<std::mutex> lock(mLock);
diff --git a/services/camera/virtualcamera/VirtualCameraProvider.h b/services/camera/virtualcamera/VirtualCameraProvider.h
index d41a005..11d3123 100644
--- a/services/camera/virtualcamera/VirtualCameraProvider.h
+++ b/services/camera/virtualcamera/VirtualCameraProvider.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -74,14 +74,9 @@
// Create new virtual camera devices
// Returns nullptr if creation was not successful.
- //
- // TODO(b/301023410) - Add camera configuration.
std::shared_ptr<VirtualCameraDevice> createCamera(
- const std::vector<
- aidl::android::companion::virtualcamera::SupportedStreamConfiguration>&
- supportedInputConfig,
- std::shared_ptr<aidl::android::companion::virtualcamera::IVirtualCameraCallback>
- virtualCameraClientCallback = nullptr);
+ const aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
+ configuration);
std::shared_ptr<VirtualCameraDevice> getCamera(const std::string& name);
@@ -105,4 +100,4 @@
} // namespace companion
} // namespace android
-#endif // ANDROID_SERVICES_VIRTUAL_CAMERA_VIRTUALCAMERAPROVIDER_H
+#endif // ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERAPROVIDER_H
diff --git a/services/camera/virtualcamera/VirtualCameraService.cc b/services/camera/virtualcamera/VirtualCameraService.cc
index 370a5a8..1144997 100644
--- a/services/camera/virtualcamera/VirtualCameraService.cc
+++ b/services/camera/virtualcamera/VirtualCameraService.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -41,6 +41,8 @@
namespace virtualcamera {
using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::companion::virtualcamera::LensFacing;
+using ::aidl::android::companion::virtualcamera::SensorOrientation;
using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
@@ -48,6 +50,7 @@
constexpr int kVgaWidth = 640;
constexpr int kVgaHeight = 480;
+constexpr int kMaxFps = 60;
constexpr char kEnableTestCameraCmd[] = "enable_test_camera";
constexpr char kDisableTestCameraCmd[] = "disable_test_camera";
constexpr char kShellCmdHelp[] = R"(
@@ -69,13 +72,29 @@
for (const SupportedStreamConfiguration& config :
configuration.supportedStreamConfigs) {
if (!isFormatSupportedForInput(config.width, config.height,
- config.pixelFormat)) {
+ config.pixelFormat, config.maxFps)) {
ALOGE("%s: Requested unsupported input format: %d x %d (%d)", __func__,
config.width, config.height, static_cast<int>(config.pixelFormat));
return ndk::ScopedAStatus::fromServiceSpecificError(
Status::EX_ILLEGAL_ARGUMENT);
}
}
+
+ if (configuration.sensorOrientation != SensorOrientation::ORIENTATION_0 &&
+ configuration.sensorOrientation != SensorOrientation::ORIENTATION_90 &&
+ configuration.sensorOrientation != SensorOrientation::ORIENTATION_180 &&
+ configuration.sensorOrientation != SensorOrientation::ORIENTATION_270) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ Status::EX_ILLEGAL_ARGUMENT);
+ }
+
+ if (configuration.lensFacing != LensFacing::FRONT &&
+ configuration.lensFacing != LensFacing::BACK &&
+ configuration.lensFacing != LensFacing::EXTERNAL) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ Status::EX_ILLEGAL_ARGUMENT);
+ }
+
return ndk::ScopedAStatus::ok();
}
@@ -121,10 +140,8 @@
return ndk::ScopedAStatus::ok();
}
- // TODO(b/301023410) Validate configuration and pass it to the camera.
std::shared_ptr<VirtualCameraDevice> camera =
- mVirtualCameraProvider->createCamera(configuration.supportedStreamConfigs,
- configuration.virtualCameraCallback);
+ mVirtualCameraProvider->createCamera(configuration);
if (camera == nullptr) {
ALOGE("Failed to create camera for binder token 0x%" PRIxPTR,
reinterpret_cast<uintptr_t>(token.get()));
@@ -241,8 +258,11 @@
bool ret;
VirtualCameraConfiguration configuration;
- configuration.supportedStreamConfigs.push_back(
- {.width = kVgaWidth, .height = kVgaHeight, Format::YUV_420_888});
+ configuration.supportedStreamConfigs.push_back({.width = kVgaWidth,
+ .height = kVgaHeight,
+ Format::YUV_420_888,
+ .maxFps = kMaxFps});
+ configuration.lensFacing = LensFacing::EXTERNAL;
registerCamera(mTestCameraToken, configuration, &ret);
if (ret) {
dprintf(out, "Successfully registered test camera %s",
diff --git a/services/camera/virtualcamera/VirtualCameraSession.cc b/services/camera/virtualcamera/VirtualCameraSession.cc
index 47780d8..03d63b8 100644
--- a/services/camera/virtualcamera/VirtualCameraSession.cc
+++ b/services/camera/virtualcamera/VirtualCameraSession.cc
@@ -18,6 +18,7 @@
#define LOG_TAG "VirtualCameraSession"
#include "VirtualCameraSession.h"
+#include <algorithm>
#include <atomic>
#include <chrono>
#include <cstddef>
@@ -150,6 +151,13 @@
return halStream;
}
+Stream getHighestResolutionStream(const std::vector<Stream>& streams) {
+ return *(std::max_element(streams.begin(), streams.end(),
+ [](const Stream& a, const Stream& b) {
+ return a.width * a.height < b.width * b.height;
+ }));
+}
+
} // namespace
VirtualCameraSession::VirtualCameraSession(
@@ -233,8 +241,9 @@
}
}
- inputWidth = streams[0].width;
- inputHeight = streams[0].height;
+ Stream maxResStream = getHighestResolutionStream(streams);
+ inputWidth = maxResStream.width;
+ inputHeight = maxResStream.height;
if (mRenderThread == nullptr) {
// If there's no client callback, start camera in test mode.
const bool testMode = mVirtualCameraClientCallback == nullptr;
diff --git a/services/camera/virtualcamera/aidl/Android.bp b/services/camera/virtualcamera/aidl/Android.bp
index 9105b09..a9c2195 100644
--- a/services/camera/virtualcamera/aidl/Android.bp
+++ b/services/camera/virtualcamera/aidl/Android.bp
@@ -8,9 +8,11 @@
unstable: true,
srcs: [
"android/companion/virtualcamera/Format.aidl",
+ "android/companion/virtualcamera/LensFacing.aidl",
"android/companion/virtualcamera/IVirtualCameraCallback.aidl",
"android/companion/virtualcamera/IVirtualCameraService.aidl",
"android/companion/virtualcamera/VirtualCameraConfiguration.aidl",
+ "android/companion/virtualcamera/SensorOrientation.aidl",
"android/companion/virtualcamera/SupportedStreamConfiguration.aidl",
],
local_include_dir: ".",
diff --git a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraCallback.aidl b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraCallback.aidl
index cbe03e9..f5a84f7 100644
--- a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraCallback.aidl
+++ b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -36,7 +36,8 @@
* @param height - height of the surface.
* @param pixelFormat - pixel format of the surface.
*/
- void onStreamConfigured(int streamId, in Surface surface, int width, int height, in Format pixelFormat);
+ void onStreamConfigured(int streamId, in Surface surface, int width, int height,
+ in Format pixelFormat);
/**
* Called when framework requests capture. This can be used by the client as a hint
diff --git a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/LensFacing.aidl b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/LensFacing.aidl
new file mode 100644
index 0000000..8568c91
--- /dev/null
+++ b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/LensFacing.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion.virtualcamera;
+
+/**
+ * Direction that the virtual camera faces relative to the device's screen.
+ *
+ * @hide
+ */
+@Backing(type="int")
+enum LensFacing {
+ FRONT = 0,
+ BACK = 1,
+ EXTERNAL = 2,
+}
diff --git a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/SensorOrientation.aidl b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/SensorOrientation.aidl
new file mode 100644
index 0000000..ef91f00
--- /dev/null
+++ b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/SensorOrientation.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package android.companion.virtualcamera;
+
+/**
+ * Sensor orientation of a virtual camera.
+ *
+ * @hide
+ */
+@Backing(type="int")
+enum SensorOrientation {
+ ORIENTATION_0 = 0,
+ ORIENTATION_90 = 90,
+ ORIENTATION_180 = 180,
+ ORIENTATION_270 = 270,
+}
diff --git a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/SupportedStreamConfiguration.aidl b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/SupportedStreamConfiguration.aidl
index 7070cbd..6f86cbe 100644
--- a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/SupportedStreamConfiguration.aidl
+++ b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/SupportedStreamConfiguration.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.companion.virtualcamera;
import android.companion.virtualcamera.Format;
@@ -26,4 +27,5 @@
int width;
int height;
Format pixelFormat = Format.UNKNOWN;
+ int maxFps;
}
diff --git a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/VirtualCameraConfiguration.aidl b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/VirtualCameraConfiguration.aidl
index c1a2f22..887ad26 100644
--- a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/VirtualCameraConfiguration.aidl
+++ b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/VirtualCameraConfiguration.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -13,9 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.companion.virtualcamera;
import android.companion.virtualcamera.IVirtualCameraCallback;
+import android.companion.virtualcamera.LensFacing;
+import android.companion.virtualcamera.SensorOrientation;
import android.companion.virtualcamera.SupportedStreamConfiguration;
/**
@@ -26,4 +29,6 @@
parcelable VirtualCameraConfiguration {
SupportedStreamConfiguration[] supportedStreamConfigs;
IVirtualCameraCallback virtualCameraCallback;
+ SensorOrientation sensorOrientation = SensorOrientation.ORIENTATION_0;
+ LensFacing lensFacing;
}
diff --git a/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
index 140ae65..027ecb7 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -19,6 +19,7 @@
#include "VirtualCameraDevice.h"
#include "aidl/android/companion/virtualcamera/Format.h"
#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
+#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
#include "aidl/android/hardware/camera/device/CameraMetadata.h"
#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
#include "android/binder_interface_utils.h"
@@ -34,7 +35,10 @@
namespace {
using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::companion::virtualcamera::LensFacing;
+using ::aidl::android::companion::virtualcamera::SensorOrientation;
using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
+using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
using ::aidl::android::hardware::camera::device::CameraMetadata;
using ::aidl::android::hardware::camera::device::Stream;
using ::aidl::android::hardware::camera::device::StreamConfiguration;
@@ -49,6 +53,7 @@
constexpr int kVgaHeight = 480;
constexpr int kHdWidth = 1280;
constexpr int kHdHeight = 720;
+constexpr int kMaxFps = 30;
struct AvailableStreamConfiguration {
const int width;
@@ -96,7 +101,7 @@
}
struct VirtualCameraConfigTestParam {
- std::vector<SupportedStreamConfiguration> inputConfig;
+ VirtualCameraConfiguration inputConfig;
std::vector<AvailableStreamConfiguration> expectedAvailableStreamConfigs;
};
@@ -106,8 +111,8 @@
TEST_P(VirtualCameraDeviceTest, cameraCharacteristicsForInputFormat) {
const VirtualCameraConfigTestParam& param = GetParam();
std::shared_ptr<VirtualCameraDevice> camera =
- ndk::SharedRefBase::make<VirtualCameraDevice>(
- kCameraId, param.inputConfig, /*virtualCameraClientCallback=*/nullptr);
+ ndk::SharedRefBase::make<VirtualCameraDevice>(kCameraId,
+ param.inputConfig);
CameraMetadata metadata;
ASSERT_TRUE(camera->getCameraCharacteristics(&metadata).isOk());
@@ -135,10 +140,16 @@
cameraCharacteristicsForInputFormat, VirtualCameraDeviceTest,
testing::Values(
VirtualCameraConfigTestParam{
- .inputConfig = {SupportedStreamConfiguration{
- .width = kVgaWidth,
- .height = kVgaHeight,
- .pixelFormat = Format::YUV_420_888}},
+ .inputConfig =
+ VirtualCameraConfiguration{
+ .supportedStreamConfigs = {SupportedStreamConfiguration{
+ .width = kVgaWidth,
+ .height = kVgaHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps}},
+ .virtualCameraCallback = nullptr,
+ .sensorOrientation = SensorOrientation::ORIENTATION_0,
+ .lensFacing = LensFacing::FRONT},
.expectedAvailableStreamConfigs =
{AvailableStreamConfiguration{
.width = kVgaWidth,
@@ -160,14 +171,22 @@
.streamConfiguration =
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT}}},
VirtualCameraConfigTestParam{
- .inputConfig = {SupportedStreamConfiguration{
- .width = kVgaWidth,
- .height = kVgaHeight,
- .pixelFormat = Format::YUV_420_888},
- SupportedStreamConfiguration{
- .width = kHdWidth,
- .height = kHdHeight,
- .pixelFormat = Format::YUV_420_888}},
+ .inputConfig =
+ VirtualCameraConfiguration{
+ .supportedStreamConfigs =
+ {SupportedStreamConfiguration{
+ .width = kVgaWidth,
+ .height = kVgaHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps},
+ SupportedStreamConfiguration{
+ .width = kHdWidth,
+ .height = kHdHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps}},
+ .virtualCameraCallback = nullptr,
+ .sensorOrientation = SensorOrientation::ORIENTATION_0,
+ .lensFacing = LensFacing::BACK},
.expectedAvailableStreamConfigs = {
AvailableStreamConfiguration{
.width = kVgaWidth,
diff --git a/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc b/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
index 615a77c..ab647a4 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -33,7 +33,10 @@
namespace {
using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::companion::virtualcamera::LensFacing;
+using ::aidl::android::companion::virtualcamera::SensorOrientation;
using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
+using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
using ::aidl::android::hardware::camera::common::Status;
using ::aidl::android::hardware::camera::common::TorchModeStatus;
@@ -49,6 +52,7 @@
constexpr int kVgaWidth = 640;
constexpr int kVgaHeight = 480;
+constexpr int kMaxFps = 30;
constexpr char kVirtualCameraNameRegex[] =
"device@[0-9]+\\.[0-9]+/virtual/[0-9]+";
@@ -79,10 +83,15 @@
std::shared_ptr<VirtualCameraProvider> mCameraProvider;
std::shared_ptr<MockCameraProviderCallback> mMockCameraProviderCallback =
ndk::SharedRefBase::make<MockCameraProviderCallback>();
- std::vector<SupportedStreamConfiguration> mInputConfigs = {
- SupportedStreamConfiguration{.width = kVgaWidth,
- .height = kVgaHeight,
- .pixelFormat = Format::YUV_420_888}};
+ VirtualCameraConfiguration mInputConfig = VirtualCameraConfiguration{
+ .supportedStreamConfigs = {SupportedStreamConfiguration{
+ .width = kVgaWidth,
+ .height = kVgaHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps}},
+ .virtualCameraCallback = nullptr,
+ .sensorOrientation = SensorOrientation::ORIENTATION_0,
+ .lensFacing = LensFacing::FRONT};
};
TEST_F(VirtualCameraProviderTest, SetNullCameraCallbackFails) {
@@ -109,7 +118,7 @@
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
std::shared_ptr<VirtualCameraDevice> camera =
- mCameraProvider->createCamera(mInputConfigs);
+ mCameraProvider->createCamera(mInputConfig);
EXPECT_THAT(camera, Not(IsNull()));
EXPECT_THAT(camera->getCameraName(), MatchesRegex(kVirtualCameraNameRegex));
@@ -127,7 +136,7 @@
.WillOnce(Return(ndk::ScopedAStatus::ok()));
std::shared_ptr<VirtualCameraDevice> camera =
- mCameraProvider->createCamera(mInputConfigs);
+ mCameraProvider->createCamera(mInputConfig);
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
// Created camera should be in the list of cameras.
@@ -139,7 +148,7 @@
TEST_F(VirtualCameraProviderTest, RemoveCamera) {
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
std::shared_ptr<VirtualCameraDevice> camera =
- mCameraProvider->createCamera(mInputConfigs);
+ mCameraProvider->createCamera(mInputConfig);
EXPECT_CALL(*mMockCameraProviderCallback,
cameraDeviceStatusChange(Eq(camera->getCameraName()),
@@ -156,7 +165,7 @@
TEST_F(VirtualCameraProviderTest, RemoveNonExistingCamera) {
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
std::shared_ptr<VirtualCameraDevice> camera =
- mCameraProvider->createCamera(mInputConfigs);
+ mCameraProvider->createCamera(mInputConfig);
// Removing non-existing camera should fail.
const std::string cameraName = "DefinitelyNoTCamera";
diff --git a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
index 38261fb..d4d00a2 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -39,6 +39,8 @@
using ::aidl::android::companion::virtualcamera::BnVirtualCameraCallback;
using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::companion::virtualcamera::LensFacing;
+using ::aidl::android::companion::virtualcamera::SensorOrientation;
using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
using ::aidl::android::hardware::camera::common::TorchModeStatus;
@@ -56,16 +58,25 @@
constexpr int kVgaWidth = 640;
constexpr int kVgaHeight = 480;
+constexpr int kMaxFps = 30;
+constexpr SensorOrientation kSensorOrientation =
+ SensorOrientation::ORIENTATION_0;
+constexpr LensFacing kLensFacing = LensFacing::FRONT;
constexpr char kCreateVirtualDevicePermissions[] =
"android.permission.CREATE_VIRTUAL_DEVICE";
const VirtualCameraConfiguration kEmptyVirtualCameraConfiguration;
VirtualCameraConfiguration createConfiguration(const int width, const int height,
- const Format format) {
+ const Format format,
+ const int maxFps) {
VirtualCameraConfiguration configuration;
- configuration.supportedStreamConfigs.push_back(
- {.width = width, .height = height, .pixelFormat = format});
+ configuration.supportedStreamConfigs.push_back({.width = width,
+ .height = height,
+ .pixelFormat = format,
+ .maxFps = maxFps});
+ configuration.sensorOrientation = kSensorOrientation;
+ configuration.lensFacing = kLensFacing;
return configuration;
}
@@ -150,7 +161,7 @@
int mDevNullFd;
VirtualCameraConfiguration mVgaYUV420OnlyConfiguration =
- createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888);
+ createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, kMaxFps);
};
TEST_F(VirtualCameraServiceTest, RegisterCameraWithYuvInputSucceeds) {
@@ -173,7 +184,7 @@
bool aidlRet;
VirtualCameraConfiguration config =
- createConfiguration(kVgaWidth, kVgaHeight, Format::RGBA_8888);
+ createConfiguration(kVgaWidth, kVgaHeight, Format::RGBA_8888, kMaxFps);
ASSERT_TRUE(mCameraService->registerCamera(ndkToken, config, &aidlRet).isOk());
@@ -208,7 +219,7 @@
bool aidlRet;
VirtualCameraConfiguration config =
- createConfiguration(kVgaWidth, kVgaHeight, Format::UNKNOWN);
+ createConfiguration(kVgaWidth, kVgaHeight, Format::UNKNOWN, kMaxFps);
ASSERT_FALSE(
mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
@@ -219,7 +230,7 @@
TEST_F(VirtualCameraServiceTest, ConfigurationWithTooHighResFails) {
bool aidlRet;
VirtualCameraConfiguration config =
- createConfiguration(1000000, 1000000, Format::YUV_420_888);
+ createConfiguration(1000000, 1000000, Format::YUV_420_888, kMaxFps);
ASSERT_FALSE(
mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
@@ -230,7 +241,7 @@
TEST_F(VirtualCameraServiceTest, ConfigurationWithUnalignedResolutionFails) {
bool aidlRet;
VirtualCameraConfiguration config =
- createConfiguration(641, 481, Format::YUV_420_888);
+ createConfiguration(641, 481, Format::YUV_420_888, kMaxFps);
ASSERT_FALSE(
mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
@@ -241,7 +252,29 @@
TEST_F(VirtualCameraServiceTest, ConfigurationWithNegativeResolutionFails) {
bool aidlRet;
VirtualCameraConfiguration config =
- createConfiguration(-1, kVgaHeight, Format::YUV_420_888);
+ createConfiguration(-1, kVgaHeight, Format::YUV_420_888, kMaxFps);
+
+ ASSERT_FALSE(
+ mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
+ EXPECT_FALSE(aidlRet);
+ EXPECT_THAT(getCameraIds(), IsEmpty());
+}
+
+TEST_F(VirtualCameraServiceTest, ConfigurationWithTooLowMaxFpsFails) {
+ bool aidlRet;
+ VirtualCameraConfiguration config =
+ createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, 0);
+
+ ASSERT_FALSE(
+ mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
+ EXPECT_FALSE(aidlRet);
+ EXPECT_THAT(getCameraIds(), IsEmpty());
+}
+
+TEST_F(VirtualCameraServiceTest, ConfigurationWithTooHighMaxFpsFails) {
+ bool aidlRet;
+ VirtualCameraConfiguration config =
+ createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, 90);
ASSERT_FALSE(
mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
diff --git a/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc b/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
index 30bd2b6..446c679 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -21,6 +21,7 @@
#include "VirtualCameraSession.h"
#include "aidl/android/companion/virtualcamera/BnVirtualCameraCallback.h"
#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
+#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
#include "aidl/android/hardware/camera/common/Status.h"
#include "aidl/android/hardware/camera/device/BnCameraDeviceCallback.h"
#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
@@ -36,14 +37,21 @@
namespace virtualcamera {
namespace {
-constexpr int kWidth = 640;
-constexpr int kHeight = 480;
+constexpr int kVgaWidth = 640;
+constexpr int kVgaHeight = 480;
+constexpr int kSvgaWidth = 800;
+constexpr int kSvgaHeight = 600;
+constexpr int kMaxFps = 30;
constexpr int kStreamId = 0;
+constexpr int kSecondStreamId = 1;
constexpr int kCameraId = 42;
using ::aidl::android::companion::virtualcamera::BnVirtualCameraCallback;
using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::companion::virtualcamera::LensFacing;
+using ::aidl::android::companion::virtualcamera::SensorOrientation;
using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
+using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
using ::aidl::android::hardware::camera::common::Status;
using ::aidl::android::hardware::camera::device::BnCameraDeviceCallback;
using ::aidl::android::hardware::camera::device::BufferRequest;
@@ -105,11 +113,20 @@
ndk::SharedRefBase::make<MockVirtualCameraCallback>();
mVirtualCameraDevice = ndk::SharedRefBase::make<VirtualCameraDevice>(
kCameraId,
- std::vector<SupportedStreamConfiguration>{
- SupportedStreamConfiguration{.width = kWidth,
- .height = kHeight,
- .pixelFormat = Format::YUV_420_888}},
- mMockVirtualCameraClientCallback);
+ VirtualCameraConfiguration{
+ .supportedStreamConfigs = {SupportedStreamConfiguration{
+ .width = kVgaWidth,
+ .height = kVgaHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps},
+ SupportedStreamConfiguration{
+ .width = kSvgaWidth,
+ .height = kSvgaHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps}},
+ .virtualCameraCallback = nullptr,
+ .sensorOrientation = SensorOrientation::ORIENTATION_0,
+ .lensFacing = LensFacing::FRONT});
mVirtualCameraSession = ndk::SharedRefBase::make<VirtualCameraSession>(
mVirtualCameraDevice, mMockCameraDeviceCallback,
mMockVirtualCameraClientCallback);
@@ -146,18 +163,22 @@
PixelFormat format = PixelFormat::YCBCR_420_888;
StreamConfiguration streamConfiguration;
streamConfiguration.streams = {
- createStream(kStreamId, kWidth, kHeight, format)};
+ createStream(kStreamId, kVgaWidth, kVgaHeight, format),
+ createStream(kSecondStreamId, kSvgaWidth, kSvgaHeight, format)};
std::vector<HalStream> halStreams;
- EXPECT_CALL(
- *mMockVirtualCameraClientCallback,
- onStreamConfigured(kStreamId, _, kWidth, kHeight, Format::YUV_420_888));
+
+ // Expect highest resolution to be picked for the client input.
+ EXPECT_CALL(*mMockVirtualCameraClientCallback,
+ onStreamConfigured(kStreamId, _, kSvgaWidth, kSvgaHeight,
+ Format::YUV_420_888));
ASSERT_TRUE(
mVirtualCameraSession->configureStreams(streamConfiguration, &halStreams)
.isOk());
EXPECT_THAT(halStreams, SizeIs(streamConfiguration.streams.size()));
- EXPECT_THAT(mVirtualCameraSession->getStreamIds(), ElementsAre(0));
+ EXPECT_THAT(mVirtualCameraSession->getStreamIds(),
+ ElementsAre(kStreamId, kSecondStreamId));
}
TEST_F(VirtualCameraSessionTest, SecondConfigureDropsUnreferencedStreams) {
@@ -165,18 +186,18 @@
StreamConfiguration streamConfiguration;
std::vector<HalStream> halStreams;
- streamConfiguration.streams = {createStream(0, kWidth, kHeight, format),
- createStream(1, kWidth, kHeight, format),
- createStream(2, kWidth, kHeight, format)};
+ streamConfiguration.streams = {createStream(0, kVgaWidth, kVgaHeight, format),
+ createStream(1, kVgaWidth, kVgaHeight, format),
+ createStream(2, kVgaWidth, kVgaHeight, format)};
ASSERT_TRUE(
mVirtualCameraSession->configureStreams(streamConfiguration, &halStreams)
.isOk());
EXPECT_THAT(mVirtualCameraSession->getStreamIds(), ElementsAre(0, 1, 2));
- streamConfiguration.streams = {createStream(0, kWidth, kHeight, format),
- createStream(2, kWidth, kHeight, format),
- createStream(3, kWidth, kHeight, format)};
+ streamConfiguration.streams = {createStream(0, kVgaWidth, kVgaHeight, format),
+ createStream(2, kVgaWidth, kVgaHeight, format),
+ createStream(3, kVgaWidth, kVgaHeight, format)};
ASSERT_TRUE(
mVirtualCameraSession->configureStreams(streamConfiguration, &halStreams)
.isOk());
@@ -201,8 +222,8 @@
TEST_F(VirtualCameraSessionTest, onProcessCaptureRequestTriggersClientCallback) {
StreamConfiguration streamConfiguration;
- streamConfiguration.streams = {
- createStream(kStreamId, kWidth, kHeight, PixelFormat::YCBCR_420_888)};
+ streamConfiguration.streams = {createStream(kStreamId, kVgaWidth, kVgaHeight,
+ PixelFormat::YCBCR_420_888)};
std::vector<CaptureRequest> requests(1);
requests[0].frameNumber = 42;
requests[0].settings = *(
@@ -226,8 +247,8 @@
TEST_F(VirtualCameraSessionTest, configureAfterCameraRelease) {
StreamConfiguration streamConfiguration;
- streamConfiguration.streams = {
- createStream(kStreamId, kWidth, kHeight, PixelFormat::YCBCR_420_888)};
+ streamConfiguration.streams = {createStream(kStreamId, kVgaWidth, kVgaHeight,
+ PixelFormat::YCBCR_420_888)};
std::vector<HalStream> halStreams;
// Release virtual camera.
@@ -240,6 +261,17 @@
Eq(static_cast<int32_t>(Status::CAMERA_DISCONNECTED)));
}
+TEST_F(VirtualCameraSessionTest, ConfigureWithEmptyStreams) {
+ StreamConfiguration streamConfiguration;
+ std::vector<HalStream> halStreams;
+
+ // Expect configuration attempt returns CAMERA_DISCONNECTED service specific code.
+ EXPECT_THAT(
+ mVirtualCameraSession->configureStreams(streamConfiguration, &halStreams)
+ .getServiceSpecificError(),
+ Eq(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT)));
+}
+
} // namespace
} // namespace virtualcamera
} // namespace companion
diff --git a/services/camera/virtualcamera/util/MetadataBuilder.cc b/services/camera/virtualcamera/util/MetadataBuilder.cc
index 92a48b9..70e22be 100644
--- a/services/camera/virtualcamera/util/MetadataBuilder.cc
+++ b/services/camera/virtualcamera/util/MetadataBuilder.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -221,8 +221,7 @@
metadataStreamConfigs;
mEntryMap[ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS] =
metadataMinFrameDurations;
- mEntryMap[ANDROID_SCALER_AVAILABLE_STALL_DURATIONS] =
- metadataMinFrameDurations;
+ mEntryMap[ANDROID_SCALER_AVAILABLE_STALL_DURATIONS] = metadataStallDurations;
return *this;
}
diff --git a/services/camera/virtualcamera/util/MetadataBuilder.h b/services/camera/virtualcamera/util/MetadataBuilder.h
index d992d31..46f4c43 100644
--- a/services/camera/virtualcamera/util/MetadataBuilder.h
+++ b/services/camera/virtualcamera/util/MetadataBuilder.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -44,7 +44,7 @@
int32_t format = 0;
// Minimal frame duration - corresponds to maximal FPS for given format.
// See ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS in CameraMetadataTag.aidl.
- std::chrono::nanoseconds minFrameDuration{std::chrono::seconds(1) / 30};
+ std::chrono::nanoseconds minFrameDuration{0};
// Minimal stall duration.
// See ANDROID_SCALER_AVAILABLE_STALL_DURATIONS in CameraMetadataTag.aidl.
std::chrono::nanoseconds minStallDuration{0};
diff --git a/services/camera/virtualcamera/util/Util.cc b/services/camera/virtualcamera/util/Util.cc
index df771b1..2d0545d 100644
--- a/services/camera/virtualcamera/util/Util.cc
+++ b/services/camera/virtualcamera/util/Util.cc
@@ -35,6 +35,7 @@
// TODO(b/301023410) - Query actual max texture size.
constexpr int kMaxTextureSize = 2048;
constexpr int kLibJpegDctSize = DCTSIZE;
+constexpr int kMaxFpsUpperLimit = 60;
constexpr std::array<Format, 2> kSupportedFormats{Format::YUV_420_888,
Format::RGBA_8888};
@@ -54,7 +55,7 @@
// Returns true if specified format is supported for virtual camera input.
bool isFormatSupportedForInput(const int width, const int height,
- const Format format) {
+ const Format format, const int maxFps) {
if (!isPixelFormatSupportedForInput(format)) {
return false;
}
@@ -71,6 +72,10 @@
return false;
}
+ if (maxFps <= 0 || maxFps > kMaxFpsUpperLimit) {
+ return false;
+ }
+
return true;
}
diff --git a/services/camera/virtualcamera/util/Util.h b/services/camera/virtualcamera/util/Util.h
index a73c99b..e0a31c0 100644
--- a/services/camera/virtualcamera/util/Util.h
+++ b/services/camera/virtualcamera/util/Util.h
@@ -50,7 +50,7 @@
// Returns true if specified format is supported for virtual camera input.
bool isFormatSupportedForInput(
int width, int height,
- ::aidl::android::companion::virtualcamera::Format format);
+ ::aidl::android::companion::virtualcamera::Format format, int maxFps);
} // namespace virtualcamera
} // namespace companion
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..7f66859 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -74,10 +74,15 @@
name: "libresourcemanagerservice",
srcs: [
+ "ClientImportanceReclaimPolicy.cpp",
+ "DefaultResourceModel.cpp",
+ "ProcessPriorityReclaimPolicy.cpp",
"ResourceManagerMetrics.cpp",
"ResourceManagerService.cpp",
+ "ResourceManagerServiceNew.cpp",
"ResourceObserverService.cpp",
"ResourceManagerServiceUtils.cpp",
+ "ResourceTracker.cpp",
"ServiceLog.cpp",
"UidObserver.cpp",
@@ -97,6 +102,7 @@
"libstatssocket",
"libprotobuf-cpp-lite",
"libactivitymanager_aidl",
+ "aconfig_mediacodec_flags_c_lib",
],
static_libs: [
diff --git a/services/mediaresourcemanager/ClientImportanceReclaimPolicy.cpp b/services/mediaresourcemanager/ClientImportanceReclaimPolicy.cpp
new file mode 100644
index 0000000..a81b32f
--- /dev/null
+++ b/services/mediaresourcemanager/ClientImportanceReclaimPolicy.cpp
@@ -0,0 +1,88 @@
+/*
+**
+** Copyright 2023, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ClientImportanceReclaimPolicy"
+#include <utils/Log.h>
+
+#include "ResourceTracker.h"
+#include "ResourceManagerService.h"
+#include "ClientImportanceReclaimPolicy.h"
+
+namespace android {
+
+using aidl::android::media::IResourceManagerClient;
+
+ClientImportanceReclaimPolicy::ClientImportanceReclaimPolicy(
+ const std::shared_ptr<ResourceTracker>& resourceTracker)
+ : mResourceTracker(resourceTracker) {
+}
+
+ClientImportanceReclaimPolicy::~ClientImportanceReclaimPolicy() {
+}
+
+// Find the biggest client from the same process with the lowest importance
+// than that of the requesting client.
+bool ClientImportanceReclaimPolicy::getClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients) {
+ pid_t callingPid = reclaimRequestInfo.mCallingPid;
+ int32_t callingImportance = reclaimRequestInfo.mCallingClientImportance;
+ MediaResource::Type type = reclaimRequestInfo.mResources[0].type;
+ MediaResource::SubType subType = reclaimRequestInfo.mResources[0].subType;
+ ClientInfo targetClient;
+ // Look to find the biggest client with lowest importance from the same process that
+ // has the other resources and with the given primary type.
+ bool found = false;
+ MediaResource::SubType primarySubType = subType;
+ for (size_t index = 1; !found && (index < reclaimRequestInfo.mResources.size()); index++) {
+ MediaResource::Type type = reclaimRequestInfo.mResources[index].type;
+ MediaResource::SubType subType = reclaimRequestInfo.mResources[index].subType;
+ found = mResourceTracker->getLeastImportantBiggestClient(
+ callingPid, callingImportance,
+ type, subType, primarySubType,
+ clients, targetClient);
+ }
+ // If no success, then select the biggest client of primary type with lowest importance
+ // from the same process.
+ if (!found) {
+ found = mResourceTracker->getLeastImportantBiggestClient(
+ callingPid, callingImportance,
+ type, subType, MediaResource::SubType::kUnspecifiedSubType,
+ clients, targetClient);
+ }
+ // If we haven't found a client yet, then select the biggest client of different type
+ // with lowest importance from the same process.
+ // This is applicable for codec type only.
+ if (!found) {
+ if (type != MediaResource::Type::kSecureCodec &&
+ type != MediaResource::Type::kNonSecureCodec) {
+ return false;
+ }
+ MediaResourceType otherType = (type == MediaResource::Type::kSecureCodec) ?
+ MediaResource::Type::kNonSecureCodec : MediaResource::Type::kSecureCodec;
+ if (!mResourceTracker->getLeastImportantBiggestClient(
+ callingPid, callingImportance,
+ otherType, subType, MediaResource::SubType::kUnspecifiedSubType,
+ clients, targetClient)) {
+ return false;
+ }
+ }
+ targetClients.emplace_back(targetClient);
+ return true;
+}
+} // namespace android
diff --git a/services/mediaresourcemanager/ClientImportanceReclaimPolicy.h b/services/mediaresourcemanager/ClientImportanceReclaimPolicy.h
new file mode 100644
index 0000000..1a54c7d
--- /dev/null
+++ b/services/mediaresourcemanager/ClientImportanceReclaimPolicy.h
@@ -0,0 +1,64 @@
+/*
+**
+** Copyright 2023, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_MEDIA_CLIENTIMPORTANCERECLAIMPOLICY_H_
+#define ANDROID_MEDIA_CLIENTIMPORTANCERECLAIMPOLICY_H_
+
+#include <media/MediaResource.h>
+#include "IReclaimPolicy.h"
+
+namespace android {
+
+class ResourceTracker;
+struct ClientInfo;
+
+/*
+ * Implementation of Reclaim Policy based on the client's importance.
+ *
+ * Find the least important (other than that of requesting client) client from the
+ * same process (that is requesting for the resource).
+ * If there are multiple clients with least importance, then pick the biggest
+ * client among them.
+ *
+ */
+class ClientImportanceReclaimPolicy : public IReclaimPolicy {
+public:
+ explicit ClientImportanceReclaimPolicy(const std::shared_ptr<ResourceTracker>& resourceTracker);
+
+ virtual ~ClientImportanceReclaimPolicy();
+
+ /*
+ * Based on the client importance, identify and return the least important client of
+ * the requesting process from the list of given clients that satisfy the resource requested.
+ *
+ * @param[in] reclaimRequestInfo Information about the resource request
+ * @param[in] client List of clients to select from.
+ * @param[out] targetClients Upon success, this will have the list of identified client(s).
+ *
+ * @return true on success, false otherwise
+ */
+ bool getClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients) override;
+
+private:
+ std::shared_ptr<ResourceTracker> mResourceTracker;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_CLIENTIMPORTANCERECLAIMPOLICY_H_
diff --git a/services/mediaresourcemanager/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..3a02443 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -29,37 +29,60 @@
#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");
+ resourceLog.append(resources.toString());
+ }
+ }
+
+ 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);
}
}
@@ -75,20 +98,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 +123,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 +202,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(
@@ -296,31 +312,21 @@
for (size_t i = 0; i < resources.size(); ++i) {
const auto &res = resources[i];
- const auto resType = std::tuple(res.type, res.subType, res.id);
if (res.value < 0 && res.type != MediaResource::Type::kDrmSession) {
ALOGW("Ignoring request to remove negative value of non-drm resource");
continue;
}
- if (info.resources.find(resType) == info.resources.end()) {
- if (res.value <= 0) {
- // We can't init a new entry with negative value, although it's allowed
- // to merge in negative values after the initial add.
- ALOGW("Ignoring request to add new resource entry with value <= 0");
- continue;
- }
+ bool isNewEntry = false;
+ if (!info.resources.add(res, &isNewEntry)) {
+ continue;
+ }
+ if (isNewEntry) {
onFirstAdded(res, info.uid);
- info.resources[resType] = res;
- } else {
- mergeResources(info.resources[resType], res);
}
+
// Add it to the list of added resources for observers.
- auto it = resourceAdded.find(resType);
- if (it == resourceAdded.end()) {
- resourceAdded[resType] = res;
- } else {
- mergeResources(it->second, res);
- }
+ resourceAdded.add(res);
}
if (info.deathNotifier == nullptr && client != nullptr) {
info.deathNotifier = DeathNotifier::Create(
@@ -367,31 +373,22 @@
ResourceList resourceRemoved;
for (size_t i = 0; i < resources.size(); ++i) {
const auto &res = resources[i];
- const auto resType = std::tuple(res.type, res.subType, res.id);
if (res.value < 0) {
ALOGW("Ignoring request to remove negative value of resource");
continue;
}
- // ignore if we don't have it
- if (info.resources.find(resType) != info.resources.end()) {
- MediaResourceParcel &resource = info.resources[resType];
+
+ long removedEntryValue = -1;
+ if (info.resources.remove(res, &removedEntryValue)) {
MediaResourceParcel actualRemoved = res;
- if (resource.value > res.value) {
- resource.value -= res.value;
- } else {
+ if (removedEntryValue != -1) {
onLastRemoved(res, info.uid);
- actualRemoved.value = resource.value;
- info.resources.erase(resType);
+ actualRemoved.value = removedEntryValue;
}
// Add it to the list of removed resources for observers.
- auto it = resourceRemoved.find(resType);
- if (it == resourceRemoved.end()) {
- resourceRemoved[resType] = actualRemoved;
- } else {
- mergeResources(it->second, actualRemoved);
- }
+ resourceRemoved.add(actualRemoved);
}
}
if (mObserverService != nullptr && !resourceRemoved.empty()) {
@@ -434,8 +431,8 @@
}
const ResourceInfo& info = foundClient->second;
- for (auto it = info.resources.begin(); it != info.resources.end(); it++) {
- onLastRemoved(it->second, info.uid);
+ for (const MediaResourceParcel& res : info.resources.getResources()) {
+ onLastRemoved(res, info.uid);
}
// Since this client has been removed, update the metrics collector.
@@ -472,114 +469,130 @@
}
}
+bool ResourceManagerService::getTargetClients(
+ const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources,
+ std::vector<ClientInfo>& targetClients) {
+ int32_t callingPid = clientInfo.pid;
+ std::scoped_lock lock{mLock};
+ if (!mProcessInfo->isPidTrusted(callingPid)) {
+ pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
+ 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;
std::string clientName = clientInfo.name;
String8 log = String8::format("reclaimResource(callingPid %d, uid %d resources %s)",
- callingPid, clientInfo.uid, getString(resources).c_str());
+ clientInfo.pid, clientInfo.uid, getString(resources).c_str());
mServiceLog->add(log);
*_aidl_return = false;
+ // 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(clientInfo, resources, targetClients)) {
+ // Nothing to reclaim from.
+ ALOGI("%s: There aren't any clients to reclaim from", __func__);
+ return Status::ok();
}
*_aidl_return = reclaimUnconditionallyFrom(targetClients);
@@ -607,7 +620,7 @@
mResourceManagerMetrics->pushReclaimAtom(clientInfo, priorities, targetClients, reclaimed);
}
-std::shared_ptr<IResourceManagerClient> ResourceManagerService::getClient(
+std::shared_ptr<IResourceManagerClient> ResourceManagerService::getClient_l(
int pid, const int64_t& clientId) const {
std::map<int, ResourceInfos>::const_iterator found = mMap.find(pid);
if (found == mMap.end()) {
@@ -625,7 +638,7 @@
return foundClient->second.client;
}
-bool ResourceManagerService::removeClient(int pid, const int64_t& clientId) {
+bool ResourceManagerService::removeClient_l(int pid, const int64_t& clientId) {
std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
if (found == mMap.end()) {
ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
@@ -652,8 +665,11 @@
int64_t failedClientId = -1;
int32_t failedClientPid = -1;
for (const ClientInfo& targetClient : targetClients) {
- std::shared_ptr<IResourceManagerClient> client = getClient(
- targetClient.mPid, targetClient.mClientId);
+ std::shared_ptr<IResourceManagerClient> client = nullptr;
+ {
+ std::scoped_lock lock{mLock};
+ client = getClient_l(targetClient.mPid, targetClient.mClientId);
+ }
if (client == nullptr) {
// skip already released clients.
continue;
@@ -675,7 +691,7 @@
{
std::scoped_lock lock{mLock};
- bool found = removeClient(failedClientPid, failedClientId);
+ bool found = removeClient_l(failedClientPid, failedClientId);
if (found) {
ALOGW("Failed to reclaim resources from client with pid %d", failedClientPid);
} else {
@@ -686,6 +702,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 +731,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 +739,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 +782,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 +893,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);
}
@@ -1000,8 +1037,7 @@
if (pendingRemovalOnly && !info.pendingRemoval) {
continue;
}
- for (auto it = resources.begin(); it != resources.end(); it++) {
- const MediaResourceParcel &resource = it->second;
+ for (const MediaResourceParcel& resource : resources.getResources()) {
if (hasResourceType(type, subType, resource)) {
if (resource.value > largestValue) {
largestValue = resource.value;
@@ -1053,4 +1089,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..dc1600a 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,146 @@
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(
+ const ClientInfoParcel& clientInfo,
+ 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_l(
+ int pid, const int64_t& clientId) const;
+
+ // Remove the client for given pid and the clientId from the map
+ virtual bool removeClient_l(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;
+ }
+ // enable/disable process priority based reclaim and client importance based reclaim
+ virtual void setReclaimPolicy(bool processPriority, bool clientImportance) {
+ // Implemented by the refactored/new RMService
+ (void)processPriority;
+ (void)clientImportance;
+ }
+ // END: TEST only functions
+protected:
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..af093ca
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
@@ -0,0 +1,385 @@
+/*
+**
+** 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 "ClientImportanceReclaimPolicy.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();
+ // Add Reclaim policies based on:
+ // - the Process priority (oom score)
+ // - the client/codec importance.
+ setReclaimPolicy(true /* processPriority */, true /* clientImportance */);
+}
+
+Status ResourceManagerServiceNew::config(const std::vector<MediaResourcePolicyParcel>& policies) {
+ 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) {
+ {
+ // Update the ResourceTracker about the change in the configuration.
+ std::scoped_lock lock{mLock};
+ mResourceTracker->updateResource(clientConfig.clientInfo);
+ }
+ 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(
+ const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources,
+ std::vector<ClientInfo>& targetClients) {
+ int32_t callingPid = clientInfo.pid;
+ std::scoped_lock lock{mLock};
+ if (!mProcessInfo->isPidTrusted(callingPid)) {
+ pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
+ 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.
+ uint32_t callingImportance = std::max(0, clientInfo.importance);
+ ReclaimRequestInfo reclaimRequestInfo{callingPid, callingImportance, resources};
+ std::vector<ClientInfo> clients;
+ if (!mDefaultResourceModel->getAllClients(reclaimRequestInfo, clients)) {
+ if (clients.empty()) {
+ 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 clients.
+ 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, 0, 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_l(
+ int pid, const int64_t& clientId) const {
+ return mResourceTracker->getClient(pid, clientId);
+}
+
+bool ResourceManagerServiceNew::removeClient_l(int pid, const int64_t& clientId) {
+ return mResourceTracker->removeClient(pid, clientId);
+}
+
+const std::map<int, ResourceInfos>& ResourceManagerServiceNew::getResourceMap() const {
+ return mResourceTracker->getResourceMap();
+}
+
+void ResourceManagerServiceNew::setReclaimPolicy(bool processPriority, bool clientImportance) {
+ mReclaimPolicies.clear();
+ if (processPriority) {
+ // Process priority (oom score) as the Default reclaim policy.
+ mReclaimPolicies.push_back(std::make_unique<ProcessPriorityReclaimPolicy>(
+ mResourceTracker));
+ }
+ if (clientImportance) {
+ mReclaimPolicies.push_back(std::make_unique<ClientImportanceReclaimPolicy>(
+ mResourceTracker));
+ }
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerServiceNew.h b/services/mediaresourcemanager/ResourceManagerServiceNew.h
new file mode 100644
index 0000000..0599936
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceManagerServiceNew.h
@@ -0,0 +1,174 @@
+/*
+**
+** 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(
+ const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources,
+ std::vector<ClientInfo>& targetClients) override;
+
+ // Removes the pid from the override map.
+ void removeProcessInfoOverride(int pid) override;
+
+ // 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;
+
+ // Get the client for given pid and the clientId from the map
+ std::shared_ptr<IResourceManagerClient> getClient_l(
+ int pid, const int64_t& clientId) const override;
+
+ // Remove the client for given pid and the clientId from the map
+ bool removeClient_l(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;
+
+ // The following utility functions are used only for testing by ResourceManagerServiceTest
+ // START: TEST only functions
+ // Gets the list of all the clients who own the specified resource type.
+ // Returns false if any client belongs to a process with higher priority than the
+ // calling process. The clients will remain unchanged if returns false.
+ bool getAllClients_l(const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clientsInfo) override;
+
+ // Gets the client who owns specified resource type from lowest possible priority process.
+ // Returns false if the calling process priority is not higher than the lowest process
+ // priority. The client will remain unchanged if returns false.
+ bool getLowestPriorityBiggestClient_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ ClientInfo& clientInfo) override;
+
+ // Gets lowest priority process that has the specified resource type.
+ // Returns false if failed. The output parameters will remain unchanged if failed.
+ bool getLowestPriorityPid_l(MediaResource::Type type, MediaResource::SubType subType,
+ int* lowestPriorityPid, int* lowestPriority) override;
+
+ // enable/disable process priority based reclaim and client importance based reclaim
+ void setReclaimPolicy(bool processPriority, bool clientImportance) override;
+ // END: TEST only functions
+
+private:
+ std::shared_ptr<ResourceTracker> mResourceTracker;
+ std::unique_ptr<IResourceModel> mDefaultResourceModel;
+ 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..679ab13 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
@@ -19,11 +19,101 @@
#define LOG_TAG "ResourceManagerServiceUtils"
#include <utils/Log.h>
+#include <binder/IServiceManager.h>
+
+#include "IMediaResourceMonitor.h"
#include "ResourceManagerService.h"
#include "ResourceManagerServiceUtils.h"
namespace android {
+bool ResourceList::add(const MediaResourceParcel& res, bool* isNewEntry) {
+ // See if it's an existing entry, if so, merge it.
+ for (MediaResourceParcel& item : mResourceList) {
+ if (item.type == res.type && item.subType == res.subType && item.id == res.id) {
+ // We already have an item. Merge them and return
+ mergeResources(item, res);
+ return true;
+ }
+ }
+
+ // Since we have't found this resource yet, it is a new entry.
+ // We can't init a new entry with negative value, although it's allowed
+ // to merge in negative values after the initial add.
+ if (res.value <= 0) {
+ ALOGW("Ignoring request to add new resource entry with value <= 0");
+ return false;
+ }
+ if (isNewEntry) {
+ *isNewEntry = true;
+ }
+ mResourceList.push_back(res);
+ return true;
+}
+
+void ResourceList::addOrUpdate(const MediaResourceParcel& res) {
+ // See if it's an existing entry, just update the value.
+ for (MediaResourceParcel& item : mResourceList) {
+ if (item.type == res.type && item.subType == res.subType && item.id == res.id) {
+ item.value = res.value;
+ return;
+ }
+ }
+
+ // Add the new entry.
+ mResourceList.push_back(res);
+}
+
+bool ResourceList::remove(const MediaResourceParcel& res, long* removedEntryValue) {
+ // Make sure we have an entry for this resource.
+ for (std::vector<MediaResourceParcel>::iterator it = mResourceList.begin();
+ it != mResourceList.end(); it++) {
+ if (it->type == res.type && it->subType == res.subType && it->id == res.id) {
+ if (it->value > res.value) {
+ // Subtract the resource value by given value.
+ it->value -= res.value;
+ } else {
+ // This entry will be removed.
+ if (removedEntryValue) {
+ *removedEntryValue = it->value;
+ }
+ mResourceList.erase(it);
+ }
+ return true;
+ }
+ }
+
+ // No such entry.
+ return false;
+}
+
+std::string ResourceList::toString() const {
+ std::string str;
+ for (const ::aidl::android::media::MediaResourceParcel& res : mResourceList) {
+ str.append(android::toString(res).c_str());
+ str.append("\n");
+ }
+
+ return std::move(str);
+}
+
+bool ResourceList::operator==(const ResourceList& rhs) const {
+ // Make sure the size is the same.
+ if (mResourceList.size() != rhs.mResourceList.size()) {
+ return false;
+ }
+
+ // Create a set from this object and check for the items from the rhs.
+ std::set<::aidl::android::media::MediaResourceParcel> lhs(
+ mResourceList.begin(), mResourceList.end());
+ for (const ::aidl::android::media::MediaResourceParcel& res : rhs.mResourceList) {
+ if (lhs.find(res) == lhs.end()) {
+ return false;
+ }
+ }
+ return true;
+}
+
// Bunch of utility functions that looks for a specific Resource.
// Check whether a given resource (of type and subtype) is found in given resource parcel.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
@@ -50,8 +140,8 @@
// Check whether a given resource (of type and subtype) is found in given resource list.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
const ResourceList& resources) {
- for (auto it = resources.begin(); it != resources.end(); it++) {
- if (hasResourceType(type, subType, it->second)) {
+ for (const MediaResourceParcel& res : resources.getResources()) {
+ if (hasResourceType(type, subType, res)) {
return true;
}
}
@@ -88,7 +178,6 @@
const std::shared_ptr<IResourceManagerClient>& client,
ResourceInfos& infos) {
ResourceInfos::iterator found = infos.find(clientInfo.id);
-
if (found == infos.end()) {
ResourceInfo info{.pid = clientInfo.pid,
.uid = static_cast<uid_t>(clientInfo.uid),
@@ -96,7 +185,8 @@
.name = clientInfo.name.empty()? "<unknown client>" : clientInfo.name,
.client = client,
.deathNotifier = nullptr,
- .pendingRemoval = false};
+ .pendingRemoval = false,
+ .importance = static_cast<uint32_t>(std::max(0, clientInfo.importance))};
auto [it, inserted] = infos.emplace(clientInfo.id, info);
found = it;
}
@@ -202,4 +292,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..32cb219 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceUtils.h
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
@@ -18,6 +18,9 @@
#ifndef ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_
#define ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_
+#include <map>
+#include <set>
+#include <memory>
#include <vector>
#include <aidl/android/media/BnResourceManagerService.h>
@@ -97,10 +100,47 @@
virtual void binderDied();
};
-// A map of tuple(type, sub-type, id) and the resource parcel.
-typedef std::map<std::tuple<
- MediaResource::Type, MediaResource::SubType, std::vector<uint8_t>>,
- ::aidl::android::media::MediaResourceParcel> ResourceList;
+// Encapsulate Resource List as vector of resources instead of map.
+// Since the number of resource is very limited, maintaining it as
+// std::vector helps with both performance and memory requiremnts.
+struct ResourceList {
+ // Add or Update an entry into ResourceList.
+ // If a new entry is added, isNewEntry will be set to true upon return
+ // returns true on successful update, false otherwise.
+ bool add(const ::aidl::android::media::MediaResourceParcel& res, bool* isNewEntry = nullptr);
+
+ // reduce the resource usage by subtracting the resource value.
+ // If the resource value is 0 after reducing the resource usage,
+ // that entry will be removed and removedEntryValue is set to the
+ // value before it was removed upon return otherwise it will be set to -1.
+ // returns true on successful removal of the resource, false otherwise.
+ bool remove(const ::aidl::android::media::MediaResourceParcel& res,
+ long* removedEntryValue = nullptr);
+
+ // Returns true if there aren't any resource entries.
+ bool empty() const {
+ return mResourceList.empty();
+ }
+
+ // Returns resource list as a non-modifiable vectors
+ const std::vector<::aidl::android::media::MediaResourceParcel>& getResources() const {
+ return mResourceList;
+ }
+
+ // Converts resource list into string format
+ std::string toString() const;
+
+ // BEGIN: Test only function
+ // Check if two resource lists are the same.
+ bool operator==(const ResourceList& rhs) const;
+
+ // Add or Update an entry into ResourceList.
+ void addOrUpdate(const ::aidl::android::media::MediaResourceParcel& res);
+ // END: Test only function
+
+private:
+ std::vector<::aidl::android::media::MediaResourceParcel> mResourceList;
+};
// Encapsulation for Resource Info, that contains
// - pid of the app
@@ -120,6 +160,19 @@
std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
ResourceList resources;
bool pendingRemoval{false};
+ uint32_t importance = 0;
+};
+
+/*
+ * Resource Reclaim request info that encapsulates
+ * - the calling/requesting process pid.
+ * - the calling/requesting client's importance.
+ * - the list of resources requesting (to be reclaimed from others)
+ */
+struct ReclaimRequestInfo {
+ int mCallingPid = -1;
+ uint32_t mCallingClientImportance = 0;
+ const std::vector<::aidl::android::media::MediaResourceParcel>& mResources;
};
/*
@@ -170,7 +223,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 +246,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/ResourceObserverService.cpp b/services/mediaresourcemanager/ResourceObserverService.cpp
index 72e249f..21e61e9 100644
--- a/services/mediaresourcemanager/ResourceObserverService.cpp
+++ b/services/mediaresourcemanager/ResourceObserverService.cpp
@@ -286,9 +286,9 @@
{
std::scoped_lock lock{mObserverLock};
- for (auto &res : resources) {
+ for (const MediaResourceParcel& res : resources.getResources()) {
// Skip if this resource doesn't map to any observable type.
- MediaObservableType observableType = getObservableType(res.second);
+ MediaObservableType observableType = getObservableType(res);
if (observableType == MediaObservableType::kInvalid) {
continue;
}
@@ -303,9 +303,9 @@
auto calleeIt = calleeList.find(subscriber.first);
if (calleeIt == calleeList.end()) {
calleeList.emplace(subscriber.first, CalleeInfo{
- subscriber.second, {{observableType, res.second.value}}});
+ subscriber.second, {{observableType, res.value}}});
} else {
- calleeIt->second.monitors.push_back({observableType, res.second.value});
+ calleeIt->second.monitors.push_back({observableType, res.value});
}
}
}
diff --git a/services/mediaresourcemanager/ResourceTracker.cpp b/services/mediaresourcemanager/ResourceTracker.cpp
new file mode 100644
index 0000000..22381c3
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceTracker.cpp
@@ -0,0 +1,769 @@
+/*
+**
+** 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 (const MediaResourceParcel& res : resources.getResources()) {
+ if (hasResourceType(type, subType, res)) {
+ foundResource = true;
+ } else if (res.subType == primarySubType) {
+ matchedPrimary = true;
+ } else if (isHwCodec(res.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) {
+ if (res.value < 0 && res.type != MediaResource::Type::kDrmSession) {
+ ALOGV("%s: Ignoring request to remove negative value of non-drm resource", __func__);
+ continue;
+ }
+ bool isNewEntry = false;
+ if (!info.resources.add(res, &isNewEntry)) {
+ continue;
+ }
+ if (isNewEntry) {
+ onFirstAdded(res, info.uid);
+ }
+
+ // Add it to the list of added resources for observers.
+ resourceAdded.add(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::updateResource(const aidl::android::media::ClientInfoParcel& clientInfo) {
+ ResourceInfos& infos = getResourceInfosForEdit(clientInfo.pid);
+
+ ResourceInfos::iterator found = infos.find(clientInfo.id);
+ if (found == infos.end()) {
+ return false;
+ }
+ // Update the client importance.
+ found->second.importance = std::max(0, clientInfo.importance);
+ return true;
+}
+
+bool ResourceTracker::removeResource(const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources) {
+ int32_t pid = clientInfo.pid;
+ 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) {
+ if (res.value < 0) {
+ ALOGV("%s: Ignoring request to remove negative value of resource", __func__);
+ continue;
+ }
+
+ long removedEntryValue = -1;
+ if (info.resources.remove(res, &removedEntryValue)) {
+ MediaResourceParcel actualRemoved = res;
+ if (removedEntryValue != -1) {
+ onLastRemoved(res, info.uid);
+ actualRemoved.value = removedEntryValue;
+ }
+
+ // Add it to the list of removed resources for observers.
+ resourceRemoved.add(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 (const MediaResourceParcel& res : info.resources.getResources()) {
+ onLastRemoved(res, 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 (const MediaResourceParcel& resource : resources.getResources()) {
+ if (hasResourceType(type, subType, resource)) {
+ if (resource.value > largestValue) {
+ largestValue = resource.value;
+ clientId = info.clientId;
+ uid = info.uid;
+ }
+ }
+ }
+ }
+
+ if (clientId == -1) {
+ 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 (const MediaResourceParcel& resource : resources.getResources()) {
+ if (resource.subType == primarySubType) {
+ matchedPrimary = true;
+ break;
+ } else if (isHwCodec(resource.subType) == isHwCodec(primarySubType)) {
+ matchedPrimary = true;
+ break;
+ }
+ }
+ // Primary type doesn't match, skip the client
+ if (!matchedPrimary) {
+ continue;
+ }
+ for (const MediaResourceParcel& resource : resources.getResources()) {
+ if (hasResourceType(type, subType, resource)) {
+ if (resource.value > largestValue) {
+ largestValue = resource.value;
+ clientId = info->clientId;
+ uid = info->uid;
+ }
+ }
+ }
+ }
+
+ if (clientId == -1) {
+ ALOGE("%s: can't find resource type %s and subtype %s for pid %d",
+ __func__, asString(type), asString(subType), targetPid);
+ return false;
+ }
+
+ clientInfo.mPid = targetPid;
+ clientInfo.mUid = uid;
+ clientInfo.mClientId = clientId;
+ return true;
+}
+
+bool ResourceTracker::getLeastImportantBiggestClient(int targetPid, int32_t importance,
+ MediaResource::Type type,
+ MediaResource::SubType subType,
+ MediaResource::SubType primarySubType,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& clientInfo) {
+ uid_t uid = -1;
+ int64_t clientId = -1;
+ uint64_t largestValue = 0;
+
+ for (const ClientInfo& client : clients) {
+ // Skip the clients that doesn't belong go the targetPid
+ if (client.mPid != targetPid) {
+ continue;
+ }
+ const ResourceInfo* info = getResourceInfo(client.mPid, client.mClientId);
+ if (info == nullptr) {
+ continue;
+ }
+
+ // Make sure the importance is lower.
+ if (info->importance <= importance) {
+ continue;
+ }
+ const ResourceList& resources = info->resources;
+ bool matchedPrimary =
+ (primarySubType == MediaResource::SubType::kUnspecifiedSubType) ? true : false;
+ for (const MediaResourceParcel& resource : resources.getResources()) {
+ if (resource.subType == primarySubType) {
+ matchedPrimary = true;
+ } else if (isHwCodec(resource.subType) == isHwCodec(primarySubType)) {
+ matchedPrimary = true;
+ }
+ }
+ // Primary type doesn't match, skip the client
+ if (!matchedPrimary) {
+ continue;
+ }
+ for (const MediaResourceParcel& resource : resources.getResources()) {
+ if (hasResourceType(type, subType, resource)) {
+ if (resource.value > largestValue) {
+ largestValue = resource.value;
+ clientId = info->clientId;
+ uid = info->uid;
+ }
+ }
+ }
+ }
+
+ if (clientId == -1) {
+ ALOGE("%s: can't find resource type %s and subtype %s for pid %d",
+ __func__, asString(type), asString(subType), targetPid);
+ return false;
+ }
+
+ clientInfo.mPid = targetPid;
+ clientInfo.mUid = uid;
+ clientInfo.mClientId = clientId;
+ return true;
+}
+
+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");
+ resourceLogs.append(resources.toString());
+ }
+ }
+ 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..20c904d
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceTracker.h
@@ -0,0 +1,256 @@
+/*
+**
+** 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);
+
+ // Update the resource info, if there is any changes.
+ bool updateResource(const aidl::android::media::ClientInfoParcel& clientInfo);
+
+ // Remove a set of resources from the given client.
+ // returns true on success, false otherwise.
+ bool removeResource(const aidl::android::media::ClientInfoParcel& clientInfo,
+ 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 biggest client from the process pid, that has the least importance
+ // (than given importance) among the given list of clients.
+ // If applicable, match the primary type too.
+ // returns true on success, false otherwise.
+ bool getLeastImportantBiggestClient(int targetPid, int32_t importance,
+ MediaResource::Type type,
+ MediaResource::SubType subType,
+ MediaResource::SubType primarySubType,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& clientInfo);
+
+ // Find the client that belongs to given process(pid) and with the given clientId.
+ // A nullptr is returned upon failure to find the client.
+ std::shared_ptr<::aidl::android::media::IResourceManagerClient> getClient(
+ 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/aidl/android/media/ClientInfoParcel.aidl b/services/mediaresourcemanager/aidl/android/media/ClientInfoParcel.aidl
index eb4bc42..aa14ace 100644
--- a/services/mediaresourcemanager/aidl/android/media/ClientInfoParcel.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/ClientInfoParcel.aidl
@@ -41,4 +41,11 @@
* Name of the resource associated with the client.
*/
@utf8InCpp String name;
+
+ /*
+ * Client importance, which ranges from 0 to int_max.
+ * The default importance is high (0)
+ * Based on the reclaim policy, this could be used during reclaim.
+ */
+ int importance = 0;
}
diff --git a/services/mediaresourcemanager/fuzzer/Android.bp b/services/mediaresourcemanager/fuzzer/Android.bp
index bbbc737..5bac062 100644
--- a/services/mediaresourcemanager/fuzzer/Android.bp
+++ b/services/mediaresourcemanager/fuzzer/Android.bp
@@ -43,6 +43,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..7e8a4a0 100644
--- a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
+++ b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
@@ -123,14 +123,16 @@
struct TestClient : public BnResourceManagerClient {
- TestClient(int pid, int uid, const std::shared_ptr<ResourceManagerService> &service)
- : mPid(pid), mUid(uid), mService(service) {}
+ TestClient(int pid, int uid, int32_t clientImportance,
+ const std::shared_ptr<ResourceManagerService> &service)
+ : mPid(pid), mUid(uid), mClientImportance(clientImportance), mService(service) {}
Status reclaimResource(bool* _aidl_return) override {
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
.uid = static_cast<int32_t>(mUid),
.id = getId(ref<TestClient>()),
- .name = "none"};
+ .name = "none",
+ .importance = mClientImportance};
mService->removeClient(clientInfo);
mWasReclaimResourceCalled = true;
*_aidl_return = true;
@@ -150,10 +152,15 @@
virtual ~TestClient() {}
+ inline int pid() const { return mPid; }
+ inline int uid() const { return mUid; }
+ inline int32_t clientImportance() const { return mClientImportance; }
+
private:
bool mWasReclaimResourceCalled = false;
int mPid;
int mUid;
+ int32_t mClientImportance = 0;
std::shared_ptr<ResourceManagerService> mService;
DISALLOW_EVIL_CONSTRUCTORS(TestClient);
};
@@ -168,6 +175,10 @@
static const int kMidPriorityPid = 25;
static const int kHighPriorityPid = 10;
+static const int32_t kHighestCodecImportance = 0;
+static const int32_t kLowestCodecImportance = 100;
+static const int32_t kMidCodecImportance = 50;
+
using EventType = TestSystemCallback::EventType;
using EventEntry = TestSystemCallback::EventEntry;
bool operator== (const EventEntry& lhs, const EventEntry& rhs) {
@@ -198,8 +209,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,14 +218,19 @@
// silently ignored.
ABinderProcess_startThreadPool();
mSystemCB = new TestSystemCallback();
- 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);
+ if (mNewRM) {
+ mService = ResourceManagerService::CreateNew(new TestProcessInfo, mSystemCB);
+ } else {
+ mService = ResourceManagerService::Create(new TestProcessInfo, mSystemCB);
+ }
+ mTestClient1 = ::ndk::SharedRefBase::make<TestClient>(kTestPid1, kTestUid1, 0, mService);
+ mTestClient2 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, 0, mService);
+ mTestClient3 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, 0, mService);
}
- std::shared_ptr<IResourceManagerClient> createTestClient(int pid, int uid) {
- return ::ndk::SharedRefBase::make<TestClient>(pid, uid, mService);
+ std::shared_ptr<IResourceManagerClient> createTestClient(int pid, int uid,
+ int32_t importance = 0) {
+ return ::ndk::SharedRefBase::make<TestClient>(pid, uid, importance, mService);
}
sp<TestSystemCallback> mSystemCB;
@@ -229,9 +245,7 @@
// convert resource1 to ResourceList
ResourceList r1;
for (size_t i = 0; i < resources1.size(); ++i) {
- const auto &res = resources1[i];
- const auto resType = std::tuple(res.type, res.subType, res.id);
- r1[resType] = res;
+ r1.addOrUpdate(resources1[i]);
}
return r1 == resources2;
}
@@ -244,6 +258,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..b3a0932 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());
@@ -197,7 +209,6 @@
resources1.clear();
resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MIN));
- expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MIN));
mService->addResource(client1Info, mTestClient1, resources1);
// Expected result:
@@ -213,29 +224,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 +247,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 +292,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 +332,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 +366,7 @@
.name = "none"};
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
@@ -402,7 +394,7 @@
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
@@ -428,7 +420,7 @@
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
mService->markClientForPendingRemoval(client2Info);
@@ -466,7 +458,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 +512,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 +537,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 +557,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 +588,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 +618,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 +664,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 +690,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 +720,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));
@@ -1510,6 +1497,269 @@
client3Config.width * client3Config.height));
EXPECT_TRUE(currentPixelCountP2 == 0);
}
+
+ void addNonSecureVideoCodecResource(std::shared_ptr<IResourceManagerClient>& client,
+ std::vector<ClientInfoParcel>& infos) {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(createNonSecureVideoCodecResource(1));
+
+ TestClient* testClient = toTestClient(client);
+ ClientInfoParcel clientInfo {.pid = static_cast<int32_t>(testClient->pid()),
+ .uid = static_cast<int32_t>(testClient->uid()),
+ .id = getId(client),
+ .name = "none",
+ .importance = testClient->clientImportance()};
+ mService->addResource(clientInfo, client, resources);
+ infos.push_back(clientInfo);
+ }
+
+ bool doReclaimResource(const ClientInfoParcel& clientInfo) {
+ bool result = false;
+ std::vector<MediaResourceParcel> reclaimResources;
+ reclaimResources.push_back(createNonSecureVideoCodecResource(1));
+ bool success = mService->reclaimResource(clientInfo, reclaimResources, &result).isOk();
+ return success && result;
+ }
+
+ // Verifies the resource reclaim policies
+ // - this verifies the reclaim policies based on:
+ // - process priority (oom score)
+ // - client priority
+ void testReclaimPolicies() {
+ // Create 3 clients with codec importance high, mid and low for a low
+ // priority pid.
+ std::vector<std::shared_ptr<IResourceManagerClient>> lowPriPidClients;
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kHighestCodecImportance));
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kMidCodecImportance));
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kLowestCodecImportance));
+
+ // Create 3 clients with codec importance high, mid and low for a high
+ // priority pid.
+ std::vector<std::shared_ptr<IResourceManagerClient>> highPriPidClients;
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kHighestCodecImportance));
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kMidCodecImportance));
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kLowestCodecImportance));
+
+ // Add non secure video codec resources for all the 3 clients of low priority pid.
+ std::vector<ClientInfoParcel> lowPriPidClientInfos;
+ for (auto& client : lowPriPidClients) {
+ addNonSecureVideoCodecResource(client, lowPriPidClientInfos);
+ }
+ // Add non secure video codec resources for all the 3 clients of high priority pid.
+ std::vector<ClientInfoParcel> highPriPidClientInfos;
+ for (auto& client : highPriPidClients) {
+ addNonSecureVideoCodecResource(client, highPriPidClientInfos);
+ }
+
+ // 1. Set reclaim policy as "Process Priority".
+ // - A process should be reclaiming from:
+ // - a lower priority process if there is any
+ // - else fail.
+ mService->setReclaimPolicy(true /*process priority*/, false /*codec importance*/);
+
+ // 1.A:
+ // - high priority process should be able to reclaim successfully.
+ // - A process should be reclaiming from the low priority process.
+ EXPECT_TRUE(doReclaimResource(highPriPidClientInfos[0]));
+ // Verify that the high priority pid's clients are untouched.
+ bool success = true;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = false;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+ // Verify that the one of the client from the low priority pid has been reclaimed.
+ success = false;
+ for (auto& client : lowPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 1.B:
+ // - low priority process should fail to reclaim.
+ EXPECT_FALSE(doReclaimResource(lowPriPidClientInfos[0]));
+
+ // 2. Set reclaim policy as "Client Importance".
+ // - A process should be reclaiming from:
+ // - a lower priority client from the same process if any
+ // - else fail.
+ mService->setReclaimPolicy(false /*process priority*/, true /*codec importance*/);
+
+ // 2.A:
+ // - high priority process should be able to reclaim successfully.
+ // - Process should be reclaiming from a lower priority client from the
+ // same process.
+ EXPECT_TRUE(doReclaimResource(highPriPidClientInfos[0]));
+ // Verify that the low priority pid's clients are untouched.
+ success = true;
+ for (auto& client : lowPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = false;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+ // Verify that the one of the low priority client from the high priority
+ // pid has been reclaimed.
+ success = false;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 2.B:
+ // - high priority process should be able to reclaim successfully.
+ // - Process should be reclaiming from a lower priority client from the
+ // same process.
+ EXPECT_TRUE(doReclaimResource(lowPriPidClientInfos[0]));
+ // Verify that the high priority pid's clients are untouched.
+ success = true;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = false;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+ // Verify that the one of the low priority client from the low priority
+ // pid has been reclaimed.
+ success = false;
+ for (auto& client : lowPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 2.C:
+ // - lowest priority client from high priority process should fail to reclaim.
+ EXPECT_FALSE(doReclaimResource(highPriPidClientInfos[2]));
+
+ // 2.D:
+ // - lowest priority client from low priority process should fail to reclaim.
+ EXPECT_FALSE(doReclaimResource(lowPriPidClientInfos[2]));
+
+ // 3. Set reclaim policy as "Process Priority and Client Importance".
+ // - A process should be reclaiming from:
+ // - a lower priority process if there is any
+ // - else a lower priority client from the same process if any
+ // - else fail.
+ mService->setReclaimPolicy(true /*process priority*/, true /*codec importance*/);
+
+ // Remove all clients from the low priority process so that we have
+ // only one process (with high priority) with all the resources.
+ for (const auto& clientInfo : lowPriPidClientInfos) {
+ mService->removeClient(clientInfo);
+ }
+ lowPriPidClientInfos.clear();
+ lowPriPidClients.clear();
+ // 3.A:
+ // - high priority process should be able to reclaim successfully.
+ EXPECT_TRUE(doReclaimResource(highPriPidClientInfos[0]));
+ // Verify that the one of the client from the high priority pid has been reclaimed.
+ success = false;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 3.B, set the policy back to ReclaimPolicyProcessPriority
+ mService->setReclaimPolicy(true /*process priority*/, false /*codec importance*/);
+
+ // Since there is only one process, the reclaim should fail.
+ EXPECT_FALSE(doReclaimResource(highPriPidClientInfos[0]));
+
+ // 4. Set reclaim policy as "Process Priority and Client Importance".
+ // - A process should be reclaiming from:
+ // - from a lower priority process if there are any
+ // - else from a lower priority client from the same process if there are any
+ // - else fail.
+ mService->setReclaimPolicy(true /*process priority*/, true /*codec importance*/);
+
+ // Remove all clients from the high priority process so that we can
+ // start a new/fresh resource allocation.
+ for (const auto& clientInfo : highPriPidClientInfos) {
+ mService->removeClient(clientInfo);
+ }
+ highPriPidClientInfos.clear();
+ highPriPidClients.clear();
+
+ // Create 3 clients with codec importance high for a low priority pid.
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kHighestCodecImportance));
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kHighestCodecImportance));
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kHighestCodecImportance));
+
+ // Create 3 clients with codec importance low for a high priority pid.
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kLowestCodecImportance));
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kLowestCodecImportance));
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kLowestCodecImportance));
+
+ // Add non secure video codec resources for all the 3 clients of low priority pid.
+ for (auto& client : lowPriPidClients) {
+ addNonSecureVideoCodecResource(client, lowPriPidClientInfos);
+ }
+ // Add non secure video codec resources for all the 3 clients of high priority pid.
+ for (auto& client : highPriPidClients) {
+ addNonSecureVideoCodecResource(client, highPriPidClientInfos);
+ }
+
+ // 4.A:
+ // - high priority process should be able to reclaim successfully.
+ EXPECT_TRUE(doReclaimResource(highPriPidClientInfos[0]));
+ // Since all clients are of same priority with in high priority process,
+ // none of the clients should be reclaimed.
+ success = true;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = false;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+ // Verify that the one of the client from the low priority pid has been reclaimed.
+ success = false;
+ for (auto& client : lowPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 4.B, set the policy back to ReclaimPolicyProcessPriority
+ // If low priority process tries to reclaim, it should fail as there
+ // aren't any lower priority clients or lower priority processes.
+ EXPECT_FALSE(doReclaimResource(lowPriPidClientInfos[0]));
+ }
+};
+
+class ResourceManagerServiceNewTest : public ResourceManagerServiceTest {
+public:
+ ResourceManagerServiceNewTest(bool newRM = true) : ResourceManagerServiceTest(newRM) {}
};
TEST_F(ResourceManagerServiceTest, config) {
@@ -1598,4 +1848,95 @@
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();
+}
+
+TEST_F(ResourceManagerServiceNewTest, reclaimPolicies) {
+ testReclaimPolicies();
+}
+
} // namespace android
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 5fb152e..79d0c90 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -75,11 +75,7 @@
this, getState());
// Stop the command thread before destroying.
- if (mThreadEnabled) {
- mThreadEnabled = false;
- mCommandQueue.stopWaiting();
- mCommandThread.stop();
- }
+ stopCommandThread();
}
std::string AAudioServiceStreamBase::dumpHeader() {
@@ -194,26 +190,27 @@
error:
closeAndClear();
- mThreadEnabled = false;
- mCommandQueue.stopWaiting();
- mCommandThread.stop();
+ stopCommandThread();
return result;
}
aaudio_result_t AAudioServiceStreamBase::close() {
aaudio_result_t result = sendCommand(CLOSE, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
+ if (result == AAUDIO_ERROR_ALREADY_CLOSED) {
+ // AAUDIO_ERROR_ALREADY_CLOSED is not a really error but just indicate the stream has
+ // already been closed. In that case, there is no need to close the stream once more.
+ ALOGD("The stream(%d) is already closed", mHandle);
+ return AAUDIO_OK;
+ }
- // Stop the command thread as the stream is closed.
- mThreadEnabled = false;
- mCommandQueue.stopWaiting();
- mCommandThread.stop();
+ stopCommandThread();
return result;
}
aaudio_result_t AAudioServiceStreamBase::close_l() {
if (getState() == AAUDIO_STREAM_STATE_CLOSED) {
- return AAUDIO_OK;
+ return AAUDIO_ERROR_ALREADY_CLOSED;
}
// This will stop the stream, just in case it was not already stopped.
@@ -766,3 +763,11 @@
.record();
return result;
}
+
+void AAudioServiceStreamBase::stopCommandThread() {
+ bool threadEnabled = true;
+ if (mThreadEnabled.compare_exchange_strong(threadEnabled, false)) {
+ mCommandQueue.stopWaiting();
+ mCommandThread.stop();
+ }
+}
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index d5061b3..96a6d44 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -360,7 +360,7 @@
EXIT_STANDBY,
};
AAudioThread mCommandThread;
- std::atomic<bool> mThreadEnabled{false};
+ std::atomic_bool mThreadEnabled{false};
AAudioCommandQueue mCommandQueue;
int32_t mFramesPerBurst = 0;
@@ -400,6 +400,8 @@
bool waitForReply = false,
int64_t timeoutNanos = 0);
+ void stopCommandThread();
+
aaudio_result_t closeAndClear();
/**