Merge "Revert "Revert "Revert "Revert^2 "Audio policy: anonymize Bluetooth MAC ...""" into main
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 645a3d4..7d234bb 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -2287,12 +2287,11 @@
* <p>When low light boost is enabled by setting the AE mode to
* 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY', it can dynamically apply a low light
* boost when the light level threshold is exceeded.</p>
- * <p>This field is present in the CaptureResult when the AE mode is set to
- * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY'. Otherwise, the field is not present.</p>
* <p>This state indicates when low light boost is 'ACTIVE' and applied. Similarly, it can
* indicate when it is not being applied by returning 'INACTIVE'.</p>
* <p>This key will be absent from the CaptureResult if AE mode is not set to
* 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY.</p>
+ * <p>The default value will always be 'INACTIVE'.</p>
*/
ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE = // byte (acamera_metadata_enum_android_control_low_light_boost_state_t)
ACAMERA_CONTROL_START + 59,
@@ -2428,27 +2427,27 @@
* </ul></p>
*
* <p>Flash strength level to use in capture mode i.e. when the applications control
- * flash with either SINGLE or TORCH mode.</p>
+ * flash with either <code>SINGLE</code> or <code>TORCH</code> mode.</p>
* <p>Use ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL and
* ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL to check whether the device supports
* flash strength control or not.
- * If the values of android.flash.info.singleStrengthMaxLevel and
+ * If the values of ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL and
* ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL are greater than 1,
* then the device supports manual flash strength control.</p>
- * <p>If the ACAMERA_FLASH_MODE <code>==</code> TORCH the value must be >= 1
+ * <p>If the ACAMERA_FLASH_MODE <code>==</code> <code>TORCH</code> the value must be >= 1
* and <= ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL.
* If the application doesn't set the key and
* ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL > 1,
* then the flash will be fired at the default level set by HAL in
* ACAMERA_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL.
- * If the ACAMERA_FLASH_MODE <code>==</code> SINGLE, then the value must be >= 1
+ * If the ACAMERA_FLASH_MODE <code>==</code> <code>SINGLE</code>, then the value must be >= 1
* and <= ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL.
* If the application does not set this key and
* ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL > 1,
* then the flash will be fired at the default level set by HAL
* in ACAMERA_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL.
- * If ACAMERA_CONTROL_AE_MODE is set to any of ON_AUTO_FLASH, ON_ALWAYS_FLASH,
- * ON_AUTO_FLASH_REDEYE, ON_EXTERNAL_FLASH values, then the strengthLevel will be ignored.</p>
+ * If ACAMERA_CONTROL_AE_MODE is set to any of <code>ON_AUTO_FLASH</code>, <code>ON_ALWAYS_FLASH</code>,
+ * <code>ON_AUTO_FLASH_REDEYE</code>, <code>ON_EXTERNAL_FLASH</code> values, then the strengthLevel will be ignored.</p>
*
* @see ACAMERA_CONTROL_AE_MODE
* @see ACAMERA_FLASH_MODE
@@ -2460,7 +2459,7 @@
ACAMERA_FLASH_STRENGTH_LEVEL = // int32
ACAMERA_FLASH_START + 6,
/**
- * <p>Maximum flash brightness level for manual flash control in SINGLE mode.</p>
+ * <p>Maximum flash brightness level for manual flash control in <code>SINGLE</code> mode.</p>
*
* <p>Type: int32</p>
*
@@ -2470,7 +2469,7 @@
* </ul></p>
*
* <p>Maximum flash brightness level in camera capture mode and
- * ACAMERA_FLASH_MODE set to SINGLE.
+ * ACAMERA_FLASH_MODE set to <code>SINGLE</code>.
* Value will be > 1 if the manual flash strength control feature is supported,
* otherwise the value will be equal to 1.
* Note that this level is just a number of supported levels (the granularity of control).
@@ -2481,7 +2480,7 @@
ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL = // int32
ACAMERA_FLASH_START + 7,
/**
- * <p>Default flash brightness level for manual flash control in SINGLE mode.</p>
+ * <p>Default flash brightness level for manual flash control in <code>SINGLE</code> mode.</p>
*
* <p>Type: int32</p>
*
@@ -2500,7 +2499,7 @@
ACAMERA_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL = // int32
ACAMERA_FLASH_START + 8,
/**
- * <p>Maximum flash brightness level for manual flash control in TORCH mode</p>
+ * <p>Maximum flash brightness level for manual flash control in <code>TORCH</code> mode</p>
*
* <p>Type: int32</p>
*
@@ -2510,7 +2509,7 @@
* </ul></p>
*
* <p>Maximum flash brightness level in camera capture mode and
- * ACAMERA_FLASH_MODE set to TORCH.
+ * ACAMERA_FLASH_MODE set to <code>TORCH</code>.
* Value will be > 1 if the manual flash strength control feature is supported,
* otherwise the value will be equal to 1.</p>
* <p>Note that this level is just a number of supported levels(the granularity of control).
@@ -2527,7 +2526,7 @@
ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL = // int32
ACAMERA_FLASH_START + 9,
/**
- * <p>Default flash brightness level for manual flash control in TORCH mode</p>
+ * <p>Default flash brightness level for manual flash control in <code>TORCH</code> mode</p>
*
* <p>Type: int32</p>
*
@@ -5875,10 +5874,16 @@
* <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
* </ul></p>
*
- * <p>If TRUE, all images produced by the camera device in the RAW image formats will
- * have lens shading correction already applied to it. If FALSE, the images will
- * not be adjusted for lens shading correction.
- * See android.request.maxNumOutputRaw for a list of RAW image formats.</p>
+ * <p>If <code>true</code>, all images produced by the camera device in the <code>RAW</code> image formats will have
+ * at least some lens shading correction already applied to it. If <code>false</code>, the images will
+ * not be adjusted for lens shading correction. See android.request.maxNumOutputRaw for a
+ * list of RAW image formats.</p>
+ * <p>When <code>true</code>, the <code>lensShadingCorrectionMap</code> key may still have values greater than 1.0,
+ * and those will need to be applied to any captured RAW frames for them to match the shading
+ * correction of processed buffers such as <code>YUV</code> or <code>JPEG</code> images. This may occur, for
+ * example, when some basic fixed lens shading correction is applied by hardware to RAW data,
+ * and additional correction is done dynamically in the camera processing pipeline after
+ * demosaicing.</p>
* <p>This key will be <code>null</code> for all devices do not report this information.
* Devices with RAW capability will always report this information in this key.</p>
*/
@@ -8305,11 +8310,8 @@
* <p>If the session configuration is not supported, the AE mode reported in the
* CaptureResult will be 'ON' instead of 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY'.</p>
* <p>When this AE mode is enabled, the CaptureResult field
- * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE will be present and not null. Otherwise, the
- * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE field will not be present in the CaptureResult.</p>
- * <p>The application can observe the CaptureResult field
- * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE to determine when low light boost is 'ACTIVE' or
- * 'INACTIVE'.</p>
+ * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE will indicate when low light boost is 'ACTIVE'
+ * or 'INACTIVE'. By default ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE will be 'INACTIVE'.</p>
* <p>The low light boost is 'ACTIVE' once the scene lighting condition is less than the
* upper bound lux value defined by ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE.
* This mode will be 'INACTIVE' once the scene lighting condition is greater than the
diff --git a/include/media/Interpolator.h b/include/media/Interpolator.h
index e26290f..5a2ab27 100644
--- a/include/media/Interpolator.h
+++ b/include/media/Interpolator.h
@@ -289,7 +289,7 @@
std::string toString() const {
std::stringstream ss;
- ss << "Interpolator{mInterpolatorType=" << static_cast<int32_t>(mInterpolatorType);
+ ss << "Interpolator{mInterpolatorType=" << media::toString(mInterpolatorType);
ss << ", mFirstSlope=" << mFirstSlope;
ss << ", mLastSlope=" << mLastSlope;
ss << ", {";
diff --git a/include/media/VolumeShaper.h b/include/media/VolumeShaper.h
index 6208db3..26da363 100644
--- a/include/media/VolumeShaper.h
+++ b/include/media/VolumeShaper.h
@@ -116,6 +116,16 @@
TYPE_SCALE,
};
+ static std::string toString(Type type) {
+ switch (type) {
+ case TYPE_ID: return "TYPE_ID";
+ case TYPE_SCALE: return "TYPE_SCALE";
+ default:
+ return std::string("Unknown Type: ")
+ .append(std::to_string(static_cast<int>(type)));
+ }
+ }
+
// Must match with VolumeShaper.java in frameworks/base.
enum OptionFlag : int32_t {
OPTION_FLAG_NONE = 0,
@@ -125,6 +135,22 @@
OPTION_FLAG_ALL = (OPTION_FLAG_VOLUME_IN_DBFS | OPTION_FLAG_CLOCK_TIME),
};
+ static std::string toString(OptionFlag flag) {
+ std::string s;
+ for (const auto& flagPair : std::initializer_list<std::pair<OptionFlag, const char*>>{
+ {OPTION_FLAG_VOLUME_IN_DBFS, "OPTION_FLAG_VOLUME_IN_DBFS"},
+ {OPTION_FLAG_CLOCK_TIME, "OPTION_FLAG_CLOCK_TIME"},
+ }) {
+ if (flag & flagPair.first) {
+ if (!s.empty()) {
+ s.append("|");
+ }
+ s.append(flagPair.second);
+ }
+ }
+ return s;
+ }
+
// Bring from base class; must match with VolumeShaper.java in frameworks/base.
using InterpolatorType = Interpolator<S, T>::InterpolatorType;
@@ -329,10 +355,10 @@
// Returns a string for debug printing.
std::string toString() const {
std::stringstream ss;
- ss << "VolumeShaper::Configuration{mType=" << static_cast<int32_t>(mType);
+ ss << "VolumeShaper::Configuration{mType=" << toString(mType);
ss << ", mId=" << mId;
if (mType != TYPE_ID) {
- ss << ", mOptionFlags=" << static_cast<int32_t>(mOptionFlags);
+ ss << ", mOptionFlags=" << toString(mOptionFlags);
ss << ", mDurationMs=" << mDurationMs;
ss << ", " << Interpolator<S, T>::toString().c_str();
}
@@ -414,6 +440,25 @@
| FLAG_CREATE_IF_NECESSARY),
};
+ static std::string toString(Flag flag) {
+ std::string s;
+ for (const auto& flagPair : std::initializer_list<std::pair<Flag, const char*>>{
+ {FLAG_REVERSE, "FLAG_REVERSE"},
+ {FLAG_TERMINATE, "FLAG_TERMINATE"},
+ {FLAG_JOIN, "FLAG_JOIN"},
+ {FLAG_DELAY, "FLAG_DELAY"},
+ {FLAG_CREATE_IF_NECESSARY, "FLAG_CREATE_IF_NECESSARY"},
+ }) {
+ if (flag & flagPair.first) {
+ if (!s.empty()) {
+ s.append("|");
+ }
+ s.append(flagPair.second);
+ }
+ }
+ return s;
+ }
+
Operation()
: Operation(FLAG_NONE, -1 /* replaceId */) {
}
@@ -508,7 +553,7 @@
std::string toString() const {
std::stringstream ss;
- ss << "VolumeShaper::Operation{mFlags=" << static_cast<int32_t>(mFlags) ;
+ ss << "VolumeShaper::Operation{mFlags=" << toString(mFlags);
ss << ", mReplaceId=" << mReplaceId;
ss << ", mXOffset=" << mXOffset;
ss << "}";
diff --git a/media/audio/aconfig/audio.aconfig b/media/audio/aconfig/audio.aconfig
index c642a94..c3ae59c 100644
--- a/media/audio/aconfig/audio.aconfig
+++ b/media/audio/aconfig/audio.aconfig
@@ -60,6 +60,13 @@
}
flag {
+ name: "music_fx_edge_to_edge"
+ namespace: "media_audio"
+ description: "Enable Edge-to-edge feature for MusicFx and handle insets"
+ bug: "336204940"
+}
+
+flag {
name: "port_to_piid_simplification"
namespace: "media_audio"
description: "PAM only needs for each piid the last portId mapping"
@@ -68,6 +75,14 @@
}
flag {
+ name: "replace_stream_bt_sco"
+ namespace: "media_audio"
+ description:
+ "Replace internally STREAM_BLUETOOTH_SCO with STREAM_VOICE_CALL"
+ bug: "345024266"
+}
+
+flag {
name: "ringer_mode_affects_alarm"
namespace: "media_audio"
description:
diff --git a/media/audio/aconfig/audioserver.aconfig b/media/audio/aconfig/audioserver.aconfig
index 94b60e2..5e70168 100644
--- a/media/audio/aconfig/audioserver.aconfig
+++ b/media/audio/aconfig/audioserver.aconfig
@@ -15,6 +15,13 @@
}
flag {
+ name: "effect_chain_callback_improve"
+ namespace: "media_audio"
+ description: "Improve effect chain callback mutex logic."
+ bug: "342413767"
+}
+
+flag {
name: "fdtostring_timeout_fix"
namespace: "media_audio"
description: "Improve fdtostring implementation to properly handle timing out."
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index 08e2fa6..3e88acd 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -465,6 +465,7 @@
mTemporalPatternIdx(0),
mLastTimestamp(0x7FFFFFFFFFFFFFFFull),
mSignalledOutputEos(false),
+ mHeaderGenerated(false),
mSignalledError(false) {
for (int i = 0; i < MAXTEMPORALLAYERS; i++) {
mTemporalLayerBitrateRatio[i] = 1.0f;
@@ -494,6 +495,7 @@
// this one is not allocated by us
mCodecInterface = nullptr;
+ mHeaderGenerated = false;
}
c2_status_t C2SoftVpxEnc::onStop() {
@@ -558,6 +560,7 @@
(uint32_t)mBitrateControlMode, mTemporalLayers, mIntf->getSyncFramePeriod(),
mMinQuantizer, mMaxQuantizer);
+ mHeaderGenerated = false;
mCodecConfiguration = new vpx_codec_enc_cfg_t;
if (!mCodecConfiguration) goto CleanUp;
codec_return = vpx_codec_enc_config_default(mCodecInterface,
@@ -873,6 +876,27 @@
return;
}
+ // Header generation is limited to Android V and above, as MediaMuxer did not handle
+ // CSD for VP9 correctly in Android U and before.
+ if (isAtLeastV() && !mHeaderGenerated) {
+ vpx_fixed_buf_t* codec_private_data = vpx_codec_get_global_headers(mCodecContext);
+ if (codec_private_data) {
+ std::unique_ptr<C2StreamInitDataInfo::output> csd =
+ C2StreamInitDataInfo::output::AllocUnique(codec_private_data->sz, 0u);
+ if (!csd) {
+ ALOGE("CSD allocation failed");
+ mSignalledError = true;
+ work->result = C2_NO_MEMORY;
+ work->workletsProcessed = 1u;
+ return;
+ }
+ memcpy(csd->m.value, codec_private_data->buf, codec_private_data->sz);
+ work->worklets.front()->output.configUpdate.push_back(std::move(csd));
+ ALOGV("CSD Produced of size %zu bytes", codec_private_data->sz);
+ }
+ mHeaderGenerated = true;
+ }
+
const C2ConstGraphicBlock inBuffer =
inputBuffer->data().graphicBlocks().front();
if (inBuffer.width() < mSize->width ||
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.h b/media/codec2/components/vpx/C2SoftVpxEnc.h
index 980de04..87d24f9 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.h
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.h
@@ -207,6 +207,9 @@
// Signalled EOS
bool mSignalledOutputEos;
+ // Header generated
+ bool mHeaderGenerated;
+
// Signalled Error
bool mSignalledError;
diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp
index b95c09e..ea4d045 100644
--- a/media/codec2/hal/aidl/ComponentStore.cpp
+++ b/media/codec2/hal/aidl/ComponentStore.cpp
@@ -36,7 +36,7 @@
#include <ostream>
#include <sstream>
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__ // Filters are not supported for APEX modules
#include <codec2/hidl/plugin/FilterPlugin.h>
#include <dlfcn.h>
#include <C2Config.h>
@@ -51,7 +51,7 @@
namespace c2 {
namespace utils {
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__ // Filters are not supported for APEX modules
using ::android::DefaultFilterPlugin;
using ::android::FilterWrapper;
#endif
@@ -144,7 +144,15 @@
::android::SetPreferredCodec2ComponentStore(store);
// Retrieve struct descriptors
- mParamReflector = mStore->getParamReflector();
+ mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__ // Filters are not supported for APEX modules
+ std::shared_ptr<C2ParamReflector> paramReflector =
+ GetFilterWrapper()->getParamReflector();
+ if (paramReflector != nullptr) {
+ ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+ mParamReflectors.push_back(paramReflector);
+ }
+#endif
// Retrieve supported parameters from store
using namespace std::placeholders;
@@ -173,8 +181,7 @@
std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
auto it = mStructDescriptors.find(coreIndex);
if (it == mStructDescriptors.end()) {
- std::shared_ptr<C2StructDescriptor> structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
if (!structDesc) {
// All supported params must be described
res = C2_BAD_INDEX;
@@ -189,7 +196,7 @@
return mParameterCache;
}
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__ // Filters are not supported for APEX modules
// static
std::shared_ptr<FilterWrapper> ComponentStore::GetFilterWrapper() {
constexpr const char kPluginPath[] = "libc2filterplugin.so";
@@ -221,8 +228,13 @@
}
}
if (!isComponentSupportsLargeAudioFrame) {
+ // TODO - b/342269852: MultiAccessUnitInterface also needs to take multiple
+ // param reflectors. Currently filters work on video domain only,
+ // and the MultiAccessUnitHelper is only enabled on audio domain;
+ // thus we pass the component's param reflector, which is mParamReflectors[0].
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
- c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+ c2interface,
+ std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
}
}
}
@@ -250,7 +262,7 @@
mStore->createComponent(name, &c2component);
if (status == C2_OK) {
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__ // Filters are not supported for APEX modules
c2component = GetFilterWrapper()->maybeWrapComponent(c2component);
#endif
onInterfaceLoaded(c2component->intf());
@@ -284,7 +296,7 @@
std::shared_ptr<C2ComponentInterface> c2interface;
c2_status_t res = mStore->createInterface(name, &c2interface);
if (res == C2_OK) {
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__ // Filters are not supported for APEX modules
c2interface = GetFilterWrapper()->maybeWrapInterface(c2interface);
#endif
onInterfaceLoaded(c2interface);
@@ -347,8 +359,7 @@
if (item == mStructDescriptors.end()) {
// not in the cache, and not known to be unsupported, query local reflector
if (!mUnsupportedStructDescriptors.count(coreIndex)) {
- std::shared_ptr<C2StructDescriptor> structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
if (!structDesc) {
mUnsupportedStructDescriptors.emplace(coreIndex);
} else {
@@ -401,6 +412,16 @@
return ScopedAStatus::ok();
}
+std::shared_ptr<C2StructDescriptor> ComponentStore::describe(const C2Param::CoreIndex &index) {
+ for (const std::shared_ptr<C2ParamReflector> &reflector : mParamReflectors) {
+ std::shared_ptr<C2StructDescriptor> desc = reflector->describe(index);
+ if (desc) {
+ return desc;
+ }
+ }
+ return nullptr;
+}
+
// Called from createComponent() after a successful creation of `component`.
void ComponentStore::reportComponentBirth(Component* component) {
ComponentStatus componentStatus;
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
index 746e1bf..b2158a6 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
@@ -118,7 +118,7 @@
c2_status_t mInit;
std::shared_ptr<C2ComponentStore> mStore;
- std::shared_ptr<C2ParamReflector> mParamReflector;
+ std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
@@ -135,6 +135,9 @@
mutable std::mutex mComponentRosterMutex;
std::map<Component*, ComponentStatus> mComponentRoster;
+ // describe from mParamReflectors
+ std::shared_ptr<C2StructDescriptor> describe(const C2Param::CoreIndex &index);
+
// Called whenever Component is created.
void reportComponentBirth(Component* component);
// Called only from the destructor of Component.
diff --git a/media/codec2/hal/common/Android.bp b/media/codec2/hal/common/Android.bp
index 4c9da33..0638363 100644
--- a/media/codec2/hal/common/Android.bp
+++ b/media/codec2/hal/common/Android.bp
@@ -28,13 +28,9 @@
"liblog",
"libstagefright_foundation",
"server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
],
-
static_libs: ["aconfig_mediacodec_flags_c_lib"],
-
- defaults: [
- "aconfig_lib_cc_static_link.defaults",
- ],
}
cc_library_static {
@@ -57,6 +53,7 @@
shared_libs: [
"libbase",
"server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
],
static_libs: ["aconfig_mediacodec_flags_c_lib"],
@@ -71,5 +68,6 @@
shared_libs: [
"libbase",
"server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
],
}
diff --git a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
index 988ab6f..1ba1889 100644
--- a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
@@ -139,7 +139,15 @@
SetPreferredCodec2ComponentStore(store);
// Retrieve struct descriptors
- mParamReflector = mStore->getParamReflector();
+ mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__
+ std::shared_ptr<C2ParamReflector> paramReflector =
+ GetFilterWrapper()->getParamReflector();
+ if (paramReflector != nullptr) {
+ ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+ mParamReflectors.push_back(paramReflector);
+ }
+#endif
// Retrieve supported parameters from store
using namespace std::placeholders;
@@ -168,8 +176,7 @@
std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
auto it = mStructDescriptors.find(coreIndex);
if (it == mStructDescriptors.end()) {
- std::shared_ptr<C2StructDescriptor> structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
if (!structDesc) {
// All supported params must be described
res = C2_BAD_INDEX;
@@ -217,7 +224,8 @@
}
if (!isComponentSupportsLargeAudioFrame) {
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
- c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+ c2interface,
+ std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
}
}
}
@@ -339,8 +347,7 @@
if (item == mStructDescriptors.end()) {
// not in the cache, and not known to be unsupported, query local reflector
if (!mUnsupportedStructDescriptors.count(coreIndex)) {
- std::shared_ptr<C2StructDescriptor> structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
if (!structDesc) {
mUnsupportedStructDescriptors.emplace(coreIndex);
} else {
@@ -386,6 +393,16 @@
return mConfigurable;
}
+std::shared_ptr<C2StructDescriptor> ComponentStore::describe(const C2Param::CoreIndex &index) {
+ for (const std::shared_ptr<C2ParamReflector> &reflector : mParamReflectors) {
+ std::shared_ptr<C2StructDescriptor> desc = reflector->describe(index);
+ if (desc) {
+ return desc;
+ }
+ }
+ return nullptr;
+}
+
// Called from createComponent() after a successful creation of `component`.
void ComponentStore::reportComponentBirth(Component* component) {
ComponentStatus componentStatus;
diff --git a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
index b5d85da..44b8ec1 100644
--- a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
@@ -117,9 +117,12 @@
// Does bookkeeping for an interface that has been loaded.
void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
+ // describe from mParamReflectors
+ std::shared_ptr<C2StructDescriptor> describe(const C2Param::CoreIndex &index);
+
c2_status_t mInit;
std::shared_ptr<C2ComponentStore> mStore;
- std::shared_ptr<C2ParamReflector> mParamReflector;
+ std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
diff --git a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
index 46af809..1b86958 100644
--- a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
@@ -139,7 +139,15 @@
SetPreferredCodec2ComponentStore(store);
// Retrieve struct descriptors
- mParamReflector = mStore->getParamReflector();
+ mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__
+ std::shared_ptr<C2ParamReflector> paramReflector =
+ GetFilterWrapper()->getParamReflector();
+ if (paramReflector != nullptr) {
+ ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+ mParamReflectors.push_back(paramReflector);
+ }
+#endif
// Retrieve supported parameters from store
using namespace std::placeholders;
@@ -168,8 +176,7 @@
std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
auto it = mStructDescriptors.find(coreIndex);
if (it == mStructDescriptors.end()) {
- std::shared_ptr<C2StructDescriptor> structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
if (!structDesc) {
// All supported params must be described
res = C2_BAD_INDEX;
@@ -218,7 +225,8 @@
if (!isComponentSupportsLargeAudioFrame) {
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
- c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+ c2interface,
+ std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
}
}
}
@@ -340,8 +348,7 @@
if (item == mStructDescriptors.end()) {
// not in the cache, and not known to be unsupported, query local reflector
if (!mUnsupportedStructDescriptors.count(coreIndex)) {
- std::shared_ptr<C2StructDescriptor> structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
if (!structDesc) {
mUnsupportedStructDescriptors.emplace(coreIndex);
} else {
@@ -423,6 +430,16 @@
return Void();
}
+std::shared_ptr<C2StructDescriptor> ComponentStore::describe(const C2Param::CoreIndex &index) {
+ for (const std::shared_ptr<C2ParamReflector> &reflector : mParamReflectors) {
+ std::shared_ptr<C2StructDescriptor> desc = reflector->describe(index);
+ if (desc) {
+ return desc;
+ }
+ }
+ return nullptr;
+}
+
// Called from createComponent() after a successful creation of `component`.
void ComponentStore::reportComponentBirth(Component* component) {
ComponentStatus componentStatus;
diff --git a/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h b/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
index 85862a9..52d2945 100644
--- a/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
@@ -125,9 +125,12 @@
// Does bookkeeping for an interface that has been loaded.
void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
+ // describe from mParamReflectors
+ std::shared_ptr<C2StructDescriptor> describe(const C2Param::CoreIndex &index);
+
c2_status_t mInit;
std::shared_ptr<C2ComponentStore> mStore;
- std::shared_ptr<C2ParamReflector> mParamReflector;
+ std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
diff --git a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
index f89c835..2e0386f 100644
--- a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
@@ -139,7 +139,15 @@
SetPreferredCodec2ComponentStore(store);
// Retrieve struct descriptors
- mParamReflector = mStore->getParamReflector();
+ mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__
+ std::shared_ptr<C2ParamReflector> paramReflector =
+ GetFilterWrapper()->getParamReflector();
+ if (paramReflector != nullptr) {
+ ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+ mParamReflectors.push_back(paramReflector);
+ }
+#endif
// Retrieve supported parameters from store
using namespace std::placeholders;
@@ -168,8 +176,7 @@
std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
auto it = mStructDescriptors.find(coreIndex);
if (it == mStructDescriptors.end()) {
- std::shared_ptr<C2StructDescriptor> structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
if (!structDesc) {
// All supported params must be described
res = C2_BAD_INDEX;
@@ -217,7 +224,8 @@
}
if (!isComponentSupportsLargeAudioFrame) {
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
- c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+ c2interface,
+ std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
}
}
}
@@ -338,8 +346,7 @@
if (item == mStructDescriptors.end()) {
// not in the cache, and not known to be unsupported, query local reflector
if (!mUnsupportedStructDescriptors.count(coreIndex)) {
- std::shared_ptr<C2StructDescriptor> structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
if (!structDesc) {
mUnsupportedStructDescriptors.emplace(coreIndex);
} else {
@@ -457,6 +464,16 @@
return Void();
}
+std::shared_ptr<C2StructDescriptor> ComponentStore::describe(const C2Param::CoreIndex &index) {
+ for (const std::shared_ptr<C2ParamReflector> &reflector : mParamReflectors) {
+ std::shared_ptr<C2StructDescriptor> desc = reflector->describe(index);
+ if (desc) {
+ return desc;
+ }
+ }
+ return nullptr;
+}
+
// Called from createComponent() after a successful creation of `component`.
void ComponentStore::reportComponentBirth(Component* component) {
ComponentStatus componentStatus;
diff --git a/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h b/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
index c08fce4..1b209e2 100644
--- a/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
@@ -132,9 +132,12 @@
// Does bookkeeping for an interface that has been loaded.
void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
+ // describe from mParamReflectors
+ std::shared_ptr<C2StructDescriptor> describe(const C2Param::CoreIndex &index);
+
c2_status_t mInit;
std::shared_ptr<C2ComponentStore> mStore;
- std::shared_ptr<C2ParamReflector> mParamReflector;
+ std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
diff --git a/media/codec2/hal/plugin/FilterWrapper.cpp b/media/codec2/hal/plugin/FilterWrapper.cpp
index b926150..ab6e3eb 100644
--- a/media/codec2/hal/plugin/FilterWrapper.cpp
+++ b/media/codec2/hal/plugin/FilterWrapper.cpp
@@ -1012,4 +1012,11 @@
return mPlugin->queryParamsForPreviousComponent(intf, params);
}
+std::shared_ptr<C2ParamReflector> FilterWrapper::getParamReflector() {
+ if (mInit != OK) {
+ return nullptr;
+ }
+ return mStore->getParamReflector();
+}
+
} // namespace android
diff --git a/media/codec2/hal/plugin/FilterWrapperStub.cpp b/media/codec2/hal/plugin/FilterWrapperStub.cpp
index 3fd5409..a21f6d0 100644
--- a/media/codec2/hal/plugin/FilterWrapperStub.cpp
+++ b/media/codec2/hal/plugin/FilterWrapperStub.cpp
@@ -57,4 +57,8 @@
return CreateCodec2BlockPool(allocatorParam, component, pool);
}
+std::shared_ptr<C2ParamReflector> FilterWrapper::getParamReflector() {
+ return nullptr;
+}
+
} // namespace android
diff --git a/media/codec2/hal/plugin/internal/FilterWrapper.h b/media/codec2/hal/plugin/internal/FilterWrapper.h
index dcffb5c..c27901e 100644
--- a/media/codec2/hal/plugin/internal/FilterWrapper.h
+++ b/media/codec2/hal/plugin/internal/FilterWrapper.h
@@ -104,6 +104,10 @@
const std::shared_ptr<C2ComponentInterface> &intf,
std::vector<std::unique_ptr<C2Param>> *params);
+ /**
+ * Return the param reflector of the filter plugin store.
+ */
+ std::shared_ptr<C2ParamReflector> getParamReflector();
private:
status_t mInit;
std::unique_ptr<Plugin> mPlugin;
diff --git a/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp b/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
index b5383ad..47412b7 100644
--- a/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
+++ b/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
@@ -37,6 +37,19 @@
kParamIndexColorAspects | C2Param::CoreIndex::IS_REQUEST_FLAG>
C2StreamColorAspectsRequestInfo;
+// In practice the vendor parameters will be defined in a separate header file,
+// but for the purpose of this sample, we just define it here.
+
+// Vendor-specific type index for filters start from this value. 0x7000 is added to
+// avoid conflict with existing vendor type indices.
+constexpr uint32_t kTypeIndexFilterStart = C2Param::TYPE_INDEX_VENDOR_START + 0x7000;
+// Answer to the Ultimate Question of Life, the Universe, and Everything
+// (Reference to The Hitchhiker's Guide to the Galaxy by Douglas Adams)
+constexpr uint32_t kParamIndexVendorUltimateAnswer = kTypeIndexFilterStart + 0;
+typedef C2StreamParam<C2Info, C2Int32Value, kParamIndexVendorUltimateAnswer>
+ C2StreamVendorUltimateAnswerInfo;
+constexpr char C2_PARAMKEY_VENDOR_ULTIMATE_ANSWER[] = "ultimate-answer";
+
namespace android {
using namespace std::literals::chrono_literals;
@@ -49,10 +62,9 @@
static const std::string NAME;
static const FilterPlugin_V1::Descriptor DESCRIPTOR;
- explicit Interface(c2_node_id_t id)
+ Interface(c2_node_id_t id, const std::shared_ptr<C2ReflectorHelper> &reflector)
: mId(id),
- mReflector(std::make_shared<C2ReflectorHelper>()),
- mHelper(mReflector) {
+ mHelper(reflector) {
}
~Interface() override = default;
C2String getName() const override { return NAME; }
@@ -126,7 +138,6 @@
}
private:
const c2_node_id_t mId;
- std::shared_ptr<C2ReflectorHelper> mReflector;
struct Helper : public C2InterfaceHelper {
explicit Helper(std::shared_ptr<C2ReflectorHelper> reflector)
: C2InterfaceHelper(reflector) {
@@ -266,6 +277,15 @@
.build());
addParameter(
+ DefineParam(mVendorUltimateAnswerInfo, C2_PARAMKEY_VENDOR_ULTIMATE_ANSWER)
+ .withDefault(new C2StreamVendorUltimateAnswerInfo::input(0u))
+ .withFields({
+ C2F(mVendorUltimateAnswerInfo, value).any(),
+ })
+ .withSetter(VendorUltimateAnswerSetter)
+ .build());
+
+ addParameter(
DefineParam(mOutputColorAspectInfo, C2_PARAMKEY_COLOR_ASPECTS)
.withDefault(new C2StreamColorAspectsInfo::output(0u))
.withFields({
@@ -336,6 +356,15 @@
return C2R::Ok();
}
+ static C2R VendorUltimateAnswerSetter(
+ bool mayBlock,
+ C2P<C2StreamVendorUltimateAnswerInfo::input> &me) {
+ (void)mayBlock;
+ ALOGI("Answer to the Ultimate Question of Life, the Universe, and Everything "
+ "set to %d", me.v.value);
+ return C2R::Ok();
+ }
+
std::shared_ptr<C2ApiFeaturesSetting> mApiFeatures;
std::shared_ptr<C2ComponentNameSetting> mName;
@@ -362,11 +391,13 @@
std::shared_ptr<C2StreamColorAspectsInfo::input> mInputColorAspectInfo;
std::shared_ptr<C2StreamColorAspectsInfo::output> mOutputColorAspectInfo;
std::shared_ptr<C2StreamColorAspectsRequestInfo::output> mColorAspectRequestInfo;
+
+ std::shared_ptr<C2StreamVendorUltimateAnswerInfo::input> mVendorUltimateAnswerInfo;
} mHelper;
};
- explicit SampleToneMappingFilter(c2_node_id_t id)
- : mIntf(std::make_shared<Interface>(id)) {
+ SampleToneMappingFilter(c2_node_id_t id, const std::shared_ptr<C2ReflectorHelper> &reflector)
+ : mIntf(std::make_shared<Interface>(id, reflector)) {
}
~SampleToneMappingFilter() override {
if (mProcessingThread.joinable()) {
@@ -802,7 +833,10 @@
// static
const FilterPlugin_V1::Descriptor SampleToneMappingFilter::Interface::DESCRIPTOR = {
// controlParams
- { C2StreamColorAspectsRequestInfo::output::PARAM_TYPE },
+ {
+ C2StreamColorAspectsRequestInfo::output::PARAM_TYPE,
+ C2StreamVendorUltimateAnswerInfo::input::PARAM_TYPE,
+ },
// affectedParams
{
C2StreamHdrStaticInfo::output::PARAM_TYPE,
@@ -815,7 +849,7 @@
SampleC2ComponentStore()
: mReflector(std::make_shared<C2ReflectorHelper>()),
mIntf(mReflector),
- mFactories(CreateFactories()) {
+ mFactories(CreateFactories(mReflector)) {
}
~SampleC2ComponentStore() = default;
@@ -892,36 +926,46 @@
template <class T>
struct ComponentFactoryImpl : public ComponentFactory {
public:
- ComponentFactoryImpl(const std::shared_ptr<const C2Component::Traits> &traits)
- : ComponentFactory(traits) {
+ ComponentFactoryImpl(
+ const std::shared_ptr<const C2Component::Traits> &traits,
+ const std::shared_ptr<C2ReflectorHelper> &reflector)
+ : ComponentFactory(traits),
+ mReflector(reflector) {
}
~ComponentFactoryImpl() override = default;
c2_status_t createComponent(
c2_node_id_t id,
std::shared_ptr<C2Component>* const component) const override {
- *component = std::make_shared<T>(id);
+ *component = std::make_shared<T>(id, mReflector);
return C2_OK;
}
c2_status_t createInterface(
c2_node_id_t id,
std::shared_ptr<C2ComponentInterface>* const interface) const override {
- *interface = std::make_shared<typename T::Interface>(id);
+ *interface = std::make_shared<typename T::Interface>(id, mReflector);
return C2_OK;
}
+ private:
+ std::shared_ptr<C2ReflectorHelper> mReflector;
};
template <class T>
- static void AddFactory(std::map<C2String, std::unique_ptr<ComponentFactory>> *factories) {
- std::shared_ptr<C2ComponentInterface> intf{new typename T::Interface(0)};
+ static void AddFactory(
+ std::map<C2String, std::unique_ptr<ComponentFactory>> *factories,
+ const std::shared_ptr<C2ReflectorHelper> &reflector) {
+ std::shared_ptr<C2ComponentInterface> intf{new typename T::Interface(0, reflector)};
std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
CHECK(C2InterfaceUtils::FillTraitsFromInterface(traits.get(), intf))
<< "Failed to fill traits from interface";
- factories->emplace(traits->name, new ComponentFactoryImpl<T>(traits));
+ factories->emplace(
+ traits->name,
+ new ComponentFactoryImpl<T>(traits, reflector));
}
- static std::map<C2String, std::unique_ptr<ComponentFactory>> CreateFactories() {
+ static std::map<C2String, std::unique_ptr<ComponentFactory>> CreateFactories(
+ const std::shared_ptr<C2ReflectorHelper> &reflector) {
std::map<C2String, std::unique_ptr<ComponentFactory>> factories;
- AddFactory<SampleToneMappingFilter>(&factories);
+ AddFactory<SampleToneMappingFilter>(&factories, reflector);
return factories;
}
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index 7076bac..3c8c1b7 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -84,6 +84,7 @@
"libui",
"libutils",
"server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
],
export_shared_lib_headers: [
@@ -91,10 +92,6 @@
"libcodec2_client",
],
- defaults: [
- "aconfig_lib_cc_static_link.defaults",
- ],
-
sanitize: {
cfi: true,
misc_undefined: [
diff --git a/media/codec2/vndk/C2Fence.cpp b/media/codec2/vndk/C2Fence.cpp
index 5d50fc3..3438406 100644
--- a/media/codec2/vndk/C2Fence.cpp
+++ b/media/codec2/vndk/C2Fence.cpp
@@ -533,8 +533,7 @@
break;
default:
ALOGV("Unsupported fence type %d", type);
- // If this is malformed-handle close the handle here.
- (void) native_handle_close(handle);
+ // Nothing else to do. The handle is owned by the caller.
// return a null-fence in this case
break;
}
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 9d9b574..21321b9 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -1115,6 +1115,17 @@
*
* The default, if you do not call this function, is {@link #AAUDIO_USAGE_MEDIA}.
*
+ * If you set Usage then you will need to associate the volume keys with the resulting stream.
+ * Otherwise the volume keys may not work correctly.
+ * This is done in Java with the following code block.
+ *
+ * <pre><code>if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ * AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usage)
+ * .setContentType(contentType).build();
+ * setVolumeControlStream(attributes.getVolumeControlStream());
+ * }
+ * </code></pre>
+ *
* Available since API level 28.
*
* @param builder reference provided by AAudio_createStreamBuilder()
@@ -1132,6 +1143,17 @@
*
* The default, if you do not call this function, is {@link #AAUDIO_CONTENT_TYPE_MUSIC}.
*
+ * If you set ContentType then you will need to associate the volume keys with the resulting stream.
+ * Otherwise the volume keys may not work correctly.
+ * This is done in Java with the following code block.
+ *
+ * <pre><code>if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ * AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usage)
+ * .setContentType(contentType).build();
+ * setVolumeControlStream(attributes.getVolumeControlStream());
+ * }
+ * </code></pre>
+ *
* Available since API level 28.
*
* @param builder reference provided by AAudio_createStreamBuilder()
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 6772201..58e4920 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -3035,6 +3035,7 @@
const sp<VolumeShaper::Configuration>& configuration,
const sp<VolumeShaper::Operation>& operation)
{
+ const int64_t beginNs = systemTime();
AutoMutex lock(mLock);
mVolumeHandler->setIdIfNecessary(configuration);
media::VolumeShaperConfiguration config;
@@ -3042,6 +3043,18 @@
media::VolumeShaperOperation op;
operation->writeToParcelable(&op);
VolumeShaper::Status status;
+
+ mediametrics::Defer defer([&] {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_APPLYVOLUMESHAPER)
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
+ .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
+ .set(AMEDIAMETRICS_PROP_TOSTRING, configuration->toString()
+ .append(" ")
+ .append(operation->toString()))
+ .record(); });
+
mAudioTrack->applyVolumeShaper(config, op, &status);
if (status == DEAD_OBJECT) {
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index cf3b43a..a707909 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -923,6 +923,11 @@
return statusTFromBinderStatus(mDelegate->setTracksInternalMute(tracksInternalMuted));
}
+status_t AudioFlingerClientAdapter::resetReferencesForTest() {
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mDelegate->resetReferencesForTest()));
+ return OK;
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// AudioFlingerServerAdapter
AudioFlingerServerAdapter::AudioFlingerServerAdapter(
@@ -1487,4 +1492,9 @@
return Status::fromStatusT(mDelegate->setTracksInternalMute(tracksInternalMute));
}
+Status AudioFlingerServerAdapter::resetReferencesForTest() {
+ RETURN_BINDER_IF_ERROR(mDelegate->resetReferencesForTest());
+ return Status::ok();
+}
+
} // namespace android
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index e213f08..79fcea8 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -1264,13 +1264,10 @@
nsec += 1000000000;
}
- if ((sec + 1) > ((time_t)(INT_MAX / mSamplingRate))) {
- mMaxSmp = sec * mSamplingRate;
- } else {
- // mSamplingRate is always > 1000
- sec = sec * 1000 + nsec / 1000000; // duration in milliseconds
- mMaxSmp = (unsigned int)(((int64_t)sec * mSamplingRate) / 1000);
- }
+ const uint64_t msec = static_cast<uint64_t>(sec) * 1000 + nsec / 1'000'000;
+ mMaxSmp = std::min(static_cast<uint64_t>(TONEGEN_INF - 1),
+ msec * mSamplingRate / 1000);
+
ALOGV("stopTone() forcing mMaxSmp to %d, total for far %" PRIu64, mMaxSmp,
mTotalSmp);
} else {
@@ -1638,14 +1635,11 @@
mpToneDesc = mpNewToneDesc;
- if (mDurationMs == -1) {
+ if (mDurationMs < 0) { // mDurationMs is signed, treat all neg numbers as INF.
mMaxSmp = TONEGEN_INF;
} else {
- if (mDurationMs > (int)(TONEGEN_INF / mSamplingRate)) {
- mMaxSmp = (mDurationMs / 1000) * mSamplingRate;
- } else {
- mMaxSmp = (mDurationMs * mSamplingRate) / 1000;
- }
+ mMaxSmp = std::min(static_cast<uint64_t>(TONEGEN_INF - 1),
+ static_cast<uint64_t>(mDurationMs) * mSamplingRate / 1000);
ALOGV("prepareWave, duration limited to %d ms", mDurationMs);
}
@@ -1676,7 +1670,8 @@
if (mpToneDesc->segments[0].duration == TONEGEN_INF) {
mNextSegSmp = TONEGEN_INF;
} else{
- mNextSegSmp = (mpToneDesc->segments[0].duration * mSamplingRate) / 1000;
+ mNextSegSmp = std::min(static_cast<uint64_t>(TONEGEN_INF - 1),
+ static_cast<uint64_t>(mpToneDesc->segments[0].duration) * mSamplingRate / 1000);
}
return true;
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
index e8fcf77..4f00f83 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
@@ -299,6 +299,12 @@
*/
void setTracksInternalMute(in TrackInternalMuteInfo[] tracksInternalMute);
+ /*
+ * Reset Circular references in AudioFlinger service.
+ * Test API
+ */
+ void resetReferencesForTest();
+
// When adding a new method, please review and update
// IAudioFlinger.h AudioFlingerServerAdapter::Delegate::TransactionCode
// AudioFlinger.cpp AudioFlinger::onTransactWrapper()
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 860a0bc..211fffa 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -392,6 +392,8 @@
virtual status_t setTracksInternalMute(
const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) = 0;
+
+ virtual status_t resetReferencesForTest() = 0;
};
/**
@@ -510,6 +512,7 @@
struct audio_port_v7 *mixPort) const override;
status_t setTracksInternalMute(
const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) override;
+ status_t resetReferencesForTest() override;
private:
const sp<media::IAudioFlingerService> mDelegate;
@@ -613,6 +616,8 @@
media::BnAudioFlingerService::TRANSACTION_getAudioPolicyConfig,
GET_AUDIO_MIX_PORT = media::BnAudioFlingerService::TRANSACTION_getAudioMixPort,
SET_TRACKS_INTERNAL_MUTE = media::BnAudioFlingerService::TRANSACTION_setTracksInternalMute,
+ RESET_REFERENCES_FOR_TEST =
+ media::BnAudioFlingerService::TRANSACTION_resetReferencesForTest,
};
protected:
@@ -751,6 +756,7 @@
media::AudioPortFw* _aidl_return) override;
Status setTracksInternalMute(
const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) override;
+ Status resetReferencesForTest() override;
private:
const sp<AudioFlingerServerAdapter::Delegate> mDelegate;
};
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
index daabdb7..e5373f3 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
@@ -65,9 +65,9 @@
{5, 3, -1, 3, 5}}}; /* Rock Preset */
static const std::vector<Equalizer::Preset> kEqPresets = {
- {0, "Normal"}, {1, "Classical"}, {2, "Dance"}, {3, "Flat"}, {4, "Folk"},
- {5, "Heavy Metal"}, {6, "Hip Hop"}, {7, "Jazz"}, {8, "Pop"}, {9, "Rock"}};
-
+ {-1, "Custom"}, {0, "Normal"}, {1, "Classical"}, {2, "Dance"},
+ {3, "Flat"}, {4, "Folk"}, {5, "Heavy Metal"}, {6, "Hip Hop"},
+ {7, "Jazz"}, {8, "Pop"}, {9, "Rock"}};
const std::vector<Range::EqualizerRange> kEqRanges = {
MAKE_RANGE(Equalizer, preset, 0, MAX_NUM_PRESETS - 1),
diff --git a/media/liberror/include/error/BinderResult.h b/media/liberror/include/error/BinderResult.h
new file mode 100644
index 0000000..1f1211c
--- /dev/null
+++ b/media/liberror/include/error/BinderResult.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <binder/Status.h>
+#include <error/expected_utils.h>
+#include <utils/Errors.h>
+
+namespace android {
+namespace error {
+
+/**
+ * A convenience short-hand for base::expected, where the error type is a binder::Status, for use
+ * when implementing binder services.
+ * Clients need to link against libbinder, since this library is header only.
+ */
+template <typename T>
+using BinderResult = base::expected<T, binder::Status>;
+
+inline base::unexpected<binder::Status> unexpectedExceptionCode(int32_t exceptionCode,
+ const char* s) {
+ return base::unexpected{binder::Status::fromExceptionCode(exceptionCode, s)};
+}
+
+inline base::unexpected<binder::Status> unexpectedServiceException(int32_t serviceSpecificCode,
+ const char* s) {
+ return base::unexpected{binder::Status::fromServiceSpecificError(serviceSpecificCode, s)};
+}
+
+} // namespace error
+} // namespace android
+
+inline std::string errorToString(const ::android::binder::Status& status) {
+ return std::string{status.toString8().c_str()};
+}
diff --git a/media/liberror/include/error/BinderStatusMatcher.h b/media/liberror/include/error/BinderStatusMatcher.h
new file mode 100644
index 0000000..11d9e65
--- /dev/null
+++ b/media/liberror/include/error/BinderStatusMatcher.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <ostream>
+
+#include <binder/Status.h>
+
+namespace android::error {
+
+class BinderStatusMatcher {
+ public:
+ using is_gtest_matcher = void;
+
+ explicit BinderStatusMatcher(binder::Status status) : status_(std::move(status)) {}
+
+ static BinderStatusMatcher hasException(binder::Status::Exception ex) {
+ return BinderStatusMatcher(binder::Status::fromExceptionCode(ex));
+ }
+
+ static BinderStatusMatcher isOk() { return BinderStatusMatcher(binder::Status::ok()); }
+
+ bool MatchAndExplain(const binder::Status& value,
+ ::testing::MatchResultListener* listener) const {
+ if (status_.exceptionCode() == value.exceptionCode() &&
+ status_.transactionError() == value.transactionError() &&
+ status_.serviceSpecificErrorCode() == value.serviceSpecificErrorCode()) {
+ return true;
+ }
+ *listener << "received binder status: " << value;
+ return false;
+ }
+
+ void DescribeTo(std::ostream* os) const { *os << "contains binder status " << status_; }
+
+ void DescribeNegationTo(std::ostream* os) const {
+ *os << "does not contain binder status " << status_;
+ }
+
+ private:
+ const binder::Status status_;
+};
+} // namespace android::error
diff --git a/media/liberror/include/error/ExpectedMatchers.h b/media/liberror/include/error/ExpectedMatchers.h
new file mode 100644
index 0000000..b81adbf
--- /dev/null
+++ b/media/liberror/include/error/ExpectedMatchers.h
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <ostream>
+#include <type_traits>
+
+namespace android::error {
+
+/**
+ * Example Usage:
+ * Given a function with signature
+ * Result<T, U> foo()
+ * Matchers can be used as follows:
+ * EXPECT_THAT(foo(), IsOkAnd(Eq(T{})));
+ * EXPECT_THAT(foo(), IsErrorAnd(Eq(U{})));
+ */
+template <typename ExpectedT>
+class IsOkAndImpl : public ::testing::MatcherInterface<ExpectedT> {
+ public:
+ using ValueT = std::remove_reference_t<ExpectedT>::value_type;
+
+ template <typename InnerMatcher>
+ explicit IsOkAndImpl(InnerMatcher innerMatcher)
+ : inner_matcher_(::testing::SafeMatcherCast<const ValueT&>(
+ std::forward<InnerMatcher>(innerMatcher))) {}
+
+ bool MatchAndExplain(ExpectedT val, ::testing::MatchResultListener* listener) const {
+ if (!val.has_value()) {
+ *listener << "which has error " << ::testing::PrintToString(val.error());
+ return false;
+ }
+ const auto res = inner_matcher_.MatchAndExplain(val.value(), listener);
+ if (!res) {
+ *listener << "which has value " << ::testing::PrintToString(val.value());
+ }
+ return res;
+ }
+
+ void DescribeTo(std::ostream* os) const {
+ *os << "contains expected value which ";
+ inner_matcher_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(std::ostream* os) const {
+ *os << "does not contain expected, or contains expected value which ";
+ inner_matcher_.DescribeNegationTo(os);
+ }
+
+ private:
+ ::testing::Matcher<const ValueT&> inner_matcher_;
+};
+
+template <typename InnerMatcher>
+class IsOkAnd {
+ public:
+ explicit IsOkAnd(InnerMatcher innerMatcher) : inner_matcher_(std::move(innerMatcher)) {}
+
+ template <typename T>
+ operator ::testing::Matcher<T>() const {
+ return ::testing::Matcher<T>{new IsOkAndImpl<const T&>(inner_matcher_)};
+ }
+
+ private:
+ InnerMatcher inner_matcher_;
+};
+
+template <typename ExpectedT>
+class IsErrorAndImpl : public ::testing::MatcherInterface<ExpectedT> {
+ public:
+ using ErrorT = typename std::remove_reference_t<ExpectedT>::error_type;
+
+ template <typename InnerMatcher>
+ explicit IsErrorAndImpl(InnerMatcher innerMatcher)
+ : inner_matcher_(::testing::SafeMatcherCast<const ErrorT&>(
+ std::forward<InnerMatcher>(innerMatcher))) {}
+
+ bool MatchAndExplain(ExpectedT val, ::testing::MatchResultListener* listener) const {
+ if (val.has_value()) {
+ *listener << "which has value " << ::testing::PrintToString(val.value());
+ return false;
+ }
+
+ const auto res = inner_matcher_.MatchAndExplain(val.error(), listener);
+ if (!res) {
+ *listener << "which has error " << ::testing::PrintToString(val.error());
+ }
+ return res;
+ }
+
+ void DescribeTo(std::ostream* os) const {
+ *os << "contains error value which ";
+ inner_matcher_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(std::ostream* os) const {
+ *os << "does not contain error value, or contains error value which ";
+ inner_matcher_.DescribeNegationTo(os);
+ }
+
+ private:
+ ::testing::Matcher<const ErrorT&> inner_matcher_;
+};
+
+template <typename InnerMatcher>
+class IsErrorAnd {
+ public:
+ explicit IsErrorAnd(InnerMatcher innerMatcher) : inner_matcher_(std::move(innerMatcher)) {}
+
+ template <typename T>
+ operator ::testing::Matcher<T>() const {
+ return ::testing::Matcher<T>{new IsErrorAndImpl<const T&>(inner_matcher_)};
+ }
+
+ private:
+ InnerMatcher inner_matcher_;
+};
+
+} // namespace android::error
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index 26aa375..e60a678 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -213,6 +213,7 @@
// format to transport packets.
// Raw byte streams are used if this
// is false.
+#define AMEDIAMETRICS_PROP_TOSTRING "toString" // string
#define AMEDIAMETRICS_PROP_TOTALINPUTBYTES "totalInputBytes" // int32 (MIDI)
#define AMEDIAMETRICS_PROP_TOTALOUTPUTBYTES "totalOutputBytes" // int32 (MIDI)
#define AMEDIAMETRICS_PROP_THREADID "threadId" // int32 value io handle
@@ -243,6 +244,7 @@
// Values are strings accepted for a given property.
// An event is a general description, which often is a function name.
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_APPLYVOLUMESHAPER "applyVolumeShaper"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP "beginAudioIntervalGroup"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CLOSE "close"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE "create"
diff --git a/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp b/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
index 652b1ee..15265bf 100644
--- a/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
+++ b/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
@@ -51,6 +51,69 @@
enum DataSourceType { HTTP, FD, STREAM, FILETYPE, SOCKET, kMaxValue = SOCKET };
+constexpr audio_flags_mask_t kAudioFlagsMasks[] = {AUDIO_FLAG_NONE,
+ AUDIO_FLAG_AUDIBILITY_ENFORCED,
+ AUDIO_FLAG_SECURE,
+ AUDIO_FLAG_SCO,
+ AUDIO_FLAG_BEACON,
+ AUDIO_FLAG_HW_AV_SYNC,
+ AUDIO_FLAG_HW_HOTWORD,
+ AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY,
+ AUDIO_FLAG_BYPASS_MUTE,
+ AUDIO_FLAG_LOW_LATENCY,
+ AUDIO_FLAG_DEEP_BUFFER,
+ AUDIO_FLAG_NO_MEDIA_PROJECTION,
+ AUDIO_FLAG_MUTE_HAPTIC,
+ AUDIO_FLAG_NO_SYSTEM_CAPTURE,
+ AUDIO_FLAG_CAPTURE_PRIVATE,
+ AUDIO_FLAG_CONTENT_SPATIALIZED,
+ AUDIO_FLAG_NEVER_SPATIALIZE,
+ AUDIO_FLAG_CALL_REDIRECTION};
+
+constexpr audio_content_type_t kAudioContentTypes[] = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_CONTENT_TYPE_SPEECH, AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_CONTENT_TYPE_MOVIE, AUDIO_CONTENT_TYPE_SONIFICATION, AUDIO_CONTENT_TYPE_ULTRASOUND};
+
+constexpr audio_source_t kAudioSources[] = {AUDIO_SOURCE_INVALID,
+ AUDIO_SOURCE_DEFAULT,
+ AUDIO_SOURCE_MIC,
+ AUDIO_SOURCE_VOICE_UPLINK,
+ AUDIO_SOURCE_VOICE_DOWNLINK,
+ AUDIO_SOURCE_VOICE_CALL,
+ AUDIO_SOURCE_CAMCORDER,
+ 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_ULTRASOUND};
+
+constexpr audio_usage_t kAudioUsages[] = {AUDIO_USAGE_UNKNOWN,
+ AUDIO_USAGE_MEDIA,
+ AUDIO_USAGE_VOICE_COMMUNICATION,
+ AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+ AUDIO_USAGE_ALARM,
+ AUDIO_USAGE_NOTIFICATION,
+ AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+ AUDIO_USAGE_NOTIFICATION_EVENT,
+ AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+ AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+ AUDIO_USAGE_GAME,
+ AUDIO_USAGE_VIRTUAL_SOURCE,
+ AUDIO_USAGE_ASSISTANT,
+ AUDIO_USAGE_CALL_ASSISTANT,
+ AUDIO_USAGE_EMERGENCY,
+ AUDIO_USAGE_SAFETY,
+ AUDIO_USAGE_VEHICLE_STATUS,
+ AUDIO_USAGE_ANNOUNCEMENT};
+
constexpr PixelFormat kPixelFormat[] = {
PIXEL_FORMAT_UNKNOWN, PIXEL_FORMAT_NONE, PIXEL_FORMAT_CUSTOM,
PIXEL_FORMAT_TRANSLUCENT, PIXEL_FORMAT_TRANSPARENT, PIXEL_FORMAT_OPAQUE,
@@ -354,7 +417,18 @@
[&]() { mMediaPlayer->attachAuxEffect(mFdp.ConsumeIntegral<int32_t>()); },
[&]() {
int32_t key = mFdp.PickValueInArray(kMediaParamKeys);
- request.writeInt32(mFdp.ConsumeIntegral<int32_t>());
+ request.writeInt32((audio_usage_t)mFdp.ConsumeIntegralInRange<int32_t>(
+ AUDIO_USAGE_UNKNOWN, AUDIO_USAGE_ANNOUNCEMENT) /* usage */);
+ request.writeInt32((audio_content_type_t)mFdp.ConsumeIntegralInRange<int32_t>(
+ AUDIO_CONTENT_TYPE_UNKNOWN,
+ AUDIO_CONTENT_TYPE_ULTRASOUND) /* content_type */);
+ request.writeInt32((audio_source_t)mFdp.ConsumeIntegralInRange<int32_t>(
+ AUDIO_SOURCE_INVALID, AUDIO_SOURCE_ULTRASOUND) /* source */);
+ request.writeInt32((audio_flags_mask_t)mFdp.ConsumeIntegralInRange<int32_t>(
+ AUDIO_FLAG_NONE, AUDIO_FLAG_CALL_REDIRECTION) /* flags */);
+ request.writeInt32(mFdp.ConsumeBool() /* hasFlattenedTag */);
+ request.writeString16(
+ String16((mFdp.ConsumeRandomLengthString()).c_str()) /* tags */);
request.setDataPosition(0);
mMediaPlayer->setParameter(key, request);
key = mFdp.PickValueInArray(kMediaParamKeys);
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 5b6848c..ac178aa 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -315,13 +315,10 @@
"libaudioclient_aidl_conversion",
"packagemanager_aidl-cpp",
"server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
"aconfig_mediacodec_flags_c_lib",
],
- defaults: [
- "aconfig_lib_cc_static_link.defaults",
- ],
-
static_libs: [
"android.media.codec-aconfig-cc",
"libstagefright_esds",
diff --git a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
index 9f46a74..b29429a 100644
--- a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
+++ b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
@@ -21,105 +21,256 @@
#include <media/stagefright/MPEG2TSWriter.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/OggWriter.h>
-
-#include "MediaMimeTypes.h"
-
#include <webm/WebmWriter.h>
namespace android {
-std::string genMimeType(FuzzedDataProvider *dataProvider) {
- uint8_t idx = dataProvider->ConsumeIntegralInRange<uint8_t>(0, kMimeTypes.size() - 1);
- return std::string(kMimeTypes[idx]);
-}
-sp<IMediaExtractor> genMediaExtractor(FuzzedDataProvider *dataProvider, std::string mimeType,
- uint16_t maxDataAmount) {
- uint32_t dataBlobSize = dataProvider->ConsumeIntegralInRange<uint16_t>(0, maxDataAmount);
- std::vector<uint8_t> data = dataProvider->ConsumeBytes<uint8_t>(dataBlobSize);
- // data:[<mediatype>][;base64],<data>
- std::string uri("data:");
- uri += mimeType;
- // Currently libstagefright only accepts base64 uris
- uri += ";base64,";
- android::AString out;
- android::encodeBase64(data.data(), data.size(), &out);
- uri += out.c_str();
-
- sp<DataSource> source =
- DataSourceFactory::getInstance()->CreateFromURI(NULL /* httpService */, uri.c_str());
-
- if (source == NULL) {
- return NULL;
- }
-
- return MediaExtractorFactory::Create(source);
-}
-
-sp<MediaSource> genMediaSource(FuzzedDataProvider *dataProvider, uint16_t maxMediaBlobSize) {
- std::string mime = genMimeType(dataProvider);
- sp<IMediaExtractor> extractor = genMediaExtractor(dataProvider, mime, maxMediaBlobSize);
-
- if (extractor == NULL) {
- return NULL;
- }
-
- for (size_t i = 0; i < extractor->countTracks(); ++i) {
- sp<MetaData> meta = extractor->getTrackMetaData(i);
-
- std::string trackMime = dataProvider->PickValueInArray(kTestedMimeTypes);
- if (!strcasecmp(mime.c_str(), trackMime.c_str())) {
- sp<IMediaSource> track = extractor->getTrack(i);
- if (track == NULL) {
- return NULL;
- }
- return new CallbackMediaSource(track);
- }
- }
-
- return NULL;
-}
-
-sp<MediaWriter> createWriter(int fd, StandardWriters writerType, sp<MetaData> fileMeta) {
+sp<MediaWriter> createWriter(int fd, StandardWriters writerType, sp<MetaData> writerMeta,
+ FuzzedDataProvider* fdp) {
sp<MediaWriter> writer;
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKeyRealTimeRecording, fdp->ConsumeBool());
+ }
+
switch (writerType) {
- case OGG:
- writer = new OggWriter(fd);
- fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_OGG);
- break;
case AAC:
- writer = new AACWriter(fd);
- fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADIF);
+ writer = sp<AACWriter>::make(fd);
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADIF);
+ }
break;
case AAC_ADTS:
- writer = new AACWriter(fd);
- fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADTS);
- break;
- case WEBM:
- writer = new WebmWriter(fd);
- fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_WEBM);
- break;
- case MPEG4:
- writer = new MPEG4Writer(fd);
- fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG_4);
+ writer = sp<AACWriter>::make(fd);
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADTS);
+ }
break;
case AMR_NB:
- writer = new AMRWriter(fd);
- fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_NB);
+ writer = sp<AMRWriter>::make(fd);
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_NB);
+ }
break;
case AMR_WB:
- writer = new AMRWriter(fd);
- fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_WB);
+ writer = sp<AMRWriter>::make(fd);
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_WB);
+ }
break;
case MPEG2TS:
- writer = new MPEG2TSWriter(fd);
- fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG2TS);
+ writer = sp<MPEG2TSWriter>::make(fd);
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG2TS);
+ }
break;
- default:
- return nullptr;
+ case MPEG4:
+ writer = sp<MPEG4Writer>::make(fd);
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG_4);
+ } else if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_HEIF);
+ } else if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_THREE_GPP);
+ }
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKey2ByteNalLength, fdp->ConsumeBool());
+ }
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKeyTimeScale,
+ fdp->ConsumeIntegralInRange<int32_t>(600, 96000));
+ }
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKey4BitTrackIds, fdp->ConsumeBool());
+ }
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt64(kKeyTrackTimeStatus, fdp->ConsumeIntegral<int64_t>());
+ }
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKeyRotation, fdp->ConsumeIntegralInRange<uint8_t>(0, 3) * 90);
+ }
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt64(kKeyTime, fdp->ConsumeIntegral<int64_t>());
+ }
+ break;
+ case OGG:
+ writer = sp<OggWriter>::make(fd);
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_OGG);
+ }
+ break;
+ case WEBM:
+ writer = sp<WebmWriter>::make(fd);
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_WEBM);
+ }
+
+ if (fdp->ConsumeBool()) {
+ writerMeta->setInt32(kKeyTimeScale,
+ fdp->ConsumeIntegralInRange<int32_t>(600, 96000));
+ }
+ break;
}
- if (writer != nullptr) {
- fileMeta->setInt32(kKeyRealTimeRecording, false);
- }
+
return writer;
}
+
+sp<FuzzSource> createSource(StandardWriters writerType, FuzzedDataProvider* fdp) {
+ sp<MetaData> meta = sp<MetaData>::make();
+
+ switch (writerType) {
+ case AAC:
+ case AAC_ADTS:
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+ meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegralInRange<uint8_t>(1, 7));
+ meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeyAACProfile, fdp->ConsumeIntegral<int32_t>());
+ }
+ break;
+ case AMR_NB:
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
+ meta->setInt32(kKeyChannelCount, 1);
+ meta->setInt32(kKeySampleRate, 8000);
+ break;
+ case AMR_WB:
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
+ meta->setInt32(kKeyChannelCount, 1);
+ meta->setInt32(kKeySampleRate, 16000);
+ break;
+ case MPEG2TS:
+ if (fdp->ConsumeBool()) {
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+ meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegral<int32_t>());
+ meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+ } else {
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+ // The +1s ensure a minimum height and width of 1.
+ meta->setInt32(kKeyWidth, fdp->ConsumeIntegral<uint16_t>() + 1);
+ meta->setInt32(kKeyHeight, fdp->ConsumeIntegral<uint16_t>() + 1);
+ }
+ break;
+ case MPEG4: {
+ auto mime = fdp->PickValueInArray<std::string>(kMpeg4MimeTypes);
+ meta->setCString(kKeyMIMEType, mime.c_str());
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeyBackgroundMode, fdp->ConsumeBool());
+ }
+
+ if (!strncasecmp(mime.c_str(), "audio/", 6)) {
+ meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegral<int32_t>());
+ meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+
+ } else {
+ // The +1s ensure a minimum height and width of 1.
+ meta->setInt32(kKeyWidth, fdp->ConsumeIntegral<uint16_t>() + 1);
+ meta->setInt32(kKeyHeight, fdp->ConsumeIntegral<uint16_t>() + 1);
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeyDisplayWidth, fdp->ConsumeIntegral<uint16_t>());
+ }
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeyDisplayHeight, fdp->ConsumeIntegral<uint16_t>());
+ }
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeyTileWidth, fdp->ConsumeIntegral<uint16_t>());
+ }
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeyTileHeight, fdp->ConsumeIntegral<uint16_t>());
+ }
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeyGridRows, fdp->ConsumeIntegral<uint8_t>());
+ }
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeyGridCols, fdp->ConsumeIntegral<uint8_t>());
+ }
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeyTemporalLayerCount, fdp->ConsumeIntegral<int32_t>());
+ }
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeySARWidth, fdp->ConsumeIntegral<uint16_t>());
+ }
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeySARHeight, fdp->ConsumeIntegral<uint16_t>());
+ }
+ }
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeyBitRate, fdp->ConsumeIntegral<int32_t>());
+ }
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeyMaxBitRate, fdp->ConsumeIntegral<int32_t>());
+ }
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeyTrackIsDefault, fdp->ConsumeBool());
+ }
+ break;
+ }
+ case OGG:
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_OPUS);
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegral<int32_t>());
+ }
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+ }
+ break;
+ case WEBM:
+ if (fdp->ConsumeBool()) {
+ if (fdp->ConsumeBool()) {
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VP8);
+ } else {
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VP9);
+ }
+
+ if (fdp->ConsumeBool()) {
+ // The +1s ensure a minimum height and width of 1.
+ meta->setInt32(kKeyWidth, fdp->ConsumeIntegral<uint16_t>() + 1);
+ meta->setInt32(kKeyHeight, fdp->ConsumeIntegral<uint16_t>() + 1);
+ }
+ } else {
+ if (fdp->ConsumeBool()) {
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
+ } else {
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_OPUS);
+ }
+
+ if (fdp->ConsumeBool()) {
+ meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegral<int32_t>());
+ }
+ meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+ }
+
+ break;
+ }
+
+ return sp<FuzzSource>::make(meta, fdp);
+}
} // namespace android
diff --git a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h
index 6856ac0..ad1218b 100644
--- a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h
+++ b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h
@@ -15,20 +15,52 @@
*/
#pragma once
-#include <datasource/DataSourceFactory.h>
+
#include <fuzzer/FuzzedDataProvider.h>
-#include <android/IMediaExtractor.h>
-#include <media/IMediaHTTPService.h>
-#include <media/mediarecorder.h>
-#include <media/stagefright/CallbackMediaSource.h>
+
+#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MediaWriter.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/foundation/base64.h>
-#include <utils/StrongPointer.h>
namespace android {
+class FuzzSource : public MediaSource {
+ public:
+ FuzzSource(sp<MetaData> meta, FuzzedDataProvider* fdp) : mMetaData(meta), mFdp(fdp) {}
+
+ status_t start(MetaData*) { return OK; }
+
+ virtual status_t stop() { return OK; }
+
+ status_t read(MediaBufferBase** buffer, const ReadOptions*) {
+ // Ensuring that mBuffer has at least two bytes to avoid check failure
+ // in MPEG2TSWriter::SourceInfo::onMessageReceived().
+ if (mFdp->remaining_bytes() > 2) {
+ auto size = mFdp->ConsumeIntegralInRange<uint8_t>(2, INT8_MAX);
+ mBuffer = mFdp->ConsumeBytes<uint8_t>(size);
+ MediaBufferBase* mbb = new MediaBuffer(mBuffer.data(), mBuffer.size());
+
+ size_t length = mFdp->ConsumeIntegralInRange<size_t>(2, mbb->size());
+ size_t offset = mFdp->ConsumeIntegralInRange<size_t>(0, mbb->size() - length);
+ mbb->set_range(offset, length);
+
+ mbb->meta_data().setInt32(kKeyIsEndOfStream, mFdp->ConsumeBool());
+ mbb->meta_data().setInt64(kKeyTime, mFdp->ConsumeIntegral<uint32_t>() / 2);
+ *buffer = mbb;
+
+ return OK;
+ }
+
+ return ERROR_END_OF_STREAM;
+ }
+
+ sp<MetaData> getFormat() { return mMetaData; }
+
+ private:
+ sp<MetaData> mMetaData = nullptr;
+ FuzzedDataProvider* mFdp = nullptr;
+ std::vector<uint8_t> mBuffer;
+};
+
enum StandardWriters {
OGG,
AAC,
@@ -42,54 +74,22 @@
kMaxValue = MPEG2TS,
};
-static std::string kTestedMimeTypes[] = {"audio/3gpp",
- "audio/amr-wb",
- "audio/vorbis",
- "audio/opus",
- "audio/mp4a-latm",
- "audio/mpeg",
- "audio/mpeg-L1",
- "audio/mpeg-L2",
- "audio/midi",
- "audio/qcelp",
- "audio/g711-alaw",
- "audio/g711-mlaw",
- "audio/flac",
- "audio/aac-adts",
- "audio/gsm",
- "audio/ac3",
- "audio/eac3",
- "audio/eac3-joc",
- "audio/ac4",
- "audio/scrambled",
- "audio/alac",
- "audio/x-ms-wma",
- "audio/x-adpcm-ms",
- "audio/x-adpcm-dvi-ima",
- "video/avc",
- "video/hevc",
- "video/mp4v-es",
- "video/3gpp",
- "video/x-vnd.on2.vp8",
- "video/x-vnd.on2.vp9",
- "video/av01",
- "video/mpeg2",
- "video/dolby-vision",
- "video/scrambled",
- "video/divx",
- "video/divx3",
- "video/xvid",
- "video/x-motion-jpeg",
- "text/3gpp-tt",
- "application/x-subrip",
- "text/vtt",
- "text/cea-608",
- "text/cea-708",
- "application/x-id3v4"};
+static const uint32_t kSampleRateTable[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000,
+};
+static const std::string kMpeg4MimeTypes[] = {
+ MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, MEDIA_MIMETYPE_IMAGE_AVIF,
-std::string genMimeType(FuzzedDataProvider *dataProvider);
-sp<IMediaExtractor> genMediaExtractor(FuzzedDataProvider *dataProvider, uint16_t dataAmount);
-sp<MediaSource> genMediaSource(FuzzedDataProvider *dataProvider, uint16_t maxMediaBlobSize);
+ MEDIA_MIMETYPE_VIDEO_AV1, MEDIA_MIMETYPE_VIDEO_AVC,
+ MEDIA_MIMETYPE_VIDEO_HEVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
+ MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
-sp<MediaWriter> createWriter(int32_t fd, StandardWriters writerType, sp<MetaData> fileMeta);
+ MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB,
+ MEDIA_MIMETYPE_AUDIO_AAC,
+};
+
+sp<MediaWriter> createWriter(int32_t fd, StandardWriters writerType, sp<MetaData> writerMeta,
+ FuzzedDataProvider* fdp);
+
+sp<FuzzSource> createSource(StandardWriters writerType, FuzzedDataProvider* fdp);
} // namespace android
diff --git a/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp b/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
index 97d1160..cd0a866 100644
--- a/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
+++ b/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
@@ -13,216 +13,49 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-// Authors: corbin.souffrant@leviathansecurity.com
-// dylan.katz@leviathansecurity.com
-
-#include <android-base/file.h>
-#include <android/content/AttributionSourceState.h>
-#include <ctype.h>
-#include <media/mediarecorder.h>
-#include <media/stagefright/MPEG4Writer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <stdlib.h>
-#include <utils/StrongPointer.h>
-#include <utils/Vector.h>
-
-#include <functional>
-#include <string>
#include "FuzzerMediaUtility.h"
-#include "fuzzer/FuzzedDataProvider.h"
-
-static constexpr uint16_t kMaxOperations = 5000;
-static constexpr uint8_t kMaxPackageNameLen = 50;
-// For other strings in mpeg we want a higher limit.
-static constexpr uint16_t kMaxMPEGStrLen = 1000;
-static constexpr uint16_t kMaxMediaBlobSize = 1000;
namespace android {
-using android::content::AttributionSourceState;
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
-std::string getFourCC(FuzzedDataProvider *fdp) {
- std::string fourCC = fdp->ConsumeRandomLengthString(4);
- // Replace any existing nulls
- for (size_t pos = 0; pos < fourCC.length(); pos++) {
- if (fourCC.at(pos) == '\0') {
- fourCC.replace(pos, 1, "a");
- }
+ // memfd_create() creates an anonymous file and returns a file
+ // descriptor that refers to it. MFD_ALLOW_SEALING allows sealing
+ // operations on this file.
+ int32_t fd = memfd_create("WriterFuzzer", MFD_ALLOW_SEALING);
+ if (fd == -1) {
+ ALOGE("memfd_create() failed: %s", strerror(errno));
+ return 0;
}
- // If our string is too short, fill the remainder with "a"s.
- while (fourCC.length() < 4) {
- fourCC += 'a';
- }
- return fourCC;
-}
+ StandardWriters writerType = fdp.ConsumeEnum<StandardWriters>();
+ sp<MetaData> writerMeta = sp<MetaData>::make();
-typedef std::vector<std::function<void(FuzzedDataProvider*,
- sp<MediaWriter>, sp<MetaData>, int tmpFileFd)>> OperationVec;
-typedef std::vector<std::function<void(FuzzedDataProvider*, MPEG4Writer*)>> MPEG4OperationVec;
-static const OperationVec operations = {
- [](FuzzedDataProvider*, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
- mediaWriter->pause();
- },
- [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int tmpFd) {
- bool valid_fd = dataProvider->ConsumeBool();
- int fd = -1;
- if (valid_fd) {
- fd = tmpFd;
- }
- // Args don't seem to be used
- Vector<String16> args;
- mediaWriter->dump(fd, args);
- },
- [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int tmpFd) {
- bool valid_fd = dataProvider->ConsumeBool();
- int fd = -1;
- if (valid_fd) {
- fd = tmpFd;
- }
- mediaWriter->setNextFd(fd);
- },
- [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
- mediaWriter->setCaptureRate(dataProvider->ConsumeFloatingPoint<float>());
- },
- [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
- mediaWriter->setMaxFileDuration(dataProvider->ConsumeIntegral<int64_t>());
- },
- [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
- mediaWriter->setStartTimeOffsetMs(dataProvider->ConsumeIntegral<int>());
-
- // Likely won't do much, but might as well as do a quick check
- // while we're here.
- mediaWriter->getStartTimeOffsetMs();
- },
- [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
- mediaWriter->setMaxFileDuration(dataProvider->ConsumeIntegral<int64_t>());
- },
- [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
- mediaWriter->setMaxFileDuration(dataProvider->ConsumeIntegral<int64_t>());
- },
-};
-
-static const MPEG4OperationVec mpeg4Operations = {
- [](FuzzedDataProvider*, MPEG4Writer *mediaWriter) { mediaWriter->notifyApproachingLimit(); },
- // Lower level write methods.
- // High-level startBox/endBox/etc are all called elsewhere,
- [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
- uint8_t val = dataProvider->ConsumeIntegral<uint8_t>();
- mediaWriter->writeInt8(val);
- },
- [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
- uint16_t val = dataProvider->ConsumeIntegral<uint16_t>();
- mediaWriter->writeInt16(val);
- },
- [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
- uint32_t val = dataProvider->ConsumeIntegral<uint32_t>();
- mediaWriter->writeInt32(val);
- },
- [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
- uint64_t val = dataProvider->ConsumeIntegral<uint64_t>();
- mediaWriter->writeInt64(val);
- },
- [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
- std::string strVal = dataProvider->ConsumeRandomLengthString(kMaxMPEGStrLen);
- mediaWriter->writeCString(strVal.c_str());
- },
- [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
- std::string fourCC = getFourCC(dataProvider);
- mediaWriter->writeFourcc(fourCC.c_str());
- },
-
- // Misc setters
- [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
- uint32_t layers = dataProvider->ConsumeIntegral<uint32_t>();
- mediaWriter->setTemporalLayerCount(layers);
- },
- [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
- uint32_t duration = dataProvider->ConsumeIntegral<uint32_t>();
- mediaWriter->setInterleaveDuration(duration);
- },
- [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
- int lat = dataProvider->ConsumeIntegral<int>();
- int lon = dataProvider->ConsumeIntegral<int>();
- mediaWriter->setGeoData(lat, lon);
- },
-};
-
-// Not all writers can always add new sources, so we'll need additional checks.
-void addSource(FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter) {
- sp<MediaSource> mediaSource = genMediaSource(dataProvider, kMaxMediaBlobSize);
- if (mediaSource == NULL) {
- // There's a static check preventing NULLs in addSource.
- return;
- }
- mediaWriter->addSource(mediaSource);
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
- FuzzedDataProvider dataProvider(data, size);
- TemporaryFile tf;
- sp<MetaData> fileMeta = new MetaData;
- StandardWriters writerType = dataProvider.ConsumeEnum<StandardWriters>();
- sp<MediaWriter> writer = createWriter(tf.fd, writerType, fileMeta);
-
- AttributionSourceState attributionSource;
- attributionSource.packageName = dataProvider.ConsumeRandomLengthString(kMaxPackageNameLen);
- attributionSource.uid = dataProvider.ConsumeIntegral<int32_t>();
- attributionSource.pid = dataProvider.ConsumeIntegral<int32_t>();
- attributionSource.token = sp<BBinder>::make();
- sp<MediaRecorder> mr = new MediaRecorder(attributionSource);
- writer->setListener(mr);
-
- uint8_t baseOpLen = operations.size();
- uint8_t totalLen = baseOpLen;
- uint8_t maxSources;
- // Different writers support different amounts of sources.
- switch (writerType) {
- case StandardWriters::AAC:
- case StandardWriters::AAC_ADTS:
- case StandardWriters::AMR_NB:
- case StandardWriters::AMR_WB:
- case StandardWriters::OGG:
- maxSources = 1;
- break;
- case StandardWriters::WEBM:
- maxSources = 2;
- break;
- default:
- maxSources = UINT8_MAX;
- break;
- }
- // Initialize some number of sources and add them to our writer.
- uint8_t sourceCount = dataProvider.ConsumeIntegralInRange<uint8_t>(0, maxSources);
- for (uint8_t i = 0; i < sourceCount; i++) {
- addSource(&dataProvider, writer);
+ sp<MediaWriter> writer = createWriter(fd, writerType, writerMeta, &fdp);
+ if (writer == nullptr) {
+ close(fd);
+ return 0;
}
- // Increase our range if additional operations are implemented.
- // Currently only MPEG4 has additiona public operations on their writer.
- if (writerType == StandardWriters::MPEG4) {
- totalLen += mpeg4Operations.size();
+ if (writerType == StandardWriters::WEBM) {
+ // This range is set to avoid CHECK failure in WEBMWriter::reset() -> EbmlVoid::EBmlVoid().
+ writer->setMaxFileSize(fdp.ConsumeIntegralInRange<int64_t>(5 * 1024 * 1024, INT64_MAX));
+ } else {
+ writer->setMaxFileSize(fdp.ConsumeIntegral<int64_t>());
}
+ writer->setMaxFileDuration(fdp.ConsumeIntegral<int64_t>());
+ writer->setCaptureRate(fdp.ConsumeFloatingPoint<float>());
- // Many operations require the writer to be started.
- writer->start(fileMeta.get());
- for (size_t ops_run = 0; dataProvider.remaining_bytes() > 0 && ops_run < kMaxOperations - 1;
- ops_run++) {
- uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, totalLen - 1);
- if (op < baseOpLen) {
- operations[op](&dataProvider, writer, fileMeta, tf.fd);
- } else if (writerType == StandardWriters::MPEG4) {
- mpeg4Operations[op - baseOpLen](&dataProvider, (MPEG4Writer*)writer.get());
- } else {
- // Here just in case, will error out.
- operations[op](&dataProvider, writer, fileMeta, tf.fd);
- }
- }
+ sp<MediaSource> source = createSource(writerType, &fdp);
+ writer->addSource(source);
+ writer->start(writerMeta.get());
+ writer->pause();
writer->stop();
- writer.clear();
- writer = nullptr;
+ close(fd);
+
return 0;
}
} // namespace android
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index c1d1a63..09edf68 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -193,6 +193,7 @@
BINDER_METHOD_ENTRY(getSoundDoseInterface) \
BINDER_METHOD_ENTRY(getAudioPolicyConfig) \
BINDER_METHOD_ENTRY(getAudioMixPort) \
+BINDER_METHOD_ENTRY(resetReferencesForTest) \
// singleton for Binder Method Statistics for IAudioFlinger
static auto& getIAudioFlingerStatistics() {
@@ -466,6 +467,8 @@
sMediaLogService->unregisterWriter(iMemory);
}
}
+ mMediaLogNotifier->requestExit();
+ mPatchCommandThread->exit();
}
//static
@@ -4986,6 +4989,13 @@
return NO_ERROR;
}
+status_t AudioFlinger::resetReferencesForTest() {
+ mDeviceEffectManager.clear();
+ mPatchPanel.clear();
+ mMelReporter->resetReferencesForTest();
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
status_t AudioFlinger::onTransactWrapper(TransactionCode code,
@@ -5021,6 +5031,7 @@
case TransactionCode::GET_AUDIO_POLICY_CONFIG:
case TransactionCode::GET_AUDIO_MIX_PORT:
case TransactionCode::SET_TRACKS_INTERNAL_MUTE:
+ case TransactionCode::RESET_REFERENCES_FOR_TEST:
ALOGW("%s: transaction %d received from PID %d",
__func__, static_cast<int>(code), IPCThreadState::self()->getCallingPid());
// return status only for non void methods
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 143a766..501aed1 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -62,6 +62,8 @@
public:
static void instantiate() ANDROID_API;
+ status_t resetReferencesForTest();
+
private:
// ---- begin IAudioFlinger interface
diff --git a/services/audioflinger/MelReporter.cpp b/services/audioflinger/MelReporter.cpp
index 1d38306..57f4ff6 100644
--- a/services/audioflinger/MelReporter.cpp
+++ b/services/audioflinger/MelReporter.cpp
@@ -117,6 +117,11 @@
}
}
+void MelReporter::resetReferencesForTest() {
+ mAfMelReporterCallback.clear();
+ mSoundDoseManager->resetReferencesForTest();
+}
+
void MelReporter::onCreateAudioPatch(audio_patch_handle_t handle,
const IAfPatchPanel::Patch& patch) {
if (!mSoundDoseManager->isCsdEnabled()) {
diff --git a/services/audioflinger/MelReporter.h b/services/audioflinger/MelReporter.h
index 0aeb225..8b062f3 100644
--- a/services/audioflinger/MelReporter.h
+++ b/services/audioflinger/MelReporter.h
@@ -103,6 +103,8 @@
const std::vector<playback_track_metadata_v7_t>& metadataVec)
EXCLUDES_AudioFlinger_Mutex;
+ void resetReferencesForTest();
+
private:
struct ActiveMelPatch {
audio_io_handle_t streamHandle{AUDIO_IO_HANDLE_NONE};
@@ -131,7 +133,7 @@
bool useHalSoundDoseInterface_l() REQUIRES(mutex());
- const sp<IAfMelReporterCallback> mAfMelReporterCallback;
+ sp<IAfMelReporterCallback> mAfMelReporterCallback;
const sp<IAfPatchPanel> mAfPatchPanel;
/* const */ sp<SoundDoseManager> mSoundDoseManager; // set onFirstRef
diff --git a/services/audioflinger/sounddose/SoundDoseManager.cpp b/services/audioflinger/sounddose/SoundDoseManager.cpp
index 3b764d1..cdc36dc 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.cpp
+++ b/services/audioflinger/sounddose/SoundDoseManager.cpp
@@ -753,6 +753,10 @@
}
}
+void SoundDoseManager::resetReferencesForTest() {
+ mMelReporterCallback.clear();
+}
+
sp<media::ISoundDose> SoundDoseManager::getSoundDoseInterface(
const sp<media::ISoundDoseCallback>& callback) {
ALOGV("%s: Register ISoundDoseCallback", __func__);
diff --git a/services/audioflinger/sounddose/SoundDoseManager.h b/services/audioflinger/sounddose/SoundDoseManager.h
index 52a3fd6..8363d9b 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.h
+++ b/services/audioflinger/sounddose/SoundDoseManager.h
@@ -157,6 +157,8 @@
void onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const override;
+ void resetReferencesForTest();
+
private:
class SoundDose : public media::BnSoundDose,
public IBinder::DeathRecipient {
@@ -229,7 +231,7 @@
mutable std::mutex mLock;
- const sp<IMelReporterCallback> mMelReporterCallback;
+ sp<IMelReporterCallback> mMelReporterCallback;
// no need for lock since MelAggregator is thread-safe
const sp<audio_utils::MelAggregator> mMelAggregator;
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
index ca78ce7..3f9ae19 100644
--- a/services/audiopolicy/engine/config/src/EngineConfig.cpp
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -22,6 +22,7 @@
#include <string>
#include <string>
#include <vector>
+#include <unordered_map>
#define LOG_TAG "APM::AudioPolicyEngine/Config"
//#define LOG_NDEBUG 0
@@ -51,6 +52,27 @@
namespace {
+ConversionResult<std::string> aidl2legacy_AudioHalProductStrategy_ProductStrategyType(int id) {
+ using AudioProductStrategyType = media::audio::common::AudioProductStrategyType;
+
+#define STRATEGY_ENTRY(name) {static_cast<int>(AudioProductStrategyType::name), "STRATEGY_" #name}
+ static const std::unordered_map<int, std::string> productStrategyMap = {STRATEGY_ENTRY(MEDIA),
+ STRATEGY_ENTRY(PHONE),
+ STRATEGY_ENTRY(SONIFICATION),
+ STRATEGY_ENTRY(SONIFICATION_RESPECTFUL),
+ STRATEGY_ENTRY(DTMF),
+ STRATEGY_ENTRY(ENFORCED_AUDIBLE),
+ STRATEGY_ENTRY(TRANSMITTED_THROUGH_SPEAKER),
+ STRATEGY_ENTRY(ACCESSIBILITY)};
+#undef STRATEGY_ENTRY
+
+ auto it = productStrategyMap.find(id);
+ if (it == productStrategyMap.end()) {
+ return base::unexpected(BAD_VALUE);
+ }
+ return it->second;
+}
+
ConversionResult<AttributesGroup> aidl2legacy_AudioHalAttributeGroup_AttributesGroup(
const media::audio::common::AudioHalAttributesGroup& aidl) {
AttributesGroup legacy;
@@ -65,7 +87,8 @@
ConversionResult<ProductStrategy> aidl2legacy_AudioHalProductStrategy_ProductStrategy(
const media::audio::common::AudioHalProductStrategy& aidl) {
ProductStrategy legacy;
- legacy.name = "strategy_" + std::to_string(aidl.id);
+ legacy.name = VALUE_OR_RETURN(
+ aidl2legacy_AudioHalProductStrategy_ProductStrategyType(aidl.id));
legacy.attributesGroups = VALUE_OR_RETURN(convertContainer<AttributesGroups>(
aidl.attributesGroups,
aidl2legacy_AudioHalAttributeGroup_AttributesGroup));
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 2a99fd8..6a94c81 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -8245,7 +8245,7 @@
if (deviceTypes.empty()) {
deviceTypes = outputDesc->devices().types();
index = curves.getVolumeIndex(deviceTypes);
- ALOGD("%s if deviceTypes is change from none to device %s, need get index %d",
+ ALOGV("%s if deviceTypes is change from none to device %s, need get index %d",
__func__, dumpDeviceTypes(deviceTypes).c_str(), index);
}
diff --git a/services/audiopolicy/permission/NativePermissionController.cpp b/services/audiopolicy/permission/NativePermissionController.cpp
index 9fcf22d..8659f2c 100644
--- a/services/audiopolicy/permission/NativePermissionController.cpp
+++ b/services/audiopolicy/permission/NativePermissionController.cpp
@@ -24,9 +24,9 @@
#include <cutils/android_filesystem_config.h>
#include <utils/Errors.h>
-using ::android::base::unexpected;
using ::android::binder::Status;
-using ::android::error::Result;
+using ::android::error::BinderResult;
+using ::android::error::unexpectedExceptionCode;
namespace com::android::media::permission {
static std::optional<std::string> getFixedPackageName(uid_t uid) {
@@ -103,23 +103,31 @@
// -- End Binder methods
-Result<std::vector<std::string>> NativePermissionController::getPackagesForUid(uid_t uid) const {
+BinderResult<std::vector<std::string>> NativePermissionController::getPackagesForUid(
+ uid_t uid) const {
uid = uid % AID_USER_OFFSET;
const auto fixed_package_opt = getFixedPackageName(uid);
if (fixed_package_opt.has_value()) {
- return Result<std::vector<std::string>>{std::in_place_t{}, {fixed_package_opt.value()}};
+ return BinderResult<std::vector<std::string>>{std::in_place_t{},
+ {fixed_package_opt.value()}};
}
std::lock_guard l{m_};
- if (!is_package_populated_) return unexpected{::android::NO_INIT};
+ if (!is_package_populated_) {
+ return unexpectedExceptionCode(
+ Status::EX_ILLEGAL_STATE,
+ "NPC::getPackagesForUid: controller never populated by system_server");
+ }
const auto cursor = package_map_.find(uid);
if (cursor != package_map_.end()) {
return cursor->second;
} else {
- return unexpected{::android::BAD_VALUE};
+ return unexpectedExceptionCode(
+ Status::EX_ILLEGAL_ARGUMENT,
+ ("NPC::getPackagesForUid: uid not found: " + std::to_string(uid)).c_str());
}
}
-Result<bool> NativePermissionController::validateUidPackagePair(
+BinderResult<bool> NativePermissionController::validateUidPackagePair(
uid_t uid, const std::string& packageName) const {
uid = uid % AID_USER_OFFSET;
const auto fixed_package_opt = getFixedPackageName(uid);
@@ -127,20 +135,27 @@
return packageName == fixed_package_opt.value();
}
std::lock_guard l{m_};
- if (!is_package_populated_) return unexpected{::android::NO_INIT};
+ if (!is_package_populated_) {
+ return unexpectedExceptionCode(
+ Status::EX_ILLEGAL_STATE,
+ "NPC::validatedUidPackagePair: controller never populated by system_server");
+ }
const auto cursor = package_map_.find(uid);
return (cursor != package_map_.end()) &&
(std::find(cursor->second.begin(), cursor->second.end(), packageName) !=
cursor->second.end());
}
-Result<bool> NativePermissionController::checkPermission(PermissionEnum perm, uid_t uid) const {
+BinderResult<bool> NativePermissionController::checkPermission(PermissionEnum perm,
+ uid_t uid) const {
std::lock_guard l{m_};
const auto& uids = permission_map_[static_cast<size_t>(perm)];
if (!uids.empty()) {
return std::binary_search(uids.begin(), uids.end(), uid);
} else {
- return unexpected{::android::NO_INIT};
+ return unexpectedExceptionCode(
+ Status::EX_ILLEGAL_STATE,
+ "NPC::checkPermission: controller never populated by system_server");
}
}
diff --git a/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp b/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp
index 2c32289..f313422 100644
--- a/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp
+++ b/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp
@@ -20,31 +20,39 @@
#include <error/expected_utils.h>
#include <utils/Log.h>
+using ::android::binder::Status;
+using ::android::error::BinderResult;
+using ::android::error::unexpectedExceptionCode;
+
namespace com::android::media::permission {
-using ::android::base::unexpected;
-
-Result<ValidatedAttributionSourceState> ValidatedAttributionSourceState::createFromBinderContext(
- AttributionSourceState attr, const IPermissionProvider& provider) {
+BinderResult<ValidatedAttributionSourceState>
+ValidatedAttributionSourceState::createFromBinderContext(AttributionSourceState attr,
+ const IPermissionProvider& provider) {
attr.pid = ::android::IPCThreadState::self()->getCallingPid();
attr.uid = ::android::IPCThreadState::self()->getCallingUid();
return createFromTrustedUidNoPackage(std::move(attr), provider);
}
-Result<ValidatedAttributionSourceState>
+BinderResult<ValidatedAttributionSourceState>
ValidatedAttributionSourceState::createFromTrustedUidNoPackage(
AttributionSourceState attr, const IPermissionProvider& provider) {
if (attr.packageName.has_value() && attr.packageName->size() != 0) {
if (VALUE_OR_RETURN(provider.validateUidPackagePair(attr.uid, attr.packageName.value()))) {
return ValidatedAttributionSourceState{std::move(attr)};
} else {
- return unexpected{::android::PERMISSION_DENIED};
+ return unexpectedExceptionCode(Status::EX_SECURITY,
+ attr.toString()
+ .insert(0, ": invalid attr ")
+ .insert(0, __PRETTY_FUNCTION__)
+ .c_str());
}
} else {
// For APIs which don't appropriately pass attribution sources or packages, we need
// to populate the package name with our best guess.
const auto packageNames = VALUE_OR_RETURN(provider.getPackagesForUid(attr.uid));
- LOG_ALWAYS_FATAL_IF(packageNames.empty());
+ LOG_ALWAYS_FATAL_IF(packageNames.empty(), "%s BUG: empty package list from controller",
+ __PRETTY_FUNCTION__);
attr.packageName = std::move(packageNames[0]);
return ValidatedAttributionSourceState{std::move(attr)};
}
diff --git a/services/audiopolicy/permission/include/media/IPermissionProvider.h b/services/audiopolicy/permission/include/media/IPermissionProvider.h
index 27a61ea..8d90543 100644
--- a/services/audiopolicy/permission/include/media/IPermissionProvider.h
+++ b/services/audiopolicy/permission/include/media/IPermissionProvider.h
@@ -22,7 +22,7 @@
#include <vector>
#include <com/android/media/permission/PermissionEnum.h>
-#include <error/Result.h>
+#include <error/BinderResult.h>
namespace com::android::media::permission {
@@ -31,19 +31,20 @@
// Get all package names which run under a certain app-id. Returns non-empty.
// Not user specific, since packages are across users. Special app-ids (system,
// shell, etc.) are handled. Fails if the provider does not know about the
- // app-id.
- virtual ::android::error::Result<std::vector<std::string>> getPackagesForUid(
+ // app-id or if the provider has not been initialized.
+ virtual ::android::error::BinderResult<std::vector<std::string>> getPackagesForUid(
uid_t uid) const = 0;
// True iff the provided package name runs under the app-id of uid.
// Special app-ids (system, shell, etc.) are handled.
- // Fails if the provider does not know about the app-id.
- virtual ::android::error::Result<bool> validateUidPackagePair(
+ // Fails if the provider does not know about the app-id or if the provider has not been
+ // initialized.
+ virtual ::android::error::BinderResult<bool> validateUidPackagePair(
uid_t uid, const std::string& packageName) const = 0;
// True iff the uid holds the permission (user aware).
// Fails with NO_INIT if cache hasn't been populated.
- virtual ::android::error::Result<bool> checkPermission(PermissionEnum permission,
- uid_t uid) const = 0;
+ virtual ::android::error::BinderResult<bool> checkPermission(PermissionEnum permission,
+ uid_t uid) const = 0;
virtual ~IPermissionProvider() = default;
};
} // namespace com::android::media::permission
diff --git a/services/audiopolicy/permission/include/media/NativePermissionController.h b/services/audiopolicy/permission/include/media/NativePermissionController.h
index d464023..a81c7a2 100644
--- a/services/audiopolicy/permission/include/media/NativePermissionController.h
+++ b/services/audiopolicy/permission/include/media/NativePermissionController.h
@@ -24,6 +24,7 @@
#include <android-base/thread_annotations.h>
#include <com/android/media/permission/BnNativePermissionController.h>
+#include <error/BinderResult.h>
namespace com::android::media::permission {
@@ -36,11 +37,12 @@
Status populatePermissionState(PermissionEnum permission, const std::vector<int>& uids) final;
// end binder methods
- ::android::error::Result<std::vector<std::string>> getPackagesForUid(uid_t uid) const final;
- ::android::error::Result<bool> validateUidPackagePair(
+ ::android::error::BinderResult<std::vector<std::string>> getPackagesForUid(
+ uid_t uid) const final;
+ ::android::error::BinderResult<bool> validateUidPackagePair(
uid_t uid, const std::string& packageName) const final;
- ::android::error::Result<bool> checkPermission(PermissionEnum permission,
- uid_t uid) const final;
+ ::android::error::BinderResult<bool> checkPermission(PermissionEnum permission,
+ uid_t uid) const final;
private:
mutable std::mutex m_;
diff --git a/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h b/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h
index 8d9da05..46f7d0a 100644
--- a/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h
+++ b/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h
@@ -17,22 +17,22 @@
#pragma once
#include <android/content/AttributionSourceState.h>
-#include <error/Result.h>
+#include <error/BinderResult.h>
#include "IPermissionProvider.h"
namespace com::android::media::permission {
using ::android::content::AttributionSourceState;
-using ::android::error::Result;
class ValidatedAttributionSourceState {
public:
/**
* Validates an attribution source from within the context of a binder transaction.
- * Overwrites the uid/pid and validates the packageName
+ * Overwrites the uid/pid and validates the packageName.
+ * Returns EX_SECURITY on package validation fail.
*/
- static Result<ValidatedAttributionSourceState> createFromBinderContext(
+ static ::android::error::BinderResult<ValidatedAttributionSourceState> createFromBinderContext(
AttributionSourceState attr, const IPermissionProvider& provider);
/**
@@ -47,9 +47,10 @@
* Create a ValidatedAttribubtionSourceState in cases where the uid/pid is trusted, but the
* packages have not been validated. Proper use of the previous two methods should avoid the
* necessity of this, but it is useful for migration purposes as well as testing this class.
+ * Returns EX_SECURITY on package validation fail.
*/
- static Result<ValidatedAttributionSourceState> createFromTrustedUidNoPackage(
- AttributionSourceState attr, const IPermissionProvider& provider);
+ static ::android::error::BinderResult<ValidatedAttributionSourceState>
+ createFromTrustedUidNoPackage(AttributionSourceState attr, const IPermissionProvider& provider);
operator AttributionSourceState() const { return state_; }
diff --git a/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp b/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp
index 3f6b787..f2423c1 100644
--- a/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp
+++ b/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp
@@ -19,14 +19,22 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <android-base/expected.h>
+#include <error/BinderStatusMatcher.h>
+#include <error/ExpectedMatchers.h>
-using ::android::base::unexpected;
-using ::android::binder::Status;
+using android::binder::Status::EX_ILLEGAL_ARGUMENT;
+using android::binder::Status::EX_ILLEGAL_STATE;
+using android::error::BinderStatusMatcher;
+using android::error::IsErrorAnd;
+using android::error::IsOkAnd;
using com::android::media::permission::NativePermissionController;
using com::android::media::permission::PermissionEnum;
using com::android::media::permission::UidPackageState;
+using ::testing::ElementsAre;
+using ::testing::IsFalse;
+using ::testing::IsTrue;
+
class NativePermissionControllerTest : public ::testing::Test {
protected:
android::sp<NativePermissionController> holder_ =
@@ -40,50 +48,37 @@
return out;
}
-static std::vector<std::string> makeVector(const char* one) {
- return {one};
-}
-
-static std::vector<std::string> makeVector(const char* one, const char* two) {
- return {one, two};
-}
-
-#define UNWRAP_EQ(expr, desired_expr) \
- do { \
- auto tmp_ = (expr); \
- EXPECT_TRUE(tmp_.has_value()); \
- if (tmp_.has_value()) EXPECT_EQ(*tmp_, desired_expr); \
- } while (0)
-
// --- Tests for non-populated ----
TEST_F(NativePermissionControllerTest, getPackagesForUid_NotPopulated) {
// Verify errors are returned
- EXPECT_EQ(controller_.getPackagesForUid(10000), unexpected{android::NO_INIT});
- EXPECT_EQ(controller_.getPackagesForUid(10001), unexpected{android::NO_INIT});
+ EXPECT_THAT(controller_.getPackagesForUid(10000),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
+ EXPECT_THAT(controller_.getPackagesForUid(10001),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
// fixed uids should work
- UNWRAP_EQ(controller_.getPackagesForUid(1000), makeVector("system"));
+ EXPECT_THAT(controller_.getPackagesForUid(1000), IsOkAnd(ElementsAre(std::string{"system"})));
}
TEST_F(NativePermissionControllerTest, validateUidPackagePair_NotPopulated) {
// Verify errors are returned
- EXPECT_EQ(controller_.validateUidPackagePair(10000, "com.package"),
- unexpected{android::NO_INIT});
+ EXPECT_THAT(controller_.validateUidPackagePair(10000, "com.package"),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
// fixed uids should work
- UNWRAP_EQ(controller_.validateUidPackagePair(1000, "system"), true);
+ EXPECT_THAT(controller_.validateUidPackagePair(1000, "system"), IsOkAnd(IsTrue()));
}
+
// --- Tests for populatePackagesForUids ----
TEST_F(NativePermissionControllerTest, populatePackages_EmptyInput) {
std::vector<UidPackageState> input;
// succeeds
- EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
// Verify unknown uid behavior
- const auto res1 = controller_.getPackagesForUid(10000);
- ASSERT_FALSE(res1.has_value());
- EXPECT_EQ(res1.error(), ::android::BAD_VALUE);
+ EXPECT_THAT(controller_.getPackagesForUid(10000),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT)));
}
TEST_F(NativePermissionControllerTest, populatePackages_ValidInput) {
@@ -92,11 +87,11 @@
createState(10001, {"com.example2.app1"}),
};
- EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
- UNWRAP_EQ(controller_.getPackagesForUid(10000),
- makeVector("com.example.app1", "com.example.app2"));
- UNWRAP_EQ(controller_.getPackagesForUid(10001), makeVector("com.example2.app1"));
+ EXPECT_THAT(controller_.getPackagesForUid(10000),
+ IsOkAnd(ElementsAre("com.example.app1", "com.example.app2")));
+ EXPECT_THAT(controller_.getPackagesForUid(10001), IsOkAnd(ElementsAre("com.example2.app1")));
}
// --- Tests for updatePackagesForUid ---
@@ -107,14 +102,14 @@
};
UidPackageState newState = createState(12000, {"com.example.other"});
- EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
- EXPECT_TRUE(controller_.updatePackagesForUid(newState).isOk());
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
+ EXPECT_THAT(controller_.updatePackagesForUid(newState), BinderStatusMatcher::isOk());
// Verify the results: only the updated package should be changed
- UNWRAP_EQ(controller_.getPackagesForUid(10000),
- makeVector("com.example.app1", "com.example.app2"));
- UNWRAP_EQ(controller_.getPackagesForUid(10001), makeVector("com.example2.app1"));
- UNWRAP_EQ(controller_.getPackagesForUid(12000), makeVector("com.example.other"));
+ EXPECT_THAT(controller_.getPackagesForUid(10000),
+ IsOkAnd(ElementsAre("com.example.app1", "com.example.app2")));
+ EXPECT_THAT(controller_.getPackagesForUid(10001), IsOkAnd(ElementsAre("com.example2.app1")));
+ EXPECT_THAT(controller_.getPackagesForUid(12000), IsOkAnd(ElementsAre("com.example.other")));
}
TEST_F(NativePermissionControllerTest, updatePackages_ExistingUid) {
@@ -123,14 +118,14 @@
createState(10001, {"com.example2.app1"}),
};
- EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
// Update packages for existing uid
UidPackageState newState = createState(10000, {"com.example.other", "com.example.new"});
- EXPECT_TRUE(controller_.updatePackagesForUid(newState).isOk());
+ EXPECT_THAT(controller_.updatePackagesForUid(newState), BinderStatusMatcher::isOk());
// Verify update
- UNWRAP_EQ(controller_.getPackagesForUid(10000),
- makeVector("com.example.other", "com.example.new"));
+ EXPECT_THAT(controller_.getPackagesForUid(10000),
+ IsOkAnd(ElementsAre("com.example.other", "com.example.new")));
}
TEST_F(NativePermissionControllerTest, updatePackages_EmptyRemovesEntry) {
@@ -138,15 +133,14 @@
createState(10000, {"com.example.app1"}),
};
- EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
UidPackageState newState{}; // Empty package list
newState.uid = 10000;
- EXPECT_TRUE(controller_.updatePackagesForUid(newState).isOk());
+ EXPECT_THAT(controller_.updatePackagesForUid(newState), BinderStatusMatcher::isOk());
// getPackages for unknown UID should error out
- const auto res = controller_.getPackagesForUid(10000);
- ASSERT_FALSE(res.has_value());
- EXPECT_EQ(res.error(), ::android::BAD_VALUE);
+ EXPECT_THAT(controller_.getPackagesForUid(10000),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT)));
}
TEST_F(NativePermissionControllerTest, validateUidPackagePair_ValidPair) {
@@ -154,9 +148,9 @@
createState(10000, {"com.example.app1", "com.example.app2"}),
};
- EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
- UNWRAP_EQ(controller_.validateUidPackagePair(10000, "com.example.app1"), true);
+ EXPECT_THAT(controller_.validateUidPackagePair(10000, "com.example.app1"), IsOkAnd(IsTrue()));
}
TEST_F(NativePermissionControllerTest, validateUidPackagePair_InvalidPackage) {
@@ -164,9 +158,9 @@
createState(10000, {"com.example.app1", "com.example.app2"}),
};
- EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
- UNWRAP_EQ(controller_.validateUidPackagePair(10000, "com.example.other"), false);
+ EXPECT_THAT(controller_.validateUidPackagePair(10000, "com.example.other"), IsOkAnd(IsFalse()));
}
TEST_F(NativePermissionControllerTest, validateUidPackagePair_UnknownUid) {
@@ -174,45 +168,44 @@
createState(10000, {"com.example.app1", "com.example.app2"}),
};
- EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
- UNWRAP_EQ(controller_.validateUidPackagePair(12000, "any.package"), false);
+ EXPECT_THAT(controller_.validateUidPackagePair(12000, "any.package"), IsOkAnd(IsFalse()));
}
TEST_F(NativePermissionControllerTest, populatePermissionState_InvalidPermission) {
- EXPECT_EQ(controller_.populatePermissionState(PermissionEnum::ENUM_SIZE, {}).exceptionCode(),
- Status::EX_ILLEGAL_ARGUMENT);
- EXPECT_EQ(controller_
- .populatePermissionState(
- static_cast<PermissionEnum>(
- static_cast<int>(PermissionEnum::ENUM_SIZE) + 1),
- {})
- .exceptionCode(),
- Status::EX_ILLEGAL_ARGUMENT);
+ EXPECT_THAT(controller_.populatePermissionState(PermissionEnum::ENUM_SIZE, {}),
+ BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT));
+ EXPECT_THAT(
+ controller_.populatePermissionState(
+ static_cast<PermissionEnum>(static_cast<int>(PermissionEnum::ENUM_SIZE) + 1),
+ {}),
+ BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT));
}
TEST_F(NativePermissionControllerTest, populatePermissionState_HoldsPermission) {
// Unsorted
std::vector<int> uids{3, 1, 2, 4, 5};
- EXPECT_TRUE(
- controller_.populatePermissionState(PermissionEnum::MODIFY_AUDIO_ROUTING, uids).isOk());
+ EXPECT_THAT(controller_.populatePermissionState(PermissionEnum::MODIFY_AUDIO_ROUTING, uids),
+ BinderStatusMatcher::isOk());
- EXPECT_TRUE(*controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 3));
+ EXPECT_THAT(controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 3),
+ IsOkAnd(IsTrue()));
}
TEST_F(NativePermissionControllerTest, populatePermissionState_DoesNotHoldPermission) {
// Unsorted
std::vector<int> uids{3, 1, 2, 4, 5};
- EXPECT_TRUE(
- controller_.populatePermissionState(PermissionEnum::MODIFY_AUDIO_ROUTING, uids).isOk());
+ EXPECT_THAT(controller_.populatePermissionState(PermissionEnum::MODIFY_AUDIO_ROUTING, uids),
+ BinderStatusMatcher::isOk());
- EXPECT_FALSE(*controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 6));
+ EXPECT_THAT(controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 6),
+ IsOkAnd(IsFalse()));
}
TEST_F(NativePermissionControllerTest, populatePermissionState_NotInitialized) {
- const auto res = controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 3);
- ASSERT_FALSE(res.has_value());
- EXPECT_EQ(res.error(), ::android::NO_INIT);
+ EXPECT_THAT(controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 3),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
}
diff --git a/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp b/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp
index efc318b..0dd8814 100644
--- a/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp
+++ b/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp
@@ -20,24 +20,35 @@
#include <gtest/gtest.h>
#include <android-base/expected.h>
+#include <error/ExpectedMatchers.h>
#include <media/IPermissionProvider.h>
+#include "error/BinderStatusMatcher.h"
using ::android::base::unexpected;
using ::android::binder::Status;
+using ::android::binder::Status::EX_ILLEGAL_ARGUMENT;
+using ::android::binder::Status::EX_ILLEGAL_STATE;
+using ::android::binder::Status::EX_SECURITY;
using ::android::content::AttributionSourceState;
-using ::android::error::Result;
+using ::android::error::BinderResult;
+using ::android::error::BinderStatusMatcher;
+using ::android::error::IsErrorAnd;
+using ::android::error::IsOkAnd;
using ::com::android::media::permission::IPermissionProvider;
using ::com::android::media::permission::PermissionEnum;
using ::com::android::media::permission::ValidatedAttributionSourceState;
+
+using ::testing::Eq;
using ::testing::Return;
class MockPermissionProvider : public IPermissionProvider {
public:
- MOCK_METHOD(Result<std::vector<std::string>>, getPackagesForUid, (uid_t uid),
+ MOCK_METHOD(BinderResult<std::vector<std::string>>, getPackagesForUid, (uid_t uid),
(override, const));
- MOCK_METHOD(Result<bool>, validateUidPackagePair, (uid_t uid, const std::string&),
+ MOCK_METHOD(BinderResult<bool>, validateUidPackagePair, (uid_t uid, const std::string&),
(override, const));
- MOCK_METHOD(Result<bool>, checkPermission, (PermissionEnum perm, uid_t), (override, const));
+ MOCK_METHOD(BinderResult<bool>, checkPermission, (PermissionEnum perm, uid_t),
+ (override, const));
};
class ValidatedAttributionSourceStateTest : public ::testing::Test {
@@ -47,21 +58,14 @@
const std::vector<std::string> mPackageList{"com.package1", "com.package2"};
};
-#define UNWRAP_EQ(expr, desired_expr) \
- do { \
- auto tmp_ = (expr); \
- EXPECT_TRUE(tmp_.has_value()); \
- if (tmp_.has_value()) EXPECT_EQ(*tmp_, desired_expr); \
- } while (0)
-
TEST_F(ValidatedAttributionSourceStateTest, providedPackageValid) {
const std::string package = "com.package1";
EXPECT_CALL(mMockProvider, validateUidPackagePair(mUid, package)).WillOnce(Return(true));
AttributionSourceState attr;
attr.uid = mUid;
attr.packageName = package;
- UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
- attr);
+ EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+ IsOkAnd(Eq(attr)));
}
TEST_F(ValidatedAttributionSourceStateTest, providedPackageInvalid) {
@@ -70,10 +74,8 @@
AttributionSourceState attr;
attr.uid = mUid;
attr.packageName = package;
- const auto res =
- ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider);
- ASSERT_FALSE(res.has_value());
- EXPECT_EQ(res.error(), ::android::PERMISSION_DENIED);
+ EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_SECURITY)));
}
TEST_F(ValidatedAttributionSourceStateTest, packageLookup_whenMissingPackage) {
@@ -83,8 +85,8 @@
AttributionSourceState expectedAttr;
expectedAttr.uid = mUid;
expectedAttr.packageName = "com.package1";
- UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
- expectedAttr);
+ EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+ IsOkAnd(Eq(expectedAttr)));
}
TEST_F(ValidatedAttributionSourceStateTest, packageLookup_whenEmptyPackage) {
@@ -95,33 +97,29 @@
AttributionSourceState expectedAttr;
expectedAttr.uid = mUid;
expectedAttr.packageName = "com.package1";
- UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
- expectedAttr);
+ EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+ IsOkAnd(Eq(expectedAttr)));
}
TEST_F(ValidatedAttributionSourceStateTest, controllerNotInitialized) {
EXPECT_CALL(mMockProvider, getPackagesForUid(mUid))
- .WillOnce(Return(unexpected{::android::NO_INIT}));
+ .WillOnce(Return(unexpected{Status::fromExceptionCode(EX_ILLEGAL_STATE)}));
AttributionSourceState attr;
attr.uid = mUid;
attr.packageName = std::string{};
AttributionSourceState expectedAttr;
expectedAttr.uid = mUid;
expectedAttr.packageName = "com.package1";
- const auto res =
- ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider);
- ASSERT_FALSE(res.has_value());
- EXPECT_EQ(res.error(), ::android::NO_INIT);
+ EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
}
TEST_F(ValidatedAttributionSourceStateTest, uidNotFound) {
EXPECT_CALL(mMockProvider, getPackagesForUid(mUid))
- .WillOnce(Return(unexpected{::android::BAD_VALUE}));
+ .WillOnce(Return(unexpected{Status::fromExceptionCode(EX_ILLEGAL_ARGUMENT)}));
AttributionSourceState attr;
attr.uid = mUid;
attr.packageName = std::string{};
- const auto res =
- ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider);
- ASSERT_FALSE(res.has_value());
- EXPECT_EQ(res.error(), ::android::BAD_VALUE);
+ EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT)));
}
diff --git a/services/camera/virtualcamera/VirtualCameraDevice.cc b/services/camera/virtualcamera/VirtualCameraDevice.cc
index e455378..c3be62b 100644
--- a/services/camera/virtualcamera/VirtualCameraDevice.cc
+++ b/services/camera/virtualcamera/VirtualCameraDevice.cc
@@ -68,7 +68,7 @@
using namespace std::chrono_literals;
-// Prefix of camera name - "device@1.1/virtual/{numerical_id}"
+// Prefix of camera name - "device@1.1/virtual/{camera_id}"
const char* kDevicePathPrefix = "device@1.1/virtual/";
constexpr int32_t kMaxJpegSize = 3 * 1024 * 1024 /*3MiB*/;
@@ -404,8 +404,8 @@
} // namespace
VirtualCameraDevice::VirtualCameraDevice(
- const uint32_t cameraId, const VirtualCameraConfiguration& configuration,
- int32_t deviceId)
+ const std::string& cameraId,
+ const VirtualCameraConfiguration& configuration, int32_t deviceId)
: mCameraId(cameraId),
mVirtualCameraClientCallback(configuration.virtualCameraCallback),
mSupportedInputConfigurations(configuration.supportedStreamConfigs) {
@@ -582,11 +582,11 @@
}
binder_status_t VirtualCameraDevice::dump(int fd, const char**, uint32_t) {
- ALOGD("Dumping virtual camera %d", mCameraId);
+ ALOGD("Dumping virtual camera %s", mCameraId.c_str());
const char* indent = " ";
const char* doubleIndent = " ";
- dprintf(fd, "%svirtual_camera %d belongs to virtual device %d\n", indent,
- mCameraId,
+ dprintf(fd, "%svirtual_camera %s belongs to virtual device %d\n", indent,
+ mCameraId.c_str(),
getDeviceId(mCameraCharacteristics)
.value_or(VirtualCameraService::kDefaultDeviceId));
dprintf(fd, "%sSupportedStreamConfiguration:\n", indent);
@@ -597,7 +597,7 @@
}
std::string VirtualCameraDevice::getCameraName() const {
- return std::string(kDevicePathPrefix) + std::to_string(mCameraId);
+ return std::string(kDevicePathPrefix) + mCameraId;
}
const std::vector<SupportedStreamConfiguration>&
diff --git a/services/camera/virtualcamera/VirtualCameraDevice.h b/services/camera/virtualcamera/VirtualCameraDevice.h
index 296383f..a33d4cf 100644
--- a/services/camera/virtualcamera/VirtualCameraDevice.h
+++ b/services/camera/virtualcamera/VirtualCameraDevice.h
@@ -37,7 +37,7 @@
: public ::aidl::android::hardware::camera::device::BnCameraDevice {
public:
explicit VirtualCameraDevice(
- uint32_t cameraId,
+ const std::string& cameraId,
const aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
configuration,
int32_t deviceId);
@@ -92,10 +92,12 @@
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
// Returns unique virtual camera name in form
- // "device@{major}.{minor}/virtual/{numerical_id}"
+ // "device@{major}.{minor}/virtual/{camera_id}"
std::string getCameraName() const;
- uint32_t getCameraId() const { return mCameraId; }
+ const std::string& getCameraId() const {
+ return mCameraId;
+ }
const std::vector<
aidl::android::companion::virtualcamera::SupportedStreamConfiguration>&
@@ -141,7 +143,7 @@
private:
std::shared_ptr<VirtualCameraDevice> sharedFromThis();
- const uint32_t mCameraId;
+ const std::string mCameraId;
const std::shared_ptr<
::aidl::android::companion::virtualcamera::IVirtualCameraCallback>
mVirtualCameraClientCallback;
diff --git a/services/camera/virtualcamera/VirtualCameraProvider.cc b/services/camera/virtualcamera/VirtualCameraProvider.cc
index 67eaec0..b2c10f6 100644
--- a/services/camera/virtualcamera/VirtualCameraProvider.cc
+++ b/services/camera/virtualcamera/VirtualCameraProvider.cc
@@ -150,11 +150,10 @@
}
std::shared_ptr<VirtualCameraDevice> VirtualCameraProvider::createCamera(
- const VirtualCameraConfiguration& configuration, const int cameraId,
- const int32_t deviceId) {
- if (cameraId < 0) {
- ALOGE("%s: Cannot create camera with negative id. cameraId: %d", __func__,
- cameraId);
+ const VirtualCameraConfiguration& configuration,
+ const std::string& cameraId, const int32_t deviceId) {
+ if (cameraId.empty()) {
+ ALOGE("%s: Cannot create camera with empty cameraId", __func__);
return nullptr;
}
diff --git a/services/camera/virtualcamera/VirtualCameraProvider.h b/services/camera/virtualcamera/VirtualCameraProvider.h
index c536547..606b44c 100644
--- a/services/camera/virtualcamera/VirtualCameraProvider.h
+++ b/services/camera/virtualcamera/VirtualCameraProvider.h
@@ -77,7 +77,7 @@
std::shared_ptr<VirtualCameraDevice> createCamera(
const aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
configuration,
- int cameraId, int32_t deviceId);
+ const std::string& cameraId, int32_t deviceId);
std::shared_ptr<VirtualCameraDevice> getCamera(const std::string& name);
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index 9a5bd1e..cd17517 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -24,6 +24,7 @@
#include <memory>
#include <mutex>
#include <thread>
+#include <utility>
#include <vector>
#include "Exif.h"
@@ -78,6 +79,15 @@
namespace {
+// helper type for the visitor
+template <class... Ts>
+struct overloaded : Ts... {
+ using Ts::operator()...;
+};
+// explicit deduction guide (not needed as of C++20)
+template <class... Ts>
+overloaded(Ts...) -> overloaded<Ts...>;
+
using namespace std::chrono_literals;
static constexpr std::chrono::milliseconds kAcquireFenceTimeout = 500ms;
@@ -89,6 +99,8 @@
static constexpr size_t kJpegThumbnailBufferSize = 32 * 1024; // 32 KiB
+static constexpr UpdateTextureTask kUpdateTextureTask;
+
CameraMetadata createCaptureResultMetadata(
const std::chrono::nanoseconds timestamp,
const RequestSettings& requestSettings,
@@ -287,6 +299,21 @@
static_cast<uint64_t>(1e9 / VirtualCameraDevice::kMinFps));
}
+class FrameAvailableListenerProxy : public ConsumerBase::FrameAvailableListener {
+ public:
+ FrameAvailableListenerProxy(std::function<void()> callback)
+ : mOnFrameAvailableCallback(callback) {
+ }
+
+ virtual void onFrameAvailable(const BufferItem&) override {
+ ALOGV("%s: onFrameAvailable", __func__);
+ mOnFrameAvailableCallback();
+ }
+
+ private:
+ std::function<void()> mOnFrameAvailableCallback;
+};
+
} // namespace
CaptureRequestBuffer::CaptureRequestBuffer(int streamId, int bufferId,
@@ -345,9 +372,25 @@
return mRequestSettings;
}
+void VirtualCameraRenderThread::requestTextureUpdate() {
+ std::lock_guard<std::mutex> lock(mLock);
+ // If queue is not empty, we don't need to set the mTextureUpdateRequested
+ // flag, since the texture will be updated during ProcessCaptureRequestTask
+ // processing anyway.
+ if (mQueue.empty()) {
+ mTextureUpdateRequested = true;
+ mCondVar.notify_one();
+ }
+}
+
void VirtualCameraRenderThread::enqueueTask(
std::unique_ptr<ProcessCaptureRequestTask> task) {
std::lock_guard<std::mutex> lock(mLock);
+ // When enqueving process capture request task, clear the
+ // mTextureUpdateRequested flag. If this flag is set, the texture was not yet
+ // updated and it will be updated when processing ProcessCaptureRequestTask
+ // anyway.
+ mTextureUpdateRequested = false;
mQueue.emplace_back(std::move(task));
mCondVar.notify_one();
}
@@ -377,8 +420,7 @@
return mInputSurfaceFuture.get();
}
-std::unique_ptr<ProcessCaptureRequestTask>
-VirtualCameraRenderThread::dequeueTask() {
+RenderThreadTask VirtualCameraRenderThread::dequeueTask() {
std::unique_lock<std::mutex> lock(mLock);
// Clang's thread safety analysis doesn't perform alias analysis,
// so it doesn't support moveable std::unique_lock.
@@ -389,12 +431,20 @@
ScopedLockAssertion lockAssertion(mLock);
mCondVar.wait(lock, [this]() REQUIRES(mLock) {
- return mPendingExit || !mQueue.empty();
+ return mPendingExit || mTextureUpdateRequested || !mQueue.empty();
});
if (mPendingExit) {
- return nullptr;
+ // Render thread task with null task signals render thread to terminate.
+ return RenderThreadTask(nullptr);
}
- std::unique_ptr<ProcessCaptureRequestTask> task = std::move(mQueue.front());
+ if (mTextureUpdateRequested) {
+ // If mTextureUpdateRequested, it's guaranteed the queue is empty, return
+ // kUpdateTextureTask to signal we want render thread to update the texture
+ // (consume buffer from the queue).
+ mTextureUpdateRequested = false;
+ return RenderThreadTask(kUpdateTextureTask);
+ }
+ RenderThreadTask task(std::move(mQueue.front()));
mQueue.pop_front();
return task;
}
@@ -409,11 +459,23 @@
EglTextureProgram::TextureFormat::RGBA);
mEglSurfaceTexture = std::make_unique<EglSurfaceTexture>(
mInputSurfaceSize.width, mInputSurfaceSize.height);
+ sp<FrameAvailableListenerProxy> frameAvailableListener =
+ sp<FrameAvailableListenerProxy>::make(
+ [this]() { requestTextureUpdate(); });
+ mEglSurfaceTexture->setFrameAvailableListener(frameAvailableListener);
mInputSurfacePromise.set_value(mEglSurfaceTexture->getSurface());
- while (std::unique_ptr<ProcessCaptureRequestTask> task = dequeueTask()) {
- processCaptureRequest(*task);
+ while (RenderThreadTask task = dequeueTask()) {
+ std::visit(
+ overloaded{[this](const std::unique_ptr<ProcessCaptureRequestTask>& t) {
+ processTask(*t);
+ },
+ [this](const UpdateTextureTask&) {
+ ALOGV("Idle update of the texture");
+ mEglSurfaceTexture->updateTexture();
+ }},
+ task);
}
// Destroy EGL utilities still on the render thread.
@@ -425,7 +487,7 @@
ALOGV("Render thread exiting");
}
-void VirtualCameraRenderThread::processCaptureRequest(
+void VirtualCameraRenderThread::processTask(
const ProcessCaptureRequestTask& request) {
std::chrono::nanoseconds timestamp =
std::chrono::duration_cast<std::chrono::nanoseconds>(
@@ -688,7 +750,7 @@
return status;
}
- PlanesLockGuard planesLock(hwBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY,
+ PlanesLockGuard planesLock(hwBuffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
fence);
if (planesLock.getStatus() != OK) {
return cameraStatus(Status::INTERNAL_ERROR);
@@ -771,8 +833,8 @@
Rect viewportRect =
viewport.value_or(Rect(framebuffer.getWidth(), framebuffer.getHeight()));
- glViewport(viewportRect.leftTop().x, viewportRect.leftTop().y,
- viewportRect.getWidth(), viewportRect.getHeight());
+ glViewport(viewportRect.left, viewportRect.top, viewportRect.getWidth(),
+ viewportRect.getHeight());
sp<GraphicBuffer> textureBuffer = mEglSurfaceTexture->getCurrentBuffer();
if (textureBuffer == nullptr) {
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.h b/services/camera/virtualcamera/VirtualCameraRenderThread.h
index b23c30c..5a5966b 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.h
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.h
@@ -23,6 +23,7 @@
#include <future>
#include <memory>
#include <thread>
+#include <variant>
#include <vector>
#include "VirtualCameraDevice.h"
@@ -34,7 +35,6 @@
#include "util/EglFramebuffer.h"
#include "util/EglProgram.h"
#include "util/EglSurfaceTexture.h"
-#include "util/MetadataUtil.h"
#include "util/Util.h"
namespace android {
@@ -94,6 +94,24 @@
const RequestSettings mRequestSettings;
};
+struct UpdateTextureTask {};
+
+struct RenderThreadTask
+ : public std::variant<std::unique_ptr<ProcessCaptureRequestTask>,
+ UpdateTextureTask> {
+ // Allow implicit conversion to bool.
+ //
+ // Returns false, if the RenderThreadTask consist of null
+ // ProcessCaptureRequestTask, which signals that the thread should terminate.
+ operator bool() const {
+ const bool isExitSignal =
+ std::holds_alternative<std::unique_ptr<ProcessCaptureRequestTask>>(
+ *this) &&
+ std::get<std::unique_ptr<ProcessCaptureRequestTask>>(*this) == nullptr;
+ return !isExitSignal;
+ }
+};
+
// Wraps dedicated rendering thread and rendering business with corresponding
// input surface.
class VirtualCameraRenderThread {
@@ -120,6 +138,12 @@
// Stop rendering thread.
void stop();
+ // Send request to render thread to update the texture.
+ // Currently queued buffers in the input surface will be consumed and the most
+ // recent buffer in the input surface will be attached to the texture), all
+ // other buffers will be returned to the buffer queue.
+ void requestTextureUpdate() EXCLUDES(mLock);
+
// Equeue capture task for processing on render thread.
void enqueueTask(std::unique_ptr<ProcessCaptureRequestTask> task)
EXCLUDES(mLock);
@@ -131,13 +155,13 @@
sp<Surface> getInputSurface();
private:
- std::unique_ptr<ProcessCaptureRequestTask> dequeueTask() EXCLUDES(mLock);
+ RenderThreadTask dequeueTask() EXCLUDES(mLock);
// Rendering thread entry point.
void threadLoop();
// Process single capture request task (always called on render thread).
- void processCaptureRequest(const ProcessCaptureRequestTask& captureRequestTask);
+ void processTask(const ProcessCaptureRequestTask& captureRequestTask);
// Flush single capture request task returning the error status immediately.
void flushCaptureRequest(const ProcessCaptureRequestTask& captureRequestTask);
@@ -192,6 +216,7 @@
std::mutex mLock;
std::deque<std::unique_ptr<ProcessCaptureRequestTask>> mQueue GUARDED_BY(mLock);
std::condition_variable mCondVar;
+ volatile bool mTextureUpdateRequested GUARDED_BY(mLock);
volatile bool mPendingExit GUARDED_BY(mLock);
// Acquisition timestamp of last frame.
diff --git a/services/camera/virtualcamera/VirtualCameraService.cc b/services/camera/virtualcamera/VirtualCameraService.cc
index 724ec62..7466089 100644
--- a/services/camera/virtualcamera/VirtualCameraService.cc
+++ b/services/camera/virtualcamera/VirtualCameraService.cc
@@ -57,12 +57,9 @@
using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
-// TODO(b/301023410) Make camera id range configurable / dynamic
-// based on already registered devices.
-std::atomic_int VirtualCameraService::sNextId{1000};
-
namespace {
+constexpr char kCameraIdPrefix[] = "v";
constexpr int kVgaWidth = 640;
constexpr int kVgaHeight = 480;
constexpr int kMaxFps = 60;
@@ -79,6 +76,8 @@
--camera_id=(ID) - override numerical ID for test camera instance
--lens_facing=(front|back|external) - specifies lens facing for test camera instance
--input_fps=(fps) - specify input fps for test camera, valid values are from 1 to 1000
+ --sensor_orientation=(0|90|180|270) - Clockwise angle through which the output image
+ needs to be rotated to be upright on the device screen in its native orientation
* disable_test_camera
)";
constexpr char kCreateVirtualDevicePermission[] =
@@ -90,6 +89,9 @@
"GL_EXT_YUV_target",
};
+// Numerical portion for id to assign to next created camera.
+static std::atomic_int sNextIdNumericalPortion{1000};
+
ndk::ScopedAStatus validateConfiguration(
const VirtualCameraConfiguration& configuration) {
if (configuration.supportedStreamConfigs.empty()) {
@@ -192,7 +194,7 @@
}
return cmd;
-};
+}
ndk::ScopedAStatus verifyRequiredEglExtensions() {
EglDisplayContext context;
@@ -211,6 +213,11 @@
return ndk::ScopedAStatus::ok();
}
+std::string createCameraId(const int32_t deviceId) {
+ return kCameraIdPrefix + std::to_string(deviceId) + "_" +
+ std::to_string(sNextIdNumericalPortion++);
+}
+
} // namespace
VirtualCameraService::VirtualCameraService(
@@ -224,13 +231,14 @@
const ::ndk::SpAIBinder& token,
const VirtualCameraConfiguration& configuration, const int32_t deviceId,
bool* _aidl_return) {
- return registerCamera(token, configuration, sNextId++, deviceId, _aidl_return);
+ return registerCamera(token, configuration, createCameraId(deviceId),
+ deviceId, _aidl_return);
}
ndk::ScopedAStatus VirtualCameraService::registerCamera(
const ::ndk::SpAIBinder& token,
- const VirtualCameraConfiguration& configuration, const int cameraId,
- const int32_t deviceId, bool* _aidl_return) {
+ const VirtualCameraConfiguration& configuration,
+ const std::string& cameraId, const int32_t deviceId, bool* _aidl_return) {
if (!mPermissionProxy.checkCallingPermission(kCreateVirtualDevicePermission)) {
ALOGE("%s: caller (pid %d, uid %d) doesn't hold %s permission", __func__,
getpid(), getuid(), kCreateVirtualDevicePermission);
@@ -308,7 +316,7 @@
}
ndk::ScopedAStatus VirtualCameraService::getCameraId(
- const ::ndk::SpAIBinder& token, int32_t* _aidl_return) {
+ const ::ndk::SpAIBinder& token, std::string* _aidl_return) {
if (!mPermissionProxy.checkCallingPermission(kCreateVirtualDevicePermission)) {
ALOGE("%s: caller (pid %d, uid %d) doesn't hold %s permission", __func__,
getpid(), getuid(), kCreateVirtualDevicePermission);
@@ -400,13 +408,12 @@
return STATUS_OK;
}
- std::optional<int> cameraId;
+ std::optional<std::string> cameraId;
auto it = options.find("camera_id");
if (it != options.end()) {
- cameraId = parseInt(it->second);
+ cameraId = it->second;
if (!cameraId.has_value()) {
- dprintf(err, "Invalid camera_id: %s\n, must be number > 0",
- it->second.c_str());
+ dprintf(err, "Invalid camera_id: %s", it->second.c_str());
return STATUS_BAD_VALUE;
}
}
@@ -434,6 +441,31 @@
}
}
+ std::optional<SensorOrientation> sensorOrientation;
+ std::optional<int> sensorOrientationInt;
+ it = options.find("sensor_orientation");
+ if (it != options.end()) {
+ sensorOrientationInt = parseInt(it->second);
+ switch (sensorOrientationInt.value_or(0)) {
+ case 0:
+ sensorOrientation = SensorOrientation::ORIENTATION_0;
+ break;
+ case 90:
+ sensorOrientation = SensorOrientation::ORIENTATION_90;
+ break;
+ case 180:
+ sensorOrientation = SensorOrientation::ORIENTATION_180;
+ break;
+ case 270:
+ sensorOrientation = SensorOrientation::ORIENTATION_270;
+ break;
+ default:
+ dprintf(err, "Invalid sensor rotation: %s\n, must be 0, 90, 180 or 270.",
+ it->second.c_str());
+ return STATUS_BAD_VALUE;
+ }
+ }
+
sp<BBinder> token = sp<BBinder>::make();
mTestCameraToken.set(AIBinder_fromPlatformBinder(token));
@@ -444,10 +476,13 @@
Format::RGBA_8888,
.maxFps = kMaxFps});
configuration.lensFacing = lensFacing.value_or(LensFacing::EXTERNAL);
+ configuration.sensorOrientation =
+ sensorOrientation.value_or(SensorOrientation::ORIENTATION_0);
configuration.virtualCameraCallback =
ndk::SharedRefBase::make<VirtualCameraTestInstance>(
inputFps.value_or(kTestCameraDefaultInputFps));
- registerCamera(mTestCameraToken, configuration, cameraId.value_or(sNextId++),
+ registerCamera(mTestCameraToken, configuration,
+ cameraId.value_or(std::to_string(sNextIdNumericalPortion++)),
kDefaultDeviceId, &ret);
if (ret) {
dprintf(out, "Successfully registered test camera %s\n",
diff --git a/services/camera/virtualcamera/VirtualCameraService.h b/services/camera/virtualcamera/VirtualCameraService.h
index f04acb5..4ef01c7 100644
--- a/services/camera/virtualcamera/VirtualCameraService.h
+++ b/services/camera/virtualcamera/VirtualCameraService.h
@@ -50,15 +50,17 @@
const ::ndk::SpAIBinder& token,
const ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
configuration,
- int cameraId, int32_t deviceId, bool* _aidl_return) EXCLUDES(mLock);
+ const std::string& cameraId, int32_t deviceId, bool* _aidl_return)
+ EXCLUDES(mLock);
// Unregisters camera corresponding to the binder token.
ndk::ScopedAStatus unregisterCamera(const ::ndk::SpAIBinder& token) override
EXCLUDES(mLock);
// Returns the camera id corresponding to the binder token.
- ndk::ScopedAStatus getCameraId(
- const ::ndk::SpAIBinder& token, int32_t* _aidl_return) override EXCLUDES(mLock);
+ ndk::ScopedAStatus getCameraId(const ::ndk::SpAIBinder& token,
+ std::string* _aidl_return) override
+ EXCLUDES(mLock);
// Returns VirtualCameraDevice corresponding to binder token or nullptr if
// there's no camera asociated with the token.
@@ -101,9 +103,6 @@
// Local binder token for test camera instance, or nullptr if there's none.
::ndk::SpAIBinder mTestCameraToken;
-
- // Numerical id to assign to next created camera.
- static std::atomic_int sNextId;
};
} // namespace virtualcamera
diff --git a/services/camera/virtualcamera/VirtualCameraSessionContext.cc b/services/camera/virtualcamera/VirtualCameraSessionContext.cc
index 284ad05..aab2d0d 100644
--- a/services/camera/virtualcamera/VirtualCameraSessionContext.cc
+++ b/services/camera/virtualcamera/VirtualCameraSessionContext.cc
@@ -129,7 +129,8 @@
streamId);
return std::optional<Stream>();
}
- return {it->second->getStreamConfig()};
+ VirtualCameraStream& stream = *it->second;
+ return {stream.getStreamConfig()};
}
std::shared_ptr<AHardwareBuffer> VirtualCameraSessionContext::fetchHardwareBuffer(
@@ -141,7 +142,8 @@
streamId);
return nullptr;
}
- return it->second->getHardwareBuffer(bufferId);
+ VirtualCameraStream& stream = *it->second;
+ return stream.getHardwareBuffer(bufferId);
}
std::shared_ptr<EglFrameBuffer>
@@ -154,7 +156,8 @@
streamId);
return nullptr;
}
- return it->second->getEglFrameBuffer(eglDisplay, bufferId);
+ VirtualCameraStream& stream = *it->second;
+ return stream.getEglFrameBuffer(eglDisplay, bufferId);
}
std::set<int> VirtualCameraSessionContext::getStreamIds() const {
diff --git a/services/camera/virtualcamera/VirtualCameraTestInstance.cc b/services/camera/virtualcamera/VirtualCameraTestInstance.cc
index 1eac4fe..ff4a2d8 100644
--- a/services/camera/virtualcamera/VirtualCameraTestInstance.cc
+++ b/services/camera/virtualcamera/VirtualCameraTestInstance.cc
@@ -125,10 +125,18 @@
ALOGV("%s: streamId %d, %dx%d pixFmt=%s", __func__, streamId, width, height,
toString(pixelFormat).c_str());
- std::lock_guard<std::mutex> lock(mLock);
- mRenderer = std::make_shared<TestPatternRenderer>(
+ auto renderer = std::make_shared<TestPatternRenderer>(
nativeWindowFromSurface(surface), mFps);
- mRenderer->start();
+
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mInputRenderers.try_emplace(streamId, renderer).second) {
+ renderer->start();
+ } else {
+ ALOGE(
+ "%s: Input stream with id %d is already active, ignoring "
+ "onStreamConfigured call",
+ __func__, streamId);
+ }
return ScopedAStatus::ok();
}
@@ -141,10 +149,17 @@
ScopedAStatus VirtualCameraTestInstance::onStreamClosed(const int32_t streamId) {
ALOGV("%s: streamId %d", __func__, streamId);
- std::lock_guard<std::mutex> lock(mLock);
- if (mRenderer != nullptr) {
- mRenderer->stop();
- mRenderer.reset();
+ std::shared_ptr<TestPatternRenderer> renderer;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ auto it = mInputRenderers.find(streamId);
+ if (it != mInputRenderers.end()) {
+ renderer = std::move(it->second);
+ mInputRenderers.erase(it);
+ }
+ }
+ if (renderer != nullptr) {
+ renderer->stop();
}
return ScopedAStatus::ok();
}
diff --git a/services/camera/virtualcamera/VirtualCameraTestInstance.h b/services/camera/virtualcamera/VirtualCameraTestInstance.h
index 43e33d5..c130645 100644
--- a/services/camera/virtualcamera/VirtualCameraTestInstance.h
+++ b/services/camera/virtualcamera/VirtualCameraTestInstance.h
@@ -17,7 +17,7 @@
#define ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERATESTINSTANCE_H
#include <atomic>
-#include <condition_variable>
+#include <map>
#include <memory>
#include <thread>
@@ -80,7 +80,10 @@
const int mFps;
std::mutex mLock;
- std::shared_ptr<TestPatternRenderer> mRenderer GUARDED_BY(mLock);
+ // Map maintaining streamId -> TestPatternRenderer mapping for active
+ // input streams.
+ std::map<int, std::shared_ptr<TestPatternRenderer>> mInputRenderers
+ GUARDED_BY(mLock);
};
} // namespace virtualcamera
diff --git a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraService.aidl b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraService.aidl
index 1bd99be..2f1e2a9 100644
--- a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraService.aidl
+++ b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraService.aidl
@@ -41,5 +41,5 @@
* Returns the camera id for a given binder token. Note that this id corresponds to the id of
* the camera device in the camera framework.
*/
- int getCameraId(in IBinder token);
+ @utf8InCpp String getCameraId(in IBinder token);
}
diff --git a/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
index 3fe7c11..32cd23f 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
@@ -54,11 +54,9 @@
using metadata_stream_t =
camera_metadata_enum_android_scaler_available_stream_configurations_t;
-constexpr int kCameraId = 42;
+constexpr char kCameraId[] = "42";
constexpr int kQvgaWidth = 320;
constexpr int kQvgaHeight = 240;
-constexpr int k360pWidth = 640;
-constexpr int k360pHeight = 360;
constexpr int kVgaWidth = 640;
constexpr int kVgaHeight = 480;
constexpr int kHdWidth = 1280;
diff --git a/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc b/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
index f1b2a92..d4bc6de 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
@@ -50,13 +50,12 @@
using ::testing::Not;
using ::testing::Return;
+constexpr char kCameraId[] = "42";
constexpr int kVgaWidth = 640;
constexpr int kVgaHeight = 480;
constexpr int kMaxFps = 30;
-constexpr int kCameraId = 9999;
constexpr int kDefaultDeviceId = 0;
-constexpr char kVirtualCameraNameRegex[] =
- "device@[0-9]+\\.[0-9]+/virtual/[0-9]+";
+constexpr char kVirtualCameraNameRegex[] = "device@[0-9]+\\.[0-9]+/virtual/.+";
class MockCameraProviderCallback : public BnCameraProviderCallback {
public:
diff --git a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
index 50977d8..719f64d 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
@@ -19,6 +19,7 @@
#include <cstdio>
#include <iterator>
#include <memory>
+#include <optional>
#include <regex>
#include "VirtualCameraService.h"
@@ -191,6 +192,16 @@
return getLensFacing(metadata);
}
+ std::optional<int32_t> getCameraSensorOrienation(const std::string& id) {
+ std::shared_ptr<VirtualCameraDevice> camera = mCameraProvider->getCamera(id);
+ if (camera == nullptr) {
+ return std::nullopt;
+ }
+ CameraMetadata metadata;
+ camera->getCameraCharacteristics(&metadata);
+ return getSensorOrientation(metadata);
+ }
+
protected:
std::shared_ptr<VirtualCameraService> mCameraService;
std::shared_ptr<VirtualCameraProvider> mCameraProvider;
@@ -390,7 +401,7 @@
}
TEST_F(VirtualCameraServiceTest, GetIdWithoutPermissionFails) {
- int32_t aidlRet;
+ std::string aidlRet;
EXPECT_CALL(mMockPermissionsProxy,
checkCallingPermission(kCreateVirtualDevicePermissions))
.WillOnce(Return(false));
@@ -445,11 +456,13 @@
}
TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithId) {
- EXPECT_THAT(execute_shell_command("enable_test_camera --camera_id=12345"),
- Eq(NO_ERROR));
+ EXPECT_THAT(
+ execute_shell_command("enable_test_camera --camera_id=hello12345"),
+ Eq(NO_ERROR));
std::vector<std::string> cameraIdsAfterEnable = getCameraIds();
- EXPECT_THAT(cameraIdsAfterEnable, ElementsAre("device@1.1/virtual/12345"));
+ EXPECT_THAT(cameraIdsAfterEnable,
+ ElementsAre("device@1.1/virtual/hello12345"));
EXPECT_THAT(execute_shell_command("disable_test_camera"), Eq(NO_ERROR));
@@ -458,9 +471,8 @@
}
TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithInvalidId) {
- EXPECT_THAT(
- execute_shell_command("enable_test_camera --camera_id=NotNumericalId"),
- Eq(STATUS_BAD_VALUE));
+ EXPECT_THAT(execute_shell_command("enable_test_camera --camera_id="),
+ Eq(STATUS_BAD_VALUE));
}
TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithUnknownCommand) {
@@ -505,6 +517,24 @@
Eq(STATUS_BAD_VALUE));
}
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithSensorOrientation90) {
+ EXPECT_THAT(
+ execute_shell_command("enable_test_camera --sensor_orientation=90"),
+ Eq(NO_ERROR));
+
+ std::vector<std::string> cameraIds = getCameraIds();
+ ASSERT_THAT(cameraIds, SizeIs(1));
+ EXPECT_THAT(getCameraSensorOrienation(cameraIds[0]), Optional(Eq(90)));
+}
+
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithSensorOrientationNoArgs) {
+ EXPECT_THAT(execute_shell_command("enable_test_camera"), Eq(NO_ERROR));
+
+ std::vector<std::string> cameraIds = getCameraIds();
+ ASSERT_THAT(cameraIds, SizeIs(1));
+ EXPECT_THAT(getCameraSensorOrienation(cameraIds[0]), Optional(Eq(0)));
+}
+
} // namespace
} // namespace virtualcamera
} // namespace companion
diff --git a/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc b/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
index 93f90b4..a9eb413 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
@@ -37,6 +37,7 @@
namespace virtualcamera {
namespace {
+constexpr char kCameraId[] = "42";
constexpr int kQvgaWidth = 320;
constexpr int kQvgaHeight = 240;
constexpr int kVgaWidth = 640;
@@ -46,7 +47,6 @@
constexpr int kMaxFps = 30;
constexpr int kStreamId = 0;
constexpr int kSecondStreamId = 1;
-constexpr int kCameraId = 42;
constexpr int kDefaultDeviceId = 0;
using ::aidl::android::companion::virtualcamera::BnVirtualCameraCallback;
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.cc b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
index 7de5020..c81d36d 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.cc
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
@@ -64,6 +64,11 @@
return mGlConsumer->getCurrentBuffer();
}
+void EglSurfaceTexture::setFrameAvailableListener(
+ const wp<ConsumerBase::FrameAvailableListener>& listener) {
+ mGlConsumer->setFrameAvailableListener(listener);
+}
+
bool EglSurfaceTexture::waitForNextFrame(const std::chrono::nanoseconds timeout) {
return mSurface->waitForNextFrame(mGlConsumer->getFrameNumber(),
static_cast<nsecs_t>(timeout.count()));
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.h b/services/camera/virtualcamera/util/EglSurfaceTexture.h
index b9c5126..ac3cf7d 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.h
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.h
@@ -21,6 +21,7 @@
#include <cstdint>
#include "GLES/gl.h"
+#include "gui/ConsumerBase.h"
#include "gui/Surface.h"
#include "utils/RefBase.h"
@@ -58,6 +59,9 @@
// Returns false on timeout, true if new frame was received before timeout.
bool waitForNextFrame(std::chrono::nanoseconds timeout);
+ void setFrameAvailableListener(
+ const wp<ConsumerBase::FrameAvailableListener>& listener);
+
// Update the texture with the most recent submitted buffer.
// Most be called on thread with EGL context.
//
diff --git a/services/camera/virtualcamera/util/MetadataUtil.cc b/services/camera/virtualcamera/util/MetadataUtil.cc
index 31a8776..4889830 100644
--- a/services/camera/virtualcamera/util/MetadataUtil.cc
+++ b/services/camera/virtualcamera/util/MetadataUtil.cc
@@ -961,6 +961,20 @@
return static_cast<int32_t>(entry.data.i32[0]);
}
+std::optional<int32_t> getSensorOrientation(
+ const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
+ auto metadata =
+ reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+ camera_metadata_ro_entry_t entry;
+ if (find_camera_metadata_ro_entry(metadata, ANDROID_SENSOR_ORIENTATION,
+ &entry) != OK) {
+ return std::nullopt;
+ }
+
+ return static_cast<int32_t>(entry.data.i32[0]);
+}
+
} // namespace virtualcamera
} // namespace companion
} // namespace android
diff --git a/services/camera/virtualcamera/util/MetadataUtil.h b/services/camera/virtualcamera/util/MetadataUtil.h
index ca6f332..22d3657 100644
--- a/services/camera/virtualcamera/util/MetadataUtil.h
+++ b/services/camera/virtualcamera/util/MetadataUtil.h
@@ -488,6 +488,11 @@
std::optional<int32_t> getDeviceId(
const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata);
+// Return the value of ANDROID_SENSOR_ORIENTATION or nullopt if the key is not
+// present (which is equivalent to a orientation of 0).
+std::optional<int32_t> getSensorOrientation(
+ const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata);
+
} // namespace virtualcamera
} // namespace companion
} // namespace android
diff --git a/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp b/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
index c6793a9..c7b4297 100644
--- a/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
+++ b/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
@@ -17,6 +17,7 @@
*****************************************************************************
* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
+#include <binder/IPCThreadState.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <media/MediaMetricsItem.h>
#include <mediametricsservice/AudioTypes.h>
@@ -26,210 +27,158 @@
#include <string.h>
#include <utils/Log.h>
#include <algorithm>
+#include <set>
using namespace android;
+static constexpr size_t STATSD_LOG_LINES_MAX = 48;
+static unsigned long long kPackedCallingUid = (unsigned long long)AID_SYSTEM << 32;
+constexpr int8_t kMaxBytes = 100;
+constexpr int8_t kMinBytes = 0;
+constexpr size_t kMaxItemLength = 16;
// low water mark
constexpr size_t kLogItemsLowWater = 1;
// high water mark
constexpr size_t kLogItemsHighWater = 2;
-constexpr size_t kMaxItemLength = 16;
-constexpr size_t kMaxApis = 64;
+
+/*
+ * Concatenating strings to generate keys in such a way that the
+ * lambda function inside AudioAnalytics() added in the 'mAction' object is covered
+ */
+
+std::string keyMediaValues[] = {
+ "metrics.manager",
+ "mediadrm",
+ "audio.device.a2dp",
+ AMEDIAMETRICS_KEY_AUDIO_MIDI,
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "*",
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*",
+ AMEDIAMETRICS_KEY_AUDIO_FLINGER,
+ AMEDIAMETRICS_KEY_AUDIO_POLICY,
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*",
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*",
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*",
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
+ "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent",
+};
+
+std::string keyMediaAction[] = {
+ "createAudioPatch",
+ "connected",
+ AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE,
+ AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT,
+ AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR,
+ AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM,
+ AMEDIAMETRICS_PROP_EVENT_VALUE_DEVICECLOSED,
+ AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME,
+ AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE,
+ AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP,
+};
class MediaMetricsServiceFuzzer {
- public:
- void invokeStartsWith(const uint8_t *data, size_t size);
- void invokeInstantiate(const uint8_t *data, size_t size);
- void invokePackageInstallerCheck(const uint8_t *data, size_t size);
- void invokeItemManipulation(const uint8_t *data, size_t size);
- void invokeItemExpansion(const uint8_t *data, size_t size);
- void invokeTimeMachineStorage(const uint8_t *data, size_t size);
- void invokeTransactionLog(const uint8_t *data, size_t size);
- void invokeAnalyticsAction(const uint8_t *data, size_t size);
- void invokeAudioAnalytics(const uint8_t *data, size_t size);
- void invokeTimedAction(const uint8_t *data, size_t size);
- void process(const uint8_t *data, size_t size);
+ public:
+ MediaMetricsServiceFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+ void process();
+ void invokeStartsWith();
+ void invokeInstantiate();
+ void invokePackageInstallerCheck();
+ void invokeTimeMachineStorage();
+ void invokeTransactionLog();
+ void invokeAnalyticsAction();
+ void invokeAudioAnalytics();
+ void invokeTimedAction();
+ void setKeyValues(std::shared_ptr<mediametrics::Item>& item, std::string keyValue);
+ std::shared_ptr<mediametrics::Item> CreateItem();
+ sp<MediaMetricsService> mMediaMetricsService;
+ FuzzedDataProvider mFdp;
std::atomic_int mValue = 0;
};
-void MediaMetricsServiceFuzzer::invokeStartsWith(const uint8_t *data, size_t size) {
- FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
- while (fdp.remaining_bytes()) {
- android::mediametrics::startsWith(fdp.ConsumeRandomLengthString(),
- fdp.ConsumeRandomLengthString());
- }
+void MediaMetricsServiceFuzzer::setKeyValues(std::shared_ptr<mediametrics::Item>& item,
+ std::string keyValue) {
+ auto invokeActionAPIs = mFdp.PickValueInArray<const std::function<void()>>({
+ [&]() { item->setInt32(keyValue.c_str(), mFdp.ConsumeIntegral<int32_t>()); },
+ [&]() { item->addInt32(keyValue.c_str(), mFdp.ConsumeIntegral<int32_t>()); },
+ [&]() { item->setInt64(keyValue.c_str(), mFdp.ConsumeIntegral<int64_t>()); },
+ [&]() { item->addInt64(keyValue.c_str(), mFdp.ConsumeIntegral<int64_t>()); },
+ [&]() { item->setDouble(keyValue.c_str(), mFdp.ConsumeFloatingPoint<double>()); },
+ [&]() { item->addDouble(keyValue.c_str(), mFdp.ConsumeFloatingPoint<double>()); },
+ [&]() { item->setTimestamp(mFdp.ConsumeIntegral<int64_t>()); },
+ [&]() {
+ std::string value = mFdp.ConsumeBool()
+ ? mFdp.ConsumeRandomLengthString(kMaxBytes)
+ : mFdp.PickValueInArray<std::string>(keyMediaAction);
+ item->setCString(keyValue.c_str(), value.c_str());
+ },
+ [&]() {
+ item->setRate(keyValue.c_str(), mFdp.ConsumeIntegral<int64_t>(),
+ mFdp.ConsumeIntegral<int64_t>());
+ },
+ [&]() {
+ mediametrics::LogItem<1> itemTemp(mFdp.ConsumeRandomLengthString(kMaxBytes));
+ itemTemp.setPid(mFdp.ConsumeIntegral<int16_t>())
+ .setUid(mFdp.ConsumeIntegral<int16_t>());
+
+ int32_t i = mFdp.ConsumeIntegral<int32_t>();
+ itemTemp.set(std::to_string(i).c_str(), (int32_t)i);
+ itemTemp.updateHeader();
+ (void)item->readFromByteString(itemTemp.getBuffer(), itemTemp.getLength());
+ },
+
+ });
+ invokeActionAPIs();
}
-void MediaMetricsServiceFuzzer::invokeInstantiate(const uint8_t *data, size_t size) {
- FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
- sp mediaMetricsService = new MediaMetricsService();
-
- while (fdp.remaining_bytes()) {
- std::unique_ptr<mediametrics::Item> random_key(
- mediametrics::Item::create(fdp.ConsumeRandomLengthString()));
- mediaMetricsService->submit(random_key.get());
- random_key->setInt32(fdp.ConsumeRandomLengthString().c_str(),
- fdp.ConsumeIntegral<int32_t>());
- mediaMetricsService->submit(random_key.get());
-
- std::unique_ptr<mediametrics::Item> audiotrack_key(
- mediametrics::Item::create("audiotrack"));
- mediaMetricsService->submit(audiotrack_key.get());
- audiotrack_key->addInt32(fdp.ConsumeRandomLengthString().c_str(),
- fdp.ConsumeIntegral<int32_t>());
- mediaMetricsService->submit(audiotrack_key.get());
+std::shared_ptr<mediametrics::Item> MediaMetricsServiceFuzzer::CreateItem() {
+ std::string key;
+ if (mFdp.ConsumeBool()) {
+ key = mFdp.ConsumeRandomLengthString(kMaxItemLength);
+ } else {
+ key = mFdp.PickValueInArray<std::string>(keyMediaValues);
}
-}
-void MediaMetricsServiceFuzzer::invokePackageInstallerCheck(const uint8_t *data, size_t size) {
- FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
- while (fdp.remaining_bytes()) {
- MediaMetricsService::useUidForPackage(fdp.ConsumeRandomLengthString().c_str(),
- fdp.ConsumeRandomLengthString().c_str());
- }
-}
-
-void MediaMetricsServiceFuzzer::invokeItemManipulation(const uint8_t *data, size_t size) {
- FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-
- mediametrics::Item item(fdp.ConsumeRandomLengthString().c_str());
- while (fdp.remaining_bytes()) {
- const uint8_t action = fdp.ConsumeIntegralInRange<uint8_t>(0, 16);
- const std::string key = fdp.ConsumeRandomLengthString();
- if (fdp.remaining_bytes() < 1 || key.length() < 1) {
- break;
+ std::shared_ptr<mediametrics::Item> item = std::make_shared<mediametrics::Item>(key.c_str());
+ size_t numKeys = mFdp.ConsumeIntegralInRange<size_t>(kMinBytes, kMaxBytes);
+ std::set<std::string> keySet;
+ for (size_t i = 0; i < numKeys; ++i) {
+ std::string keyValue;
+ if (mFdp.ConsumeBool()) {
+ keyValue = mFdp.ConsumeRandomLengthString(kMaxBytes);
+ } else {
+ keyValue = mFdp.PickValueInArray<std::string>(
+ {AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_STATE, "logSessionIkeyd"});
}
- switch (action) {
- case 0: {
- item.setInt32(key.c_str(), fdp.ConsumeIntegral<int32_t>());
- break;
- }
- case 1: {
- item.addInt32(key.c_str(), fdp.ConsumeIntegral<int32_t>());
- break;
- }
- case 2: {
- int32_t i32 = 0;
- item.getInt32(key.c_str(), &i32);
- break;
- }
- case 3: {
- item.setInt64(key.c_str(), fdp.ConsumeIntegral<int64_t>());
- break;
- }
- case 4: {
- item.addInt64(key.c_str(), fdp.ConsumeIntegral<int64_t>());
- break;
- }
- case 5: {
- int64_t i64 = 0;
- item.getInt64(key.c_str(), &i64);
- break;
- }
- case 6: {
- item.setDouble(key.c_str(), fdp.ConsumeFloatingPoint<double>());
- break;
- }
- case 7: {
- item.addDouble(key.c_str(), fdp.ConsumeFloatingPoint<double>());
- break;
- }
- case 8: {
- double d = 0;
- item.getDouble(key.c_str(), &d);
- break;
- }
- case 9: {
- item.setCString(key.c_str(), fdp.ConsumeRandomLengthString().c_str());
- break;
- }
- case 10: {
- char *s = nullptr;
- item.getCString(key.c_str(), &s);
- if (s) free(s);
- break;
- }
- case 11: {
- std::string s;
- item.getString(key.c_str(), &s);
- break;
- }
- case 12: {
- item.setRate(key.c_str(), fdp.ConsumeIntegral<int64_t>(),
- fdp.ConsumeIntegral<int64_t>());
- break;
- }
- case 13: {
- int64_t b = 0, h = 0;
- double d = 0;
- item.getRate(key.c_str(), &b, &h, &d);
- break;
- }
- case 14: {
- (void)item.filter(key.c_str());
- break;
- }
- case 15: {
- const char *arr[1] = {""};
- arr[0] = const_cast<char *>(key.c_str());
- (void)item.filterNot(1, arr);
- break;
- }
- case 16: {
- (void)item.toString().c_str();
- break;
- }
+ if (keySet.find(keyValue) == keySet.end()) {
+ setKeyValues(item, keyValue);
+ keySet.insert(keyValue);
}
}
-
- Parcel p;
- mediametrics::Item item2;
-
- (void)item.writeToParcel(&p);
- p.setDataPosition(0); // rewind for reading
- (void)item2.readFromParcel(p);
-
- char *byteData = nullptr;
- size_t length = 0;
- (void)item.writeToByteString(&byteData, &length);
- (void)item2.readFromByteString(byteData, length);
- if (byteData) {
- free(byteData);
- }
-
- sp mediaMetricsService = new MediaMetricsService();
- mediaMetricsService->submit(&item2);
+ return item;
}
-void MediaMetricsServiceFuzzer::invokeItemExpansion(const uint8_t *data, size_t size) {
- FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-
- mediametrics::LogItem<1> item("FuzzItem");
- item.setPid(fdp.ConsumeIntegral<int16_t>()).setUid(fdp.ConsumeIntegral<int16_t>());
-
- while (fdp.remaining_bytes()) {
- int32_t i = fdp.ConsumeIntegral<int32_t>();
- item.set(std::to_string(i).c_str(), (int32_t)i);
- }
- item.updateHeader();
-
- mediametrics::Item item2;
- (void)item2.readFromByteString(item.getBuffer(), item.getLength());
-
- sp mediaMetricsService = new MediaMetricsService();
- mediaMetricsService->submit(&item2);
+void MediaMetricsServiceFuzzer::invokeStartsWith() {
+ android::mediametrics::startsWith(mFdp.ConsumeRandomLengthString(kMaxBytes),
+ mFdp.ConsumeRandomLengthString(kMaxBytes));
}
-void MediaMetricsServiceFuzzer::invokeTimeMachineStorage(const uint8_t *data, size_t size) {
- FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+void MediaMetricsServiceFuzzer::invokeInstantiate() {
+ auto item = CreateItem();
+ mMediaMetricsService->submit(item.get());
+}
- auto item = std::make_shared<mediametrics::Item>("FuzzKey");
- int32_t i32 = fdp.ConsumeIntegral<int32_t>();
- int64_t i64 = fdp.ConsumeIntegral<int64_t>();
- double d = fdp.ConsumeFloatingPoint<double>();
- std::string str = fdp.ConsumeRandomLengthString();
- std::pair<int64_t, int64_t> pair(fdp.ConsumeIntegral<int64_t>(),
- fdp.ConsumeIntegral<int64_t>());
+void MediaMetricsServiceFuzzer::invokePackageInstallerCheck() {
+ MediaMetricsService::useUidForPackage(mFdp.ConsumeRandomLengthString(kMaxBytes).c_str(),
+ mFdp.ConsumeRandomLengthString(kMaxBytes).c_str());
+}
+
+void MediaMetricsServiceFuzzer::invokeTimeMachineStorage() {
+ auto item = CreateItem();
+ int32_t i32 = mFdp.ConsumeIntegral<int32_t>();
+ int64_t i64 = mFdp.ConsumeIntegral<int64_t>();
+ double d = mFdp.ConsumeFloatingPoint<double>();
+ std::string str = mFdp.ConsumeRandomLengthString(kMaxBytes);
+ std::pair<int64_t, int64_t> pair(mFdp.ConsumeIntegral<int64_t>(),
+ mFdp.ConsumeIntegral<int64_t>());
(*item).set("i32", i32).set("i64", i64).set("double", d).set("string", str).set("rate", pair);
android::mediametrics::TimeMachine timeMachine;
@@ -253,124 +202,89 @@
timeMachine.get("Key.string", &str, -1);
}
-void MediaMetricsServiceFuzzer::invokeTransactionLog(const uint8_t *data, size_t size) {
- FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-
- auto item = std::make_shared<mediametrics::Item>("Key1");
- (*item)
- .set("one", fdp.ConsumeIntegral<int32_t>())
- .set("two", fdp.ConsumeIntegral<int32_t>())
- .setTimestamp(fdp.ConsumeIntegral<int32_t>());
+void MediaMetricsServiceFuzzer::invokeTransactionLog() {
+ auto item = CreateItem();
android::mediametrics::TransactionLog transactionLog(
kLogItemsLowWater, kLogItemsHighWater); // keep at most 2 items
transactionLog.size();
transactionLog.put(item);
- transactionLog.size();
-
- auto item2 = std::make_shared<mediametrics::Item>("Key2");
- (*item2)
- .set("three", fdp.ConsumeIntegral<int32_t>())
- .set("[Key1]three", fdp.ConsumeIntegral<int32_t>())
- .setTimestamp(fdp.ConsumeIntegral<int32_t>());
-
- transactionLog.put(item2);
- transactionLog.size();
-
- auto item3 = std::make_shared<mediametrics::Item>("Key3");
- (*item3)
- .set("six", fdp.ConsumeIntegral<int32_t>())
- .set("[Key1]four", fdp.ConsumeIntegral<int32_t>()) // affects Key1
- .set("[Key1]five", fdp.ConsumeIntegral<int32_t>()) // affects key1
- .setTimestamp(fdp.ConsumeIntegral<int32_t>());
-
- transactionLog.put(item3);
- transactionLog.size();
}
-void MediaMetricsServiceFuzzer::invokeAnalyticsAction(const uint8_t *data, size_t size) {
- FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-
+void MediaMetricsServiceFuzzer::invokeAnalyticsAction() {
mediametrics::AnalyticsActions analyticsActions;
bool action = false;
- while (fdp.remaining_bytes()) {
- analyticsActions.addAction(
- (fdp.ConsumeRandomLengthString() + std::string(".event")).c_str(),
- fdp.ConsumeRandomLengthString(),
+ analyticsActions.addAction(
+ (mFdp.ConsumeRandomLengthString(kMaxBytes) + std::string(".event")).c_str(),
+ mFdp.ConsumeRandomLengthString(kMaxBytes),
std::make_shared<mediametrics::AnalyticsActions::Function>(
- [&](const std::shared_ptr<const android::mediametrics::Item> &) {
- action = true;
- }));
- }
+ [&](const std::shared_ptr<const android::mediametrics::Item>&) {
+ action = true;
+ }));
- FuzzedDataProvider fdp2 = FuzzedDataProvider(data, size);
- size_t apiCount = 0;
- while (fdp2.remaining_bytes() && ++apiCount <= kMaxApis) {
- // make a test item
- auto item = std::make_shared<mediametrics::Item>(
- fdp2.ConsumeRandomLengthString(kMaxItemLength).c_str());
- (*item).set("event", fdp2.ConsumeRandomLengthString().c_str());
+ // make a test item
+ auto item = CreateItem();
+ (*item).set("event", mFdp.ConsumeRandomLengthString(kMaxBytes).c_str());
- // get the actions and execute them
- auto actions = analyticsActions.getActionsForItem(item);
- for (const auto &action : actions) {
- action->operator()(item);
+ // get the actions and execute them
+ auto actions = analyticsActions.getActionsForItem(item);
+ for (const auto& action : actions) {
+ action->operator()(item);
}
- }
}
-void MediaMetricsServiceFuzzer::invokeAudioAnalytics(const uint8_t *data, size_t size) {
- FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+void MediaMetricsServiceFuzzer::invokeAudioAnalytics() {
+ int32_t maxLogLine = mFdp.ConsumeIntegralInRange<int32_t>(0, STATSD_LOG_LINES_MAX);
std::shared_ptr<android::mediametrics::StatsdLog> statsdLog =
- std::make_shared<android::mediametrics::StatsdLog>(10);
+ std::make_shared<android::mediametrics::StatsdLog>(maxLogLine);
android::mediametrics::AudioAnalytics audioAnalytics{statsdLog};
- while (fdp.remaining_bytes()) {
- auto item = std::make_shared<mediametrics::Item>(fdp.ConsumeRandomLengthString().c_str());
- int32_t transactionUid = fdp.ConsumeIntegral<int32_t>(); // arbitrary
- (*item)
- .set(fdp.ConsumeRandomLengthString().c_str(), fdp.ConsumeIntegral<int32_t>())
- .set(fdp.ConsumeRandomLengthString().c_str(), fdp.ConsumeIntegral<int32_t>())
- .set(AMEDIAMETRICS_PROP_ALLOWUID, transactionUid)
- .setUid(transactionUid)
- .setTimestamp(fdp.ConsumeIntegral<int32_t>());
- audioAnalytics.submit(item, fdp.ConsumeBool());
+ auto item = CreateItem();
+ Parcel parcel;
+ item->writeToParcel(&parcel);
+ parcel.setDataPosition(0);
+ if (mFdp.ConsumeBool()) {
+ item->readFromParcel(parcel);
}
-
- audioAnalytics.dump(1000);
+ audioAnalytics.submit(item, mFdp.ConsumeBool());
}
-void MediaMetricsServiceFuzzer::invokeTimedAction(const uint8_t *data, size_t size) {
- FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+void MediaMetricsServiceFuzzer::invokeTimedAction() {
android::mediametrics::TimedAction timedAction;
+ timedAction.postIn(std::chrono::seconds(mFdp.ConsumeIntegral<uint32_t>()),
+ [this] { ++mValue; });
+ timedAction.size();
+}
- while (fdp.remaining_bytes()) {
- timedAction.postIn(std::chrono::seconds(fdp.ConsumeIntegral<int32_t>()),
- [this] { ++mValue; });
- timedAction.size();
+void MediaMetricsServiceFuzzer::process() {
+ mMediaMetricsService = sp<MediaMetricsService>::make();
+
+ if (mFdp.ConsumeBool()) {
+ IPCThreadState::self()->restoreCallingIdentity(kPackedCallingUid);
+ } else {
+ IPCThreadState::self()->restoreCallingIdentity(mFdp.ConsumeIntegral<size_t>());
+ }
+ while (mFdp.remaining_bytes()) {
+ auto invokeAPIs = mFdp.PickValueInArray<const std::function<void()>>({
+ [&]() { invokeStartsWith(); },
+ [&]() { invokeInstantiate(); },
+ [&]() { invokePackageInstallerCheck(); },
+ [&]() { invokeTimeMachineStorage(); },
+ [&]() { invokeTransactionLog(); },
+ [&]() { invokeAudioAnalytics(); },
+ [&]() { invokeTimedAction(); },
+ });
+ invokeAPIs();
}
}
-void MediaMetricsServiceFuzzer::process(const uint8_t *data, size_t size) {
- invokeStartsWith(data, size);
- invokeInstantiate(data, size);
- invokePackageInstallerCheck(data, size);
- invokeItemManipulation(data, size);
- invokeItemExpansion(data, size);
- invokeTimeMachineStorage(data, size);
- invokeTransactionLog(data, size);
- invokeAnalyticsAction(data, size);
- invokeAudioAnalytics(data, size);
- invokeTimedAction(data, size);
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size < 1) {
return 0;
}
- MediaMetricsServiceFuzzer mediaMetricsServiceFuzzer;
- mediaMetricsServiceFuzzer.process(data, size);
+ MediaMetricsServiceFuzzer mediaMetricsServiceFuzzer(data, size);
+ mediaMetricsServiceFuzzer.process();
return 0;
}
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 4e46bbf..20a5ea8 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -398,6 +398,7 @@
}
// implement Runnable, periodically send timestamps to client and process commands from queue.
+// Enter standby mode if idle for a while.
__attribute__((no_sanitize("integer")))
void AAudioServiceStreamBase::run() {
ALOGD("%s() %s entering >>>>>>>>>>>>>> COMMANDS", __func__, getTypeText());
@@ -406,6 +407,7 @@
TimestampScheduler timestampScheduler;
int64_t nextTimestampReportTime;
int64_t nextDataReportTime;
+ // When to try to enter standby.
int64_t standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
// Balance the incStrong from when the thread was launched.
holdStream->decStrong(nullptr);
@@ -417,28 +419,26 @@
int32_t loopCount = 0;
while (mThreadEnabled.load()) {
loopCount++;
- int64_t timeoutNanos = -1;
- if (isDisconnected_l()) {
- if (!isStandby_l()) {
- // If the stream is disconnected but not in standby mode, wait until standby time.
+ int64_t timeoutNanos = -1; // wait forever
+ if (isDisconnected_l() || isIdle_l()) {
+ if (isStandbyImplemented() && !isStandby_l()) {
+ // If not in standby mode, wait until standby time.
timeoutNanos = standbyTime - AudioClock::getNanoseconds();
timeoutNanos = std::max<int64_t>(0, timeoutNanos);
- } // else {
- // If the stream is disconnected and in standby mode, keep `timeoutNanos` as
- // -1 to wait forever until next command as the stream can only be closed.
- // }
- } else if (isRunning() || (isIdle_l() && !isStandby_l())) {
- timeoutNanos = (isRunning() ? std::min(nextTimestampReportTime, nextDataReportTime)
- : standbyTime) - AudioClock::getNanoseconds();
+ }
+ // Otherwise, keep `timeoutNanos` as -1 to wait forever until next command.
+ } else if (isRunning()) {
+ timeoutNanos = std::min(nextTimestampReportTime, nextDataReportTime)
+ - AudioClock::getNanoseconds();
timeoutNanos = std::max<int64_t>(0, timeoutNanos);
}
-
auto command = mCommandQueue.waitForCommand(timeoutNanos);
if (!mThreadEnabled) {
// Break the loop if the thread is disabled.
break;
}
+ // Is it time to send timestamps?
if (isRunning() && !isDisconnected_l()) {
auto currentTimestamp = AudioClock::getNanoseconds();
if (currentTimestamp >= nextDataReportTime) {
@@ -454,19 +454,24 @@
nextTimestampReportTime = timestampScheduler.nextAbsoluteTime();
}
}
- if ((isIdle_l() || isDisconnected_l()) && AudioClock::getNanoseconds() >= standbyTime) {
+
+ // Is it time to enter standby?
+ if ((isIdle_l() || isDisconnected_l())
+ && isStandbyImplemented()
+ && !isStandby_l()
+ && (AudioClock::getNanoseconds() >= standbyTime)) {
+ ALOGD("%s() call standby_l(), %d loops", __func__, loopCount);
aaudio_result_t result = standby_l();
if (result != AAUDIO_OK) {
- // If standby failed because of the function is not implemented, there is no
- // need to retry. Otherwise, retry standby later.
- ALOGW("Failed to enter standby, error=%d", result);
- standbyTime = result == AAUDIO_ERROR_UNIMPLEMENTED
- ? std::numeric_limits<int64_t>::max()
- : AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
+ ALOGW("Failed to enter standby, error = %d", result);
+ // Try again later.
+ standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
}
}
if (command != nullptr) {
+ ALOGD("%s() got COMMAND opcode %d after %d loops",
+ __func__, command->operationCode, loopCount);
std::scoped_lock<std::mutex> _commandLock(command->lock);
switch (command->operationCode) {
case START:
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 8057f87..20737bc 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -316,9 +316,14 @@
mDisconnected = flag;
}
+ // If you implemented this method then please also override isStandbyImplemented().
virtual aaudio_result_t standby_l() REQUIRES(mLock) {
return AAUDIO_ERROR_UNIMPLEMENTED;
}
+ virtual bool isStandbyImplemented() {
+ return false;
+ }
+
class ExitStandbyParam : public AAudioCommandParam {
public:
explicit ExitStandbyParam(AudioEndpointParcelable* parcelable)
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index f4ce83d..f20ea10 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -73,6 +73,9 @@
aaudio_result_t stop_l() REQUIRES(mLock) override;
aaudio_result_t standby_l() REQUIRES(mLock) override;
+ bool isStandbyImplemented() override {
+ return true;
+ }
aaudio_result_t exitStandby_l(AudioEndpointParcelable* parcelable) REQUIRES(mLock) override;